summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CREDITS130
-rw-r--r--FS/Changes5
-rw-r--r--FS/FS.pm239
-rw-r--r--FS/FS/CGI.pm393
-rw-r--r--FS/FS/ClientAPI.pm44
-rw-r--r--FS/FS/ClientAPI/Agent.pm113
-rw-r--r--FS/FS/ClientAPI/MyAccount.pm580
-rw-r--r--FS/FS/ClientAPI/Signup.pm288
-rw-r--r--FS/FS/ClientAPI/passwd.pm53
-rw-r--r--FS/FS/Conf.pm1263
-rw-r--r--FS/FS/ConfItem.pm63
-rw-r--r--FS/FS/InitHandler.pm91
-rw-r--r--FS/FS/Misc.pm102
-rw-r--r--FS/FS/Msgcat.pm98
-rw-r--r--FS/FS/Record.pm1670
-rw-r--r--FS/FS/Report.pm46
-rw-r--r--FS/FS/Report/Table.pm27
-rw-r--r--FS/FS/Report/Table/Monthly.pm172
-rw-r--r--FS/FS/SearchCache.pm96
-rw-r--r--FS/FS/UI/Base.pm194
-rw-r--r--FS/FS/UI/CGI.pm239
-rw-r--r--FS/FS/UI/Gtk.pm224
-rw-r--r--FS/FS/UI/agent.pm62
-rw-r--r--FS/FS/UID.pm316
-rw-r--r--FS/FS/acct_snarf.pm128
-rwxr-xr-xFS/FS/addr_block.pm331
-rw-r--r--FS/FS/agent.pm279
-rw-r--r--FS/FS/agent_type.pm166
-rw-r--r--FS/FS/cust_bill.pm1479
-rw-r--r--FS/FS/cust_bill_event.pm180
-rw-r--r--FS/FS/cust_bill_pay.pm226
-rw-r--r--FS/FS/cust_bill_pkg.pm215
-rw-r--r--FS/FS/cust_bill_pkg_detail.pm124
-rw-r--r--FS/FS/cust_credit.pm330
-rw-r--r--FS/FS/cust_credit_bill.pm192
-rw-r--r--FS/FS/cust_credit_refund.pm205
-rw-r--r--FS/FS/cust_main.pm3033
-rw-r--r--FS/FS/cust_main_county.pm290
-rw-r--r--FS/FS/cust_main_invoice.pm177
-rw-r--r--FS/FS/cust_pay.pm427
-rw-r--r--FS/FS/cust_pay_batch.pm397
-rw-r--r--FS/FS/cust_pkg.pm926
-rw-r--r--FS/FS/cust_refund.pm295
-rw-r--r--FS/FS/cust_svc.pm633
-rw-r--r--FS/FS/cust_tax_exempt.pm132
-rw-r--r--FS/FS/domain_record.pm417
-rw-r--r--FS/FS/export_svc.pm124
-rw-r--r--FS/FS/msgcat.pm132
-rw-r--r--FS/FS/nas.pm154
-rw-r--r--FS/FS/part_bill_event.pm186
-rw-r--r--FS/FS/part_export.pm590
-rw-r--r--FS/FS/part_export/acct_sql.pm177
-rw-r--r--FS/FS/part_export/apache.pm47
-rw-r--r--FS/FS/part_export/bind.pm35
-rw-r--r--FS/FS/part_export/bind_slave.pm28
-rw-r--r--FS/FS/part_export/bsdshell.pm25
-rw-r--r--FS/FS/part_export/communigate_pro.pm178
-rw-r--r--FS/FS/part_export/communigate_pro_singledomain.pm37
-rw-r--r--FS/FS/part_export/cp.pm160
-rw-r--r--FS/FS/part_export/cyrus.pm120
-rw-r--r--FS/FS/part_export/domain_shellcommands.pm161
-rw-r--r--FS/FS/part_export/forward_shellcommands.pm159
-rw-r--r--FS/FS/part_export/http.pm134
-rw-r--r--FS/FS/part_export/infostreet.pm277
-rw-r--r--FS/FS/part_export/ldap.pm294
-rw-r--r--FS/FS/part_export/null.pm13
-rw-r--r--FS/FS/part_export/passwdfile.pm18
-rw-r--r--FS/FS/part_export/postfix.pm32
-rw-r--r--FS/FS/part_export/router.pm190
-rw-r--r--FS/FS/part_export/shellcommands.pm338
-rw-r--r--FS/FS/part_export/shellcommands_withdomain.pm105
-rw-r--r--FS/FS/part_export/sqlmail.pm220
-rw-r--r--FS/FS/part_export/sqlradius.pm337
-rw-r--r--FS/FS/part_export/sqlradius_withdomain.pm28
-rw-r--r--FS/FS/part_export/sysvshell.pm25
-rw-r--r--FS/FS/part_export/textradius.pm191
-rw-r--r--FS/FS/part_export/vpopmail.pm252
-rw-r--r--FS/FS/part_export/www_shellcommands.pm166
-rw-r--r--FS/FS/part_export_option.pm134
-rw-r--r--FS/FS/part_pkg.pm333
-rw-r--r--FS/FS/part_pop_local.pm117
-rw-r--r--FS/FS/part_referral.pm126
-rw-r--r--FS/FS/part_svc.pm324
-rw-r--r--FS/FS/part_svc_column.pm118
-rwxr-xr-xFS/FS/part_svc_router.pm32
-rwxr-xr-xFS/FS/part_virtual_field.pm303
-rw-r--r--FS/FS/pkg_svc.pm155
-rw-r--r--FS/FS/port.pm160
-rw-r--r--FS/FS/prepay_credit.pm127
-rw-r--r--FS/FS/queue.pm438
-rw-r--r--FS/FS/queue_arg.pm121
-rw-r--r--FS/FS/queue_depend.pm121
-rw-r--r--FS/FS/raddb.pm1599
-rw-r--r--FS/FS/radius_usergroup.pm131
-rwxr-xr-xFS/FS/router.pm144
-rw-r--r--FS/FS/session.pm269
-rw-r--r--FS/FS/svc_Common.pm515
-rw-r--r--FS/FS/svc_acct.pm1415
-rw-r--r--FS/FS/svc_acct_pop.pm210
-rwxr-xr-xFS/FS/svc_broadband.pm243
-rw-r--r--FS/FS/svc_domain.pm445
-rw-r--r--FS/FS/svc_external.pm180
-rw-r--r--FS/FS/svc_forward.pm306
-rw-r--r--FS/FS/svc_www.pm284
-rw-r--r--FS/FS/type_pkgs.pm126
-rw-r--r--FS/MANIFEST210
-rw-r--r--FS/MANIFEST.SKIP1
-rw-r--r--FS/Makefile.PL10
-rw-r--r--FS/README6
-rw-r--r--FS/bin/freeside-addoutsource24
-rw-r--r--FS/bin/freeside-addoutsourceuser15
-rw-r--r--FS/bin/freeside-adduser63
-rwxr-xr-xFS/bin/freeside-apply-credits21
-rwxr-xr-xFS/bin/freeside-bill128
-rwxr-xr-xFS/bin/freeside-count-active-customers17
-rwxr-xr-xFS/bin/freeside-daily141
-rw-r--r--FS/bin/freeside-deloutsource11
-rw-r--r--FS/bin/freeside-deloutsourceuser6
-rw-r--r--FS/bin/freeside-deluser64
-rwxr-xr-xFS/bin/freeside-email59
-rwxr-xr-xFS/bin/freeside-expiration-alerter226
-rw-r--r--FS/bin/freeside-queued267
-rw-r--r--FS/bin/freeside-radgroup76
-rw-r--r--FS/bin/freeside-reexport71
-rw-r--r--FS/bin/freeside-selfservice-server266
-rw-r--r--FS/bin/freeside-setinvoice42
-rwxr-xr-xFS/bin/freeside-setup1123
-rw-r--r--FS/bin/freeside-sqlradius-radacctd180
-rwxr-xr-xFS/bin/freeside-sqlradius-reset76
-rw-r--r--FS/bin/freeside-sqlradius-seconds58
-rw-r--r--FS/t/CGI.t5
-rw-r--r--FS/t/ClientAPI.t5
-rw-r--r--FS/t/Conf.t5
-rw-r--r--FS/t/ConfItem.t5
-rw-r--r--FS/t/InitHandler.t5
-rw-r--r--FS/t/Misc.t5
-rw-r--r--FS/t/Msgcat.t5
-rw-r--r--FS/t/Record.t5
-rw-r--r--FS/t/Report-Table-Monthly.t5
-rw-r--r--FS/t/Report-Table.t5
-rw-r--r--FS/t/Report.t5
-rw-r--r--FS/t/SearchCache.t5
-rw-r--r--FS/t/UID.t5
-rw-r--r--FS/t/acct_snarf.t5
-rw-r--r--FS/t/agent.t5
-rw-r--r--FS/t/agent_type.t5
-rw-r--r--FS/t/cust_bill.t5
-rw-r--r--FS/t/cust_bill_event.t5
-rw-r--r--FS/t/cust_bill_pay.t5
-rw-r--r--FS/t/cust_bill_pkg.t5
-rw-r--r--FS/t/cust_bill_pkg_detail.t5
-rw-r--r--FS/t/cust_credit.t5
-rw-r--r--FS/t/cust_credit_bill.t5
-rw-r--r--FS/t/cust_credit_refund.t5
-rw-r--r--FS/t/cust_main.t5
-rw-r--r--FS/t/cust_main_county.t5
-rw-r--r--FS/t/cust_main_invoice.t5
-rw-r--r--FS/t/cust_pay.t5
-rw-r--r--FS/t/cust_pay_batch.t5
-rw-r--r--FS/t/cust_pkg.t5
-rw-r--r--FS/t/cust_refund.t5
-rw-r--r--FS/t/cust_svc.t5
-rw-r--r--FS/t/cust_tax_exempt.pm5
-rw-r--r--FS/t/cust_tax_exempt.t5
-rw-r--r--FS/t/domain_record.t5
-rw-r--r--FS/t/export_svc.t5
-rw-r--r--FS/t/msgcat.t5
-rw-r--r--FS/t/nas.t5
-rw-r--r--FS/t/part_bill_event.t5
-rw-r--r--FS/t/part_export-acct_sql.t5
-rw-r--r--FS/t/part_export-apache.t5
-rw-r--r--FS/t/part_export-bind.t5
-rw-r--r--FS/t/part_export-bind_slave.t5
-rw-r--r--FS/t/part_export-bsdshell.t5
-rw-r--r--FS/t/part_export-communigate_pro.t5
-rw-r--r--FS/t/part_export-communigate_pro_singledomain.t5
-rw-r--r--FS/t/part_export-cp.t5
-rw-r--r--FS/t/part_export-cyrus.t5
-rw-r--r--FS/t/part_export-domain_shellcommands.t5
-rw-r--r--FS/t/part_export-forward_shellcommands.t5
-rw-r--r--FS/t/part_export-http.t5
-rw-r--r--FS/t/part_export-infostreet.t5
-rw-r--r--FS/t/part_export-ldap.t5
-rw-r--r--FS/t/part_export-null.t5
-rw-r--r--FS/t/part_export-passwdfile.t5
-rw-r--r--FS/t/part_export-postfix.t5
-rw-r--r--FS/t/part_export-router.t5
-rw-r--r--FS/t/part_export-shellcommands.t5
-rw-r--r--FS/t/part_export-shellcommands_withdomain.t5
-rw-r--r--FS/t/part_export-sqlmail.t5
-rw-r--r--FS/t/part_export-sqlradius.t5
-rw-r--r--FS/t/part_export-sqlradius_withdomain.t5
-rw-r--r--FS/t/part_export-sysvshell.t5
-rw-r--r--FS/t/part_export-textradius.t5
-rw-r--r--FS/t/part_export-vpopmail.t5
-rw-r--r--FS/t/part_export-www_shellcommands.t5
-rw-r--r--FS/t/part_export.t5
-rw-r--r--FS/t/part_export_option.t5
-rw-r--r--FS/t/part_pkg.t5
-rw-r--r--FS/t/part_pop_local.t5
-rw-r--r--FS/t/part_referral.t5
-rw-r--r--FS/t/part_svc.t5
-rw-r--r--FS/t/part_svc_column.t5
-rw-r--r--FS/t/pkg_svc.t5
-rw-r--r--FS/t/port.t5
-rw-r--r--FS/t/prepay_credit.t5
-rw-r--r--FS/t/queue.t5
-rw-r--r--FS/t/queue_arg.t5
-rw-r--r--FS/t/queue_depend.t5
-rw-r--r--FS/t/raddb.t5
-rw-r--r--FS/t/radius_usergroup.t5
-rw-r--r--FS/t/session.t5
-rw-r--r--FS/t/svc_Common.t5
-rw-r--r--FS/t/svc_acct.t5
-rw-r--r--FS/t/svc_acct_pop.t5
-rw-r--r--FS/t/svc_broadband.t5
-rw-r--r--FS/t/svc_domain.t5
-rw-r--r--FS/t/svc_external.t5
-rw-r--r--FS/t/svc_forward.t5
-rw-r--r--FS/t/svc_www.t5
-rw-r--r--FS/t/type_pkgs.t5
-rw-r--r--GPL339
-rw-r--r--INSTALL1
-rw-r--r--Makefile294
-rw-r--r--README43
-rw-r--r--README.1.5.0pre117
-rw-r--r--TODO9
-rwxr-xr-xbin/apache.export67
-rwxr-xr-xbin/bind.export191
-rwxr-xr-xbin/bind.import214
-rwxr-xr-xbin/bsdshell.export114
-rw-r--r--bin/create-fetchmailrc47
-rwxr-xr-xbin/create-history-tables93
-rwxr-xr-xbin/dbdef-create24
-rwxr-xr-xbin/fix-sequences69
-rwxr-xr-xbin/freeside-init60
-rwxr-xr-xbin/freeside-session-kill103
-rw-r--r--bin/freeside.import146
-rwxr-xr-xbin/fs-migrate-part_svc41
-rwxr-xr-xbin/fs-migrate-payref31
-rwxr-xr-xbin/fs-migrate-svc_acct_sm229
-rwxr-xr-xbin/fs-radius-add-check68
-rwxr-xr-xbin/fs-radius-add-reply69
-rwxr-xr-xbin/generate-prepay35
-rwxr-xr-xbin/generate-raddb47
-rwxr-xr-xbin/generate-tests21
-rwxr-xr-xbin/masonize80
-rwxr-xr-xbin/passwd.import120
-rwxr-xr-xbin/pod2x56
-rwxr-xr-xbin/populate-msgcat127
-rwxr-xr-xbin/postfix.export122
-rwxr-xr-xbin/postfix_courierimap.import137
-rw-r--r--bin/sendmail.import178
-rw-r--r--bin/sequences.reset32
-rwxr-xr-xbin/shadow.reimport125
-rwxr-xr-xbin/sqlradius-norealm.reimport113
-rw-r--r--bin/sqlradius.import152
-rwxr-xr-xbin/sqlradius.reimport160
-rwxr-xr-xbin/svc_acct.export641
-rwxr-xr-xbin/svc_acct.import238
-rwxr-xr-xbin/svc_domain.erase17
-rwxr-xr-xbin/sysvshell.export112
-rw-r--r--conf/agent_defaultpkg0
-rw-r--r--conf/alerter_template20
-rw-r--r--conf/declinetemplate10
-rw-r--r--conf/home1
-rw-r--r--conf/invoice_from1
-rw-r--r--conf/invoice_latex155
-rw-r--r--conf/invoice_latexfooter5
-rw-r--r--conf/invoice_latexnotes9
-rw-r--r--conf/invoice_latexsmallfooter1
-rw-r--r--conf/invoice_template27
-rw-r--r--conf/locale1
-rw-r--r--conf/logo.eps1267
-rw-r--r--conf/lpr1
-rw-r--r--conf/maxsearchrecordsperpage1
-rw-r--r--conf/report_template14
-rw-r--r--conf/shells5
-rw-r--r--conf/show-msgcat-codes0
-rw-r--r--conf/smtpmachine1
-rw-r--r--conf/soadefaultttl1
-rw-r--r--conf/soaexpire1
-rw-r--r--conf/soarefresh1
-rw-r--r--conf/soaretry1
-rw-r--r--debian/README.Debian6
-rw-r--r--debian/changelog9
-rw-r--r--debian/conffiles.ex7
-rw-r--r--debian/control59
-rw-r--r--debian/copyright10
-rw-r--r--debian/cron.d.ex4
-rw-r--r--debian/dirs2
-rw-r--r--debian/docs3
-rw-r--r--debian/ex.doc-base.package22
-rw-r--r--debian/freeside-doc.docs2
-rw-r--r--debian/freeside-doc.files2
-rw-r--r--debian/init.d.ex70
-rw-r--r--debian/manpage.1.ex60
-rw-r--r--debian/manpage.sgml.ex143
-rw-r--r--debian/menu.ex2
-rw-r--r--debian/postinst.ex47
-rw-r--r--debian/postrm.ex36
-rw-r--r--debian/preinst.ex42
-rw-r--r--debian/prerm.ex37
-rwxr-xr-xdebian/rules113
-rw-r--r--debian/watch.ex5
-rwxr-xr-xeg/TEMPLATE_cust_main.import198
-rw-r--r--eg/export_template.pm81
-rw-r--r--eg/table_template-svc.pm161
-rw-r--r--eg/table_template.pm112
-rw-r--r--etc/abbr_state.txt72
-rw-r--r--etc/countries.txt239
-rw-r--r--etc/domain-template.txt231
-rwxr-xr-xetc/megapop.pl116
-rw-r--r--etc/sql-reserved-words.txt103
-rwxr-xr-xfs_passwd/fs_passwd131
-rwxr-xr-xfs_radlog/fs_radlogd51
-rwxr-xr-xfs_selfadmin/FS-MailAdminServer/MailAdminClient.pm541
-rwxr-xr-xfs_selfadmin/FS-MailAdminServer/cgi/mailadmin.cgi698
-rwxr-xr-xfs_selfadmin/FS-MailAdminServer/fs_mailadmind366
-rw-r--r--fs_selfadmin/README27
-rwxr-xr-xfs_selfadmin/fs_mailadmin_server642
-rwxr-xr-xfs_selfservice/DEPLOY20
-rw-r--r--fs_selfservice/FS-SelfService/Changes6
-rw-r--r--fs_selfservice/FS-SelfService/MANIFEST6
-rw-r--r--fs_selfservice/FS-SelfService/Makefile.PL19
-rw-r--r--fs_selfservice/FS-SelfService/SelfService.pm1057
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent.cgi265
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_login.html22
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_main.html40
-rw-r--r--fs_selfservice/FS-SelfService/cgi/cvv2.html25
-rw-r--r--fs_selfservice/FS-SelfService/cgi/cvv2.pngbin0 -> 3854 bytes
-rw-r--r--fs_selfservice/FS-SelfService/cgi/cvv2_amex.pngbin0 -> 4573 bytes
-rw-r--r--fs_selfservice/FS-SelfService/cgi/list_customers.html41
-rw-r--r--fs_selfservice/FS-SelfService/cgi/login.html29
-rw-r--r--fs_selfservice/FS-SelfService/cgi/make_payment.html120
-rw-r--r--fs_selfservice/FS-SelfService/cgi/myaccount.html47
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/passwd.cgi60
-rw-r--r--fs_selfservice/FS-SelfService/cgi/passwd.html28
-rw-r--r--fs_selfservice/FS-SelfService/cgi/payment_results.html18
-rw-r--r--fs_selfservice/FS-SelfService/cgi/selfservice.cgi188
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup.html233
-rw-r--r--fs_selfservice/FS-SelfService/cgi/view_customer.html84
-rw-r--r--fs_selfservice/FS-SelfService/cgi/view_invoice.html21
-rw-r--r--fs_selfservice/FS-SelfService/freeside-selfservice-clientd256
-rw-r--r--fs_selfservice/FS-SelfService/test.pl17
-rwxr-xr-xfs_selfservice/fs_passwd_test19
-rw-r--r--fs_sesmon/FS-SessionClient/Changes5
-rw-r--r--fs_sesmon/FS-SessionClient/MANIFEST11
-rw-r--r--fs_sesmon/FS-SessionClient/MANIFEST.SKIP1
-rw-r--r--fs_sesmon/FS-SessionClient/Makefile.PL10
-rw-r--r--fs_sesmon/FS-SessionClient/SessionClient.pm122
-rw-r--r--fs_sesmon/FS-SessionClient/bin/freeside-login36
-rw-r--r--fs_sesmon/FS-SessionClient/bin/freeside-logout36
-rw-r--r--fs_sesmon/FS-SessionClient/cgi/login.cgi108
-rw-r--r--fs_sesmon/FS-SessionClient/cgi/logout.cgi83
-rw-r--r--fs_sesmon/FS-SessionClient/fs_sessiond65
-rw-r--r--fs_sesmon/FS-SessionClient/test.pl21
-rw-r--r--fs_sesmon/fs_session_server140
-rw-r--r--fs_signup/FS-SignupClient/Changes5
-rw-r--r--fs_signup/FS-SignupClient/MANIFEST7
-rw-r--r--fs_signup/FS-SignupClient/MANIFEST.SKIP1
-rw-r--r--fs_signup/FS-SignupClient/Makefile.PL17
-rw-r--r--fs_signup/FS-SignupClient/SignupClient.pm208
-rw-r--r--fs_signup/FS-SignupClient/cgi/cvv2.html25
-rw-r--r--fs_signup/FS-SignupClient/cgi/cvv2.pngbin0 -> 3854 bytes
-rw-r--r--fs_signup/FS-SignupClient/cgi/cvv2_amex.pngbin0 -> 4573 bytes
-rw-r--r--fs_signup/FS-SignupClient/cgi/decline.html5
-rw-r--r--fs_signup/FS-SignupClient/cgi/map.gifbin0 -> 8181 bytes
-rwxr-xr-xfs_signup/FS-SignupClient/cgi/signup-agentselect.html195
-rwxr-xr-xfs_signup/FS-SignupClient/cgi/signup-alternate.html218
-rwxr-xr-xfs_signup/FS-SignupClient/cgi/signup-snarf.html228
-rwxr-xr-xfs_signup/FS-SignupClient/cgi/signup.cgi388
-rwxr-xr-xfs_signup/FS-SignupClient/cgi/signup.html219
-rw-r--r--fs_signup/FS-SignupClient/cgi/stateselect.html134
-rw-r--r--fs_signup/FS-SignupClient/cgi/success.html11
-rw-r--r--fs_signup/FS-SignupClient/test.pl20
-rw-r--r--fs_signup/cck.template14
-rwxr-xr-xfs_signup/ieak.template40
-rwxr-xr-xfs_webdemo/register.cgi136
-rw-r--r--fs_webdemo/register.html33
-rwxr-xr-xfs_webdemo/registerd192
-rwxr-xr-xfs_webdemo/registerd.Pg221
-rw-r--r--htetc/global.asa238
-rw-r--r--htetc/handler.pl301
-rwxr-xr-xhttemplate/.htaccess3
-rw-r--r--httemplate/autohandler21
-rw-r--r--httemplate/browse/addr_block.cgi76
-rwxr-xr-xhttemplate/browse/agent.cgi100
-rwxr-xr-xhttemplate/browse/agent_type.cgi60
-rwxr-xr-xhttemplate/browse/cust_main_county.cgi142
-rwxr-xr-xhttemplate/browse/cust_pay_batch.cgi76
-rw-r--r--httemplate/browse/generic.cgi46
-rwxr-xr-xhttemplate/browse/msgcat.cgi50
-rwxr-xr-xhttemplate/browse/nas.cgi80
-rwxr-xr-xhttemplate/browse/part_bill_event.cgi71
-rwxr-xr-xhttemplate/browse/part_export.cgi39
-rwxr-xr-xhttemplate/browse/part_pkg.cgi173
-rwxr-xr-xhttemplate/browse/part_referral.cgi97
-rwxr-xr-xhttemplate/browse/part_svc.cgi133
-rw-r--r--httemplate/browse/part_virtual_field.cgi39
-rwxr-xr-xhttemplate/browse/queue.cgi7
-rw-r--r--httemplate/browse/router.cgi57
-rwxr-xr-xhttemplate/browse/svc_acct_pop.cgi63
-rw-r--r--httemplate/config/config-process.cgi51
-rw-r--r--httemplate/config/config-view.cgi64
-rw-r--r--httemplate/config/config.cgi176
-rw-r--r--httemplate/docs/ach.html12
-rwxr-xr-xhttemplate/docs/admin.html81
-rw-r--r--httemplate/docs/billing.html54
-rw-r--r--httemplate/docs/config.html36
-rw-r--r--httemplate/docs/cvv2.html25
-rwxr-xr-xhttemplate/docs/export.html55
-rw-r--r--httemplate/docs/ieak.html75
-rw-r--r--httemplate/docs/index.html30
-rw-r--r--httemplate/docs/install.html212
-rwxr-xr-xhttemplate/docs/legacy.html39
-rw-r--r--httemplate/docs/man/FS/part_export/.cvs_is_on_crack0
-rw-r--r--httemplate/docs/overview.diabin0 -> 2800 bytes
-rw-r--r--httemplate/docs/overview.pngbin0 -> 13064 bytes
-rwxr-xr-xhttemplate/docs/passwd.html23
-rw-r--r--httemplate/docs/schema.diabin0 -> 14438 bytes
-rw-r--r--httemplate/docs/schema.html435
-rw-r--r--httemplate/docs/schema.pngbin0 -> 681043 bytes
-rw-r--r--httemplate/docs/session.html59
-rw-r--r--httemplate/docs/signup.html54
-rwxr-xr-xhttemplate/docs/ssh.html16
-rwxr-xr-xhttemplate/docs/trouble.html26
-rw-r--r--httemplate/docs/upgrade-1.4.2.html27
-rw-r--r--httemplate/docs/upgrade10.html226
-rw-r--r--httemplate/docs/upgrade7.html24
-rw-r--r--httemplate/docs/upgrade8.html392
-rw-r--r--httemplate/docs/upgrade9.html28
-rwxr-xr-xhttemplate/edit/REAL_cust_pkg.cgi131
-rwxr-xr-xhttemplate/edit/agent.cgi79
-rwxr-xr-xhttemplate/edit/agent_type.cgi63
-rwxr-xr-xhttemplate/edit/cust_bill_pay.cgi95
-rwxr-xr-xhttemplate/edit/cust_credit.cgi63
-rwxr-xr-xhttemplate/edit/cust_credit_bill.cgi101
-rwxr-xr-xhttemplate/edit/cust_main.cgi572
-rwxr-xr-xhttemplate/edit/cust_main_county-expand.cgi54
-rwxr-xr-xhttemplate/edit/cust_main_county.cgi98
-rwxr-xr-xhttemplate/edit/cust_pay.cgi129
-rwxr-xr-xhttemplate/edit/cust_pkg.cgi117
-rwxr-xr-xhttemplate/edit/msgcat.cgi58
-rwxr-xr-xhttemplate/edit/part_bill_event.cgi288
-rw-r--r--httemplate/edit/part_export.cgi128
-rwxr-xr-xhttemplate/edit/part_pkg.cgi627
-rwxr-xr-xhttemplate/edit/part_referral.cgi48
-rwxr-xr-xhttemplate/edit/part_svc.cgi284
-rw-r--r--httemplate/edit/part_virtual_field.cgi92
-rwxr-xr-xhttemplate/edit/process/REAL_cust_pkg.cgi24
-rwxr-xr-xhttemplate/edit/process/addr_block/add.cgi20
-rwxr-xr-xhttemplate/edit/process/addr_block/allocate.cgi25
-rwxr-xr-xhttemplate/edit/process/addr_block/deallocate.cgi24
-rwxr-xr-xhttemplate/edit/process/addr_block/split.cgi19
-rwxr-xr-xhttemplate/edit/process/agent.cgi28
-rwxr-xr-xhttemplate/edit/process/agent_type.cgi55
-rwxr-xr-xhttemplate/edit/process/cust_bill_pay.cgi31
-rwxr-xr-xhttemplate/edit/process/cust_credit.cgi30
-rwxr-xr-xhttemplate/edit/process/cust_credit_bill.cgi43
-rwxr-xr-xhttemplate/edit/process/cust_main.cgi133
-rwxr-xr-xhttemplate/edit/process/cust_main_county-collapse.cgi35
-rwxr-xr-xhttemplate/edit/process/cust_main_county-expand.cgi58
-rwxr-xr-xhttemplate/edit/process/cust_main_county.cgi30
-rwxr-xr-xhttemplate/edit/process/cust_pay.cgi39
-rwxr-xr-xhttemplate/edit/process/cust_pkg.cgi43
-rwxr-xr-xhttemplate/edit/process/domain_record.cgi34
-rw-r--r--httemplate/edit/process/generic.cgi70
-rw-r--r--httemplate/edit/process/msgcat.cgi20
-rwxr-xr-xhttemplate/edit/process/part_bill_event.cgi54
-rw-r--r--httemplate/edit/process/part_export.cgi39
-rwxr-xr-xhttemplate/edit/process/part_pkg.cgi117
-rwxr-xr-xhttemplate/edit/process/part_referral.cgi28
-rwxr-xr-xhttemplate/edit/process/part_svc.cgi62
-rw-r--r--httemplate/edit/process/quick-charge.cgi32
-rw-r--r--httemplate/edit/process/quick-cust_pkg.cgi25
-rw-r--r--httemplate/edit/process/router.cgi67
-rwxr-xr-xhttemplate/edit/process/svc_acct.cgi49
-rwxr-xr-xhttemplate/edit/process/svc_acct_pop.cgi28
-rw-r--r--httemplate/edit/process/svc_broadband.cgi45
-rwxr-xr-xhttemplate/edit/process/svc_domain.cgi31
-rwxr-xr-xhttemplate/edit/process/svc_external.cgi29
-rwxr-xr-xhttemplate/edit/process/svc_forward.cgi29
-rw-r--r--httemplate/edit/process/svc_www.cgi36
-rwxr-xr-xhttemplate/edit/router.cgi77
-rwxr-xr-xhttemplate/edit/svc_acct.cgi301
-rwxr-xr-xhttemplate/edit/svc_acct_pop.cgi56
-rw-r--r--httemplate/edit/svc_broadband.cgi175
-rwxr-xr-xhttemplate/edit/svc_domain.cgi98
-rw-r--r--httemplate/edit/svc_external.cgi105
-rwxr-xr-xhttemplate/edit/svc_forward.cgi177
-rw-r--r--httemplate/edit/svc_www.cgi221
-rw-r--r--httemplate/elements/calendar-en.js114
-rw-r--r--httemplate/elements/calendar-setup.js163
-rw-r--r--httemplate/elements/calendar-win2k-2.css263
-rw-r--r--httemplate/elements/calendar.js1641
-rw-r--r--httemplate/elements/calendar_stripped.js12
-rw-r--r--httemplate/elements/header.html19
-rw-r--r--httemplate/elements/menubar.html8
-rw-r--r--httemplate/elements/pager.html42
-rw-r--r--httemplate/elements/small_custview.html2
-rw-r--r--httemplate/elements/table.html8
-rwxr-xr-xhttemplate/graph/money_time-graph.cgi68
-rw-r--r--httemplate/graph/money_time.cgi125
-rw-r--r--httemplate/images/ach.pngbin0 -> 29759 bytes
-rw-r--r--httemplate/images/calendar.pngbin0 -> 426 bytes
-rw-r--r--httemplate/images/cvv2.pngbin0 -> 3854 bytes
-rw-r--r--httemplate/images/cvv2_amex.pngbin0 -> 4573 bytes
-rw-r--r--httemplate/images/mid-logo.pngbin0 -> 9727 bytes
-rw-r--r--httemplate/images/small-logo.pngbin0 -> 4781 bytes
-rw-r--r--httemplate/index.html206
-rwxr-xr-xhttemplate/misc/bill.cgi38
-rwxr-xr-xhttemplate/misc/cancel-unaudited.cgi34
-rwxr-xr-xhttemplate/misc/cancel_pkg.cgi15
-rwxr-xr-xhttemplate/misc/catchall.cgi133
-rwxr-xr-xhttemplate/misc/change_pkg.cgi66
-rwxr-xr-xhttemplate/misc/cust_main-cancel.cgi16
-rw-r--r--httemplate/misc/cust_main-import.cgi51
-rw-r--r--httemplate/misc/cust_main-import_charges.cgi14
-rwxr-xr-xhttemplate/misc/delete-cust_credit.cgi16
-rwxr-xr-xhttemplate/misc/delete-cust_pay.cgi16
-rwxr-xr-xhttemplate/misc/delete-customer.cgi60
-rwxr-xr-xhttemplate/misc/delete-domain_record.cgi15
-rwxr-xr-xhttemplate/misc/delete-part_export.cgi15
-rw-r--r--httemplate/misc/download-batch.cgi16
-rw-r--r--httemplate/misc/dump.cgi19
-rwxr-xr-xhttemplate/misc/email-invoice.cgi23
-rwxr-xr-xhttemplate/misc/expire_pkg.cgi55
-rwxr-xr-xhttemplate/misc/link.cgi74
-rw-r--r--httemplate/misc/meta-import.cgi64
-rw-r--r--httemplate/misc/payment.cgi209
-rwxr-xr-xhttemplate/misc/print-invoice.cgi29
-rwxr-xr-xhttemplate/misc/process/catchall.cgi33
-rw-r--r--httemplate/misc/process/cust_main-import.cgi30
-rw-r--r--httemplate/misc/process/cust_main-import_charges.cgi26
-rwxr-xr-xhttemplate/misc/process/delete-customer.cgi29
-rwxr-xr-xhttemplate/misc/process/expire_pkg.cgi25
-rwxr-xr-xhttemplate/misc/process/link.cgi54
-rw-r--r--httemplate/misc/process/meta-import.cgi178
-rw-r--r--httemplate/misc/process/payment.cgi148
-rw-r--r--httemplate/misc/queue.cgi47
-rwxr-xr-xhttemplate/misc/susp_pkg.cgi15
-rwxr-xr-xhttemplate/misc/unapply-cust_credit.cgi18
-rwxr-xr-xhttemplate/misc/unapply-cust_pay.cgi18
-rwxr-xr-xhttemplate/misc/unprovision.cgi29
-rwxr-xr-xhttemplate/misc/unsusp_pkg.cgi15
-rw-r--r--httemplate/misc/upload-batch.cgi30
-rw-r--r--httemplate/misc/whois.cgi25
-rwxr-xr-xhttemplate/search/cust_bill.cgi165
-rwxr-xr-xhttemplate/search/cust_bill.html101
-rw-r--r--httemplate/search/cust_bill_event.cgi62
-rwxr-xr-xhttemplate/search/cust_bill_event.html23
-rwxr-xr-xhttemplate/search/cust_credit.html76
-rwxr-xr-xhttemplate/search/cust_main-otaker.cgi28
-rwxr-xr-xhttemplate/search/cust_main-payinfo.html20
-rwxr-xr-xhttemplate/search/cust_main-quickpay.html44
-rwxr-xr-xhttemplate/search/cust_main.cgi640
-rwxr-xr-xhttemplate/search/cust_main.html42
-rwxr-xr-xhttemplate/search/cust_pay.cgi133
-rwxr-xr-xhttemplate/search/cust_pay.html18
-rwxr-xr-xhttemplate/search/cust_pkg.cgi363
-rwxr-xr-xhttemplate/search/cust_pkg_report.cgi63
-rw-r--r--httemplate/search/elements/search.html126
-rw-r--r--httemplate/search/report_cust_credit.html57
-rw-r--r--httemplate/search/report_cust_pay.html54
-rw-r--r--httemplate/search/report_prepaid_income.cgi86
-rw-r--r--httemplate/search/report_prepaid_income.html39
-rwxr-xr-xhttemplate/search/report_receivables.cgi158
-rwxr-xr-xhttemplate/search/report_tax.cgi168
-rwxr-xr-xhttemplate/search/report_tax.html43
-rw-r--r--httemplate/search/sql.html7
-rwxr-xr-xhttemplate/search/svc_acct.cgi294
-rwxr-xr-xhttemplate/search/svc_acct.html19
-rwxr-xr-xhttemplate/search/svc_domain.cgi161
-rwxr-xr-xhttemplate/search/svc_domain.html19
-rwxr-xr-xhttemplate/search/svc_forward.cgi79
-rwxr-xr-xhttemplate/search/svc_www.cgi42
-rwxr-xr-xhttemplate/view/cust_bill-pdf.cgi17
-rwxr-xr-xhttemplate/view/cust_bill-ps.cgi13
-rwxr-xr-xhttemplate/view/cust_bill.cgi61
-rwxr-xr-xhttemplate/view/cust_main.cgi1020
-rwxr-xr-xhttemplate/view/cust_pkg.cgi164
-rwxr-xr-xhttemplate/view/svc_acct.cgi216
-rw-r--r--httemplate/view/svc_broadband.cgi142
-rwxr-xr-xhttemplate/view/svc_domain.cgi108
-rw-r--r--httemplate/view/svc_external.cgi51
-rwxr-xr-xhttemplate/view/svc_forward.cgi84
-rw-r--r--httemplate/view/svc_www.cgi61
-rw-r--r--init.d/freeside-init58
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/Changes352
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/MANIFEST38
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/Makefile.PL83
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/Pg.h46
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/Pg.pm1913
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/Pg.xs644
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/README166
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/README.win3263
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/dbd-pg.pod411
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/dbdimp.c2024
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/dbdimp.h81
-rwxr-xr-xinstall/5.005/DBD-Pg-1.22-fixvercmp/eg/ApacheDBI.pl70
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/eg/lotest.pl74
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/eg/notify_test.patch82
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/00basic.t10
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/01connect.t26
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/01constants.t25
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/01setup.t38
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/02prepare.t84
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/03bind.t85
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/04execute.t113
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/05fetch.t131
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/06disconnect.t31
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/07reuse.t28
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/08txn.t102
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/09autocommit.t68
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/11quoting.t50
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/12placeholders.t125
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/13pgtype.t43
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/15funct.t353
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/99cleanup.t24
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info.pm1167
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler.pm305
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler/Prompt.pm170
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS.pm55
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS/PostgreSQL.pm730
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Request.pm287
-rw-r--r--install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Util.pm456
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/Changes62
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema.pm367
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup.pm141
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Index.pm37
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Unique.pm38
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/Column.pm300
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD.pm113
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Pg.pm175
-rwxr-xr-xinstall/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Sybase.pm141
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/mysql.pm126
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/Table.pm471
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/MANIFEST19
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/MANIFEST.SKIP1
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/Makefile.PL11
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/README42
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/TODO6
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load-mysql.t5
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load-pg.t12
-rw-r--r--install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load.t5
-rw-r--r--install/5.005/Net-Whois-Raw/COPYRIGHT7
-rw-r--r--install/5.005/Net-Whois-Raw/Changes53
-rw-r--r--install/5.005/Net-Whois-Raw/MANIFEST10
-rw-r--r--install/5.005/Net-Whois-Raw/META.yml11
-rwxr-xr-xinstall/5.005/Net-Whois-Raw/Makefile.PL24
-rw-r--r--install/5.005/Net-Whois-Raw/README129
-rw-r--r--install/5.005/Net-Whois-Raw/lib/Net/Whois/Raw.pm393
-rw-r--r--install/5.005/Net-Whois-Raw/lib/Net/Whois/Raw/Data.pm509
-rwxr-xr-xinstall/5.005/Net-Whois-Raw/pwhois106
-rw-r--r--install/5.005/Net-Whois-Raw/t/01.t22
-rw-r--r--install/debian/3.0/INSTALL31
-rwxr-xr-xinstall/fedora/fc1/INSTALL66
-rw-r--r--install/fedora/fc1/sources.list12
-rwxr-xr-xinstall/freebsd/INSTALL40
-rw-r--r--install/freebsd/ports44
-rw-r--r--install/openbsd/INSTALL54
-rw-r--r--install/openbsd/cpan15
-rw-r--r--install/openbsd/ports24
-rw-r--r--install/redhat/7.3/INSTALL40
-rw-r--r--install/redhat/7.3/sources.list2
-rw-r--r--install/redhat/9/INSTALL48
-rw-r--r--install/redhat/9/sources.list2
-rw-r--r--install/suse/9.0/INSTALL52
-rw-r--r--rt/FREESIDE_MODIFIED6
-rwxr-xr-xrt/bin/rt1816
-rw-r--r--rt/config.layout.in (renamed from rt/config.layout)23
-rw-r--r--rt/etc/RT_SiteConfig.pm12
-rw-r--r--rt/etc/schema.Oracle354
-rw-r--r--rt/lib/RT/URI/freeside.pm188
-rw-r--r--rt/sbin/rt-setup-database5
-rw-r--r--rt/sbin/rt-setup-database.in5
-rw-r--r--sql-ledger/SL/AM.pm694
-rw-r--r--sql-ledger/SL/AP.pm381
-rw-r--r--sql-ledger/SL/AR.pm381
-rw-r--r--sql-ledger/SL/CA.pm262
-rw-r--r--sql-ledger/SL/CP.pm308
-rw-r--r--sql-ledger/SL/CT.pm447
-rw-r--r--sql-ledger/SL/Form.pm1397
-rw-r--r--sql-ledger/SL/GL.pm462
-rw-r--r--sql-ledger/SL/IC.pm936
-rw-r--r--sql-ledger/SL/IR.pm995
-rw-r--r--sql-ledger/SL/IS.pm1231
-rw-r--r--sql-ledger/SL/Inifile.pm87
-rw-r--r--sql-ledger/SL/Mailer.pm147
-rw-r--r--sql-ledger/SL/Menu.pm117
-rw-r--r--sql-ledger/SL/Num2text.pm162
-rw-r--r--sql-ledger/SL/OE.pm674
-rw-r--r--sql-ledger/SL/PE.pm276
-rw-r--r--sql-ledger/SL/RC.pm186
-rw-r--r--sql-ledger/SL/RP.pm1310
-rw-r--r--sql-ledger/SL/User.pm692
-rw-r--r--sql-ledger/VERSION1
-rwxr-xr-xsql-ledger/am.pl126
-rw-r--r--sql-ledger/bin/lynx/menu.pl128
-rw-r--r--sql-ledger/bin/mozilla/admin.pl1504
-rw-r--r--sql-ledger/bin/mozilla/am.pl1051
-rw-r--r--sql-ledger/bin/mozilla/ap.pl1103
-rw-r--r--sql-ledger/bin/mozilla/ar.pl1135
-rw-r--r--sql-ledger/bin/mozilla/arap.pl406
-rw-r--r--sql-ledger/bin/mozilla/ca.pl413
-rw-r--r--sql-ledger/bin/mozilla/cp.pl528
-rw-r--r--sql-ledger/bin/mozilla/ct.pl631
-rw-r--r--sql-ledger/bin/mozilla/gl.pl806
-rw-r--r--sql-ledger/bin/mozilla/ic.pl1638
-rw-r--r--sql-ledger/bin/mozilla/io.pl1149
-rw-r--r--sql-ledger/bin/mozilla/ir.pl653
-rw-r--r--sql-ledger/bin/mozilla/is.pl739
-rw-r--r--sql-ledger/bin/mozilla/login.pl217
-rw-r--r--sql-ledger/bin/mozilla/menu.pl160
-rw-r--r--sql-ledger/bin/mozilla/oe.pl1111
-rw-r--r--sql-ledger/bin/mozilla/pe.pl549
-rw-r--r--sql-ledger/bin/mozilla/rc.pl371
-rw-r--r--sql-ledger/bin/mozilla/rp.pl1730
-rw-r--r--sql-ledger/css/sql-ledger.css113
-rw-r--r--sql-ledger/doc/COPYING355
-rw-r--r--sql-ledger/doc/README287
-rw-r--r--sql-ledger/doc/UPGRADE-1.6-1.861
-rw-r--r--sql-ledger/doc/UPGRADE-1.8-1.8.323
-rw-r--r--sql-ledger/doc/UPGRADE-1.8.3-1.8.410
-rw-r--r--sql-ledger/doc/UPGRADE-1.8.4-1.8.518
-rw-r--r--sql-ledger/doc/UPGRADE-1.8.5-1.8.76
-rw-r--r--sql-ledger/doc/UPGRADE-1.8.7-2.0.020
-rw-r--r--sql-ledger/doc/UPGRADE-2.0-2.0.88
-rw-r--r--sql-ledger/doc/copyright23
-rw-r--r--sql-ledger/doc/faq.html747
-rw-r--r--sql-ledger/favicon.icobin0 -> 3638 bytes
-rw-r--r--sql-ledger/locale/br/COPYING24
-rw-r--r--sql-ledger/locale/br/LANGUAGE1
-rw-r--r--sql-ledger/locale/br/admin122
-rw-r--r--sql-ledger/locale/br/all487
-rw-r--r--sql-ledger/locale/br/am139
-rw-r--r--sql-ledger/locale/br/ap133
-rw-r--r--sql-ledger/locale/br/ar133
-rw-r--r--sql-ledger/locale/br/arap30
-rw-r--r--sql-ledger/locale/br/ca50
-rw-r--r--sql-ledger/locale/br/cp75
-rw-r--r--sql-ledger/locale/br/ct69
-rw-r--r--sql-ledger/locale/br/gl124
-rw-r--r--sql-ledger/locale/br/ic205
-rw-r--r--sql-ledger/locale/br/io106
-rw-r--r--sql-ledger/locale/br/ir178
-rw-r--r--sql-ledger/locale/br/is185
-rw-r--r--sql-ledger/locale/br/login28
-rw-r--r--sql-ledger/locale/br/menu72
-rw-r--r--sql-ledger/locale/br/oe199
-rw-r--r--sql-ledger/locale/br/pe35
-rw-r--r--sql-ledger/locale/br/rc37
-rw-r--r--sql-ledger/locale/br/rp117
-rw-r--r--sql-ledger/locale/cn/COPYING24
-rw-r--r--sql-ledger/locale/cn/LANGUAGE1
-rw-r--r--sql-ledger/locale/cn/admin124
-rw-r--r--sql-ledger/locale/cn/all495
-rw-r--r--sql-ledger/locale/cn/am139
-rw-r--r--sql-ledger/locale/cn/ap133
-rw-r--r--sql-ledger/locale/cn/ar133
-rw-r--r--sql-ledger/locale/cn/arap30
-rw-r--r--sql-ledger/locale/cn/ca50
-rw-r--r--sql-ledger/locale/cn/cp77
-rw-r--r--sql-ledger/locale/cn/ct71
-rw-r--r--sql-ledger/locale/cn/gl124
-rw-r--r--sql-ledger/locale/cn/ic206
-rw-r--r--sql-ledger/locale/cn/io106
-rw-r--r--sql-ledger/locale/cn/ir178
-rw-r--r--sql-ledger/locale/cn/is185
-rw-r--r--sql-ledger/locale/cn/login27
-rw-r--r--sql-ledger/locale/cn/menu71
-rw-r--r--sql-ledger/locale/cn/oe200
-rw-r--r--sql-ledger/locale/cn/pe35
-rw-r--r--sql-ledger/locale/cn/rc37
-rw-r--r--sql-ledger/locale/cn/rp120
-rw-r--r--sql-ledger/locale/ct/COPYING21
-rw-r--r--sql-ledger/locale/ct/LANGUAGE1
-rw-r--r--sql-ledger/locale/ct/admin122
-rw-r--r--sql-ledger/locale/ct/all487
-rw-r--r--sql-ledger/locale/ct/am139
-rw-r--r--sql-ledger/locale/ct/ap133
-rw-r--r--sql-ledger/locale/ct/ar133
-rw-r--r--sql-ledger/locale/ct/arap30
-rw-r--r--sql-ledger/locale/ct/ca50
-rw-r--r--sql-ledger/locale/ct/cp75
-rw-r--r--sql-ledger/locale/ct/ct69
-rw-r--r--sql-ledger/locale/ct/gl124
-rw-r--r--sql-ledger/locale/ct/ic205
-rw-r--r--sql-ledger/locale/ct/io106
-rw-r--r--sql-ledger/locale/ct/ir178
-rw-r--r--sql-ledger/locale/ct/is185
-rw-r--r--sql-ledger/locale/ct/login28
-rw-r--r--sql-ledger/locale/ct/menu72
-rw-r--r--sql-ledger/locale/ct/oe199
-rw-r--r--sql-ledger/locale/ct/pe35
-rw-r--r--sql-ledger/locale/ct/rc37
-rw-r--r--sql-ledger/locale/ct/rp117
-rw-r--r--sql-ledger/locale/cz/COPYING23
-rw-r--r--sql-ledger/locale/cz/LANGUAGE1
-rw-r--r--sql-ledger/locale/cz/admin122
-rw-r--r--sql-ledger/locale/cz/all487
-rw-r--r--sql-ledger/locale/cz/am139
-rw-r--r--sql-ledger/locale/cz/ap133
-rw-r--r--sql-ledger/locale/cz/ar133
-rw-r--r--sql-ledger/locale/cz/arap30
-rw-r--r--sql-ledger/locale/cz/ca50
-rw-r--r--sql-ledger/locale/cz/cp75
-rw-r--r--sql-ledger/locale/cz/ct69
-rw-r--r--sql-ledger/locale/cz/gl124
-rw-r--r--sql-ledger/locale/cz/ic205
-rw-r--r--sql-ledger/locale/cz/io106
-rw-r--r--sql-ledger/locale/cz/ir178
-rw-r--r--sql-ledger/locale/cz/is185
-rw-r--r--sql-ledger/locale/cz/login28
-rw-r--r--sql-ledger/locale/cz/menu72
-rw-r--r--sql-ledger/locale/cz/oe199
-rw-r--r--sql-ledger/locale/cz/pe35
-rw-r--r--sql-ledger/locale/cz/rc37
-rw-r--r--sql-ledger/locale/cz/rp117
-rw-r--r--sql-ledger/locale/de/COPYING22
-rw-r--r--sql-ledger/locale/de/LANGUAGE1
-rw-r--r--sql-ledger/locale/de/Num2text185
-rw-r--r--sql-ledger/locale/de/admin124
-rw-r--r--sql-ledger/locale/de/all499
-rw-r--r--sql-ledger/locale/de/am139
-rw-r--r--sql-ledger/locale/de/ap133
-rw-r--r--sql-ledger/locale/de/ar134
-rw-r--r--sql-ledger/locale/de/arap30
-rw-r--r--sql-ledger/locale/de/ca50
-rw-r--r--sql-ledger/locale/de/cp77
-rw-r--r--sql-ledger/locale/de/ct71
-rw-r--r--sql-ledger/locale/de/gl124
-rw-r--r--sql-ledger/locale/de/ic205
-rw-r--r--sql-ledger/locale/de/io108
-rw-r--r--sql-ledger/locale/de/ir180
-rw-r--r--sql-ledger/locale/de/is187
-rwxr-xr-xsql-ledger/locale/de/locales.pl303
-rw-r--r--sql-ledger/locale/de/login27
-rw-r--r--sql-ledger/locale/de/menu73
-rw-r--r--sql-ledger/locale/de/oe202
-rw-r--r--sql-ledger/locale/de/pe45
-rw-r--r--sql-ledger/locale/de/rc37
-rw-r--r--sql-ledger/locale/de/rp119
-rw-r--r--sql-ledger/locale/dk/COPYING24
-rw-r--r--sql-ledger/locale/dk/LANGUAGE1
-rw-r--r--sql-ledger/locale/dk/admin122
-rw-r--r--sql-ledger/locale/dk/all487
-rw-r--r--sql-ledger/locale/dk/am139
-rw-r--r--sql-ledger/locale/dk/ap133
-rw-r--r--sql-ledger/locale/dk/ar133
-rw-r--r--sql-ledger/locale/dk/arap30
-rw-r--r--sql-ledger/locale/dk/ca50
-rw-r--r--sql-ledger/locale/dk/cp75
-rw-r--r--sql-ledger/locale/dk/ct69
-rw-r--r--sql-ledger/locale/dk/gl124
-rw-r--r--sql-ledger/locale/dk/ic205
-rw-r--r--sql-ledger/locale/dk/io106
-rw-r--r--sql-ledger/locale/dk/ir178
-rw-r--r--sql-ledger/locale/dk/is185
-rw-r--r--sql-ledger/locale/dk/login28
-rw-r--r--sql-ledger/locale/dk/menu72
-rw-r--r--sql-ledger/locale/dk/oe199
-rw-r--r--sql-ledger/locale/dk/pe35
-rw-r--r--sql-ledger/locale/dk/rc37
-rw-r--r--sql-ledger/locale/dk/rp117
-rw-r--r--sql-ledger/locale/ee/COPYING25
-rw-r--r--sql-ledger/locale/ee/LANGUAGE1
-rw-r--r--sql-ledger/locale/ee/admin124
-rw-r--r--sql-ledger/locale/ee/all497
-rw-r--r--sql-ledger/locale/ee/am139
-rw-r--r--sql-ledger/locale/ee/ap133
-rw-r--r--sql-ledger/locale/ee/ar134
-rw-r--r--sql-ledger/locale/ee/arap30
-rw-r--r--sql-ledger/locale/ee/ca50
-rw-r--r--sql-ledger/locale/ee/cp77
-rw-r--r--sql-ledger/locale/ee/ct71
-rw-r--r--sql-ledger/locale/ee/gl124
-rw-r--r--sql-ledger/locale/ee/ic208
-rw-r--r--sql-ledger/locale/ee/io108
-rw-r--r--sql-ledger/locale/ee/ir180
-rw-r--r--sql-ledger/locale/ee/is187
-rw-r--r--sql-ledger/locale/ee/login27
-rw-r--r--sql-ledger/locale/ee/menu71
-rw-r--r--sql-ledger/locale/ee/oe202
-rw-r--r--sql-ledger/locale/ee/pe35
-rw-r--r--sql-ledger/locale/ee/rc37
-rw-r--r--sql-ledger/locale/ee/rp120
-rw-r--r--sql-ledger/locale/en_GB/COPYING23
-rw-r--r--sql-ledger/locale/en_GB/LANGUAGE1
-rw-r--r--sql-ledger/locale/en_GB/admin124
-rw-r--r--sql-ledger/locale/en_GB/all499
-rw-r--r--sql-ledger/locale/en_GB/am139
-rw-r--r--sql-ledger/locale/en_GB/ap133
-rw-r--r--sql-ledger/locale/en_GB/ar134
-rw-r--r--sql-ledger/locale/en_GB/arap30
-rw-r--r--sql-ledger/locale/en_GB/bp54
-rw-r--r--sql-ledger/locale/en_GB/ca50
-rw-r--r--sql-ledger/locale/en_GB/cp77
-rw-r--r--sql-ledger/locale/en_GB/ct71
-rw-r--r--sql-ledger/locale/en_GB/gl124
-rw-r--r--sql-ledger/locale/en_GB/ic205
-rw-r--r--sql-ledger/locale/en_GB/io108
-rw-r--r--sql-ledger/locale/en_GB/ir180
-rw-r--r--sql-ledger/locale/en_GB/is187
-rw-r--r--sql-ledger/locale/en_GB/login27
-rw-r--r--sql-ledger/locale/en_GB/menu73
-rw-r--r--sql-ledger/locale/en_GB/oe202
-rw-r--r--sql-ledger/locale/en_GB/pe45
-rw-r--r--sql-ledger/locale/en_GB/rc37
-rw-r--r--sql-ledger/locale/en_GB/rp119
-rw-r--r--sql-ledger/locale/es/COPYING26
-rw-r--r--sql-ledger/locale/es/LANGUAGE1
-rw-r--r--sql-ledger/locale/es/Num2text195
-rw-r--r--sql-ledger/locale/es/admin124
-rw-r--r--sql-ledger/locale/es/all490
-rw-r--r--sql-ledger/locale/es/am139
-rw-r--r--sql-ledger/locale/es/ap133
-rw-r--r--sql-ledger/locale/es/ar133
-rw-r--r--sql-ledger/locale/es/arap30
-rw-r--r--sql-ledger/locale/es/ca50
-rw-r--r--sql-ledger/locale/es/cp75
-rw-r--r--sql-ledger/locale/es/ct69
-rw-r--r--sql-ledger/locale/es/gl124
-rw-r--r--sql-ledger/locale/es/ic205
-rw-r--r--sql-ledger/locale/es/io106
-rw-r--r--sql-ledger/locale/es/ir178
-rw-r--r--sql-ledger/locale/es/is185
-rw-r--r--sql-ledger/locale/es/login27
-rw-r--r--sql-ledger/locale/es/menu71
-rw-r--r--sql-ledger/locale/es/oe200
-rw-r--r--sql-ledger/locale/es/pe35
-rw-r--r--sql-ledger/locale/es/rc37
-rw-r--r--sql-ledger/locale/es/rp117
-rw-r--r--sql-ledger/locale/fi/COPYING23
-rw-r--r--sql-ledger/locale/fi/LANGUAGE1
-rw-r--r--sql-ledger/locale/fi/admin126
-rw-r--r--sql-ledger/locale/fi/all494
-rw-r--r--sql-ledger/locale/fi/am140
-rw-r--r--sql-ledger/locale/fi/ap133
-rw-r--r--sql-ledger/locale/fi/ar133
-rw-r--r--sql-ledger/locale/fi/arap30
-rw-r--r--sql-ledger/locale/fi/ca50
-rw-r--r--sql-ledger/locale/fi/cp75
-rw-r--r--sql-ledger/locale/fi/ct71
-rw-r--r--sql-ledger/locale/fi/gl124
-rw-r--r--sql-ledger/locale/fi/ic205
-rw-r--r--sql-ledger/locale/fi/io106
-rw-r--r--sql-ledger/locale/fi/ir178
-rw-r--r--sql-ledger/locale/fi/is185
-rw-r--r--sql-ledger/locale/fi/login27
-rw-r--r--sql-ledger/locale/fi/menu71
-rw-r--r--sql-ledger/locale/fi/oe199
-rw-r--r--sql-ledger/locale/fi/pe35
-rw-r--r--sql-ledger/locale/fi/rc37
-rw-r--r--sql-ledger/locale/fi/rp117
-rw-r--r--sql-ledger/locale/fr/COPYING27
-rw-r--r--sql-ledger/locale/fr/LANGUAGE1
-rw-r--r--sql-ledger/locale/fr/admin124
-rw-r--r--sql-ledger/locale/fr/all495
-rw-r--r--sql-ledger/locale/fr/am139
-rw-r--r--sql-ledger/locale/fr/ap133
-rw-r--r--sql-ledger/locale/fr/ar133
-rw-r--r--sql-ledger/locale/fr/arap30
-rw-r--r--sql-ledger/locale/fr/ca50
-rw-r--r--sql-ledger/locale/fr/cp77
-rw-r--r--sql-ledger/locale/fr/ct71
-rw-r--r--sql-ledger/locale/fr/gl124
-rw-r--r--sql-ledger/locale/fr/ic206
-rw-r--r--sql-ledger/locale/fr/io106
-rw-r--r--sql-ledger/locale/fr/ir178
-rw-r--r--sql-ledger/locale/fr/is185
-rw-r--r--sql-ledger/locale/fr/login27
-rw-r--r--sql-ledger/locale/fr/menu71
-rw-r--r--sql-ledger/locale/fr/oe200
-rw-r--r--sql-ledger/locale/fr/pe35
-rw-r--r--sql-ledger/locale/fr/rc37
-rw-r--r--sql-ledger/locale/fr/rp120
-rw-r--r--sql-ledger/locale/hu/COPYING23
-rw-r--r--sql-ledger/locale/hu/LANGUAGE1
-rw-r--r--sql-ledger/locale/hu/admin124
-rw-r--r--sql-ledger/locale/hu/all499
-rw-r--r--sql-ledger/locale/hu/am139
-rw-r--r--sql-ledger/locale/hu/ap133
-rw-r--r--sql-ledger/locale/hu/ar134
-rw-r--r--sql-ledger/locale/hu/arap30
-rw-r--r--sql-ledger/locale/hu/ca50
-rw-r--r--sql-ledger/locale/hu/cp77
-rw-r--r--sql-ledger/locale/hu/ct71
-rw-r--r--sql-ledger/locale/hu/gl124
-rw-r--r--sql-ledger/locale/hu/ic205
-rw-r--r--sql-ledger/locale/hu/io108
-rw-r--r--sql-ledger/locale/hu/ir180
-rw-r--r--sql-ledger/locale/hu/is187
-rw-r--r--sql-ledger/locale/hu/login27
-rw-r--r--sql-ledger/locale/hu/menu73
-rw-r--r--sql-ledger/locale/hu/oe202
-rw-r--r--sql-ledger/locale/hu/pe45
-rw-r--r--sql-ledger/locale/hu/rc37
-rw-r--r--sql-ledger/locale/hu/rp119
-rw-r--r--sql-ledger/locale/is/COPYING23
-rw-r--r--sql-ledger/locale/is/LANGUAGE1
-rw-r--r--sql-ledger/locale/is/admin124
-rw-r--r--sql-ledger/locale/is/all496
-rw-r--r--sql-ledger/locale/is/am139
-rw-r--r--sql-ledger/locale/is/ap133
-rw-r--r--sql-ledger/locale/is/ar134
-rw-r--r--sql-ledger/locale/is/arap30
-rw-r--r--sql-ledger/locale/is/ca50
-rw-r--r--sql-ledger/locale/is/cp77
-rw-r--r--sql-ledger/locale/is/ct71
-rw-r--r--sql-ledger/locale/is/gl124
-rw-r--r--sql-ledger/locale/is/ic206
-rw-r--r--sql-ledger/locale/is/io106
-rw-r--r--sql-ledger/locale/is/ir178
-rw-r--r--sql-ledger/locale/is/is185
-rw-r--r--sql-ledger/locale/is/login27
-rw-r--r--sql-ledger/locale/is/menu71
-rw-r--r--sql-ledger/locale/is/oe200
-rw-r--r--sql-ledger/locale/is/pe35
-rw-r--r--sql-ledger/locale/is/rc37
-rw-r--r--sql-ledger/locale/is/rp120
-rw-r--r--sql-ledger/locale/it/COPYING25
-rw-r--r--sql-ledger/locale/it/LANGUAGE1
-rw-r--r--sql-ledger/locale/it/Num2text163
-rw-r--r--sql-ledger/locale/it/admin124
-rw-r--r--sql-ledger/locale/it/all495
-rw-r--r--sql-ledger/locale/it/am139
-rw-r--r--sql-ledger/locale/it/ap133
-rw-r--r--sql-ledger/locale/it/ar133
-rw-r--r--sql-ledger/locale/it/arap30
-rw-r--r--sql-ledger/locale/it/ca50
-rw-r--r--sql-ledger/locale/it/cp77
-rw-r--r--sql-ledger/locale/it/ct71
-rw-r--r--sql-ledger/locale/it/gl124
-rw-r--r--sql-ledger/locale/it/ic206
-rw-r--r--sql-ledger/locale/it/io106
-rw-r--r--sql-ledger/locale/it/ir178
-rw-r--r--sql-ledger/locale/it/is185
-rw-r--r--sql-ledger/locale/it/login27
-rw-r--r--sql-ledger/locale/it/menu71
-rw-r--r--sql-ledger/locale/it/oe200
-rw-r--r--sql-ledger/locale/it/pe35
-rw-r--r--sql-ledger/locale/it/qe199
-rw-r--r--sql-ledger/locale/it/rc37
-rw-r--r--sql-ledger/locale/it/rp120
-rw-r--r--sql-ledger/locale/lt/COPYING23
-rw-r--r--sql-ledger/locale/lt/LANGUAGE1
-rw-r--r--sql-ledger/locale/lt/admin124
-rw-r--r--sql-ledger/locale/lt/all497
-rw-r--r--sql-ledger/locale/lt/am139
-rw-r--r--sql-ledger/locale/lt/ap133
-rw-r--r--sql-ledger/locale/lt/ar134
-rw-r--r--sql-ledger/locale/lt/arap30
-rw-r--r--sql-ledger/locale/lt/ca50
-rw-r--r--sql-ledger/locale/lt/cp77
-rw-r--r--sql-ledger/locale/lt/ct71
-rw-r--r--sql-ledger/locale/lt/gl124
-rw-r--r--sql-ledger/locale/lt/ic208
-rw-r--r--sql-ledger/locale/lt/io108
-rw-r--r--sql-ledger/locale/lt/ir180
-rw-r--r--sql-ledger/locale/lt/is187
-rw-r--r--sql-ledger/locale/lt/login27
-rw-r--r--sql-ledger/locale/lt/menu71
-rw-r--r--sql-ledger/locale/lt/oe202
-rw-r--r--sql-ledger/locale/lt/pe35
-rw-r--r--sql-ledger/locale/lt/rc37
-rw-r--r--sql-ledger/locale/lt/rp120
-rw-r--r--sql-ledger/locale/mx/COPYING23
-rw-r--r--sql-ledger/locale/mx/LANGUAGE1
-rw-r--r--sql-ledger/locale/mx/admin128
-rw-r--r--sql-ledger/locale/mx/all496
-rw-r--r--sql-ledger/locale/mx/am140
-rw-r--r--sql-ledger/locale/mx/ap133
-rw-r--r--sql-ledger/locale/mx/ar133
-rw-r--r--sql-ledger/locale/mx/arap30
-rw-r--r--sql-ledger/locale/mx/ca50
-rw-r--r--sql-ledger/locale/mx/cp75
-rw-r--r--sql-ledger/locale/mx/ct69
-rw-r--r--sql-ledger/locale/mx/gl124
-rw-r--r--sql-ledger/locale/mx/ic206
-rw-r--r--sql-ledger/locale/mx/io106
-rw-r--r--sql-ledger/locale/mx/ir178
-rw-r--r--sql-ledger/locale/mx/is185
-rw-r--r--sql-ledger/locale/mx/login28
-rw-r--r--sql-ledger/locale/mx/menu72
-rw-r--r--sql-ledger/locale/mx/oe200
-rw-r--r--sql-ledger/locale/mx/pe35
-rw-r--r--sql-ledger/locale/mx/rc37
-rw-r--r--sql-ledger/locale/mx/rp117
-rw-r--r--sql-ledger/locale/nl/COPYING26
-rw-r--r--sql-ledger/locale/nl/LANGUAGE1
-rw-r--r--sql-ledger/locale/nl/Num2text161
-rw-r--r--sql-ledger/locale/nl/admin124
-rw-r--r--sql-ledger/locale/nl/all491
-rw-r--r--sql-ledger/locale/nl/am139
-rw-r--r--sql-ledger/locale/nl/ap133
-rw-r--r--sql-ledger/locale/nl/ar133
-rw-r--r--sql-ledger/locale/nl/arap30
-rw-r--r--sql-ledger/locale/nl/ca50
-rw-r--r--sql-ledger/locale/nl/cp75
-rw-r--r--sql-ledger/locale/nl/ct71
-rw-r--r--sql-ledger/locale/nl/gl124
-rw-r--r--sql-ledger/locale/nl/ic206
-rw-r--r--sql-ledger/locale/nl/io106
-rw-r--r--sql-ledger/locale/nl/ir178
-rw-r--r--sql-ledger/locale/nl/is185
-rw-r--r--sql-ledger/locale/nl/login27
-rw-r--r--sql-ledger/locale/nl/menu71
-rw-r--r--sql-ledger/locale/nl/oe200
-rw-r--r--sql-ledger/locale/nl/pe35
-rw-r--r--sql-ledger/locale/nl/rc37
-rw-r--r--sql-ledger/locale/nl/rp116
-rw-r--r--sql-ledger/locale/no/COPYING24
-rw-r--r--sql-ledger/locale/no/LANGUAGE1
-rw-r--r--sql-ledger/locale/no/admin124
-rw-r--r--sql-ledger/locale/no/all496
-rw-r--r--sql-ledger/locale/no/am139
-rw-r--r--sql-ledger/locale/no/ap133
-rw-r--r--sql-ledger/locale/no/ar134
-rw-r--r--sql-ledger/locale/no/arap30
-rw-r--r--sql-ledger/locale/no/ca50
-rw-r--r--sql-ledger/locale/no/cp77
-rw-r--r--sql-ledger/locale/no/ct71
-rw-r--r--sql-ledger/locale/no/gl124
-rw-r--r--sql-ledger/locale/no/ic206
-rw-r--r--sql-ledger/locale/no/io106
-rw-r--r--sql-ledger/locale/no/ir178
-rw-r--r--sql-ledger/locale/no/is185
-rw-r--r--sql-ledger/locale/no/login27
-rw-r--r--sql-ledger/locale/no/menu71
-rw-r--r--sql-ledger/locale/no/oe200
-rw-r--r--sql-ledger/locale/no/pe35
-rw-r--r--sql-ledger/locale/no/rc37
-rw-r--r--sql-ledger/locale/no/rp120
-rw-r--r--sql-ledger/locale/pa/COPYING23
-rw-r--r--sql-ledger/locale/pa/LANGUAGE1
-rw-r--r--sql-ledger/locale/pa/admin128
-rw-r--r--sql-ledger/locale/pa/all496
-rw-r--r--sql-ledger/locale/pa/am140
-rw-r--r--sql-ledger/locale/pa/ap133
-rw-r--r--sql-ledger/locale/pa/ar133
-rw-r--r--sql-ledger/locale/pa/arap30
-rw-r--r--sql-ledger/locale/pa/ca50
-rw-r--r--sql-ledger/locale/pa/cp75
-rw-r--r--sql-ledger/locale/pa/ct69
-rw-r--r--sql-ledger/locale/pa/gl124
-rw-r--r--sql-ledger/locale/pa/ic206
-rw-r--r--sql-ledger/locale/pa/io106
-rw-r--r--sql-ledger/locale/pa/ir178
-rw-r--r--sql-ledger/locale/pa/is185
-rw-r--r--sql-ledger/locale/pa/login28
-rw-r--r--sql-ledger/locale/pa/menu72
-rw-r--r--sql-ledger/locale/pa/oe200
-rw-r--r--sql-ledger/locale/pa/pe35
-rw-r--r--sql-ledger/locale/pa/rc37
-rw-r--r--sql-ledger/locale/pa/rp117
-rw-r--r--sql-ledger/locale/pl/COPYING23
-rw-r--r--sql-ledger/locale/pl/LANGUAGE1
-rw-r--r--sql-ledger/locale/pl/admin122
-rw-r--r--sql-ledger/locale/pl/all487
-rw-r--r--sql-ledger/locale/pl/am139
-rw-r--r--sql-ledger/locale/pl/ap133
-rw-r--r--sql-ledger/locale/pl/ar133
-rw-r--r--sql-ledger/locale/pl/arap30
-rw-r--r--sql-ledger/locale/pl/ca50
-rw-r--r--sql-ledger/locale/pl/cp75
-rw-r--r--sql-ledger/locale/pl/ct69
-rw-r--r--sql-ledger/locale/pl/gl124
-rw-r--r--sql-ledger/locale/pl/ic205
-rw-r--r--sql-ledger/locale/pl/io106
-rw-r--r--sql-ledger/locale/pl/ir178
-rw-r--r--sql-ledger/locale/pl/is185
-rw-r--r--sql-ledger/locale/pl/login28
-rw-r--r--sql-ledger/locale/pl/menu72
-rw-r--r--sql-ledger/locale/pl/oe199
-rw-r--r--sql-ledger/locale/pl/pe35
-rw-r--r--sql-ledger/locale/pl/rc37
-rw-r--r--sql-ledger/locale/pl/rp117
-rw-r--r--sql-ledger/locale/pt/COPYING23
-rw-r--r--sql-ledger/locale/pt/LANGUAGE1
-rw-r--r--sql-ledger/locale/pt/admin122
-rw-r--r--sql-ledger/locale/pt/all487
-rw-r--r--sql-ledger/locale/pt/am139
-rw-r--r--sql-ledger/locale/pt/ap133
-rw-r--r--sql-ledger/locale/pt/ar133
-rw-r--r--sql-ledger/locale/pt/arap30
-rw-r--r--sql-ledger/locale/pt/ca50
-rw-r--r--sql-ledger/locale/pt/cp75
-rw-r--r--sql-ledger/locale/pt/ct69
-rw-r--r--sql-ledger/locale/pt/gl124
-rw-r--r--sql-ledger/locale/pt/ic205
-rw-r--r--sql-ledger/locale/pt/io106
-rw-r--r--sql-ledger/locale/pt/ir178
-rw-r--r--sql-ledger/locale/pt/is185
-rw-r--r--sql-ledger/locale/pt/login28
-rw-r--r--sql-ledger/locale/pt/menu72
-rw-r--r--sql-ledger/locale/pt/oe199
-rw-r--r--sql-ledger/locale/pt/pe35
-rw-r--r--sql-ledger/locale/pt/rc37
-rw-r--r--sql-ledger/locale/pt/rp117
-rw-r--r--sql-ledger/locale/ru/COPYING23
-rw-r--r--sql-ledger/locale/ru/LANGUAGE1
-rw-r--r--sql-ledger/locale/ru/admin122
-rw-r--r--sql-ledger/locale/ru/all487
-rw-r--r--sql-ledger/locale/ru/am139
-rw-r--r--sql-ledger/locale/ru/ap133
-rw-r--r--sql-ledger/locale/ru/ar133
-rw-r--r--sql-ledger/locale/ru/arap30
-rw-r--r--sql-ledger/locale/ru/ca50
-rw-r--r--sql-ledger/locale/ru/cp75
-rw-r--r--sql-ledger/locale/ru/ct69
-rw-r--r--sql-ledger/locale/ru/gl124
-rw-r--r--sql-ledger/locale/ru/ic205
-rw-r--r--sql-ledger/locale/ru/io106
-rw-r--r--sql-ledger/locale/ru/ir178
-rw-r--r--sql-ledger/locale/ru/is185
-rw-r--r--sql-ledger/locale/ru/login28
-rw-r--r--sql-ledger/locale/ru/menu72
-rw-r--r--sql-ledger/locale/ru/oe199
-rw-r--r--sql-ledger/locale/ru/pe35
-rw-r--r--sql-ledger/locale/ru/rc37
-rw-r--r--sql-ledger/locale/ru/rp117
-rw-r--r--sql-ledger/locale/se/COPYING23
-rw-r--r--sql-ledger/locale/se/LANGUAGE1
-rw-r--r--sql-ledger/locale/se/admin124
-rw-r--r--sql-ledger/locale/se/all491
-rw-r--r--sql-ledger/locale/se/am139
-rw-r--r--sql-ledger/locale/se/ap133
-rw-r--r--sql-ledger/locale/se/ar133
-rw-r--r--sql-ledger/locale/se/arap30
-rw-r--r--sql-ledger/locale/se/ca50
-rw-r--r--sql-ledger/locale/se/cp75
-rw-r--r--sql-ledger/locale/se/ct71
-rw-r--r--sql-ledger/locale/se/gl124
-rw-r--r--sql-ledger/locale/se/ic205
-rw-r--r--sql-ledger/locale/se/io106
-rw-r--r--sql-ledger/locale/se/ir178
-rw-r--r--sql-ledger/locale/se/is185
-rw-r--r--sql-ledger/locale/se/login27
-rw-r--r--sql-ledger/locale/se/menu71
-rw-r--r--sql-ledger/locale/se/oe199
-rw-r--r--sql-ledger/locale/se/pe35
-rw-r--r--sql-ledger/locale/se/rc37
-rw-r--r--sql-ledger/locale/se/rp117
-rw-r--r--sql-ledger/locale/tr/COPYING23
-rw-r--r--sql-ledger/locale/tr/LANGUAGE1
-rw-r--r--sql-ledger/locale/tr/admin122
-rw-r--r--sql-ledger/locale/tr/all487
-rw-r--r--sql-ledger/locale/tr/am139
-rw-r--r--sql-ledger/locale/tr/ap133
-rw-r--r--sql-ledger/locale/tr/ar133
-rw-r--r--sql-ledger/locale/tr/arap30
-rw-r--r--sql-ledger/locale/tr/ca50
-rw-r--r--sql-ledger/locale/tr/cp75
-rw-r--r--sql-ledger/locale/tr/ct69
-rw-r--r--sql-ledger/locale/tr/gl124
-rw-r--r--sql-ledger/locale/tr/ic205
-rw-r--r--sql-ledger/locale/tr/io106
-rw-r--r--sql-ledger/locale/tr/ir178
-rw-r--r--sql-ledger/locale/tr/is185
-rw-r--r--sql-ledger/locale/tr/login28
-rw-r--r--sql-ledger/locale/tr/menu72
-rw-r--r--sql-ledger/locale/tr/oe199
-rw-r--r--sql-ledger/locale/tr/pe35
-rw-r--r--sql-ledger/locale/tr/rc37
-rw-r--r--sql-ledger/locale/tr/rp117
-rw-r--r--sql-ledger/locale/tw/COPYING25
-rw-r--r--sql-ledger/locale/tw/LANGUAGE1
-rw-r--r--sql-ledger/locale/tw/admin122
-rw-r--r--sql-ledger/locale/tw/all487
-rw-r--r--sql-ledger/locale/tw/am139
-rw-r--r--sql-ledger/locale/tw/ap133
-rw-r--r--sql-ledger/locale/tw/ar133
-rw-r--r--sql-ledger/locale/tw/arap30
-rw-r--r--sql-ledger/locale/tw/ca50
-rw-r--r--sql-ledger/locale/tw/cp75
-rw-r--r--sql-ledger/locale/tw/ct69
-rw-r--r--sql-ledger/locale/tw/gl124
-rw-r--r--sql-ledger/locale/tw/ic205
-rw-r--r--sql-ledger/locale/tw/io106
-rw-r--r--sql-ledger/locale/tw/ir178
-rw-r--r--sql-ledger/locale/tw/is185
-rw-r--r--sql-ledger/locale/tw/login28
-rw-r--r--sql-ledger/locale/tw/menu72
-rw-r--r--sql-ledger/locale/tw/oe199
-rw-r--r--sql-ledger/locale/tw/pe35
-rw-r--r--sql-ledger/locale/tw/rc37
-rw-r--r--sql-ledger/locale/tw/rp117
-rw-r--r--sql-ledger/locale/ua/COPYING23
-rw-r--r--sql-ledger/locale/ua/LANGUAGE1
-rw-r--r--sql-ledger/locale/ua/admin124
-rw-r--r--sql-ledger/locale/ua/all495
-rw-r--r--sql-ledger/locale/ua/am139
-rw-r--r--sql-ledger/locale/ua/ap133
-rw-r--r--sql-ledger/locale/ua/ar133
-rw-r--r--sql-ledger/locale/ua/arap30
-rw-r--r--sql-ledger/locale/ua/ca50
-rw-r--r--sql-ledger/locale/ua/cp77
-rw-r--r--sql-ledger/locale/ua/ct71
-rw-r--r--sql-ledger/locale/ua/gl124
-rw-r--r--sql-ledger/locale/ua/ic206
-rw-r--r--sql-ledger/locale/ua/io106
-rw-r--r--sql-ledger/locale/ua/ir178
-rw-r--r--sql-ledger/locale/ua/is185
-rw-r--r--sql-ledger/locale/ua/login27
-rw-r--r--sql-ledger/locale/ua/menu71
-rw-r--r--sql-ledger/locale/ua/oe200
-rw-r--r--sql-ledger/locale/ua/pe35
-rw-r--r--sql-ledger/locale/ua/rc37
-rw-r--r--sql-ledger/locale/ua/rp120
-rw-r--r--sql-ledger/locale/ve/COPYING23
-rw-r--r--sql-ledger/locale/ve/LANGUAGE1
-rw-r--r--sql-ledger/locale/ve/admin124
-rw-r--r--sql-ledger/locale/ve/all491
-rw-r--r--sql-ledger/locale/ve/am139
-rw-r--r--sql-ledger/locale/ve/ap133
-rw-r--r--sql-ledger/locale/ve/ar133
-rw-r--r--sql-ledger/locale/ve/arap30
-rw-r--r--sql-ledger/locale/ve/ca50
-rw-r--r--sql-ledger/locale/ve/cp75
-rw-r--r--sql-ledger/locale/ve/ct71
-rw-r--r--sql-ledger/locale/ve/gl124
-rw-r--r--sql-ledger/locale/ve/ic206
-rw-r--r--sql-ledger/locale/ve/io106
-rw-r--r--sql-ledger/locale/ve/ir178
-rw-r--r--sql-ledger/locale/ve/is185
-rw-r--r--sql-ledger/locale/ve/login27
-rw-r--r--sql-ledger/locale/ve/menu71
-rw-r--r--sql-ledger/locale/ve/oe200
-rw-r--r--sql-ledger/locale/ve/pe35
-rw-r--r--sql-ledger/locale/ve/rc37
-rw-r--r--sql-ledger/locale/ve/rp116
-rwxr-xr-xsql-ledger/login.pl132
-rw-r--r--sql-ledger/menu.ini394
-rwxr-xr-xsql-ledger/setup.pl594
-rw-r--r--sql-ledger/sql-ledger.conf.default33
-rw-r--r--sql-ledger/sql-ledger.pngbin0 -> 6963 bytes
-rw-r--r--sql-ledger/sql/Austria-chart.sql143
-rw-r--r--sql-ledger/sql/Austria-gifi.sql334
-rw-r--r--sql-ledger/sql/Brazil_General-chart.sql70
-rw-r--r--sql-ledger/sql/Canada-gifi.sql754
-rw-r--r--sql-ledger/sql/Canada_General-chart.sql77
-rw-r--r--sql-ledger/sql/Czech_Republic-chart.sql317
-rw-r--r--sql-ledger/sql/Danish_Default-chart.sql75
-rw-r--r--sql-ledger/sql/Default-chart.sql81
-rw-r--r--sql-ledger/sql/Dutch_Default-chart.sql80
-rw-r--r--sql-ledger/sql/Dutch_Standard-chart.sql233
-rw-r--r--sql-ledger/sql/France-chart.sql951
-rw-r--r--sql-ledger/sql/German-Sample-chart.sql216
-rw-r--r--sql-ledger/sql/German-Sample-gifi.sql19
-rw-r--r--sql-ledger/sql/Germany-DATEV-SKR03-chart.sql262
-rw-r--r--sql-ledger/sql/Germany-DATEV-SKR03-gifi.sql550
-rw-r--r--sql-ledger/sql/Germany-SKR03-chart.sql267
-rw-r--r--sql-ledger/sql/Germany-SKR03-gifi.sql1083
-rw-r--r--sql-ledger/sql/Italy-chart.sql179
-rw-r--r--sql-ledger/sql/Oracle-indices.sql57
-rw-r--r--sql-ledger/sql/Oracle-tables.sql388
-rw-r--r--sql-ledger/sql/Oracle-upgrade-1.8.0-1.8.4.sql28
-rw-r--r--sql-ledger/sql/Oracle-upgrade-1.8.4-1.8.5.sql77
-rw-r--r--sql-ledger/sql/Oracle-upgrade-1.8.5-2.0.0.sql100
-rw-r--r--sql-ledger/sql/Oracle-upgrade-2.0.0-2.0.8.sql19
-rw-r--r--sql-ledger/sql/Pg-indices.sql57
-rw-r--r--sql-ledger/sql/Pg-tables.sql289
-rw-r--r--sql-ledger/sql/Pg-upgrade-1.2.6-1.2.7.sql4
-rw-r--r--sql-ledger/sql/Pg-upgrade-1.2.7-1.4.0.sql173
-rw-r--r--sql-ledger/sql/Pg-upgrade-1.4.0-1.6.0.sql126
-rw-r--r--sql-ledger/sql/Pg-upgrade-1.6.0-1.8.0.sql104
-rw-r--r--sql-ledger/sql/Pg-upgrade-1.8.0-1.8.4.sql21
-rw-r--r--sql-ledger/sql/Pg-upgrade-1.8.4-1.8.5.sql63
-rw-r--r--sql-ledger/sql/Pg-upgrade-1.8.5-2.0.0.sql92
-rw-r--r--sql-ledger/sql/Pg-upgrade-2.0.0-2.0.8.sql12
-rw-r--r--sql-ledger/sql/Poland-chart.sql337
-rw-r--r--sql-ledger/sql/Simplified_Chinese_Default-chart.sql78
-rw-r--r--sql-ledger/sql/Spain-chart.sql132
-rw-r--r--sql-ledger/sql/Swiss-German-chart.sql160
-rw-r--r--sql-ledger/sql/Swiss-German-gifi.sql55
-rw-r--r--sql-ledger/sql/Traditional_Chinese_Default-chart.sql78
-rw-r--r--sql-ledger/sql/US_General-chart.sql98
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-balance_sheet.html103
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-check.tex71
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-income_statement.html77
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-invoice.html315
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-invoice.tex223
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-packing_list.html143
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-packing_list.tex116
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-purchase_order.html187
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-purchase_order.tex198
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-receipt.tex71
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-sales_order.html221
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-sales_order.tex137
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-statement.html125
-rw-r--r--sql-ledger/templates/Brazilian_Portuguese-statement.tex137
-rw-r--r--sql-ledger/templates/Danish-balance_sheet.html96
-rw-r--r--sql-ledger/templates/Danish-check.tex71
-rw-r--r--sql-ledger/templates/Danish-income_statement.html73
-rw-r--r--sql-ledger/templates/Danish-invoice.html273
-rw-r--r--sql-ledger/templates/Danish-invoice.tex152
-rw-r--r--sql-ledger/templates/Danish-packing_list.html145
-rw-r--r--sql-ledger/templates/Danish-packing_list.tex123
-rw-r--r--sql-ledger/templates/Danish-purchase_order.html191
-rw-r--r--sql-ledger/templates/Danish-purchase_order.tex143
-rw-r--r--sql-ledger/templates/Danish-receipt.tex71
-rw-r--r--sql-ledger/templates/Danish-sales_order.html210
-rw-r--r--sql-ledger/templates/Danish-sales_order.tex144
-rw-r--r--sql-ledger/templates/Danish-statement.html121
-rw-r--r--sql-ledger/templates/Danish-statement.tex137
-rw-r--r--sql-ledger/templates/Default-balance_sheet.html100
-rw-r--r--sql-ledger/templates/Default-check.tex77
-rw-r--r--sql-ledger/templates/Default-income_statement.html82
-rw-r--r--sql-ledger/templates/Default-invoice.html309
-rw-r--r--sql-ledger/templates/Default-invoice.tex231
-rw-r--r--sql-ledger/templates/Default-packing_list.html148
-rw-r--r--sql-ledger/templates/Default-packing_list.tex122
-rw-r--r--sql-ledger/templates/Default-purchase_order.html224
-rw-r--r--sql-ledger/templates/Default-purchase_order.tex198
-rw-r--r--sql-ledger/templates/Default-receipt.tex74
-rw-r--r--sql-ledger/templates/Default-sales_order.html212
-rw-r--r--sql-ledger/templates/Default-sales_order.tex143
-rw-r--r--sql-ledger/templates/Default-statement.html121
-rw-r--r--sql-ledger/templates/Default-statement.tex137
-rw-r--r--sql-ledger/templates/Dutch-balance_sheet.html104
-rw-r--r--sql-ledger/templates/Dutch-check.tex71
-rw-r--r--sql-ledger/templates/Dutch-income_statement.html83
-rw-r--r--sql-ledger/templates/Dutch-invoice.html239
-rw-r--r--sql-ledger/templates/Dutch-invoice.tex138
-rw-r--r--sql-ledger/templates/Dutch-packing_list.html121
-rw-r--r--sql-ledger/templates/Dutch-packing_list.tex114
-rw-r--r--sql-ledger/templates/Dutch-purchase_order.html186
-rw-r--r--sql-ledger/templates/Dutch-purchase_order.tex137
-rw-r--r--sql-ledger/templates/Dutch-receipt.tex71
-rw-r--r--sql-ledger/templates/Dutch-sales_order.html208
-rw-r--r--sql-ledger/templates/Dutch-sales_order.tex134
-rw-r--r--sql-ledger/templates/Dutch-statement.html121
-rw-r--r--sql-ledger/templates/Dutch-statement.tex137
-rw-r--r--sql-ledger/templates/Estonian-balance_sheet.html103
-rw-r--r--sql-ledger/templates/Estonian-check.tex71
-rw-r--r--sql-ledger/templates/Estonian-income_statement.html84
-rw-r--r--sql-ledger/templates/Estonian-invoice.html215
-rw-r--r--sql-ledger/templates/Estonian-invoice.tex147
-rw-r--r--sql-ledger/templates/Estonian-packing_list.html147
-rw-r--r--sql-ledger/templates/Estonian-packing_list.tex119
-rw-r--r--sql-ledger/templates/Estonian-purchase_order.html195
-rw-r--r--sql-ledger/templates/Estonian-purchase_order.tex143
-rw-r--r--sql-ledger/templates/Estonian-receipt.tex71
-rw-r--r--sql-ledger/templates/Estonian-sales_order.html214
-rw-r--r--sql-ledger/templates/Estonian-sales_order.tex141
-rw-r--r--sql-ledger/templates/Estonian-statement.html121
-rw-r--r--sql-ledger/templates/Estonian-statement.tex137
-rw-r--r--sql-ledger/templates/French-balance_sheet.html109
-rw-r--r--sql-ledger/templates/French-check.tex71
-rw-r--r--sql-ledger/templates/French-income_statement.html86
-rw-r--r--sql-ledger/templates/French-invoice.html309
-rw-r--r--sql-ledger/templates/French-invoice.tex151
-rw-r--r--sql-ledger/templates/French-packing_list.html152
-rw-r--r--sql-ledger/templates/French-packing_list.tex125
-rw-r--r--sql-ledger/templates/French-purchase_order.html207
-rw-r--r--sql-ledger/templates/French-purchase_order.tex143
-rw-r--r--sql-ledger/templates/French-receipt.tex71
-rw-r--r--sql-ledger/templates/French-sales_order.html229
-rw-r--r--sql-ledger/templates/French-sales_order.tex144
-rw-r--r--sql-ledger/templates/French-statement.html133
-rw-r--r--sql-ledger/templates/French-statement.tex137
-rw-r--r--sql-ledger/templates/German-balance_sheet.html100
-rw-r--r--sql-ledger/templates/German-check.tex71
-rw-r--r--sql-ledger/templates/German-income_statement.html78
-rw-r--r--sql-ledger/templates/German-invoice.html265
-rw-r--r--sql-ledger/templates/German-invoice.tex155
-rw-r--r--sql-ledger/templates/German-packing_list.html146
-rw-r--r--sql-ledger/templates/German-packing_list.tex118
-rw-r--r--sql-ledger/templates/German-purchase_order.html188
-rw-r--r--sql-ledger/templates/German-purchase_order.tex143
-rw-r--r--sql-ledger/templates/German-receipt.tex71
-rw-r--r--sql-ledger/templates/German-sales_order.html213
-rw-r--r--sql-ledger/templates/German-sales_order.tex142
-rw-r--r--sql-ledger/templates/German-statement.html121
-rw-r--r--sql-ledger/templates/German-statement.tex137
-rw-r--r--sql-ledger/templates/Service-balance_sheet.html100
-rw-r--r--sql-ledger/templates/Service-check.tex71
-rw-r--r--sql-ledger/templates/Service-income_statement.html82
-rw-r--r--sql-ledger/templates/Service-invoice.html226
-rw-r--r--sql-ledger/templates/Service-invoice.tex151
-rw-r--r--sql-ledger/templates/Service-packing_list.html148
-rw-r--r--sql-ledger/templates/Service-packing_list.tex120
-rw-r--r--sql-ledger/templates/Service-purchase_order.html194
-rw-r--r--sql-ledger/templates/Service-purchase_order.tex143
-rw-r--r--sql-ledger/templates/Service-receipt.tex71
-rw-r--r--sql-ledger/templates/Service-sales_order.html198
-rw-r--r--sql-ledger/templates/Service-sales_order.tex139
-rw-r--r--sql-ledger/templates/Service-statement.html121
-rw-r--r--sql-ledger/templates/Service-statement.tex137
-rw-r--r--sql-ledger/templates/Spanish_A4-balance_sheet.html100
-rw-r--r--sql-ledger/templates/Spanish_A4-check.tex71
-rw-r--r--sql-ledger/templates/Spanish_A4-income_statement.html77
-rw-r--r--sql-ledger/templates/Spanish_A4-invoice.html153
-rw-r--r--sql-ledger/templates/Spanish_A4-invoice.tex108
-rw-r--r--sql-ledger/templates/Spanish_A4-packing_list.html155
-rw-r--r--sql-ledger/templates/Spanish_A4-packing_list.tex108
-rw-r--r--sql-ledger/templates/Spanish_A4-purchase_order.html153
-rw-r--r--sql-ledger/templates/Spanish_A4-purchase_order.tex107
-rw-r--r--sql-ledger/templates/Spanish_A4-receipt.tex71
-rw-r--r--sql-ledger/templates/Spanish_A4-sales_order.html153
-rw-r--r--sql-ledger/templates/Spanish_A4-sales_order.tex107
-rw-r--r--sql-ledger/templates/Spanish_A4-statement.html121
-rw-r--r--sql-ledger/templates/Spanish_A4-statement.tex137
-rw-r--r--sql-ledger/templates/Spanish_Letter-balance_sheet.html100
-rw-r--r--sql-ledger/templates/Spanish_Letter-check.tex71
-rw-r--r--sql-ledger/templates/Spanish_Letter-income_statement.html77
-rw-r--r--sql-ledger/templates/Spanish_Letter-invoice.html153
-rw-r--r--sql-ledger/templates/Spanish_Letter-invoice.tex110
-rw-r--r--sql-ledger/templates/Spanish_Letter-packing_list.html155
-rw-r--r--sql-ledger/templates/Spanish_Letter-packing_list.tex108
-rw-r--r--sql-ledger/templates/Spanish_Letter-purchase_order.html153
-rw-r--r--sql-ledger/templates/Spanish_Letter-purchase_order.tex107
-rw-r--r--sql-ledger/templates/Spanish_Letter-receipt.tex71
-rw-r--r--sql-ledger/templates/Spanish_Letter-sales_order.html153
-rw-r--r--sql-ledger/templates/Spanish_Letter-sales_order.tex107
-rw-r--r--sql-ledger/templates/Spanish_Letter-statement.html121
-rw-r--r--sql-ledger/templates/Spanish_Letter-statement.tex137
-rw-r--r--sql-ledger/users/members.default5
-rwxr-xr-xtest/cgi-test560
1521 files changed, 212796 insertions, 2170 deletions
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 0000000..39b53a7
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,130 @@
+Thanks to Matt Simerson <matt@michweb.net> of MichWeb Inc. for documentation
+and pre-release testing. Without his help the documentation in 1.0.0
+release would have consisted of a single screenfull of text.
+(To clear up some misunderstanding, Matt did not write the current
+documentation.)
+
+Steve Cleff <cleff@yahoo.com> did the default background image in 1.0.x and
+is also the creator of Freeside's elusive mascot, Snakeman, who we hope will
+make an appearance in an upcoming version.
+
+Jerry St. Pierre <jstpi@city.timmins.on.ca> did the "SISD" graphic used in
+1.0.x and most of 1.1.x.
+
+Mark Norris of Urban Design, Inc. <http://www.urban.com/> did the red "S"
+logo for later 1.1.x versions and 1.2.x
+
+Brian McCane? <bmccane@maxbaud.net> contributed PostgreSQL support, HTML
+style enhancements and many, many bugfixes.
+
+Cerkit <cerkit@alfheim.net> contributed rsync support and desynced hosts.
+His changes will hopefully be included in an upcoming version.
+
+CompleteHOST, Inc. (http://www.completehost.com) funded the development of the
+following features:
+ - Multiple, separate databases and configurations on one box.
+ - Per-customer pricing (custom packages)
+ - Internationalization wrt addresses (cust_main, cust_main_county)
+Thanks!
+
+Mark Williamson <mark.williamson@ebbs.com.au> and Roger Mangraviti
+<rem@atu.com.au> contributed state/provence listings for Australia.
+
+Peter Wemm <peter@netplex.com.au> sent in a bunch of bugfixes for the 1.2
+release.
+
+Greg Kuhnert <gregk@no1.com.au> sent some documentation updates.
+
+Joel Griffiths <griff@aver-computer.com> contribued many bugfixes as well as
+the print-batch script.
+
+NetLoud <http://www.netloud.com/> funded the development of the following
+features:
+ - IEAK support for the signup server
+ - Pre-payment support
+
+NetAcces.Net (not netaccess.net) funded the development of the following
+features:
+ - DNS tracking and export to BIND configuration files
+ - Web site virtual host tracking and export to Apache configuration files
+
+Kristian Hoffmann <khoff@pc-intouch.com> contributed Netscape CCK
+autoconfiguration support for the signup server, lots of great mailing
+lists posts which I shamelessly made into documentation, fixes to get rid of
+the embarassing and non-database-normal "owed" field, and many other things
+I'm forgetting. Most recently Kristian and Mark (last name?) contributed
+the IP address tracking and svc_broadband in 1.5.
+
+Jeff Finucane <jeff@cmh.net> send in a bunch of bugfixes (for the sendmail
+export, cancel-unaudited.cgi), patches to support billing date modification,
+and probably other things too (sorry if I forgot them). And yet even more
+bug squashing, thanks! *and* he single-handedly implemented all the necessary
+work to get rid of svc_acct_sm and the "default domain" thanks!! and rewrote
+the financials! wow, thanks jeff! and contributed financial reports!
+
+Kenny Elliott <kenny@neoserve.com> contributed ICRADIUS radreply table support,
+allowing attributes with ICRADIUS, helped fix many bugs, and some
+other stuff I can't recall (sorry).
+
+Stephen Amadei <amadei@dandy.net> contribued portability cleanups for the
+low-level DBI stuff.
+
+Jason Spence <thalakan@frys.com> contributed admin.html and other
+documentation, autocapnames javascript, bugfixes & other neat stuff I can't
+remember.
+
+Brad Dameron <bdameron@tscnet.com> contributed code to do configurable state
+and referral defaults.
+
+Surf and Sip, Inc., <http://www.surfandsip.com> sponsored a long-requested
+feature - the session monitor and time-based prepaid cards.
+Matt Peterson <matt@peterson.org> and Mack ? <mackn@mackn.net> tested
+the new features and contributed many bugfixes.
+
+Landel Telecom <http://www.landel.com/> sponsored shipping addresses and
+customer notes, as well as an update of the CP provisioning.
+
+nikotel, Inc. <http://www.nikojet.com> sponsored the inclusion of
+customer-to-customer referrals in the web interface and signup server.
+
+Three Bubba's Innanet <http://www.inna.net> sponsored expedited check entry,
+the "similar names warning" feature, and a number of other enhancements.
+
+Dave Burgess <burgess@neonramp.com> sent in a bunch of fixes and small changes
+and will doubtless send more once he's got his tree under control.
+
+Luke Pfeifer <freeside@globalli.com> contributed the "subscription" price plan.
+
+Noment Networks, LLC <http://www.noment.com/> sponsored ICRADIUS/FreeRADIUS
+groups, message catalogs, and signup server enhancements.
+
+Donald Greer <dgreer@austintx.com> provided the SQL to work around MySQL's lack
+of subqueries, and Dale Hege <fhege@lumenexus.net> provided the patches.
+Thanks!
+
+<baloo@gimpgirl.com> sent in several documentation patches.
+
+"Stephen Bechard" <steve@destek.net> sent in patches for svc_www services and
+other fixes.
+
+Charles A Beasley <cbeasley@noment.net> contributed quota editing for the
+Infostreet export.
+
+Richard Siddall <richard.siddall@elirion.net> sent in Mason fixes and other
+things I'm probably forgetting.
+
+Contains "JS Calendar" v0.9.3 <http://dynarch.com/mishoo/calendar.epl>
+by Mihai Bazon <mishoo@infoiasi.ro> licensed under the terms of the GNU LGPL.
+
+Latex invoice template based on a template from eBills
+<http://ebills.sourceforge.net/> by Mark Asplen-Taylor <mark@asplen.co.uk>,
+licensed under the terms fo the GNU GPL.
+
+Contains "Request Tracker" <http://www.bestpractical.com/rt/> by Jesse
+Vincent <jesse@bestpractical.com> licensed under the terms of the GNU GPL.
+
+Contains "SQL Ledger" <http://www.sql-ledger.com/> by DWS Systems Inc. and
+contributors licensed under the terms of the GNU GPL.
+
+Everything else is my (Ivan Kohler <ivan@420.am>) fault.
+
diff --git a/FS/Changes b/FS/Changes
new file mode 100644
index 0000000..c94ef10
--- /dev/null
+++ b/FS/Changes
@@ -0,0 +1,5 @@
+Revision history for Perl extension FS.
+
+0.01 Wed Aug 4 00:13:45 1999
+ - original version; created by h2xs 1.19
+
diff --git a/FS/FS.pm b/FS/FS.pm
new file mode 100644
index 0000000..6c560d9
--- /dev/null
+++ b/FS/FS.pm
@@ -0,0 +1,239 @@
+package FS;
+
+use strict;
+use vars qw($VERSION);
+
+$VERSION = '0.01';
+
+#find missing entries in this file with:
+# for a in `ls *pm | cut -d. -f1`; do grep 'L<FS::'$a'>' ../FS.pm >/dev/null || echo "missing $a" ; done
+
+1;
+__END__
+
+=head1 NAME
+
+FS - Freeside Perl modules
+
+=head1 SYNOPSIS
+
+Freeside perl modules and CLI utilities.
+
+=head2 Utility classes
+
+L<FS::Conf> - Freeside configuration values
+
+L<FS::ConfItem> - Freeside configuration option meta-data.
+
+L<FS::UID> - User class (not yet OO)
+
+L<FS::CGI> - Non OO-subroutines for the web interface.
+
+L<FS::Msgcat> - Message catalog
+
+L<FS::SearchCache> - Search cache
+
+L<FS::raddb> - RADIUS dictionary
+
+=head2 Database record classes
+
+L<FS::Record> - Database record base class
+
+L<FS::svc_acct_pop> - POP (Point of Presence, not Post
+Office Protocol) class
+
+L<FS::part_pop_local> - Local calling area class
+
+L<FS::part_referral> - Referral class
+
+L<FS::cust_main_county> - Locale (tax rate) class
+
+L<FS::cust_tax_exempt> - Tax exemption record class
+
+L<FS::svc_Common> - Service base class
+
+L<FS::svc_acct> - Account (shell, RADIUS, POP3) class
+
+L<FS::acct_snarf> - External mail account class
+
+L<FS::radius_usergroup> - RADIUS groups
+
+L<FS::svc_domain> - Domain class
+
+L<FS::domain_record> - DNS zone entries
+
+L<FS::svc_forward> - Mail forwarding class
+
+L<FS::svc_www> - Web virtual host class.
+
+L<FS::svc_broadband> - DSL, wireless and other broadband class.
+
+L<FS::svc_external> - Externally tracked service class.
+
+L<FS::part_svc> - Service definition class
+
+L<FS::part_svc_column> - Column constraint class
+
+L<FS::export_svc> - Class linking service definitions (see L<FS::part_svc>)
+with exports (see L<FS::part_export>)
+
+L<FS::part_export> - External provisioning export class
+
+L<FS::part_export_option> - Export option class
+
+L<FS::part_pkg> - Package (billing item) definition class
+
+L<FS::pkg_svc> - Class linking package (billing item)
+definitions (see L<FS::part_pkg>) with service definitions
+(see L<FS::part_svc>)
+
+L<FS::agent> - Agent (reseller) class
+
+L<FS::agent_type> - Agent type class
+
+L<FS::type_pkgs> - Class linking agent types (see
+L<FS::agent_type>) with package (billing item) definitions
+(see L<FS::part_pkg>)
+
+L<FS::cust_svc> - Service class
+
+L<FS::cust_pkg> - Package (billing item) class
+
+L<FS::cust_main> - Customer class
+
+L<FS::cust_main_invoice> - Invoice destination
+class
+
+L<FS::cust_bill> - Invoice class
+
+L<FS::cust_bill_pkg> - Invoice line item class
+
+L<FS::cust_bill_pkg_detail> - Invoice line item detail class
+
+L<FS::part_bill_event> - Invoice event definition class
+
+L<FS::cust_bill_event> - Completed invoice event class
+
+L<FS::cust_pay> - Payment class
+
+L<FS::cust_bill_pay> - Payment application class
+
+L<FS::cust_credit> - Credit class
+
+L<FS::cust_refund> - Refund class
+
+L<FS::cust_credit_refund> - Refund application class
+
+L<FS::cust_credit_bill> - Credit invoice application class
+
+L<FS::cust_pay_batch> - Credit card transaction queue class
+
+L<FS::prepay_credit> - Prepaid "calling card" credit class.
+
+L<FS::nas> - Network Access Server class
+
+L<FS::port> - NAS port class
+
+L<FS::session> - User login session class
+
+L<FS::queue> - Job queue
+
+L<FS::queue_arg> - Job arguments
+
+L<FS::queue_depend> - Job dependencies
+
+L<FS::msgcat> - Message catalogs
+
+=head1 Remote API modules
+
+L<FS::SelfService>
+
+L<FS::SignupClient>
+
+L<FS::SessionClient>
+
+L<FS::MailAdminServer> (deprecated in favor of the self-service server)
+
+=head2 Command-line utilities
+
+L<freeside-adduser>
+
+L<freeside-queued>
+
+L<freeside-daily>
+
+L<freeside-expiration-alerter>
+
+L<freeside-email>
+
+L<freeside-cc-receipts-report>
+
+L<freeside-credit-report>
+
+L<freeside-receivables-report>
+
+L<freeside-tax-report>
+
+L<freeside-bill>
+
+L<freeside-overdue>
+
+=head2 User Interface classes (under (stalled) development; not yet usable)
+
+L<FS::UI::Base> - User-interface base class
+
+L<FS::UI::Gtk> - Gtk user-interface class
+
+L<FS::UI::CGI> - CGI (HTML) user-interface class
+
+L<FS::UI::agent> - agent table user-interface class
+
+=head2 Notes
+
+To quote perl(1), "If you're intending to read these straight through for the
+first time, the suggested order will tend to reduce the number of forward
+references."
+
+If you've never used OO modules before,
+http://www.perl.com/doc/FMTEYEWTK/easy_objects.html might help you out.
+
+=head1 DESCRIPTION
+
+Freeside is a billing and administration package for Internet Service
+Providers.
+
+The Freeside home page is at <http://www.sisd.com/freeside>.
+
+The main documentation is in httemplate/docs.
+
+=head1 SUPPORT
+
+A mailing list for users is available. Send a blank message to
+<ivan-freeside-subscribe@sisd.com> to subscribe.
+
+A mailing list for developers is available. It is intended to be lower volume
+and higher SNR than the users list. Send a blank message to
+<ivan-freeside-devel-subscribe@sisd.com> to subscribe.
+
+Commercial support is available; see
+<http://www.sisd.com/freeside/commercial.html>.
+
+=head1 AUTHOR
+
+Primarily Ivan Kohler <ivan@sisd.com>, with help from many kind folks.
+
+See the CREDITS file in the Freeside distribution for a (hopefully) complete
+list and the individal files for details.
+
+=head1 SEE ALSO
+
+perl(1), main Freeside documentation in htdocs/docs/
+
+=head1 BUGS
+
+Those modules which would be useful separately should be pulled out,
+renamed appropriately and uploaded to CPAN. So far: DBIx::DBSchema, Net::SSH
+and Net::SCP...
+
+=cut
+
diff --git a/FS/FS/CGI.pm b/FS/FS/CGI.pm
new file mode 100644
index 0000000..1ddc62c
--- /dev/null
+++ b/FS/FS/CGI.pm
@@ -0,0 +1,393 @@
+package FS::CGI;
+
+use strict;
+use vars qw(@EXPORT_OK @ISA);
+use Exporter;
+use CGI;
+use URI::URL;
+#use CGI::Carp qw(fatalsToBrowser);
+use FS::UID;
+
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(header menubar idiot eidiot popurl table itable ntable
+ small_custview myexit http_header);
+
+=head1 NAME
+
+FS::CGI - Subroutines for the web interface
+
+=head1 SYNOPSIS
+
+ use FS::CGI qw(header menubar idiot eidiot popurl);
+
+ print header( 'Title', '' );
+ print header( 'Title', menubar('item', 'URL', ... ) );
+
+ idiot "error message";
+ eidiot "error message";
+
+ $url = popurl; #returns current url
+ $url = popurl(3); #three levels up
+
+=head1 DESCRIPTION
+
+Provides a few common subroutines for the web interface.
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item header TITLE, MENUBAR
+
+Returns an HTML header.
+
+=cut
+
+sub header {
+ use Carp;
+ carp 'FS::CGI::header deprecated; include /elements/header.html instead';
+
+ my($title,$menubar,$etc)=@_; #$etc is for things like onLoad= etc.
+ $etc = '' unless defined $etc;
+
+ my $x = <<END;
+ <HTML>
+ <HEAD>
+ <TITLE>
+ $title
+ </TITLE>
+ <META HTTP-Equiv="Cache-Control" Content="no-cache">
+ <META HTTP-Equiv="Pragma" Content="no-cache">
+ <META HTTP-Equiv="Expires" Content="0">
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8"$etc>
+ <FONT SIZE=6>
+ $title
+ </FONT>
+ <BR><BR>
+END
+ $x .= $menubar. "<BR><BR>" if $menubar;
+ $x;
+}
+
+=item http_header
+
+Sets an http header.
+
+=cut
+
+sub http_header {
+ my ( $header, $value ) = @_;
+ if (exists $ENV{MOD_PERL}) {
+ if ( defined $main::Response
+ && $main::Response->isa('Apache::ASP::Response') ) { #Apache::ASP
+ if ( $header =~ /^Content-Type$/ ) {
+ $main::Response->{ContentType} = $value;
+ } else {
+ $main::Response->AddHeader( $header => $value );
+ }
+ } elsif ( defined $HTML::Mason::Commands::r ) { #Mason
+ ## is this the correct pacakge for $r ??? for 1.0x and 1.1x ?
+ if ( $header =~ /^Content-Type$/ ) {
+ $HTML::Mason::Commands::r->content_type($value);
+ } else {
+ $HTML::Mason::Commands::r->header_out( $header => $value );
+ }
+ } else {
+ die "http_header called in unknown environment";
+ }
+ } else {
+ die "http_header called not running under mod_perl";
+ }
+
+}
+
+=item menubar ITEM, URL, ...
+
+Returns an HTML menubar.
+
+=cut
+
+sub menubar { #$menubar=menubar('Main Menu', '../', 'Item', 'url', ... );
+ use Carp;
+ carp 'FS::CGI::menubar deprecated; include /elements/menubar.html instead';
+
+ my($item,$url,@html);
+ while (@_) {
+ ($item,$url)=splice(@_,0,2);
+ push @html, qq!<A HREF="$url">$item</A>!;
+ }
+ join(' | ',@html);
+}
+
+=item idiot ERROR
+
+This is depriciated. Don't use it.
+
+Sends an HTML error message.
+
+=cut
+
+sub idiot {
+ #warn "idiot depriciated";
+ my($error)=@_;
+# my $cgi = &FS::UID::cgi();
+# if ( $cgi->isa('CGI::Base') ) {
+# no strict 'subs';
+# &CGI::Base::SendHeaders;
+# } else {
+# print $cgi->header( @FS::CGI::header );
+# }
+ print <<END;
+<HTML>
+ <HEAD>
+ <TITLE>Error processing your request</TITLE>
+ <META HTTP-Equiv="Cache-Control" Content="no-cache">
+ <META HTTP-Equiv="Pragma" Content="no-cache">
+ <META HTTP-Equiv="Expires" Content="0">
+ </HEAD>
+ <BODY>
+ <CENTER>
+ <H4>Error processing your request</H4>
+ </CENTER>
+ Your request could not be processed because of the following error:
+ <P><B>$error</B>
+ </BODY>
+</HTML>
+END
+
+}
+
+=item eidiot ERROR
+
+This is depriciated. Don't use it.
+
+Sends an HTML error message, then exits.
+
+=cut
+
+sub eidiot {
+ warn "eidiot depriciated";
+ $HTML::Mason::Commands::r->send_http_header
+ if defined $HTML::Mason::Commands::r;
+ idiot(@_);
+ &myexit();
+}
+
+=item myexit
+
+You probably shouldn't use this; but if you must:
+
+If running under mod_perl, calles Apache::exit, otherwise, calls exit.
+
+=cut
+
+sub myexit {
+ if (exists $ENV{MOD_PERL}) {
+
+ if ( defined $main::Response
+ && $main::Response->isa('Apache::ASP::Response') ) { #Apache::ASP
+ $main::Response->End();
+ require Apache;
+ Apache::exit();
+ } elsif ( defined $HTML::Mason::Commands::m ) { #Mason
+ #$HTML::Mason::Commands::m->flush_buffer();
+ $HTML::Mason::Commands::m->abort();
+ die "shouldn't fall through to here (mason \$m->abort didn't)";
+ } else {
+ #??? well, it is $ENV{MOD_PERL}
+ warn "running under unknown mod_perl environment; trying Apache::exit()";
+ require Apache;
+ Apache::exit();
+ }
+ } else {
+ exit;
+ }
+}
+
+=item popurl LEVEL
+
+Returns current URL with LEVEL levels of path removed from the end (default 0).
+
+=cut
+
+sub popurl {
+ my($up)=@_;
+ my $cgi = &FS::UID::cgi;
+ my $url_string = $cgi->isa('Apache') ? $cgi->uri : $cgi->url;
+ $url_string =~ s/\?.*//;
+ my $url = new URI::URL ( $url_string );
+ my(@path)=$url->path_components;
+ splice @path, 0-$up;
+ $url->path_components(@path);
+ my $x = $url->as_string;
+ $x .= '/' unless $x =~ /\/$/;
+ $x;
+}
+
+=item table
+
+Returns HTML tag for beginning a table.
+
+=cut
+
+sub table {
+ use Carp;
+ carp 'FS::CGI::table deprecated; include /elements/table.html instead';
+
+ my $col = shift;
+ if ( $col ) {
+ qq!<TABLE BGCOLOR="$col" BORDER=1 WIDTH="100%" CELLSPACING=0 CELLPADDING=2 BORDERCOLOR="#999999">!;
+ } else {
+ '<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2 BORDERCOLOR="#999999">';
+ }
+}
+
+=item itable
+
+Returns HTML tag for beginning an (invisible) table.
+
+=cut
+
+sub itable {
+ my $col = shift;
+ my $cellspacing = shift || 0;
+ if ( $col ) {
+ qq!<TABLE BGCOLOR="$col" BORDER=0 CELLSPACING=$cellspacing WIDTH="100%">!;
+ } else {
+ qq!<TABLE BORDER=0 CELLSPACING=$cellspacing WIDTH="100%">!;
+ }
+}
+
+=item ntable
+
+This is getting silly.
+
+=cut
+
+sub ntable {
+ my $col = shift;
+ my $cellspacing = shift || 0;
+ if ( $col ) {
+ qq!<TABLE BGCOLOR="$col" BORDER=0 CELLSPACING=$cellspacing>!;
+ } else {
+ '<TABLE BORDER CELLSPACING=0 CELLPADDING=2 BORDERCOLOR="#999999">';
+ }
+
+}
+
+=item small_custview CUSTNUM || CUST_MAIN_OBJECT, COUNTRYDEFAULT
+
+Sheesh. I should just switch to Mason.
+
+=cut
+
+sub small_custview {
+ use FS::Record qw(qsearchs);
+ use FS::cust_main;
+
+ my $arg = shift;
+ my $countrydefault = shift || 'US';
+
+ my $cust_main = ref($arg) ? $arg
+ : qsearchs('cust_main', { 'custnum' => $arg } )
+ or die "unknown custnum $arg";
+
+ my $html = 'Customer #<B>'. $cust_main->custnum. '</B>'.
+ ' - <B><FONT COLOR="'. $cust_main->statuscolor. '">'.
+ ucfirst($cust_main->status). '</FONT></B>'.
+ ntable('#e8e8e8'). '<TR><TD>'. ntable("#cccccc",2).
+ '<TR><TD ALIGN="right" VALIGN="top">Billing<BR>Address</TD><TD BGCOLOR="#ffffff">'.
+ $cust_main->getfield('last'). ', '. $cust_main->first. '<BR>';
+
+ $html .= $cust_main->company. '<BR>' if $cust_main->company;
+ $html .= $cust_main->address1. '<BR>';
+ $html .= $cust_main->address2. '<BR>' if $cust_main->address2;
+ $html .= $cust_main->city. ', '. $cust_main->state. ' '. $cust_main->zip. '<BR>';
+ $html .= $cust_main->country. '<BR>'
+ if $cust_main->country && $cust_main->country ne $countrydefault;
+
+ $html .= '</TD></TR><TR><TD></TD><TD BGCOLOR="#ffffff">';
+ if ( $cust_main->daytime && $cust_main->night ) {
+ use FS::Msgcat;
+ $html .= ( FS::Msgcat::_gettext('daytime') || 'Day' ).
+ ' '. $cust_main->daytime.
+ '<BR>'. ( FS::Msgcat::_gettext('night') || 'Night' ).
+ ' '. $cust_main->night;
+ } elsif ( $cust_main->daytime || $cust_main->night ) {
+ $html .= $cust_main->daytime || $cust_main->night;
+ }
+ if ( $cust_main->fax ) {
+ $html .= '<BR>Fax '. $cust_main->fax;
+ }
+
+ $html .= '</TD></TR></TABLE></TD>';
+
+ if ( defined $cust_main->dbdef_table->column('ship_last') ) {
+
+ my $pre = $cust_main->ship_last ? 'ship_' : '';
+
+ $html .= '<TD>'. ntable("#cccccc",2).
+ '<TR><TD ALIGN="right" VALIGN="top">Service<BR>Address</TD><TD BGCOLOR="#ffffff">'.
+ $cust_main->get("${pre}last"). ', '.
+ $cust_main->get("${pre}first"). '<BR>';
+ $html .= $cust_main->get("${pre}company"). '<BR>'
+ if $cust_main->get("${pre}company");
+ $html .= $cust_main->get("${pre}address1"). '<BR>';
+ $html .= $cust_main->get("${pre}address2"). '<BR>'
+ if $cust_main->get("${pre}address2");
+ $html .= $cust_main->get("${pre}city"). ', '.
+ $cust_main->get("${pre}state"). ' '.
+ $cust_main->get("${pre}ship_zip"). '<BR>';
+ $html .= $cust_main->get("${pre}country"). '<BR>'
+ if $cust_main->get("${pre}country")
+ && $cust_main->get("${pre}country") ne $countrydefault;
+
+ $html .= '</TD></TR><TR><TD></TD><TD BGCOLOR="#ffffff">';
+
+ if ( $cust_main->get("${pre}daytime") && $cust_main->get("${pre}night") ) {
+ use FS::Msgcat;
+ $html .= ( FS::Msgcat::_gettext('daytime') || 'Day' ).
+ ' '. $cust_main->get("${pre}daytime").
+ '<BR>'. ( FS::Msgcat::_gettext('night') || 'Night' ).
+ ' '. $cust_main->get("${pre}night");
+ } elsif ( $cust_main->get("${pre}daytime")
+ || $cust_main->get("${pre}night") ) {
+ $html .= $cust_main->get("${pre}daytime")
+ || $cust_main->get("${pre}night");
+ }
+ if ( $cust_main->get("${pre}fax") ) {
+ $html .= '<BR>Fax '. $cust_main->get("${pre}fax");
+ }
+
+ $html .= '</TD></TR></TABLE></TD>';
+ }
+
+ $html .= '</TR></TABLE>';
+
+ $html .= '<BR>Balance: <B>$'. $cust_main->balance. '</B><BR>';
+
+ # last payment might be good here too?
+
+ $html;
+}
+
+=back
+
+=head1 BUGS
+
+Not OO.
+
+Not complete.
+
+small_custview sooooo doesn't belong here. i should just switch to Mason.
+
+=head1 SEE ALSO
+
+L<CGI>, L<CGI::Base>
+
+=cut
+
+1;
+
+
diff --git a/FS/FS/ClientAPI.pm b/FS/FS/ClientAPI.pm
new file mode 100644
index 0000000..7cbbdbf
--- /dev/null
+++ b/FS/FS/ClientAPI.pm
@@ -0,0 +1,44 @@
+package FS::ClientAPI;
+
+use strict;
+use vars qw(%handler $domain);
+
+%handler = ();
+
+#find modules
+foreach my $INC ( @INC ) {
+ foreach my $file ( glob("$INC/FS/ClientAPI/*.pm") ) {
+ $file =~ /\/(\w+)\.pm$/ or do {
+ warn "unrecognized ClientAPI file: $file";
+ next
+ };
+ my $mod = $1;
+ #warn "using FS::ClientAPI::$mod";
+ eval "use FS::ClientAPI::$mod;";
+ die "error using FS::ClientAPI::$mod: $@" if $@;
+ }
+}
+
+#(sub for modules)
+sub register_handlers {
+ my $self = shift;
+ my %new_handlers = @_;
+ foreach my $key ( keys %new_handlers ) {
+ warn "WARNING: redefining sub $key" if exists $handler{$key};
+ #warn "registering $key";
+ $handler{$key} = $new_handlers{$key};
+ }
+}
+
+#---
+
+sub dispatch {
+ my ( $self, $name ) = ( shift, shift );
+ my $sub = $handler{$name}
+ or die "unknown FS::ClientAPI sub $name (known: ". join(" ", keys %handler );
+ #or die "unknown FS::ClientAPI sub $name";
+ &{$sub}(@_);
+}
+
+1;
+
diff --git a/FS/FS/ClientAPI/Agent.pm b/FS/FS/ClientAPI/Agent.pm
new file mode 100644
index 0000000..212faaa
--- /dev/null
+++ b/FS/FS/ClientAPI/Agent.pm
@@ -0,0 +1,113 @@
+package FS::ClientAPI::Agent;
+
+#some false laziness w/MyAccount
+
+use strict;
+use vars qw($cache);
+use Digest::MD5 qw(md5_hex);
+use Cache::SharedMemoryCache; #store in db?
+use FS::Record qw(qsearchs); # qsearch);
+use FS::agent;
+
+use FS::ClientAPI;
+FS::ClientAPI->register_handlers(
+ 'Agent/agent_login' => \&agent_login,
+ 'Agent/agent_info' => \&agent_info,
+ 'Agent/agent_list_customers' => \&agent_list_customers,
+);
+
+#store in db?
+my $cache = new Cache::SharedMemoryCache( {
+ 'namespace' => 'FS::ClientAPI::Agent',
+} );
+
+sub agent_login {
+ my $p = shift;
+
+ #don't allow a blank login to first unconfigured agent with no user/pass
+ return { error => 'Must specify your reseller username and password.' }
+ unless length($p->{'username'}) && length($p->{'password'});
+
+ my $agent = qsearchs( 'agent', {
+ 'username' => $p->{'username'},
+ '_password' => $p->{'password'},
+ } );
+
+ unless ( $agent ) { return { error => 'Incorrect password.' } }
+
+ my $session = {
+ 'agentnum' => $agent->agentnum,
+ 'agent' => $agent->agent,
+ };
+
+ my $session_id;
+ do {
+ $session_id = md5_hex(md5_hex(time(). {}. rand(). $$))
+ } until ( ! defined $cache->get($session_id) ); #just in case
+
+ $cache->set( $session_id, $session, '1 hour' );
+
+ { 'error' => '',
+ 'session_id' => $session_id,
+ };
+}
+
+sub agent_info {
+ my $p = shift;
+
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ #my %return;
+
+ my $agentnum = $session->{'agentnum'};
+
+ my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } )
+ or return { 'error' => "unknown agentnum $agentnum" };
+
+ { 'error' => '',
+ 'agentnum' => $agentnum,
+ 'agent' => $agent->agent,
+ 'num_prospect' => $agent->num_prospect_cust_main,
+ 'num_active' => $agent->num_active_cust_main,
+ 'num_susp' => $agent->num_susp_cust_main,
+ 'num_cancel' => $agent->num_cancel_cust_main,
+ #%return,
+ };
+
+}
+
+sub agent_list_customers {
+ my $p = shift;
+
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ #my %return;
+
+ my $agentnum = $session->{'agentnum'};
+
+ my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } )
+ or return { 'error' => "unknown agentnum $agentnum" };
+
+ my @cust_main = ();
+
+ warn $p->{'susp'};
+
+ push @cust_main,
+ map $agent->$_(), map $_.'_cust_main',
+ grep $p->{$_}, qw( prospect active susp cancel );
+
+ { customers => [ map {
+ my $cust_main = $_;
+ my $hashref = $cust_main->hashref;
+ $hashref->{$_} = $cust_main->$_()
+ foreach qw(name status statuscolor);
+ delete $hashref->{$_} foreach qw( payinfo paycvv );
+ $hashref;
+ } @cust_main
+ ],
+ }
+
+}
+
diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
new file mode 100644
index 0000000..e8ce6b4
--- /dev/null
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -0,0 +1,580 @@
+package FS::ClientAPI::MyAccount;
+
+use strict;
+use vars qw($cache);
+use Digest::MD5 qw(md5_hex);
+use Date::Format;
+use Business::CreditCard;
+use Cache::SharedMemoryCache; #store in db?
+use FS::CGI qw(small_custview); #doh
+use FS::Conf;
+use FS::Record qw(qsearch qsearchs);
+use FS::Msgcat qw(gettext);
+use FS::svc_acct;
+use FS::svc_domain;
+use FS::svc_external;
+use FS::part_svc;
+use FS::cust_main;
+use FS::cust_bill;
+use FS::cust_main_county;
+use FS::cust_pkg;
+
+use FS::ClientAPI; #hmm
+FS::ClientAPI->register_handlers(
+ 'MyAccount/login' => \&login,
+ 'MyAccount/customer_info' => \&customer_info,
+ 'MyAccount/edit_info' => \&edit_info,
+ 'MyAccount/invoice' => \&invoice,
+ 'MyAccount/list_invoices' => \&list_invoices,
+ 'MyAccount/cancel' => \&cancel,
+ 'MyAccount/payment_info' => \&payment_info,
+ 'MyAccount/process_payment' => \&process_payment,
+ 'MyAccount/list_pkgs' => \&list_pkgs,
+ 'MyAccount/order_pkg' => \&order_pkg,
+ 'MyAccount/cancel_pkg' => \&cancel_pkg,
+ 'MyAccount/charge' => \&charge,
+);
+
+use vars qw( @cust_main_editable_fields );
+@cust_main_editable_fields = qw(
+ first last company address1 address2 city
+ county state zip country daytime night fax
+ ship_first ship_last ship_company ship_address1 ship_address2 ship_city
+ ship_state ship_zip ship_country ship_daytime ship_night ship_fax
+ payby payinfo payname
+);
+
+#store in db?
+my $cache = new Cache::SharedMemoryCache( {
+ 'namespace' => 'FS::ClientAPI::MyAccount',
+} );
+
+#false laziness w/FS::ClientAPI::passwd::passwd
+sub login {
+ my $p = shift;
+
+ my $svc_domain = qsearchs('svc_domain', { 'domain' => $p->{'domain'} } )
+ or return { error => 'Domain '. $p->{'domain'}. ' not found' };
+
+ my $svc_acct = qsearchs( 'svc_acct', { 'username' => $p->{'username'},
+ 'domsvc' => $svc_domain->svcnum, }
+ );
+ return { error => 'User not found.' } unless $svc_acct;
+
+ my $conf = new FS::Conf;
+ my $pkg_svc = $svc_acct->cust_svc->pkg_svc;
+ return { error => 'Only primary user may log in.' }
+ if $conf->exists('selfservice_server-primary_only')
+ && ( ! $pkg_svc || $pkg_svc->primary_svc ne 'Y' );
+
+ return { error => 'Incorrect password.' }
+ unless $svc_acct->check_password($p->{'password'});
+
+ my $session = {
+ 'svcnum' => $svc_acct->svcnum,
+ };
+
+ my $cust_pkg = $svc_acct->cust_svc->cust_pkg;
+ if ( $cust_pkg ) {
+ my $cust_main = $cust_pkg->cust_main;
+ $session->{'custnum'} = $cust_main->custnum;
+ }
+
+ my $session_id;
+ do {
+ $session_id = md5_hex(md5_hex(time(). {}. rand(). $$))
+ } until ( ! defined $cache->get($session_id) ); #just in case
+
+ $cache->set( $session_id, $session, '1 hour' );
+
+ return { 'error' => '',
+ 'session_id' => $session_id,
+ };
+}
+
+sub customer_info {
+ my $p = shift;
+
+ my($session, $custnum, $context);
+ if ( $p->{'session_id'} ) {
+ $context = 'customer';
+ $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+ $custnum = $session->{'custnum'};
+ } elsif ( $p->{'agent_session_id'} ) {
+ $context = 'agent';
+ my $agent_cache = new Cache::SharedMemoryCache( {
+ 'namespace' => 'FS::ClientAPI::Agent',
+ } );
+ $session = $agent_cache->get($p->{'agent_session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+ $custnum = $p->{'custnum'};
+ } else {
+ return { 'error' => "Can't resume session" }; #better error message
+ }
+
+ my %return;
+ if ( $custnum ) { #customer record
+
+ my $search = { 'custnum' => $custnum };
+ $search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent';
+ my $cust_main = qsearchs('cust_main', $search )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ $return{balance} = $cust_main->balance;
+
+ my @open = map {
+ {
+ invnum => $_->invnum,
+ date => time2str("%b %o, %Y", $_->_date),
+ owed => $_->owed,
+ };
+ } $cust_main->open_cust_bill;
+ $return{open_invoices} = \@open;
+
+ my $conf = new FS::Conf;
+ $return{small_custview} =
+ small_custview( $cust_main, $conf->config('defaultcountry') );
+
+ $return{name} = $cust_main->first. ' '. $cust_main->get('last');
+
+ for (@cust_main_editable_fields) {
+ $return{$_} = $cust_main->get($_);
+ }
+
+ if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
+ $return{payinfo} = $cust_main->payinfo_masked;
+ @return{'month', 'year'} = $cust_main->paydate_monthyear;
+ }
+
+ $return{'invoicing_list'} =
+ join(', ', grep { $_ ne 'POST' } $cust_main->invoicing_list );
+ $return{'postal_invoicing'} =
+ 0 < ( grep { $_ eq 'POST' } $cust_main->invoicing_list );
+
+ } else { #no customer record
+
+ my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $session->{'svcnum'} } )
+ or die "unknown svcnum";
+ $return{name} = $svc_acct->email;
+
+ }
+
+ return { 'error' => '',
+ 'custnum' => $custnum,
+ %return,
+ };
+
+}
+
+sub edit_info {
+ my $p = shift;
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my $custnum = $session->{'custnum'}
+ or return { 'error' => "no customer record" };
+
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ my $new = new FS::cust_main { $cust_main->hash };
+ $new->set( $_ => $p->{$_} )
+ foreach grep { exists $p->{$_} } @cust_main_editable_fields;
+
+ if ( $p->{'payby'} =~ /^(CARD|DCRD)$/ ) {
+ $new->paydate($p->{'year'}. '-'. $p->{'month'}. '-01');
+ if ( $new->payinfo eq $cust_main->payinfo_masked ) {
+ $new->payinfo($cust_main->payinfo);
+ } else {
+ $new->paycvv($p->{'paycvv'});
+ }
+ }
+
+ my @invoicing_list;
+ if ( exists $p->{'invoicing_list'} || exists $p->{'postal_invoicing'} ) {
+ #false laziness with httemplate/edit/process/cust_main.cgi
+ @invoicing_list = split( /\s*\,\s*/, $p->{'invoicing_list'} );
+ push @invoicing_list, 'POST' if $p->{'postal_invoicing'};
+ } else {
+ @invoicing_list = $cust_main->invoicing_list;
+ }
+
+ my $error = $new->replace($cust_main, \@invoicing_list);
+ return { 'error' => $error } if $error;
+ #$cust_main = $new;
+
+ return { 'error' => '' };
+}
+
+sub payment_info {
+ my $p = shift;
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my %return;
+
+ my $custnum = $session->{'custnum'};
+
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ $return{balance} = $cust_main->balance;
+
+ $return{payname} = $cust_main->payname
+ || ( $cust_main->first. ' '. $cust_main->get('last') );
+
+ $return{$_} = $cust_main->get($_) for qw(address1 address2 city state zip);
+
+ $return{payby} = $cust_main->payby;
+
+ if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
+ #warn $return{card_type} = cardtype($cust_main->payinfo);
+ $return{payinfo} = $cust_main->payinfo;
+
+ @return{'month', 'year'} = $cust_main->paydate_monthyear;
+
+ }
+
+ #list all counties/states/countries
+ $return{'cust_main_county'} =
+ [ map { $_->hashref } qsearch('cust_main_county', {}) ];
+
+ #shortcut for one-country folks
+ my $conf = new FS::Conf;
+ my %states = map { $_->state => 1 }
+ qsearch('cust_main_county', {
+ 'country' => $conf->config('defaultcountry') || 'US'
+ } );
+ $return{'states'} = [ sort { $a cmp $b } keys %states ];
+
+ $return{card_types} = {
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ };
+
+ my $_date = time;
+ $return{paybatch} = "webui-MyAccount-$_date-$$-". rand() * 2**32;
+
+ return { 'error' => '',
+ %return,
+ };
+
+};
+
+#some false laziness with httemplate/process/payment.cgi - look there for
+#ACH and CVV support stuff
+sub process_payment {
+
+ my $p = shift;
+
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my %return;
+
+ my $custnum = $session->{'custnum'};
+
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ $p->{'payname'} =~ /^([\w \,\.\-\']+)$/
+ or return { 'error' => gettext('illegal_name'). " payname: ". $p->{'payname'} };
+ my $payname = $1;
+
+ $p->{'paybatch'} =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
+ or return { 'error' => gettext('illegal_text'). " paybatch: ". $p->{'paybatch'} };
+ my $paybatch = $1;
+
+ my $payinfo;
+ my $paycvv = '';
+ #if ( $payby eq 'CHEK' ) {
+ #
+ # $p->{'payinfo1'} =~ /^(\d+)$/
+ # or return { 'error' => "illegal account number ". $p->{'payinfo1'} };
+ # my $payinfo1 = $1;
+ # $p->{'payinfo2'} =~ /^(\d+)$/
+ # or return { 'error' => "illegal ABA/routing number ". $p->{'payinfo2'} };
+ # my $payinfo2 = $1;
+ # $payinfo = $payinfo1. '@'. $payinfo2;
+ #
+ #} elsif ( $payby eq 'CARD' ) {
+
+ $payinfo = $p->{'payinfo'};
+ $payinfo =~ s/\D//g;
+ $payinfo =~ /^(\d{13,16})$/
+ or return { 'error' => gettext('invalid_card') }; # . ": ". $self->payinfo
+ $payinfo = $1;
+ validate($payinfo)
+ or return { 'error' => gettext('invalid_card') }; # . ": ". $self->payinfo
+ return { 'error' => gettext('unknown_card_type') }
+ if cardtype($payinfo) eq "Unknown";
+
+ if ( defined $cust_main->dbdef_table->column('paycvv') ) {
+ if ( length($p->{'paycvv'} ) ) {
+ if ( cardtype($payinfo) eq 'American Express card' ) {
+ $p->{'paycvv'} =~ /^(\d{4})$/
+ or return { 'error' => "CVV2 (CID) for American Express cards is four digits." };
+ $paycvv = $1;
+ } else {
+ $p->{'paycvv'} =~ /^(\d{3})$/
+ or return { 'error' => "CVV2 (CVC2/CID) is three digits." };
+ $paycvv = $1;
+ }
+ }
+ }
+
+ #} else {
+ # die "unknown payby $payby";
+ #}
+
+ my $error = $cust_main->realtime_bop( 'CC', $p->{'amount'},
+ 'quiet' => 1,
+ 'payinfo' => $payinfo,
+ 'paydate' => $p->{'year'}. '-'. $p->{'month'}. '-01',
+ 'payname' => $payname,
+ 'paybatch' => $paybatch,
+ 'paycvv' => $paycvv,
+ map { $_ => $p->{$_} } qw( address1 address2 city state zip )
+ );
+ return { 'error' => $error } if $error;
+
+ $cust_main->apply_payments;
+
+ if ( $p->{'save'} ) {
+ my $new = new FS::cust_main { $cust_main->hash };
+ $new->set( $_ => $p->{$_} )
+ foreach qw( payname address1 address2 city state zip payinfo );
+ $new->set( 'paydate' => $p->{'year'}. '-'. $p->{'month'}. '-01' );
+ $new->set( 'payby' => $p->{'auto'} ? 'CARD' : 'DCRD' );
+ my $error = $new->replace($cust_main);
+ return { 'error' => $error } if $error;
+ $cust_main = $new;
+ }
+
+ return { 'error' => '' };
+
+}
+
+sub invoice {
+ my $p = shift;
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my $custnum = $session->{'custnum'};
+
+ my $invnum = $p->{'invnum'};
+
+ my $cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum,
+ 'custnum' => $custnum } )
+ or return { 'error' => "Can't find invnum" };
+
+ #my %return;
+
+ return { 'error' => '',
+ 'invnum' => $invnum,
+ 'invoice_text' => join('', $cust_bill->print_text ),
+ };
+
+}
+
+sub list_invoices {
+ my $p = shift;
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my $custnum = $session->{'custnum'};
+
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ my @cust_bill = $cust_main->cust_bill;
+
+ return { 'error' => '',
+ 'invoices' => [ map { { 'invnum' => $_->invnum,
+ '_date' => $_->_date,
+ }
+ } @cust_bill
+ ]
+ };
+}
+
+sub cancel {
+ my $p = shift;
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my $custnum = $session->{'custnum'};
+
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ my @errors = $cust_main->cancel( 'quiet'=>1 );
+
+ my $error = scalar(@errors) ? join(' / ', @errors) : '';
+
+ return { 'error' => $error };
+
+}
+
+sub list_pkgs {
+ my $p = shift;
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my $custnum = $session->{'custnum'};
+
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ return { 'cust_pkg' => [ map { $_->hashref } $cust_main->ncancelled_pkgs ] };
+
+}
+
+sub order_pkg {
+ my $p = shift;
+
+ my($session, $custnum, $context);
+
+ if ( $p->{'session_id'} ) {
+ $context = 'customer';
+ $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+ $custnum = $session->{'custnum'};
+ } elsif ( $p->{'agent_session_id'} ) {
+ $context = 'agent';
+ my $agent_cache = new Cache::SharedMemoryCache( {
+ 'namespace' => 'FS::ClientAPI::Agent',
+ } );
+ $session = $agent_cache->get($p->{'agent_session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+ $custnum = $p->{'custnum'};
+ } else {
+ return { 'error' => "Can't resume session" }; #better error message
+ }
+
+ my $search = { 'custnum' => $custnum };
+ $search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent';
+
+ my $cust_main = qsearchs('cust_main', $search )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ #false laziness w/ClientAPI/Signup.pm
+
+ my $cust_pkg = new FS::cust_pkg ( {
+ 'custnum' => $custnum,
+ 'pkgpart' => $p->{'pkgpart'},
+ } );
+ my $error = $cust_pkg->check;
+ return { 'error' => $error } if $error;
+
+ my @svc = ();
+ unless ( $p->{'svcpart'} eq 'none' ) {
+
+ my $svcdb;
+ my $svcpart = '';
+ if ( $p->{'svcpart'} =~ /^(\d+)$/ ) {
+ $svcpart = $1;
+ my $part_svc = qsearchs('part_svc', { 'svcpart' => $svcpart } );
+ return { 'error' => "Unknown svcpart $svcpart" } unless $part_svc;
+ $svcdb = $part_svc->svcdb;
+ } else {
+ $svcdb = 'svc_acct';
+ }
+ $svcpart ||= $cust_pkg->part_pkg->svcpart($svcdb);
+
+ my %fields = (
+ 'svc_acct' => [ qw( username _password sec_phrase popnum ) ],
+ 'svc_domain' => [ qw( domain ) ],
+ 'svc_external' => [ qw( id title ) ],
+ );
+
+ my $svc_x = "FS::$svcdb"->new( {
+ 'svcpart' => $svcpart,
+ map { $_ => $p->{$_} } @{$fields{$svcdb}}
+ } );
+
+ if ( $svcdb eq 'svc_acct' ) {
+ my @acct_snarf;
+ my $snarfnum = 1;
+ while ( length($p->{"snarf_machine$snarfnum"}) ) {
+ my $acct_snarf = new FS::acct_snarf ( {
+ 'machine' => $p->{"snarf_machine$snarfnum"},
+ 'protocol' => $p->{"snarf_protocol$snarfnum"},
+ 'username' => $p->{"snarf_username$snarfnum"},
+ '_password' => $p->{"snarf_password$snarfnum"},
+ } );
+ $snarfnum++;
+ push @acct_snarf, $acct_snarf;
+ }
+ $svc_x->child_objects( \@acct_snarf );
+ }
+
+ my $y = $svc_x->setdefault; # arguably should be in new method
+ return { 'error' => $y } if $y && !ref($y);
+
+ $error = $svc_x->check;
+ return { 'error' => $error } if $error;
+
+ push @svc, $svc_x;
+
+ }
+
+ use Tie::RefHash;
+ tie my %hash, 'Tie::RefHash';
+ %hash = ( $cust_pkg => \@svc );
+ #msgcat
+ $error = $cust_main->order_pkgs( \%hash, '', 'noexport' => 1 );
+ return { 'error' => $error } if $error;
+
+ my $conf = new FS::Conf;
+ if ( $conf->exists('signup_server-realtime') ) {
+
+ my $old_balance = $cust_main->balance;
+
+ my $bill_error = $cust_main->bill;
+ $cust_main->apply_payments;
+ $cust_main->apply_credits;
+ $bill_error = $cust_main->collect;
+
+ if ( $cust_main->balance > $old_balance
+ && $cust_main->payby !~ /^(BILL|DCRD|DCHK)$/ ) {
+ $cust_pkg->cancel('quiet'=>1);
+ return { 'error' => '_decline' };
+ } else {
+ $cust_pkg->reexport;
+ }
+
+ } else {
+ $cust_pkg->reexport;
+ }
+
+ return { error => '', pkgnum => $cust_pkg->pkgnum };
+
+}
+
+sub cancel_pkg {
+ my $p = shift;
+ my $session = $cache->get($p->{'session_id'})
+ or return { 'error' => "Can't resume session" }; #better error message
+
+ my $custnum = $session->{'custnum'};
+
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or return { 'error' => "unknown custnum $custnum" };
+
+ my $pkgnum = $p->{'pkgnum'};
+
+ my $cust_pkg = qsearchs('cust_pkg', { 'custnum' => $custnum,
+ 'pkgnum' => $pkgnum, } )
+ or return { 'error' => "unknown pkgnum $pkgnum" };
+
+ my $error = $cust_pkg->cancel( 'quiet'=>1 );
+ return { 'error' => $error };
+
+}
+
+1;
+
diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm
new file mode 100644
index 0000000..2e2b80f
--- /dev/null
+++ b/FS/FS/ClientAPI/Signup.pm
@@ -0,0 +1,288 @@
+package FS::ClientAPI::Signup;
+
+use strict;
+use Tie::RefHash;
+use FS::Conf;
+use FS::Record qw(qsearch qsearchs dbdef);
+use FS::Msgcat qw(gettext);
+use FS::agent;
+use FS::cust_main_county;
+use FS::part_pkg;
+use FS::svc_acct_pop;
+use FS::cust_main;
+use FS::cust_pkg;
+use FS::svc_acct;
+use FS::acct_snarf;
+use FS::queue;
+
+use FS::ClientAPI; #hmm
+FS::ClientAPI->register_handlers(
+ 'Signup/signup_info' => \&signup_info,
+ 'Signup/new_customer' => \&new_customer,
+);
+
+sub signup_info {
+ my $packet = shift;
+
+ my $conf = new FS::Conf;
+
+ use vars qw($signup_info); #cache for performance;
+ $signup_info ||= {
+
+ 'cust_main_county' =>
+ [ map { $_->hashref } qsearch('cust_main_county', {}) ],
+
+ 'agent' =>
+ [
+ map { $_->hashref }
+ qsearch('agent', dbdef->table('agent')->column('disabled')
+ ? { 'disabled' => '' }
+ : {}
+ )
+ ],
+
+ 'part_referral' =>
+ [
+ map { $_->hashref }
+ qsearch('part_referral',
+ dbdef->table('part_referral')->column('disabled')
+ ? { 'disabled' => '' }
+ : {}
+ )
+ ],
+
+ 'agentnum2part_pkg' =>
+ {
+ map {
+ my $href = $_->pkgpart_hashref;
+ $_->agentnum =>
+ [
+ map { { 'payby' => [ $_->payby ], %{$_->hashref} } }
+ grep { $_->svcpart('svc_acct') && $href->{ $_->pkgpart } }
+ qsearch( 'part_pkg', { 'disabled' => '' } )
+ ];
+ } qsearch('agent', dbdef->table('agent')->column('disabled')
+ ? { 'disabled' => '' }
+ : {}
+ )
+ },
+
+ 'svc_acct_pop' => [ map { $_->hashref } qsearch('svc_acct_pop',{} ) ],
+
+ 'security_phrase' => $conf->exists('security_phrase'),
+
+ 'payby' => [ $conf->config('signup_server-payby') ],
+
+ 'cvv_enabled' => defined dbdef->table('cust_main')->column('paycvv'),
+
+ 'msgcat' => { map { $_=>gettext($_) } qw(
+ passwords_dont_match invalid_card unknown_card_type not_a
+ ) },
+
+ 'statedefault' => $conf->config('statedefault') || 'CA',
+
+ 'countrydefault' => $conf->config('countrydefault') || 'US',
+
+ 'refnum' => $conf->config('signup_server-default_refnum'),
+
+ };
+
+ my $agentnum = $conf->config('signup_server-default_agentnum');
+
+ my $session = '';
+ if ( exists $packet->{'session_id'} ) {
+ my $cache = new Cache::SharedMemoryCache( {
+ 'namespace' => 'FS::ClientAPI::Agent',
+ } );
+ $session = $cache->get($packet->{'session_id'});
+ if ( $session ) {
+ $agentnum = $session->{'agentnum'};
+ } else {
+ return { 'error' => "Can't resume session" }; #better error message
+ }
+ }
+
+ if ( $agentnum ) {
+ $signup_info->{'part_pkg'} = $signup_info->{'agentnum2part_pkg'}{$agentnum};
+ } else {
+ delete $signup_info->{'part_pkg'};
+ }
+
+ if ( $session ) {
+ my $agent_signup_info = { %$signup_info };
+ delete $agent_signup_info->{agentnum2part_pkg};
+ $agent_signup_info->{'agent'} = $session->{'agent'};
+ $agent_signup_info;
+ } else {
+ $signup_info;
+ }
+
+}
+
+sub new_customer {
+ my $packet = shift;
+
+ my $conf = new FS::Conf;
+
+ #things that aren't necessary in base class, but are for signup server
+ #return "Passwords don't match"
+ # if $hashref->{'_password'} ne $hashref->{'_password2'}
+ return { 'error' => gettext('empty_password') }
+ unless $packet->{'_password'};
+ # a bit inefficient for large numbers of pops
+ return { 'error' => gettext('no_access_number_selected') }
+ unless $packet->{'popnum'} || !scalar(qsearch('svc_acct_pop',{} ));
+
+ my $agentnum;
+ if ( exists $packet->{'session_id'} ) {
+ my $cache = new Cache::SharedMemoryCache( {
+ 'namespace' => 'FS::ClientAPI::Agent',
+ } );
+ my $session = $cache->get($packet->{'session_id'});
+ if ( $session ) {
+ $agentnum = $session->{'agentnum'};
+ } else {
+ return { 'error' => "Can't resume session" }; #better error message
+ }
+ } else {
+ $agentnum = $packet->{agentnum}
+ || $conf->config('signup_server-default_agentnum');
+ }
+
+ #shares some stuff with htdocs/edit/process/cust_main.cgi... take any
+ # common that are still here and library them.
+ my $cust_main = new FS::cust_main ( {
+ #'custnum' => '',
+ 'agentnum' => $agentnum,
+ 'refnum' => $packet->{refnum}
+ || $conf->config('signup_server-default_refnum'),
+
+ map { $_ => $packet->{$_} } qw(
+ last first ss company address1 address2 city county state zip country
+ daytime night fax payby payinfo paycvv paydate payname referral_custnum
+ comments
+ ),
+
+ } );
+
+ return { 'error' => "Illegal payment type" }
+ unless grep { $_ eq $packet->{'payby'} }
+ $conf->config('signup_server-payby');
+
+ $cust_main->payinfo($cust_main->daytime)
+ if $cust_main->payby eq 'LECB' && ! $cust_main->payinfo;
+
+ my @invoicing_list = split( /\s*\,\s*/, $packet->{'invoicing_list'} );
+
+ $packet->{'pkgpart'} =~ /^(\d+)$/ or '' =~ /^()$/;
+ my $pkgpart = $1;
+ return { 'error' => 'Please select a package' } unless $pkgpart; #msgcat
+
+ my $part_pkg =
+ qsearchs( 'part_pkg', { 'pkgpart' => $pkgpart } )
+ or return { 'error' => "WARNING: unknown pkgpart: $pkgpart" };
+ my $svcpart = $part_pkg->svcpart('svc_acct');
+
+ my $cust_pkg = new FS::cust_pkg ( {
+ #later#'custnum' => $custnum,
+ 'pkgpart' => $packet->{'pkgpart'},
+ } );
+ my $error = $cust_pkg->check;
+ return { 'error' => $error } if $error;
+
+ my $svc_acct = new FS::svc_acct ( {
+ 'svcpart' => $svcpart,
+ map { $_ => $packet->{$_} }
+ qw( username _password sec_phrase popnum ),
+ } );
+
+ my @acct_snarf;
+ my $snarfnum = 1;
+ while ( exists($packet->{"snarf_machine$snarfnum"})
+ && length($packet->{"snarf_machine$snarfnum"}) ) {
+ my $acct_snarf = new FS::acct_snarf ( {
+ 'machine' => $packet->{"snarf_machine$snarfnum"},
+ 'protocol' => $packet->{"snarf_protocol$snarfnum"},
+ 'username' => $packet->{"snarf_username$snarfnum"},
+ '_password' => $packet->{"snarf_password$snarfnum"},
+ } );
+ $snarfnum++;
+ push @acct_snarf, $acct_snarf;
+ }
+ $svc_acct->child_objects( \@acct_snarf );
+
+ my $y = $svc_acct->setdefault; # arguably should be in new method
+ return { 'error' => $y } if $y && !ref($y);
+
+ $error = $svc_acct->check;
+ return { 'error' => $error } if $error;
+
+ #setup a job dependancy to delay provisioning
+ my $placeholder = new FS::queue ( {
+ 'job' => 'FS::ClientAPI::Signup::__placeholder',
+ 'status' => 'locked',
+ } );
+ $error = $placeholder->insert;
+ return { 'error' => $error } if $error;
+
+ use Tie::RefHash;
+ tie my %hash, 'Tie::RefHash';
+ %hash = ( $cust_pkg => [ $svc_acct ] );
+ #msgcat
+ $error = $cust_main->insert(
+ \%hash,
+ \@invoicing_list,
+ 'depend_jobnum' => $placeholder->jobnum,
+ );
+ if ( $error ) {
+ my $perror = $placeholder->delete;
+ $error .= " (Additionally, error removing placeholder: $perror)" if $perror;
+ return { 'error' => $error };
+ }
+
+ if ( $conf->exists('signup_server-realtime') ) {
+
+ #warn "[fs_signup_server] Billing customer...\n" if $Debug;
+
+ my $bill_error = $cust_main->bill;
+ #warn "[fs_signup_server] error billing new customer: $bill_error"
+ # if $bill_error;
+
+ $cust_main->apply_payments;
+ $cust_main->apply_credits;
+
+ $bill_error = $cust_main->collect;
+ #warn "[fs_signup_server] error collecting from new customer: $bill_error"
+ # if $bill_error;
+
+ if ( $cust_main->balance > 0 ) {
+
+ #this makes sense. credit is "un-doing" the invoice
+ $cust_main->credit( $cust_main->balance, 'signup server decline' );
+ $cust_main->apply_credits;
+
+ #should check list for errors...
+ #$cust_main->suspend;
+ local $FS::svc_Common::noexport_hack = 1;
+ $cust_main->cancel('quiet'=>1);
+
+ my $perror = $placeholder->depended_delete;
+ warn "error removing provisioning jobs after decline: $perror" if $perror;
+ unless ( $perror ) {
+ $perror = $placeholder->delete;
+ warn "error removing placeholder after decline: $perror" if $perror;
+ }
+
+ return { 'error' => '_decline' };
+ }
+
+ }
+
+ $error = $placeholder->delete;
+ return { 'error' => $error } if $error;
+
+ return { error => '' };
+
+}
+
+1;
diff --git a/FS/FS/ClientAPI/passwd.pm b/FS/FS/ClientAPI/passwd.pm
new file mode 100644
index 0000000..cb839ec
--- /dev/null
+++ b/FS/FS/ClientAPI/passwd.pm
@@ -0,0 +1,53 @@
+package FS::ClientAPI::passwd;
+
+use strict;
+use FS::Record qw(qsearchs);
+use FS::svc_acct;
+use FS::svc_domain;
+
+use FS::ClientAPI; #hmm
+FS::ClientAPI->register_handlers(
+ 'passwd/passwd' => \&passwd,
+ 'passwd/chfn' => \&chfn,
+ 'passwd/chsh' => \&chsh,
+);
+
+sub passwd {
+ my $packet = shift;
+
+ my $domain = $FS::ClientAPI::domain || $packet->{'domain'};
+ my $svc_domain = qsearchs('svc_domain', { 'domain' => $domain } )
+ or return { error => "Domain $domain not found" };
+
+ my $old_password = $packet->{'old_password'};
+ my $new_password = $packet->{'new_password'};
+ my $new_gecos = $packet->{'new_gecos'};
+ my $new_shell = $packet->{'new_shell'};
+
+ #false laziness w/FS::ClientAPI::MyAccount::login
+
+ my $svc_acct = qsearchs( 'svc_acct', { 'username' => $packet->{'username'},
+ 'domsvc' => $svc_domain->svcnum, }
+ );
+ return { error => 'User not found.' } unless $svc_acct;
+ return { error => 'Incorrect password.' }
+ unless $svc_acct->check_password($old_password);
+
+ my %hash = $svc_acct->hash;
+ my $new_svc_acct = new FS::svc_acct ( \%hash );
+ $new_svc_acct->setfield('_password', $new_password )
+ if $new_password && $new_password ne $old_password;
+ $new_svc_acct->setfield('finger',$new_gecos) if $new_gecos;
+ $new_svc_acct->setfield('shell',$new_shell) if $new_shell;
+ my $error = $new_svc_acct->replace($svc_acct);
+
+ return { error => $error };
+
+}
+
+sub chfn {}
+
+sub chsh {}
+
+1;
+
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
new file mode 100644
index 0000000..6f7b2d6
--- /dev/null
+++ b/FS/FS/Conf.pm
@@ -0,0 +1,1263 @@
+package FS::Conf;
+
+use vars qw($default_dir @config_items $DEBUG );
+use IO::File;
+use File::Basename;
+use FS::ConfItem;
+
+$DEBUG = 0;
+
+=head1 NAME
+
+FS::Conf - Freeside configuration values
+
+=head1 SYNOPSIS
+
+ use FS::Conf;
+
+ $conf = new FS::Conf "/config/directory";
+
+ $FS::Conf::default_dir = "/config/directory";
+ $conf = new FS::Conf;
+
+ $dir = $conf->dir;
+
+ $value = $conf->config('key');
+ @list = $conf->config('key');
+ $bool = $conf->exists('key');
+
+ $conf->touch('key');
+ $conf->set('key' => 'value');
+ $conf->delete('key');
+
+ @config_items = $conf->config_items;
+
+=head1 DESCRIPTION
+
+Read and write Freeside configuration values. Keys currently map to filenames,
+but this may change in the future.
+
+=head1 METHODS
+
+=over 4
+
+=item new [ DIRECTORY ]
+
+Create a new configuration object. A directory arguement is required if
+$FS::Conf::default_dir has not been set.
+
+=cut
+
+sub new {
+ my($proto,$dir) = @_;
+ my($class) = ref($proto) || $proto;
+ my($self) = { 'dir' => $dir || $default_dir } ;
+ bless ($self, $class);
+}
+
+=item dir
+
+Returns the directory.
+
+=cut
+
+sub dir {
+ my($self) = @_;
+ my $dir = $self->{dir};
+ -e $dir or die "FATAL: $dir doesn't exist!";
+ -d $dir or die "FATAL: $dir isn't a directory!";
+ -r $dir or die "FATAL: Can't read $dir!";
+ -x $dir or die "FATAL: $dir not searchable (executable)!";
+ $dir =~ /^(.*)$/;
+ $1;
+}
+
+=item config KEY
+
+Returns the configuration value or values (depending on context) for key.
+
+=cut
+
+sub config {
+ my($self,$file)=@_;
+ my($dir)=$self->dir;
+ my $fh = new IO::File "<$dir/$file" or return;
+ if ( wantarray ) {
+ map {
+ /^(.*)$/
+ or die "Illegal line (array context) in $dir/$file:\n$_\n";
+ $1;
+ } <$fh>;
+ } else {
+ <$fh> =~ /^(.*)$/
+ or die "Illegal line (scalar context) in $dir/$file:\n$_\n";
+ $1;
+ }
+}
+
+=item exists KEY
+
+Returns true if the specified key exists, even if the corresponding value
+is undefined.
+
+=cut
+
+sub exists {
+ my($self,$file)=@_;
+ my($dir) = $self->dir;
+ -e "$dir/$file";
+}
+
+=item config_orbase KEY SUFFIX
+
+Returns the configuration value or values (depending on context) for
+KEY_SUFFIX, if it exists, otherwise for KEY
+
+=cut
+
+sub config_orbase {
+ my( $self, $file, $suffix ) = @_;
+ if ( $self->exists("${file}_$suffix") ) {
+ $self->config("${file}_$suffix");
+ } else {
+ $self->config($file);
+ }
+}
+
+=item touch KEY
+
+Creates the specified configuration key if it does not exist.
+
+=cut
+
+sub touch {
+ my($self, $file) = @_;
+ my $dir = $self->dir;
+ unless ( $self->exists($file) ) {
+ warn "[FS::Conf] TOUCH $file\n" if $DEBUG;
+ system('touch', "$dir/$file");
+ }
+}
+
+=item set KEY VALUE
+
+Sets the specified configuration key to the given value.
+
+=cut
+
+sub set {
+ my($self, $file, $value) = @_;
+ my $dir = $self->dir;
+ $value =~ /^(.*)$/s;
+ $value = $1;
+ unless ( join("\n", @{[ $self->config($file) ]}) eq $value ) {
+ warn "[FS::Conf] SET $file\n" if $DEBUG;
+# warn "$dir" if is_tainted($dir);
+# warn "$dir" if is_tainted($file);
+ chmod 0644, "$dir/$file";
+ my $fh = new IO::File ">$dir/$file" or return;
+ chmod 0644, "$dir/$file";
+ print $fh "$value\n";
+ }
+}
+#sub is_tainted {
+# return ! eval { join('',@_), kill 0; 1; };
+# }
+
+=item delete KEY
+
+Deletes the specified configuration key.
+
+=cut
+
+sub delete {
+ my($self, $file) = @_;
+ my $dir = $self->dir;
+ if ( $self->exists($file) ) {
+ warn "[FS::Conf] DELETE $file\n";
+ unlink "$dir/$file";
+ }
+}
+
+=item config_items
+
+Returns all of the possible configuration items as FS::ConfItem objects. See
+L<FS::ConfItem>.
+
+=cut
+
+sub config_items {
+ my $self = shift;
+ #quelle kludge
+ @config_items,
+ ( map {
+ my $basename = basename($_);
+ $basename =~ /^(.*)$/;
+ $basename = $1;
+ new FS::ConfItem {
+ 'key' => $basename,
+ 'section' => 'billing',
+ 'description' => 'Alternate template file for invoices. See the <a href="../docs/billing.html">billing documentation</a> for details.',
+ 'type' => 'textarea',
+ }
+ } glob($self->dir. '/invoice_template_*')
+ ),
+ ( map {
+ my $basename = basename($_);
+ $basename =~ /^(.*)$/;
+ $basename = $1;
+ new FS::ConfItem {
+ 'key' => $basename,
+ 'section' => 'billing',
+ 'description' => 'Alternate LaTeX template for invoices. See the <a href="../docs/billing.html">billing documentation</a> for details.',
+ 'type' => 'textarea',
+ }
+ } glob($self->dir. '/invoice_latex_*')
+ ),
+ ( map {
+ my $basename = basename($_);
+ $basename =~ /^(.*)$/;
+ $basename = $1;
+ new FS::ConfItem {
+ 'key' => $basename,
+ 'section' => 'billing',
+ 'description' => 'Alternate Notes section for LaTeX typeset PostScript invoices. See the <a href="../docs/billing.html">billing documentation</a> for details.',
+ 'type' => 'textarea',
+ }
+ } glob($self->dir. '/invoice_latexnotes_*')
+ );
+}
+
+=back
+
+=head1 BUGS
+
+If this was more than just crud that will never be useful outside Freeside I'd
+worry that config_items is freeside-specific and icky.
+
+=head1 SEE ALSO
+
+"Configuration" in the web interface (config/config.cgi).
+
+httemplate/docs/config.html
+
+=cut
+
+@config_items = map { new FS::ConfItem $_ } (
+
+ {
+ 'key' => 'address',
+ 'section' => 'deprecated',
+ 'description' => 'This configuration option is no longer used. See <a href="#invoice_template">invoice_template</a> instead.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'alerter_template',
+ 'section' => 'billing',
+ 'description' => 'Template file for billing method expiration alerts. See the <a href="../docs/billing.html#invoice_template">billing documentation</a> for details.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'apacheroot',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>www_shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead. The directory containing Apache virtual hosts',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'apacheip',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add an <i>apache</i> <a href="../browse/part_export.cgi">export</a> instead. Used to be the current IP address to assign to new virtual hosts',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'apachemachine',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>www_shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead. A machine with the apacheroot directory and user home directories. The existance of this file enables setup of virtual host directories, and, in conjunction with the `home\' configuration file, symlinks into user home directories.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'apachemachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add an <i>apache</i> <a href="../browse/part_export.cgi">export</a> instead. Used to be Apache machines, one per line. This enables export of `/etc/apache/vhosts.conf\', which can be included in your Apache configuration via the <a href="http://www.apache.org/docs/mod/core.html#include">Include</a> directive.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'bindprimary',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>bind</i> <a href="../browse/part_export.cgi">export</a> instead. Your BIND primary nameserver. This enables export of /var/named/named.conf and zone files into /var/named',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'bindsecondaries',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>bind_slave</i> <a href="../browse/part_export.cgi">export</a> instead. Your BIND secondary nameservers, one per line. This enables export of /var/named/named.conf',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'business-onlinepayment',
+ 'section' => 'billing',
+ 'description' => '<a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> support, at least three lines: processor, login, and password. An optional fourth line specifies the action or actions (multiple actions are separated with `,\': for example: `Authorization Only, Post Authorization\'). Optional additional lines are passed to Business::OnlinePayment as %processor_options.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'business-onlinepayment-ach',
+ 'section' => 'billing',
+ 'description' => 'Alternate <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> support for ACH transactions (defaults to regular <b>business-onlinepayment</b>). At least three lines: processor, login, and password. An optional fourth line specifies the action or actions (multiple actions are separated with `,\': for example: `Authorization Only, Post Authorization\'). Optional additional lines are passed to Business::OnlinePayment as %processor_options.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'business-onlinepayment-description',
+ 'section' => 'billing',
+ 'description' => 'String passed as the description field to <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a>. Evaluated as a double-quoted perl string, with the following variables available: <code>$agent</code> (the agent name), and <code>$pkgs</code> (a comma-separated list of packages for which these charges apply)',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'bsdshellmachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>bsdshell</i> <a href="../browse/part_export.cgi">export</a> instead. Your BSD flavored shell (and mail) machines, one per line. This enables export of `/etc/passwd\' and `/etc/master.passwd\'.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'countrydefault',
+ 'section' => 'UI',
+ 'description' => 'Default two-letter country code (if not supplied, the default is `US\')',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'cyrus',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>cyrus</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to integrate with <a href="http://asg.web.cmu.edu/cyrus/imapd/">Cyrus IMAP Server</a>, three lines: IMAP server, admin username, and admin password. Cyrus::IMAP::Admin should be installed locally and the connection to the server secured.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'cp_app',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>cp</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to integrate with <a href="http://www.cp.net/">Critial Path Account Provisioning Protocol</a>, four lines: "host:port", username, password, and workgroup (for new users).',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'deletecustomers',
+ 'section' => 'UI',
+ 'description' => 'Enable customer deletions. Be very careful! Deleting a customer will remove all traces that this customer ever existed! It should probably only be used when auditing a legacy database. Normally, you cancel all of a customers\' packages if they cancel service.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'deletepayments',
+ 'section' => 'UI',
+ 'description' => 'Enable deletion of unclosed payments. Be very careful! Only delete payments that were data-entry errors, not adjustments. Optionally specify one or more comma-separated email addresses to be notified when a payment is deleted.',
+ 'type' => [qw( checkbox text )],
+ },
+
+ {
+ 'key' => 'deletecredits',
+ 'section' => 'UI',
+ 'description' => 'Enable deletion of unclosed credits. Be very careful! Only delete credits that were data-entry errors, not adjustments. Optionally specify one or more comma-separated email addresses to be notified when a credit is deleted.',
+ 'type' => [qw( checkbox text )],
+ },
+
+ {
+ 'key' => 'unapplypayments',
+ 'section' => 'UI',
+ 'description' => 'Enable "unapplication" of unclosed payments.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'unapplycredits',
+ 'section' => 'UI',
+ 'description' => 'Enable "unapplication" of unclosed credits.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'dirhash',
+ 'section' => 'shell',
+ 'description' => 'Optional numeric value to control directory hashing. If positive, hashes directories for the specified number of levels from the front of the username. If negative, hashes directories for the specified number of levels from the end of the username. Some examples: <ul><li>1: user -> <a href="#home">/home</a>/u/user<li>2: user -> <a href="#home">/home</a>/u/s/user<li>-1: user -> <a href="#home">/home</a>/r/user<li>-2: user -> <a href="#home">home</a>/r/e/user</ul>',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'disable_customer_referrals',
+ 'section' => 'UI',
+ 'description' => 'Disable new customer-to-customer referrals in the web interface',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'editreferrals',
+ 'section' => 'UI',
+ 'description' => 'Enable advertising source modification for existing customers',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'emailinvoiceonly',
+ 'section' => 'billing',
+ 'description' => 'Disables postal mail invoices',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'disablepostalinvoicedefault',
+ 'section' => 'billing',
+ 'description' => 'Disables postal mail invoices as the default option in the UI. Be careful not to setup customers which are not sent invoices. See <a href ="#emailinvoiceauto">emailinvoiceauto</a>.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'emailinvoiceauto',
+ 'section' => 'billing',
+ 'description' => 'Automatically adds new accounts to the email invoice list',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'exclude_ip_addr',
+ 'section' => '',
+ 'description' => 'Exclude these from the list of available broadband service IP addresses. (One per line)',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'erpcdmachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, ERPCD is no longer supported. Used to be ERPCD authenticaion machines, one per line. This enables export of `/usr/annex/acp_passwd\' and `/usr/annex/acp_dialup\'',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'hidecancelledpackages',
+ 'section' => 'UI',
+ 'description' => 'Prevent cancelled packages from showing up in listings (though they will still be in the database)',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'hidecancelledcustomers',
+ 'section' => 'UI',
+ 'description' => 'Prevent customers with only cancelled packages from showing up in listings (though they will still be in the database)',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'home',
+ 'section' => 'required',
+ 'description' => 'For new users, prefixed to username to create a directory name. Should have a leading but not a trailing slash.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'icradiusmachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to enable radcheck and radreply table population - by default in the Freeside database, or in the database specified by the <a href="http://rootwood.haze.st/aspside/config/config-view.cgi#icradius_secrets">icradius_secrets</a> config option (the radcheck and radreply tables needs to be created manually). You do not need to use MySQL for your Freeside database to export to an ICRADIUS/FreeRADIUS MySQL database with this option. <blockquote><b>ADDITIONAL DEPRECATED FUNCTIONALITY</b> (instead use <a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Replication">MySQL replication</a> or point icradius_secrets to the external database) - your <a href="ftp://ftp.cheapnet.net/pub/icradius">ICRADIUS</a> machines or <a href="http://www.freeradius.org/">FreeRADIUS</a> (with MySQL authentication) machines, one per line. Machines listed in this file will have the radcheck table exported to them. Each line should contain four items, separted by whitespace: machine name, MySQL database name, MySQL username, and MySQL password. For example: <CODE>"radius.isp.tld&nbsp;radius_db&nbsp;radius_user&nbsp;passw0rd"</CODE></blockquote>',
+ 'type' => [qw( checkbox textarea )],
+ },
+
+ {
+ 'key' => 'icradius_mysqldest',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead. Used to be the destination directory for the MySQL databases, on the ICRADIUS/FreeRADIUS machines. Defaults to "/usr/local/var/".',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'icradius_mysqlsource',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead. Used to be the source directory for for the MySQL radcheck table files, on the Freeside machine. Defaults to "/usr/local/var/freeside".',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'icradius_secrets',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to specify a database for ICRADIUS/FreeRADIUS export. Three lines: DBI data source, username and password.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'invoice_from',
+ 'section' => 'required',
+ 'description' => 'Return address on email invoices',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'invoice_template',
+ 'section' => 'required',
+ 'description' => 'Required template file for invoices. See the <a href="../docs/billing.html">billing documentation</a> for details.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'invoice_latex',
+ 'section' => 'billing',
+ 'description' => 'Optional LaTeX template for typeset PostScript invoices.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'invoice_latexnotes',
+ 'section' => 'billing',
+ 'description' => 'Notes section for LaTeX typeset PostScript invoices.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'invoice_latexfooter',
+ 'section' => 'billing',
+ 'description' => 'Footer for LaTeX typeset PostScript invoices.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'invoice_latexsmallfooter',
+ 'section' => 'billing',
+ 'description' => 'Optional small footer for multi-page LaTeX typeset PostScript invoices.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'invoice_default_terms',
+ 'section' => 'billing',
+ 'description' => 'Optional default invoice term, used to calculate a due date printed on invoices.',
+ 'type' => 'select',
+ 'select_enum' => [ '', 'Payable upon receipt', 'Net 0', 'Net 10', 'Net 15', 'Net 30', 'Net 45', 'Net 60' ],
+ },
+
+ {
+ 'key' => 'invoice_send_receipts',
+ 'section' => 'billing',
+ 'description' => 'Send receipts for payments and credits.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'lpr',
+ 'section' => 'required',
+ 'description' => 'Print command for paper invoices, for example `lpr -h\'',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'maildisablecatchall',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, now the default. Turning this option on used to disable the requirement that each virtual domain have a catch-all mailbox.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'money_char',
+ 'section' => '',
+ 'description' => 'Currency symbol - defaults to `$\'',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'mxmachines',
+ 'section' => 'deprecated',
+ 'description' => 'MX entries for new domains, weight and machine, one per line, with trailing `.\'',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'nsmachines',
+ 'section' => 'deprecated',
+ 'description' => 'NS nameservers for new domains, one per line, with trailing `.\'',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'defaultrecords',
+ 'section' => 'BIND',
+ 'description' => 'DNS entries to add automatically when creating a domain',
+ 'type' => 'editlist',
+ 'editlist_parts' => [ { type=>'text' },
+ { type=>'immutable', value=>'IN' },
+ { type=>'select',
+ select_enum=>{ map { $_=>$_ } qw(A CNAME MX NS)} },
+ { type=> 'text' }, ],
+ },
+
+ {
+ 'key' => 'arecords',
+ 'section' => 'deprecated',
+ 'description' => 'A list of tab seperated CNAME records to add automatically when creating a domain',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'cnamerecords',
+ 'section' => 'deprecated',
+ 'description' => 'A list of tab seperated CNAME records to add automatically when creating a domain',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'nismachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>. Your NIS master (not slave master) machines, one per line. This enables export of `/etc/global/passwd\' and `/etc/global/shadow\'.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'passwordmin',
+ 'section' => 'password',
+ 'description' => 'Minimum password length (default 6)',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'passwordmax',
+ 'section' => 'password',
+ 'description' => 'Maximum password length (default 8) (don\'t set this over 12 if you need to import or export crypt() passwords)',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'qmailmachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add <i>qmail</i> and <i>shellcommands</i> <a href="../browse/part_export.cgi">exports</a> instead. This option used to export `/var/qmail/control/virtualdomains\', `/var/qmail/control/recipientmap\', and `/var/qmail/control/rcpthosts\'. Setting this option (even if empty) also turns on user `.qmail-extension\' file maintenance in conjunction with the <b>shellmachine</b> option.',
+ 'type' => [qw( checkbox textarea )],
+ },
+
+ {
+ 'key' => 'radiusmachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to export to be: your RADIUS authentication machines, one per line. This enables export of `/etc/raddb/users\'.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'referraldefault',
+ 'section' => 'UI',
+ 'description' => 'Default referral, specified by refnum',
+ 'type' => 'text',
+ },
+
+# {
+# 'key' => 'registries',
+# 'section' => 'required',
+# 'description' => 'Directory which contains domain registry information. Each registry is a directory.',
+# },
+
+ {
+ 'key' => 'report_template',
+ 'section' => 'deprecated',
+ 'description' => 'Deprecated template file for reports.',
+ 'type' => 'textarea',
+ },
+
+
+ {
+ 'key' => 'maxsearchrecordsperpage',
+ 'section' => 'UI',
+ 'description' => 'If set, number of search records to return per page.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'sendmailconfigpath',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>sendmail</i> <a href="../browse/part_export.cgi">export</a> instead. Used to be sendmail configuration file path. Defaults to `/etc\'. Many newer distributions use `/etc/mail\'.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'sendmailmachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>sendmail</i> <a href="../browse/part_export.cgi">export</a> instead. Used to be sendmail machines, one per line. This enables export of `/etc/virtusertable\' and `/etc/sendmail.cw\'.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'sendmailrestart',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>sendmail</i> <a href="../browse/part_export.cgi">export</a> instead. Used to define the command which is run on sendmail machines after files are copied.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'session-start',
+ 'section' => 'session',
+ 'description' => 'If defined, the command which is executed on the Freeside machine when a session begins. The contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$ip</code>, <code>$nasip</code> and <code>$nasfqdn</code>, which are the IP address of the starting session, and the IP address and fully-qualified domain name of the NAS this session is on.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'session-stop',
+ 'section' => 'session',
+ 'description' => 'If defined, the command which is executed on the Freeside machine when a session ends. The contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$ip</code>, <code>$nasip</code> and <code>$nasfqdn</code>, which are the IP address of the starting session, and the IP address and fully-qualified domain name of the NAS this session is on.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'shellmachine',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to contain a single machine with user home directories mounted. This enables home directory creation, renaming and archiving/deletion. In conjunction with `qmailmachines\', it also enables `.qmail-extension\' file maintenance.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'shellmachine-useradd',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to contain command(s) to run on shellmachine when an account is created. If the <b>shellmachine</b> option is set but this option is not, <code>useradd -d $dir -m -s $shell -u $uid $username</code> is the default. If this option is set but empty, <code>cp -pr /etc/skel $dir; chown -R $uid.$gid $dir</code> is the default instead. Otherwise the value is evaluated as a double-quoted perl string, with the following variables available: <code>$username</code>, <code>$uid</code>, <code>$gid</code>, <code>$dir</code>, and <code>$shell</code>.',
+ 'type' => [qw( checkbox text )],
+ },
+
+ {
+ 'key' => 'shellmachine-userdel',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to contain command(s) to run on shellmachine when an account is deleted. If the <b>shellmachine</b> option is set but this option is not, <code>userdel $username</code> is the default. If this option is set but empty, <code>rm -rf $dir</code> is the default instead. Otherwise the value is evaluated as a double-quoted perl string, with the following variables available: <code>$username</code> and <code>$dir</code>.',
+ 'type' => [qw( checkbox text )],
+ },
+
+ {
+ 'key' => 'shellmachine-usermod',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to contain command(s) to run on shellmachine when an account is modified. If the <b>shellmachine</b> option is set but this option is empty, <code>[ -d $old_dir ] &amp;&amp; mv $old_dir $new_dir || ( chmod u+t $old_dir; mkdir $new_dir; cd $old_dir; find . -depth -print | cpio -pdm $new_dir; chmod u-t $new_dir; chown -R $uid.$gid $new_dir; rm -rf $old_dir )</code> is the default. Otherwise the contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$old_dir</code>, <code>$new_dir</code>, <code>$uid</code> and <code>$gid</code>.',
+ #'type' => [qw( checkbox text )],
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'shellmachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>sysvshell</i> <a href="../browse/part_export.cgi">export</a> instead. Your Linux and System V flavored shell (and mail) machines, one per line. This enables export of `/etc/passwd\' and `/etc/shadow\' files.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'shells',
+ 'section' => 'required',
+ 'description' => 'Legal shells (think /etc/shells). You probably want to `cut -d: -f7 /etc/passwd | sort | uniq\' initially so that importing doesn\'t fail with `Illegal shell\' errors, then remove any special entries afterwords. A blank line specifies that an empty shell is permitted.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'showpasswords',
+ 'section' => 'UI',
+ 'description' => 'Display unencrypted user passwords in the web interface',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'signupurl',
+ 'section' => 'UI',
+ 'description' => 'if you are using customer-to-customer referrals, and you enter the URL of your <a href="../docs/signup.html">signup server CGI</a>, the customer view screen will display a customized link to the signup server with the appropriate customer as referral',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'smtpmachine',
+ 'section' => 'required',
+ 'description' => 'SMTP relay for Freeside\'s outgoing mail',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'soadefaultttl',
+ 'section' => 'BIND',
+ 'description' => 'SOA default TTL for new domains.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'soaemail',
+ 'section' => 'BIND',
+ 'description' => 'SOA email for new domains, in BIND form (`.\' instead of `@\'), with trailing `.\'',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'soaexpire',
+ 'section' => 'BIND',
+ 'description' => 'SOA expire for new domains',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'soamachine',
+ 'section' => 'BIND',
+ 'description' => 'SOA machine for new domains, with trailing `.\'',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'soarefresh',
+ 'section' => 'BIND',
+ 'description' => 'SOA refresh for new domains',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'soaretry',
+ 'section' => 'BIND',
+ 'description' => 'SOA retry for new domains',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'statedefault',
+ 'section' => 'UI',
+ 'description' => 'Default state or province (if not supplied, the default is `CA\')',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'radiusprepend',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, real-time text radius now edits an existing file in place - just (turn off freeside-queued and) edit your RADIUS users file directly. The contents used to be be prepended to the top of the RADIUS users file (text exports only).',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'textradiusprepend',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, use RADIUS check attributes instead. The contents used to be prepended to the first line of a user\'s RADIUS entry in text exports.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'unsuspendauto',
+ 'section' => 'billing',
+ 'description' => 'Enables the automatic unsuspension of suspended packages when a customer\'s balance due changes from positive to zero or negative as the result of a payment or credit',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'usernamemin',
+ 'section' => 'username',
+ 'description' => 'Minimum username length (default 2)',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'usernamemax',
+ 'section' => 'username',
+ 'description' => 'Maximum username length',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'username-ampersand',
+ 'section' => 'username',
+ 'description' => 'Allow the ampersand character (&amp;) in usernames. Be careful when using this option in conjunction with <a href="../browse/part_export.cgi">exports</a> which execute shell commands, as the ampersand will be interpreted by the shell if not quoted.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'username-letter',
+ 'section' => 'username',
+ 'description' => 'Usernames must contain at least one letter',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'username-letterfirst',
+ 'section' => 'username',
+ 'description' => 'Usernames must start with a letter',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'username-noperiod',
+ 'section' => 'username',
+ 'description' => 'Disallow periods in usernames',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'username-nounderscore',
+ 'section' => 'username',
+ 'description' => 'Disallow underscores in usernames',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'username-nodash',
+ 'section' => 'username',
+ 'description' => 'Disallow dashes in usernames',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'username-uppercase',
+ 'section' => 'username',
+ 'description' => 'Allow uppercase characters in usernames',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'username_policy',
+ 'section' => 'deprecated',
+ 'description' => 'This file controls the mechanism for preventing duplicate usernames in passwd/radius files exported from svc_accts. This should be one of \'prepend domsvc\' \'append domsvc\' \'append domain\' or \'append @domain\'',
+ 'type' => 'select',
+ 'select_enum' => [ 'prepend domsvc', 'append domsvc', 'append domain', 'append @domain' ],
+ #'type' => 'text',
+ },
+
+ {
+ 'key' => 'vpopmailmachines',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>vpopmail</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to contain your vpopmail pop toasters, one per line. Each line is of the form "machinename vpopdir vpopuid vpopgid". For example: <code>poptoaster.domain.tld /home/vpopmail 508 508</code> Note: vpopuid and vpopgid are values taken from the vpopmail machine\'s /etc/passwd',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'vpopmailrestart',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, add a <i>vpopmail</i> <a href="../browse/part_export.cgi">export</a> instead. This option used to define the shell commands to run on vpopmail machines after files are copied. An example can be found in eg/vpopmailrestart of the source distribution.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'safe-part_pkg',
+ 'section' => 'UI',
+ 'description' => 'Validates package definition setup and recur expressions against a preset list. Useful for webdemos, annoying to powerusers.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'safe-part_bill_event',
+ 'section' => 'UI',
+ 'description' => 'Validates invoice event expressions against a preset list. Useful for webdemos, annoying to powerusers.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'show_ss',
+ 'section' => 'UI',
+ 'description' => 'Turns on display/collection of SS# in the web interface.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'agent_defaultpkg',
+ 'section' => 'UI',
+ 'description' => 'Setting this option will cause new packages to be available to all agent types by default.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'legacy_link',
+ 'section' => 'UI',
+ 'description' => 'Display options in the web interface to link legacy pre-Freeside services.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'legacy_link-steal',
+ 'section' => 'UI',
+ 'description' => 'Allow "stealing" an already-audited service from one customer (or package) to another using the link function.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'queue_dangerous_controls',
+ 'section' => 'UI',
+ 'description' => 'Enable queue modification controls on account pages and for new jobs. Unless you are a developer working on new export code, you should probably leave this off to avoid causing provisioning problems.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'security_phrase',
+ 'section' => 'password',
+ 'description' => 'Enable the tracking of a "security phrase" with each account. Not recommended, as it is vulnerable to social engineering.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'locale',
+ 'section' => 'UI',
+ 'description' => 'Message locale',
+ 'type' => 'select',
+ 'select_enum' => [ qw(en_US) ],
+ },
+
+ {
+ 'key' => 'selfservice_server-quiet',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, the self-service server no longer sends superfluous decline and cancel emails. Used to disable decline and cancel emails generated by transactions initiated by the selfservice server.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'signup_server-quiet',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, the signup server is now part of the self-service server and no longer sends superfluous decline and cancel emails. Used to disable decline and cancel emails generated by transactions initiated by the signup server. Does not disable welcome emails.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'signup_server-payby',
+ 'section' => '',
+ 'description' => 'Acceptable payment types for the signup server',
+ 'type' => 'selectmultiple',
+ 'select_enum' => [ qw(CARD DCRD CHEK DCHK LECB PREPAY BILL COMP) ],
+ },
+
+ {
+ 'key' => 'signup_server-email',
+ 'section' => 'deprecated',
+ 'description' => '<b>DEPRECATED</b>, this feature is no longer available. See the ***fill me in*** report instead. Used to contain a comma-separated list of email addresses to receive notification of signups via the signup server.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'signup_server-default_agentnum',
+ 'section' => '',
+ 'description' => 'Default agentnum for the signup server',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'signup_server-default_refnum',
+ 'section' => '',
+ 'description' => 'Default advertising source number for the signup server',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'show-msgcat-codes',
+ 'section' => 'UI',
+ 'description' => 'Show msgcat codes in error messages. Turn this option on before reporting errors to the mailing list.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'signup_server-realtime',
+ 'section' => '',
+ 'description' => 'Run billing for signup server signups immediately, and suspend accounts which subsequently have a balance.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'declinetemplate',
+ 'section' => 'billing',
+ 'description' => 'Template file for credit card decline emails.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'emaildecline',
+ 'section' => 'billing',
+ 'description' => 'Enable emailing of credit card decline notices.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'emaildecline-exclude',
+ 'section' => 'billing',
+ 'description' => 'List of error messages that should not trigger email decline notices, one per line.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'cancelmessage',
+ 'section' => 'billing',
+ 'description' => 'Template file for cancellation emails.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'cancelsubject',
+ 'section' => 'billing',
+ 'description' => 'Subject line for cancellation emails.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'emailcancel',
+ 'section' => 'billing',
+ 'description' => 'Enable emailing of cancellation notices.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'require_cardname',
+ 'section' => 'billing',
+ 'description' => 'Require an "Exact name on card" to be entered explicitly; don\'t default to using the first and last name.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'enable_taxclasses',
+ 'section' => 'billing',
+ 'description' => 'Enable per-package tax classes',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'welcome_email',
+ 'section' => '',
+ 'description' => 'Template file for welcome email. Welcome emails are sent to the customer email invoice destination(s) each time a svc_acct record is created. See the <a href="http://search.cpan.org/doc/MJD/Text-Template-1.42/Template.pm">Text::Template</a> documentation for details on the template substitution language. The following variables are available: <code>$username</code>, <code>$password</code>, <code>$first</code>, <code>$last</code> and <code>$pkg</code>.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'welcome_email-from',
+ 'section' => '',
+ 'description' => 'From: address header for welcome email',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'welcome_email-subject',
+ 'section' => '',
+ 'description' => 'Subject: header for welcome email',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'welcome_email-mimetype',
+ 'section' => '',
+ 'description' => 'MIME type for welcome email',
+ 'type' => 'select',
+ 'select_enum' => [ 'text/plain', 'text/html' ],
+ },
+
+ {
+ 'key' => 'payby-default',
+ 'section' => 'UI',
+ 'description' => 'Default payment type. HIDE disables display of billing information and sets customers to BILL.',
+ 'type' => 'select',
+ 'select_enum' => [ '', qw(CARD DCRD CHEK DCHK LECB BILL COMP HIDE) ],
+ },
+
+ {
+ 'key' => 'svc_acct-notes',
+ 'section' => 'UI',
+ 'description' => 'Extra HTML to be displayed on the Account View screen.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'radius-password',
+ 'section' => '',
+ 'description' => 'RADIUS attribute for plain-text passwords.',
+ 'type' => 'select',
+ 'select_enum' => [ 'Password', 'User-Password' ],
+ },
+
+ {
+ 'key' => 'radius-ip',
+ 'section' => '',
+ 'description' => 'RADIUS attribute for IP addresses.',
+ 'type' => 'select',
+ 'select_enum' => [ 'Framed-IP-Address', 'Framed-Address' ],
+ },
+
+ {
+ 'key' => 'svc_acct-alldomains',
+ 'section' => '',
+ 'description' => 'Allow accounts to select any domain in the database. Normally accounts can only select from the domain set in the service definition and those purchased by the customer.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'dump-scpdest',
+ 'section' => '',
+ 'description' => 'destination for scp database dumps: user@host:/path',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'users-allow_comp',
+ 'section' => '',
+ 'description' => 'Usernames (Freeside users, created with <a href="../docs/man/bin/freeside-adduser.html">freeside-adduser</a>) which can create complimentary customers, one per line. If no usernames are entered, all users can create complimentary accounts.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'cvv-save',
+ 'section' => 'billing',
+ 'description' => 'Save CVV2 information after the initial transaction for the selected credit card types. Enabling this option may be in violation of your merchant agreement(s), so please check them carefully before enabling this option for any credit card types.',
+ 'type' => 'selectmultiple',
+ 'select_enum' => [ "VISA card",
+ "MasterCard",
+ "Discover card",
+ "American Express card",
+ "Diner's Club/Carte Blanche",
+ "enRoute",
+ "JCB",
+ "BankCard",
+ ],
+ },
+
+ {
+ 'key' => 'allow_negative_charges',
+ 'section' => 'billing',
+ 'description' => 'Allow negative charges. Normally not used unless importing data from a legacy system that requires this.',
+ 'type' => 'checkbox',
+ },
+ {
+ 'key' => 'auto_unset_catchall',
+ 'section' => '',
+ 'description' => 'When canceling a svc_acct that is the email catchall for one or more svc_domains, automatically set their catchall fields to null. If this option is not set, the attempt will simply fail.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'system_usernames',
+ 'section' => 'username',
+ 'description' => 'A list of system usernames that cannot be edited or removed, one per line. Use a bare username to prohibit modification/deletion of the username in any domain, or username@domain to prohibit modification/deletetion of a specific username and domain.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'cust_pkg-change_svcpart',
+ 'section' => '',
+ 'description' => "When changing packages, move services even if svcparts don't match between old and new pacakge definitions. Use with caution! No provision is made for export differences between the old and new service definitions. Probably only should be used when your exports for all service definitions of a given svcdb are identical.",
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'disable_autoreverse',
+ 'section' => 'BIND',
+ 'description' => 'Disable automatic synchronization of reverse-ARPA entries.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'svc_www-enable_subdomains',
+ 'section' => '',
+ 'description' => 'Enable selection of specific subdomains for virtual host creation.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'svc_www-usersvc_svcpart',
+ 'section' => '',
+ 'description' => 'Allowable service definition svcparts for virtual hosts, one per line.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'selfservice_server-primary_only',
+ 'section' => '',
+ 'description' => 'Only allow primary accounts to access self-service functionality.',
+ 'type' => 'checkbox',
+ },
+
+
+
+);
+
+1;
+
diff --git a/FS/FS/ConfItem.pm b/FS/FS/ConfItem.pm
new file mode 100644
index 0000000..83295b4
--- /dev/null
+++ b/FS/FS/ConfItem.pm
@@ -0,0 +1,63 @@
+package FS::ConfItem;
+
+=head1 NAME
+
+FS::ConfItem - Configutaion option meta-data.
+
+=head1 SYNOPSIS
+
+ use FS::Conf;
+ @config_items = $conf->config_items;
+
+ foreach $item ( @config_items ) {
+ $key = $item->key;
+ $section = $item->section;
+ $description = $item->description;
+ }
+
+=head1 DESCRIPTION
+
+=head1 METHODS
+
+=over 4
+
+=item new
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = @_ ? shift : {};
+ bless ($self, $class);
+}
+
+=item key
+
+=item section
+
+=item description
+
+=cut
+
+sub AUTOLOAD {
+ my $self = shift;
+ my $field = $AUTOLOAD;
+ $field =~ s/.*://;
+ $self->{$field};
+}
+
+=back
+
+=head1 BUGS
+
+Terse docs.
+
+=head1 SEE ALSO
+
+L<FS::Conf>
+
+=cut
+
+1;
+
diff --git a/FS/FS/InitHandler.pm b/FS/FS/InitHandler.pm
new file mode 100644
index 0000000..5038cf3
--- /dev/null
+++ b/FS/FS/InitHandler.pm
@@ -0,0 +1,91 @@
+package FS::InitHandler;
+
+# this leaks memory under graceful restarts and i wouldn't use it on any
+# modern server. useful for very slow machines with memory to spare, just
+# always do a full restart
+
+use strict;
+use vars qw($DEBUG);
+use FS::UID qw(adminsuidsetup);
+use FS::Record;
+
+$DEBUG = 1;
+
+sub handler {
+
+ use Date::Format;
+ use Date::Parse;
+ use Tie::IxHash;
+ use HTML::Entities;
+ use IO::Handle;
+ use IO::File;
+ use String::Approx;
+ use HTML::Widgets::SelectLayers 0.02;
+ #use FS::UID;
+ #use FS::Record;
+ use FS::Conf;
+ use FS::CGI;
+ use FS::Msgcat;
+
+ use FS::agent;
+ use FS::agent_type;
+ use FS::domain_record;
+ use FS::cust_bill;
+ use FS::cust_bill_pay;
+ use FS::cust_credit;
+ use FS::cust_credit_bill;
+ use FS::cust_main;
+ use FS::cust_main_county;
+ use FS::cust_pay;
+ use FS::cust_pkg;
+ use FS::cust_refund;
+ use FS::cust_svc;
+ use FS::nas;
+ use FS::part_bill_event;
+ use FS::part_pkg;
+ use FS::part_referral;
+ use FS::part_svc;
+ use FS::pkg_svc;
+ use FS::port;
+ use FS::queue;
+ use FS::raddb;
+ use FS::session;
+ use FS::svc_acct;
+ use FS::svc_acct_pop;
+ use FS::svc_domain;
+ use FS::svc_forward;
+ use FS::svc_www;
+ use FS::type_pkgs;
+ use FS::part_export;
+ use FS::part_export_option;
+ use FS::export_svc;
+ use FS::msgcat;
+
+ warn "[FS::InitHandler] handler called\n" if $DEBUG;
+
+ #this is sure to be broken on freebsd
+ $> = $FS::UID::freeside_uid;
+
+ open(MAPSECRETS,"<$FS::UID::conf_dir/mapsecrets")
+ or die "can't read $FS::UID::conf_dir/mapsecrets: $!";
+
+ my %seen;
+ while (<MAPSECRETS>) {
+ next if /^\s*(#|$)/;
+ /^([\w\-\.]+)\s(.*)$/
+ or do { warn "strange line in mapsecrets: $_"; next; };
+ my($user, $datasrc) = ($1, $2);
+ next if $seen{$datasrc}++;
+ warn "[FS::InitHandler] preloading $datasrc for $user\n" if $DEBUG;
+ adminsuidsetup($user);
+ }
+
+ close MAPSECRETS;
+
+ #lalala probably broken on freebsd
+ ($<, $>) = ($>, $<);
+ $< = 0;
+
+}
+
+1;
diff --git a/FS/FS/Misc.pm b/FS/FS/Misc.pm
new file mode 100644
index 0000000..efad2df
--- /dev/null
+++ b/FS/FS/Misc.pm
@@ -0,0 +1,102 @@
+package FS::Misc;
+
+use strict;
+use vars qw ( @ISA @EXPORT_OK );
+use Exporter;
+
+@ISA = qw( Exporter );
+@EXPORT_OK = qw( send_email );
+
+=head1 NAME
+
+FS::Misc - Miscellaneous subroutines
+
+=head1 SYNOPSIS
+
+ use FS::Misc qw(send_email);
+
+ send_email();
+
+=head1 DESCRIPTION
+
+Miscellaneous subroutines. This module contains miscellaneous subroutines
+called from multiple other modules. These are not OO or necessarily related,
+but are collected here to elimiate code duplication.
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item send_email OPTION => VALUE ...
+
+Options:
+
+I<from> - (required)
+
+I<to> - (required) comma-separated scalar or arrayref of recipients
+
+I<subject> - (required)
+
+I<content-type> - (optional) MIME type
+
+I<body> - (required) arrayref of body text lines
+
+=cut
+
+use vars qw( $conf );
+use Date::Format;
+use Mail::Header;
+use Mail::Internet 1.44;
+use FS::UID;
+
+FS::UID->install_callback( sub {
+ $conf = new FS::Conf;
+} );
+
+sub send_email {
+ my(%options) = @_;
+
+ $ENV{MAILADDRESS} = $options{'from'};
+ my $to = ref($options{to}) ? join(', ', @{ $options{to} } ) : $options{to};
+ my @header = (
+ 'From: '. $options{'from'},
+ 'To: '. $to,
+ 'Sender: '. $options{'from'},
+ 'Reply-To: '. $options{'from'},
+ 'Date: '. time2str("%a, %d %b %Y %X %z", time),
+ 'Subject: '. $options{'subject'},
+ );
+ push @header, 'Content-Type: '. $options{'content-type'}
+ if exists($options{'content-type'});
+ my $header = new Mail::Header ( \@header );
+
+ my $message = new Mail::Internet (
+ 'Header' => $header,
+ 'Body' => $options{'body'},
+ );
+
+ my $smtpmachine = $conf->config('smtpmachine');
+ $!=0;
+
+ my $rv = $message->smtpsend( 'Host' => $smtpmachine )
+ or $message->smtpsend( Host => $smtpmachine, Debug => 1 );
+
+ if ($rv) { #smtpsend returns a list of addresses, not true/false
+ return '';
+ } else {
+ return "can't send email to $to via server $smtpmachine with SMTP: $!";
+ }
+
+}
+
+=head1 BUGS
+
+This package exists.
+
+=head1 SEE ALSO
+
+L<FS::UID>, L<FS::CGI>, L<FS::Record>, the base documentation.
+
+=cut
+
+1;
diff --git a/FS/FS/Msgcat.pm b/FS/FS/Msgcat.pm
new file mode 100644
index 0000000..625743d
--- /dev/null
+++ b/FS/FS/Msgcat.pm
@@ -0,0 +1,98 @@
+package FS::Msgcat;
+
+use strict;
+use vars qw( @ISA @EXPORT_OK $conf $locale $debug );
+use Exporter;
+use FS::UID;
+#use FS::Record qw( qsearchs ); # wtf? won't import...
+use FS::Record;
+use FS::Conf;
+use FS::msgcat;
+
+@ISA = qw(Exporter);
+@EXPORT_OK = qw( gettext geterror );
+
+$FS::UID::callback{'Msgcat'} = sub {
+ $conf = new FS::Conf;
+ $locale = $conf->config('locale') || 'en_US';
+ $debug = $conf->exists('show-msgcat-codes')
+};
+
+=head1 NAME
+
+FS::Msgcat - Message catalog functions
+
+=head1 SYNOPSIS
+
+ use FS::Msgcat qw(gettext geterror);
+
+ #simple interface for retreiving messages...
+ $message = gettext('msgcode');
+ #or errors (includes the error code)
+ $message = geterror('msgcode');
+
+=head1 DESCRIPTION
+
+FS::Msgcat provides functions to use the message catalog. If you want to
+maintain the message catalog database, see L<FS::msgcat> instead.
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item gettext MSGCODE
+
+Returns the full message for the supplied message code.
+
+=cut
+
+sub gettext {
+ $debug ? geterror(@_) : _gettext(@_);
+}
+
+sub _gettext {
+ my $msgcode = shift;
+ my $msgcat = FS::Record::qsearchs('msgcat', {
+ 'msgcode' => $msgcode,
+ 'locale' => $locale
+ } );
+ if ( $msgcat ) {
+ $msgcat->msg;
+ } else {
+ warn "WARNING: message for msgcode $msgcode in locale $locale not found";
+ $msgcode;
+ }
+
+}
+
+=item geterror MSGCODE
+
+Returns the full message for the supplied message code, including the message
+code.
+
+=cut
+
+sub geterror {
+ my $msgcode = shift;
+ my $msg = _gettext($msgcode);
+ if ( $msg eq $msgcode ) {
+ "Error code $msgcode (message for locale $locale not found)";
+ } else {
+ "$msg (error code $msgcode)";
+ }
+}
+
+=back
+
+=head1 BUGS
+
+i18n/l10n, eek
+
+=head1 SEE ALSO
+
+L<FS::msgcat>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm
new file mode 100644
index 0000000..946e39d
--- /dev/null
+++ b/FS/FS/Record.pm
@@ -0,0 +1,1670 @@
+package FS::Record;
+
+use strict;
+use vars qw( $dbdef_file $dbdef $setup_hack $AUTOLOAD @ISA @EXPORT_OK $DEBUG
+ $me %dbdef_cache %virtual_fields_cache );
+use subs qw(reload_dbdef);
+use Exporter;
+use Carp qw(carp cluck croak confess);
+use File::CounterFile;
+use Locale::Country;
+use DBI qw(:sql_types);
+use DBIx::DBSchema 0.23;
+use FS::UID qw(dbh getotaker datasrc driver_name);
+use FS::SearchCache;
+use FS::Msgcat qw(gettext);
+
+use FS::part_virtual_field;
+
+use Tie::IxHash;
+
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(dbh fields hfields qsearch qsearchs dbdef jsearch);
+
+$DEBUG = 0;
+$me = '[FS::Record]';
+
+#ask FS::UID to run this stuff for us later
+$FS::UID::callback{'FS::Record'} = sub {
+ $File::CounterFile::DEFAULT_DIR = "/usr/local/etc/freeside/counters.". datasrc;
+ $dbdef_file = "/usr/local/etc/freeside/dbdef.". datasrc;
+ &reload_dbdef unless $setup_hack; #$setup_hack needed now?
+};
+
+=head1 NAME
+
+FS::Record - Database record objects
+
+=head1 SYNOPSIS
+
+ use FS::Record;
+ use FS::Record qw(dbh fields qsearch qsearchs dbdef);
+
+ $record = new FS::Record 'table', \%hash;
+ $record = new FS::Record 'table', { 'column' => 'value', ... };
+
+ $record = qsearchs FS::Record 'table', \%hash;
+ $record = qsearchs FS::Record 'table', { 'column' => 'value', ... };
+ @records = qsearch FS::Record 'table', \%hash;
+ @records = qsearch FS::Record 'table', { 'column' => 'value', ... };
+
+ $table = $record->table;
+ $dbdef_table = $record->dbdef_table;
+
+ $value = $record->get('column');
+ $value = $record->getfield('column');
+ $value = $record->column;
+
+ $record->set( 'column' => 'value' );
+ $record->setfield( 'column' => 'value' );
+ $record->column('value');
+
+ %hash = $record->hash;
+
+ $hashref = $record->hashref;
+
+ $error = $record->insert;
+
+ $error = $record->delete;
+
+ $error = $new_record->replace($old_record);
+
+ # external use deprecated - handled by the database (at least for Pg, mysql)
+ $value = $record->unique('column');
+
+ $error = $record->ut_float('column');
+ $error = $record->ut_number('column');
+ $error = $record->ut_numbern('column');
+ $error = $record->ut_money('column');
+ $error = $record->ut_text('column');
+ $error = $record->ut_textn('column');
+ $error = $record->ut_alpha('column');
+ $error = $record->ut_alphan('column');
+ $error = $record->ut_phonen('column');
+ $error = $record->ut_anything('column');
+ $error = $record->ut_name('column');
+
+ $dbdef = reload_dbdef;
+ $dbdef = reload_dbdef "/non/standard/filename";
+ $dbdef = dbdef;
+
+ $quoted_value = _quote($value,'table','field');
+
+ #deprecated
+ $fields = hfields('table');
+ if ( $fields->{Field} ) { # etc.
+
+ @fields = fields 'table'; #as a subroutine
+ @fields = $record->fields; #as a method call
+
+
+=head1 DESCRIPTION
+
+(Mostly) object-oriented interface to database records. Records are currently
+implemented on top of DBI. FS::Record is intended as a base class for
+table-specific classes to inherit from, i.e. FS::cust_main.
+
+=head1 CONSTRUCTORS
+
+=over 4
+
+=item new [ TABLE, ] HASHREF
+
+Creates a new record. It doesn't store it in the database, though. See
+L<"insert"> for that.
+
+Note that the object stores this hash reference, not a distinct copy of the
+hash it points to. You can ask the object for a copy with the I<hash>
+method.
+
+TABLE can only be omitted when a dervived class overrides the table method.
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = {};
+ bless ($self, $class);
+
+ unless ( defined ( $self->table ) ) {
+ $self->{'Table'} = shift;
+ carp "warning: FS::Record::new called with table name ". $self->{'Table'};
+ }
+
+ my $hashref = $self->{'Hash'} = shift;
+
+ foreach my $field ( grep !defined($hashref->{$_}), $self->fields ) {
+ $hashref->{$field}='';
+ }
+
+ $self->_cache($hashref, shift) if $self->can('_cache') && @_;
+
+ $self;
+}
+
+sub new_or_cached {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = {};
+ bless ($self, $class);
+
+ $self->{'Table'} = shift unless defined ( $self->table );
+
+ my $hashref = $self->{'Hash'} = shift;
+ my $cache = shift;
+ if ( defined( $cache->cache->{$hashref->{$cache->key}} ) ) {
+ my $obj = $cache->cache->{$hashref->{$cache->key}};
+ $obj->_cache($hashref, $cache) if $obj->can('_cache');
+ $obj;
+ } else {
+ $cache->cache->{$hashref->{$cache->key}} = $self->new($hashref, $cache);
+ }
+
+}
+
+sub create {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = {};
+ bless ($self, $class);
+ if ( defined $self->table ) {
+ cluck "create constructor is deprecated, use new!";
+ $self->new(@_);
+ } else {
+ croak "FS::Record::create called (not from a subclass)!";
+ }
+}
+
+=item qsearch TABLE, HASHREF, SELECT, EXTRA_SQL, CACHE_OBJ
+
+Searches the database for all records matching (at least) the key/value pairs
+in HASHREF. Returns all the records found as `FS::TABLE' objects if that
+module is loaded (i.e. via `use FS::cust_main;'), otherwise returns FS::Record
+objects.
+
+###oops, argh, FS::Record::new only lets us create database fields.
+#Normal behaviour if SELECT is not specified is `*', as in
+#C<SELECT * FROM table WHERE ...>. However, there is an experimental new
+#feature where you can specify SELECT - remember, the objects returned,
+#although blessed into the appropriate `FS::TABLE' package, will only have the
+#fields you specify. This might have unwanted results if you then go calling
+#regular FS::TABLE methods
+#on it.
+
+=cut
+
+sub qsearch {
+ my($stable, $record, $select, $extra_sql, $cache ) = @_;
+ #$stable =~ /^([\w\_]+)$/ or die "Illegal table: $table";
+ #for jsearch
+ $stable =~ /^([\w\s\(\)\.\,\=]+)$/ or die "Illegal table: $stable";
+ $stable = $1;
+ $select ||= '*';
+ my $dbh = dbh;
+
+ my $table = $cache ? $cache->table : $stable;
+ my $pkey = $dbdef->table($table)->primary_key;
+
+ my @real_fields = grep exists($record->{$_}), real_fields($table);
+ my @virtual_fields = grep exists($record->{$_}), "FS::$table"->virtual_fields;
+
+ my $statement = "SELECT $select FROM $stable";
+ if ( @real_fields or @virtual_fields ) {
+ $statement .= ' WHERE '. join(' AND ',
+ ( map {
+
+ my $op = '=';
+ my $column = $_;
+ if ( ref($record->{$_}) ) {
+ $op = $record->{$_}{'op'} if $record->{$_}{'op'};
+ #$op = 'LIKE' if $op =~ /^ILIKE$/i && driver_name ne 'Pg';
+ if ( uc($op) eq 'ILIKE' ) {
+ $op = 'LIKE';
+ $record->{$_}{'value'} = lc($record->{$_}{'value'});
+ $column = "LOWER($_)";
+ }
+ $record->{$_} = $record->{$_}{'value'}
+ }
+
+ if ( ! defined( $record->{$_} ) || $record->{$_} eq '' ) {
+ if ( $op eq '=' ) {
+ if ( driver_name eq 'Pg' ) {
+ my $type = $dbdef->table($table)->column($column)->type;
+ if ( $type =~ /(int|serial)/i ) {
+ qq-( $column IS NULL )-;
+ } else {
+ qq-( $column IS NULL OR $column = '' )-;
+ }
+ } else {
+ qq-( $column IS NULL OR $column = "" )-;
+ }
+ } elsif ( $op eq '!=' ) {
+ if ( driver_name eq 'Pg' ) {
+ my $type = $dbdef->table($table)->column($column)->type;
+ if ( $type =~ /(int|serial)/i ) {
+ qq-( $column IS NOT NULL )-;
+ } else {
+ qq-( $column IS NOT NULL AND $column != '' )-;
+ }
+ } else {
+ qq-( $column IS NOT NULL AND $column != "" )-;
+ }
+ } else {
+ if ( driver_name eq 'Pg' ) {
+ qq-( $column $op '' )-;
+ } else {
+ qq-( $column $op "" )-;
+ }
+ }
+ } else {
+ "$column $op ?";
+ }
+ } @real_fields ),
+ ( map {
+ my $op = '=';
+ my $column = $_;
+ if ( ref($record->{$_}) ) {
+ $op = $record->{$_}{'op'} if $record->{$_}{'op'};
+ if ( uc($op) eq 'ILIKE' ) {
+ $op = 'LIKE';
+ $record->{$_}{'value'} = lc($record->{$_}{'value'});
+ $column = "LOWER($_)";
+ }
+ $record->{$_} = $record->{$_}{'value'};
+ }
+
+ # ... EXISTS ( SELECT name, value FROM part_virtual_field
+ # JOIN virtual_field
+ # ON part_virtual_field.vfieldpart = virtual_field.vfieldpart
+ # WHERE recnum = svc_acct.svcnum
+ # AND (name, value) = ('egad', 'brain') )
+
+ my $value = $record->{$_};
+
+ my $subq;
+
+ $subq = ($value ? 'EXISTS ' : 'NOT EXISTS ') .
+ "( SELECT part_virtual_field.name, virtual_field.value ".
+ "FROM part_virtual_field JOIN virtual_field ".
+ "ON part_virtual_field.vfieldpart = virtual_field.vfieldpart ".
+ "WHERE virtual_field.recnum = ${table}.${pkey} ".
+ "AND part_virtual_field.name = '${column}'".
+ ($value ?
+ " AND virtual_field.value ${op} '${value}'"
+ : "") . ")";
+ $subq;
+
+ } @virtual_fields ) );
+
+ }
+
+ $statement .= " $extra_sql" if defined($extra_sql);
+
+ warn "[debug]$me $statement\n" if $DEBUG > 1;
+ my $sth = $dbh->prepare($statement)
+ or croak "$dbh->errstr doing $statement";
+
+ my $bind = 1;
+
+ foreach my $field (
+ grep defined( $record->{$_} ) && $record->{$_} ne '', @real_fields
+ ) {
+ if ( $record->{$field} =~ /^\d+(\.\d+)?$/
+ && $dbdef->table($table)->column($field)->type =~ /(int|serial)/i
+ ) {
+ $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_INTEGER } );
+ } else {
+ $sth->bind_param($bind++, $record->{$field}, { TYPE => SQL_VARCHAR } );
+ }
+ }
+
+# $sth->execute( map $record->{$_},
+# grep defined( $record->{$_} ) && $record->{$_} ne '', @fields
+# ) or croak "Error executing \"$statement\": ". $sth->errstr;
+
+ $sth->execute or croak "Error executing \"$statement\": ". $sth->errstr;
+
+ my %result;
+ tie %result, "Tie::IxHash";
+ @virtual_fields = "FS::$table"->virtual_fields;
+
+ my @stuff = @{ $sth->fetchall_arrayref( {} ) };
+ if($pkey) {
+ %result = map { $_->{$pkey}, $_ } @stuff;
+ } else {
+ @result{@stuff} = @stuff;
+ }
+
+ $sth->finish;
+ if ( keys(%result) and @virtual_fields ) {
+ $statement =
+ "SELECT virtual_field.recnum, part_virtual_field.name, ".
+ "virtual_field.value ".
+ "FROM part_virtual_field JOIN virtual_field USING (vfieldpart) ".
+ "WHERE part_virtual_field.dbtable = '$table' AND ".
+ "virtual_field.recnum IN (".
+ join(',', keys(%result)). ") AND part_virtual_field.name IN ('".
+ join(q!', '!, @virtual_fields) . "')";
+ warn "[debug]$me $statement\n" if $DEBUG > 1;
+ $sth = $dbh->prepare($statement) or croak "$dbh->errstr doing $statement";
+ $sth->execute or croak "Error executing \"$statement\": ". $sth->errstr;
+
+ foreach (@{ $sth->fetchall_arrayref({}) }) {
+ my $recnum = $_->{recnum};
+ my $name = $_->{name};
+ my $value = $_->{value};
+ if (exists($result{$recnum})) {
+ $result{$recnum}->{$name} = $value;
+ }
+ }
+ }
+
+ if ( eval 'scalar(@FS::'. $table. '::ISA);' ) {
+ if ( eval 'FS::'. $table. '->can(\'new\')' eq \&new ) {
+ #derivied class didn't override new method, so this optimization is safe
+ if ( $cache ) {
+ map {
+ new_or_cached( "FS::$table", { %{$_} }, $cache )
+ } values(%result);
+ } else {
+ map {
+ new( "FS::$table", { %{$_} } )
+ } values(%result);
+ }
+ } else {
+ warn "untested code (class FS::$table uses custom new method)";
+ map {
+ eval 'FS::'. $table. '->new( { %{$_} } )';
+ } values(%result);
+ }
+ } else {
+ cluck "warning: FS::$table not loaded; returning FS::Record objects";
+ map {
+ FS::Record->new( $table, { %{$_} } );
+ } values(%result);
+ }
+
+}
+
+=item jsearch TABLE, HASHREF, SELECT, EXTRA_SQL, PRIMARY_TABLE, PRIMARY_KEY
+
+Experimental JOINed search method. Using this method, you can execute a
+single SELECT spanning multiple tables, and cache the results for subsequent
+method calls. Interface will almost definately change in an incompatible
+fashion.
+
+Arguments:
+
+=cut
+
+sub jsearch {
+ my($table, $record, $select, $extra_sql, $ptable, $pkey ) = @_;
+ my $cache = FS::SearchCache->new( $ptable, $pkey );
+ my %saw;
+ ( $cache,
+ grep { !$saw{$_->getfield($pkey)}++ }
+ qsearch($table, $record, $select, $extra_sql, $cache )
+ );
+}
+
+=item qsearchs TABLE, HASHREF
+
+Same as qsearch, except that if more than one record matches, it B<carp>s but
+returns the first. If this happens, you either made a logic error in asking
+for a single item, or your data is corrupted.
+
+=cut
+
+sub qsearchs { # $result_record = &FS::Record:qsearchs('table',\%hash);
+ my $table = $_[0];
+ my(@result) = qsearch(@_);
+ carp "warning: Multiple records in scalar search ($table)"
+ if scalar(@result) > 1;
+ #should warn more vehemently if the search was on a primary key?
+ scalar(@result) ? ($result[0]) : ();
+}
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item table
+
+Returns the table name.
+
+=cut
+
+sub table {
+# cluck "warning: FS::Record::table deprecated; supply one in subclass!";
+ my $self = shift;
+ $self -> {'Table'};
+}
+
+=item dbdef_table
+
+Returns the DBIx::DBSchema::Table object for the table.
+
+=cut
+
+sub dbdef_table {
+ my($self)=@_;
+ my($table)=$self->table;
+ $dbdef->table($table);
+}
+
+=item get, getfield COLUMN
+
+Returns the value of the column/field/key COLUMN.
+
+=cut
+
+sub get {
+ my($self,$field) = @_;
+ # to avoid "Use of unitialized value" errors
+ if ( defined ( $self->{Hash}->{$field} ) ) {
+ $self->{Hash}->{$field};
+ } else {
+ '';
+ }
+}
+sub getfield {
+ my $self = shift;
+ $self->get(@_);
+}
+
+=item set, setfield COLUMN, VALUE
+
+Sets the value of the column/field/key COLUMN to VALUE. Returns VALUE.
+
+=cut
+
+sub set {
+ my($self,$field,$value) = @_;
+ $self->{'Hash'}->{$field} = $value;
+}
+sub setfield {
+ my $self = shift;
+ $self->set(@_);
+}
+
+=item AUTLOADED METHODS
+
+$record->column is a synonym for $record->get('column');
+
+$record->column('value') is a synonym for $record->set('column','value');
+
+=cut
+
+# readable/safe
+sub AUTOLOAD {
+ my($self,$value)=@_;
+ my($field)=$AUTOLOAD;
+ $field =~ s/.*://;
+ if ( defined($value) ) {
+ confess "errant AUTOLOAD $field for $self (arg $value)"
+ unless ref($self) && $self->can('setfield');
+ $self->setfield($field,$value);
+ } else {
+ confess "errant AUTOLOAD $field for $self (no args)"
+ unless ref($self) && $self->can('getfield');
+ $self->getfield($field);
+ }
+}
+
+# efficient
+#sub AUTOLOAD {
+# my $field = $AUTOLOAD;
+# $field =~ s/.*://;
+# if ( defined($_[1]) ) {
+# $_[0]->setfield($field, $_[1]);
+# } else {
+# $_[0]->getfield($field);
+# }
+#}
+
+=item hash
+
+Returns a list of the column/value pairs, usually for assigning to a new hash.
+
+To make a distinct duplicate of an FS::Record object, you can do:
+
+ $new = new FS::Record ( $old->table, { $old->hash } );
+
+=cut
+
+sub hash {
+ my($self) = @_;
+ %{ $self->{'Hash'} };
+}
+
+=item hashref
+
+Returns a reference to the column/value hash.
+
+=cut
+
+sub hashref {
+ my($self) = @_;
+ $self->{'Hash'};
+}
+
+=item insert
+
+Inserts this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ my $error = $self->check;
+ return $error if $error;
+
+ #single-field unique keys are given a value if false
+ #(like MySQL's AUTO_INCREMENT or Pg SERIAL)
+ foreach ( $self->dbdef_table->unique->singles ) {
+ $self->unique($_) unless $self->getfield($_);
+ }
+
+ #and also the primary key, if the database isn't going to
+ my $primary_key = $self->dbdef_table->primary_key;
+ my $db_seq = 0;
+ if ( $primary_key ) {
+ my $col = $self->dbdef_table->column($primary_key);
+
+ $db_seq =
+ uc($col->type) eq 'SERIAL'
+ || ( driver_name eq 'Pg'
+ && defined($col->default)
+ && $col->default =~ /^nextval\(/i
+ )
+ || ( driver_name eq 'mysql'
+ && defined($col->local)
+ && $col->local =~ /AUTO_INCREMENT/i
+ );
+ $self->unique($primary_key) unless $self->getfield($primary_key) || $db_seq;
+ }
+
+ my $table = $self->table;
+ #false laziness w/delete
+ my @real_fields =
+ grep defined($self->getfield($_)) && $self->getfield($_) ne "",
+ real_fields($table)
+ ;
+ my @values = map { _quote( $self->getfield($_), $table, $_) } @real_fields;
+ #eslaf
+
+ my $statement = "INSERT INTO $table ( ".
+ join( ', ', @real_fields ).
+ ") VALUES (".
+ join( ', ', @values ).
+ ")"
+ ;
+ warn "[debug]$me $statement\n" if $DEBUG > 1;
+ my $sth = dbh->prepare($statement) or return dbh->errstr;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ $sth->execute or return $sth->errstr;
+
+ my $insertid = '';
+ if ( $db_seq ) { # get inserted id from the database, if applicable
+ warn "[debug]$me retreiving sequence from database\n" if $DEBUG;
+ if ( driver_name eq 'Pg' ) {
+
+ my $oid = $sth->{'pg_oid_status'};
+ my $i_sql = "SELECT $primary_key FROM $table WHERE oid = ?";
+ my $i_sth = dbh->prepare($i_sql) or do {
+ dbh->rollback if $FS::UID::AutoCommit;
+ return dbh->errstr;
+ };
+ $i_sth->execute($oid) or do {
+ dbh->rollback if $FS::UID::AutoCommit;
+ return $i_sth->errstr;
+ };
+ $insertid = $i_sth->fetchrow_arrayref->[0];
+
+ } elsif ( driver_name eq 'mysql' ) {
+
+ $insertid = dbh->{'mysql_insertid'};
+ # work around mysql_insertid being null some of the time, ala RT :/
+ unless ( $insertid ) {
+ warn "WARNING: DBD::mysql didn't return mysql_insertid; ".
+ "using SELECT LAST_INSERT_ID();";
+ my $i_sql = "SELECT LAST_INSERT_ID()";
+ my $i_sth = dbh->prepare($i_sql) or do {
+ dbh->rollback if $FS::UID::AutoCommit;
+ return dbh->errstr;
+ };
+ $i_sth->execute or do {
+ dbh->rollback if $FS::UID::AutoCommit;
+ return $i_sth->errstr;
+ };
+ $insertid = $i_sth->fetchrow_arrayref->[0];
+ }
+
+ } else {
+ dbh->rollback if $FS::UID::AutoCommit;
+ return "don't know how to retreive inserted ids from ". driver_name.
+ ", try using counterfiles (maybe run dbdef-create?)";
+ }
+ $self->setfield($primary_key, $insertid);
+ }
+
+ my @virtual_fields =
+ grep defined($self->getfield($_)) && $self->getfield($_) ne "",
+ $self->virtual_fields;
+ if (@virtual_fields) {
+ my %v_values = map { $_, $self->getfield($_) } @virtual_fields;
+
+ my $vfieldpart = $self->vfieldpart_hashref;
+
+ my $v_statement = "INSERT INTO virtual_field(recnum, vfieldpart, value) ".
+ "VALUES (?, ?, ?)";
+
+ my $v_sth = dbh->prepare($v_statement) or do {
+ dbh->rollback if $FS::UID::AutoCommit;
+ return dbh->errstr;
+ };
+
+ foreach (keys(%v_values)) {
+ $v_sth->execute($self->getfield($primary_key),
+ $vfieldpart->{$_},
+ $v_values{$_})
+ or do {
+ dbh->rollback if $FS::UID::AutoCommit;
+ return $v_sth->errstr;
+ };
+ }
+ }
+
+
+ my $h_sth;
+ if ( defined $dbdef->table('h_'. $table) ) {
+ my $h_statement = $self->_h_statement('insert');
+ warn "[debug]$me $h_statement\n" if $DEBUG > 2;
+ $h_sth = dbh->prepare($h_statement) or do {
+ dbh->rollback if $FS::UID::AutoCommit;
+ return dbh->errstr;
+ };
+ } else {
+ $h_sth = '';
+ }
+ $h_sth->execute or return $h_sth->errstr if $h_sth;
+
+ dbh->commit or croak dbh->errstr if $FS::UID::AutoCommit;
+
+ '';
+}
+
+=item add
+
+Depriciated (use insert instead).
+
+=cut
+
+sub add {
+ cluck "warning: FS::Record::add deprecated!";
+ insert @_; #call method in this scope
+}
+
+=item delete
+
+Delete this record from the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ my $statement = "DELETE FROM ". $self->table. " WHERE ". join(' AND ',
+ map {
+ $self->getfield($_) eq ''
+ #? "( $_ IS NULL OR $_ = \"\" )"
+ ? ( driver_name eq 'Pg'
+ ? "$_ IS NULL"
+ : "( $_ IS NULL OR $_ = \"\" )"
+ )
+ : "$_ = ". _quote($self->getfield($_),$self->table,$_)
+ } ( $self->dbdef_table->primary_key )
+ ? ( $self->dbdef_table->primary_key)
+ : real_fields($self->table)
+ );
+ warn "[debug]$me $statement\n" if $DEBUG > 1;
+ my $sth = dbh->prepare($statement) or return dbh->errstr;
+
+ my $h_sth;
+ if ( defined $dbdef->table('h_'. $self->table) ) {
+ my $h_statement = $self->_h_statement('delete');
+ warn "[debug]$me $h_statement\n" if $DEBUG > 2;
+ $h_sth = dbh->prepare($h_statement) or return dbh->errstr;
+ } else {
+ $h_sth = '';
+ }
+
+ my $primary_key = $self->dbdef_table->primary_key;
+ my $v_sth;
+ my @del_vfields;
+ my $vfp = $self->vfieldpart_hashref;
+ foreach($self->virtual_fields) {
+ next if $self->getfield($_) eq '';
+ unless(@del_vfields) {
+ my $st = "DELETE FROM virtual_field WHERE recnum = ? AND vfieldpart = ?";
+ $v_sth = dbh->prepare($st) or return dbh->errstr;
+ }
+ push @del_vfields, $_;
+ }
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $rc = $sth->execute or return $sth->errstr;
+ #not portable #return "Record not found, statement:\n$statement" if $rc eq "0E0";
+ $h_sth->execute or return $h_sth->errstr if $h_sth;
+ $v_sth->execute($self->getfield($primary_key), $vfp->{$_})
+ or return $v_sth->errstr
+ foreach (@del_vfields);
+
+ dbh->commit or croak dbh->errstr if $FS::UID::AutoCommit;
+
+ #no need to needlessly destoy the data either (causes problems actually)
+ #undef $self; #no need to keep object!
+
+ '';
+}
+
+=item del
+
+Depriciated (use delete instead).
+
+=cut
+
+sub del {
+ cluck "warning: FS::Record::del deprecated!";
+ &delete(@_); #call method in this scope
+}
+
+=item replace OLD_RECORD
+
+Replace the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my $new = shift;
+
+ my $old;
+ if ( @_ ) {
+ $old = shift;
+ } else {
+ warn "[debug]$me replace called with no arguments; autoloading old record\n"
+ if $DEBUG;
+ my $primary_key = $new->dbdef_table->primary_key;
+ if ( $primary_key ) {
+ $old = qsearchs($new->table, { $primary_key => $new->$primary_key() } )
+ or croak "can't find ". $new->table. ".$primary_key ".
+ $new->$primary_key();
+ } else {
+ croak $new->table. " has no primary key; pass old record as argument";
+ }
+ }
+
+ warn "[debug]$me $new ->replace $old\n" if $DEBUG;
+
+ return "Records not in same table!" unless $new->table eq $old->table;
+
+ my $primary_key = $old->dbdef_table->primary_key;
+ return "Can't change $primary_key"
+ if $primary_key
+ && ( $old->getfield($primary_key) ne $new->getfield($primary_key) );
+
+ my $error = $new->check;
+ return $error if $error;
+
+ #my @diff = grep $new->getfield($_) ne $old->getfield($_), $old->fields;
+ my %diff = map { ($new->getfield($_) ne $old->getfield($_))
+ ? ($_, $new->getfield($_)) : () } $old->fields;
+
+ unless ( keys(%diff) ) {
+ carp "[warning]$me $new -> replace $old: records identical";
+ return '';
+ }
+
+ my $statement = "UPDATE ". $old->table. " SET ". join(', ',
+ map {
+ "$_ = ". _quote($new->getfield($_),$old->table,$_)
+ } real_fields($old->table)
+ ). ' WHERE '.
+ join(' AND ',
+ map {
+ $old->getfield($_) eq ''
+ #? "( $_ IS NULL OR $_ = \"\" )"
+ ? ( driver_name eq 'Pg'
+ ? "( $_ IS NULL OR $_ = '' )"
+ : "( $_ IS NULL OR $_ = \"\" )"
+ )
+ : "$_ = ". _quote($old->getfield($_),$old->table,$_)
+ } ( $primary_key ? ( $primary_key ) : real_fields($old->table) )
+ )
+ ;
+ warn "[debug]$me $statement\n" if $DEBUG > 1;
+ my $sth = dbh->prepare($statement) or return dbh->errstr;
+
+ my $h_old_sth;
+ if ( defined $dbdef->table('h_'. $old->table) ) {
+ my $h_old_statement = $old->_h_statement('replace_old');
+ warn "[debug]$me $h_old_statement\n" if $DEBUG > 2;
+ $h_old_sth = dbh->prepare($h_old_statement) or return dbh->errstr;
+ } else {
+ $h_old_sth = '';
+ }
+
+ my $h_new_sth;
+ if ( defined $dbdef->table('h_'. $new->table) ) {
+ my $h_new_statement = $new->_h_statement('replace_new');
+ warn "[debug]$me $h_new_statement\n" if $DEBUG > 2;
+ $h_new_sth = dbh->prepare($h_new_statement) or return dbh->errstr;
+ } else {
+ $h_new_sth = '';
+ }
+
+ # For virtual fields we have three cases with different SQL
+ # statements: add, replace, delete
+ my $v_add_sth;
+ my $v_rep_sth;
+ my $v_del_sth;
+ my (@add_vfields, @rep_vfields, @del_vfields);
+ my $vfp = $old->vfieldpart_hashref;
+ foreach(grep { exists($diff{$_}) } $new->virtual_fields) {
+ if($diff{$_} eq '') {
+ # Delete
+ unless(@del_vfields) {
+ my $st = "DELETE FROM virtual_field WHERE recnum = ? ".
+ "AND vfieldpart = ?";
+ warn "[debug]$me $st\n" if $DEBUG > 2;
+ $v_del_sth = dbh->prepare($st) or return dbh->errstr;
+ }
+ push @del_vfields, $_;
+ } elsif($old->getfield($_) eq '') {
+ # Add
+ unless(@add_vfields) {
+ my $st = "INSERT INTO virtual_field (value, recnum, vfieldpart) ".
+ "VALUES (?, ?, ?)";
+ warn "[debug]$me $st\n" if $DEBUG > 2;
+ $v_add_sth = dbh->prepare($st) or return dbh->errstr;
+ }
+ push @add_vfields, $_;
+ } else {
+ # Replace
+ unless(@rep_vfields) {
+ my $st = "UPDATE virtual_field SET value = ? ".
+ "WHERE recnum = ? AND vfieldpart = ?";
+ warn "[debug]$me $st\n" if $DEBUG > 2;
+ $v_rep_sth = dbh->prepare($st) or return dbh->errstr;
+ }
+ push @rep_vfields, $_;
+ }
+ }
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $rc = $sth->execute or return $sth->errstr;
+ #not portable #return "Record not found (or records identical)." if $rc eq "0E0";
+ $h_old_sth->execute or return $h_old_sth->errstr if $h_old_sth;
+ $h_new_sth->execute or return $h_new_sth->errstr if $h_new_sth;
+
+ $v_del_sth->execute($old->getfield($primary_key),
+ $vfp->{$_})
+ or return $v_del_sth->errstr
+ foreach(@del_vfields);
+
+ $v_add_sth->execute($new->getfield($_),
+ $old->getfield($primary_key),
+ $vfp->{$_})
+ or return $v_add_sth->errstr
+ foreach(@add_vfields);
+
+ $v_rep_sth->execute($new->getfield($_),
+ $old->getfield($primary_key),
+ $vfp->{$_})
+ or return $v_rep_sth->errstr
+ foreach(@rep_vfields);
+
+ dbh->commit or croak dbh->errstr if $FS::UID::AutoCommit;
+
+ '';
+
+}
+
+=item rep
+
+Depriciated (use replace instead).
+
+=cut
+
+sub rep {
+ cluck "warning: FS::Record::rep deprecated!";
+ replace @_; #call method in this scope
+}
+
+=item check
+
+Checks virtual fields (using check_blocks). Subclasses should still provide
+a check method to validate real fields, foreign keys, etc., and call this
+method via $self->SUPER::check.
+
+(FIXME: Should this method try to make sure that it I<is> being called from
+a subclass's check method, to keep the current semantics as far as possible?)
+
+=cut
+
+sub check {
+ #confess "FS::Record::check not implemented; supply one in subclass!";
+ my $self = shift;
+
+ foreach my $field ($self->virtual_fields) {
+ for ($self->getfield($field)) {
+ # See notes on check_block in FS::part_virtual_field.
+ eval $self->pvf($field)->check_block;
+ if ( $@ ) {
+ #this is bad, probably want to follow the stack backtrace up and see
+ #wtf happened
+ my $err = "Fatal error checking $field for $self";
+ cluck "$err: $@";
+ return "$err (see log for backtrace): $@";
+
+ }
+ $self->setfield($field, $_);
+ }
+ }
+ '';
+}
+
+sub _h_statement {
+ my( $self, $action ) = @_;
+
+ my @fields =
+ grep defined($self->getfield($_)) && $self->getfield($_) ne "",
+ real_fields($self->table);
+ ;
+ my @values = map { _quote( $self->getfield($_), $self->table, $_) } @fields;
+
+ "INSERT INTO h_". $self->table. " ( ".
+ join(', ', qw(history_date history_user history_action), @fields ).
+ ") VALUES (".
+ join(', ', time, dbh->quote(getotaker()), dbh->quote($action), @values).
+ ")"
+ ;
+}
+
+=item unique COLUMN
+
+B<Warning>: External use is B<deprecated>.
+
+Replaces COLUMN in record with a unique number, using counters in the
+filesystem. Used by the B<insert> method on single-field unique columns
+(see L<DBIx::DBSchema::Table>) and also as a fallback for primary keys
+that aren't SERIAL (Pg) or AUTO_INCREMENT (mysql).
+
+Returns the new value.
+
+=cut
+
+sub unique {
+ my($self,$field) = @_;
+ my($table)=$self->table;
+
+ croak "Unique called on field $field, but it is ",
+ $self->getfield($field),
+ ", not null!"
+ if $self->getfield($field);
+
+ #warn "table $table is tainted" if is_tainted($table);
+ #warn "field $field is tainted" if is_tainted($field);
+
+ my($counter) = new File::CounterFile "$table.$field",0;
+# hack for web demo
+# getotaker() =~ /^([\w\-]{1,16})$/ or die "Illegal CGI REMOTE_USER!";
+# my($user)=$1;
+# my($counter) = new File::CounterFile "$user/$table.$field",0;
+# endhack
+
+ my $index = $counter->inc;
+ $index = $counter->inc while qsearchs($table, { $field=>$index } );
+
+ $index =~ /^(\d*)$/;
+ $index=$1;
+
+ $self->setfield($field,$index);
+
+}
+
+=item ut_float COLUMN
+
+Check/untaint floating point numeric data: 1.1, 1, 1.1e10, 1e10. May not be
+null. If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub ut_float {
+ my($self,$field)=@_ ;
+ ($self->getfield($field) =~ /^(\d+\.\d+)$/ ||
+ $self->getfield($field) =~ /^(\d+)$/ ||
+ $self->getfield($field) =~ /^(\d+\.\d+e\d+)$/ ||
+ $self->getfield($field) =~ /^(\d+e\d+)$/)
+ or return "Illegal or empty (float) $field: ". $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_snumber COLUMN
+
+Check/untaint signed numeric data (whole numbers). May not be null. If there
+is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub ut_snumber {
+ my($self, $field) = @_;
+ $self->getfield($field) =~ /^(-?)\s*(\d+)$/
+ or return "Illegal or empty (numeric) $field: ". $self->getfield($field);
+ $self->setfield($field, "$1$2");
+ '';
+}
+
+=item ut_number COLUMN
+
+Check/untaint simple numeric data (whole numbers). May not be null. If there
+is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub ut_number {
+ my($self,$field)=@_;
+ $self->getfield($field) =~ /^(\d+)$/
+ or return "Illegal or empty (numeric) $field: ". $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_numbern COLUMN
+
+Check/untaint simple numeric data (whole numbers). May be null. If there is
+an error, returns the error, otherwise returns false.
+
+=cut
+
+sub ut_numbern {
+ my($self,$field)=@_;
+ $self->getfield($field) =~ /^(\d*)$/
+ or return "Illegal (numeric) $field: ". $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_money COLUMN
+
+Check/untaint monetary numbers. May be negative. Set to 0 if null. If there
+is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub ut_money {
+ my($self,$field)=@_;
+ $self->setfield($field, 0) if $self->getfield($field) eq '';
+ $self->getfield($field) =~ /^(\-)? ?(\d*)(\.\d{2})?$/
+ or return "Illegal (money) $field: ". $self->getfield($field);
+ #$self->setfield($field, "$1$2$3" || 0);
+ $self->setfield($field, ( ($1||''). ($2||''). ($3||'') ) || 0);
+ '';
+}
+
+=item ut_text COLUMN
+
+Check/untaint text. Alphanumerics, spaces, and the following punctuation
+symbols are currently permitted: ! @ # $ % & ( ) - + ; : ' " , . ? / =
+May not be null. If there is an error, returns the error, otherwise returns
+false.
+
+=cut
+
+sub ut_text {
+ my($self,$field)=@_;
+ #warn "msgcat ". \&msgcat. "\n";
+ #warn "notexist ". \&notexist. "\n";
+ #warn "AUTOLOAD ". \&AUTOLOAD. "\n";
+ $self->getfield($field) =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]+)$/
+ or return gettext('illegal_or_empty_text'). " $field: ".
+ $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_textn COLUMN
+
+Check/untaint text. Alphanumerics, spaces, and the following punctuation
+symbols are currently permitted: ! @ # $ % & ( ) - + ; : ' " , . ? /
+May be null. If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub ut_textn {
+ my($self,$field)=@_;
+ $self->getfield($field) =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
+ or return gettext('illegal_text'). " $field: ". $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_alpha COLUMN
+
+Check/untaint alphanumeric strings (no spaces). May not be null. If there is
+an error, returns the error, otherwise returns false.
+
+=cut
+
+sub ut_alpha {
+ my($self,$field)=@_;
+ $self->getfield($field) =~ /^(\w+)$/
+ or return "Illegal or empty (alphanumeric) $field: ".
+ $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_alpha COLUMN
+
+Check/untaint alphanumeric strings (no spaces). May be null. If there is an
+error, returns the error, otherwise returns false.
+
+=cut
+
+sub ut_alphan {
+ my($self,$field)=@_;
+ $self->getfield($field) =~ /^(\w*)$/
+ or return "Illegal (alphanumeric) $field: ". $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_phonen COLUMN [ COUNTRY ]
+
+Check/untaint phone numbers. May be null. If there is an error, returns
+the error, otherwise returns false.
+
+Takes an optional two-letter ISO country code; without it or with unsupported
+countries, ut_phonen simply calls ut_alphan.
+
+=cut
+
+sub ut_phonen {
+ my( $self, $field, $country ) = @_;
+ return $self->ut_alphan($field) unless defined $country;
+ my $phonen = $self->getfield($field);
+ if ( $phonen eq '' ) {
+ $self->setfield($field,'');
+ } elsif ( $country eq 'US' || $country eq 'CA' ) {
+ $phonen =~ s/\D//g;
+ $phonen =~ /^(\d{3})(\d{3})(\d{4})(\d*)$/
+ or return gettext('illegal_phone'). " $field: ". $self->getfield($field);
+ $phonen = "$1-$2-$3";
+ $phonen .= " x$4" if $4;
+ $self->setfield($field,$phonen);
+ } else {
+ warn "warning: don't know how to check phone numbers for country $country";
+ return $self->ut_textn($field);
+ }
+ '';
+}
+
+=item ut_ip COLUMN
+
+Check/untaint ip addresses. IPv4 only for now.
+
+=cut
+
+sub ut_ip {
+ my( $self, $field ) = @_;
+ $self->getfield($field) =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
+ or return "Illegal (IP address) $field: ". $self->getfield($field);
+ for ( $1, $2, $3, $4 ) { return "Illegal (IP address) $field" if $_ > 255; }
+ $self->setfield($field, "$1.$2.$3.$4");
+ '';
+}
+
+=item ut_ipn COLUMN
+
+Check/untaint ip addresses. IPv4 only for now. May be null.
+
+=cut
+
+sub ut_ipn {
+ my( $self, $field ) = @_;
+ if ( $self->getfield($field) =~ /^()$/ ) {
+ $self->setfield($field,'');
+ '';
+ } else {
+ $self->ut_ip($field);
+ }
+}
+
+=item ut_domain COLUMN
+
+Check/untaint host and domain names.
+
+=cut
+
+sub ut_domain {
+ my( $self, $field ) = @_;
+ #$self->getfield($field) =~/^(\w+\.)*\w+$/
+ $self->getfield($field) =~/^(([\w\-]+\.)*\w+)$/
+ or return "Illegal (domain) $field: ". $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_name COLUMN
+
+Check/untaint proper names; allows alphanumerics, spaces and the following
+punctuation: , . - '
+
+May not be null.
+
+=cut
+
+sub ut_name {
+ my( $self, $field ) = @_;
+ $self->getfield($field) =~ /^([\w \,\.\-\']+)$/
+ or return gettext('illegal_name'). " $field: ". $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_zip COLUMN
+
+Check/untaint zip codes.
+
+=cut
+
+sub ut_zip {
+ my( $self, $field, $country ) = @_;
+ if ( $country eq 'US' ) {
+ $self->getfield($field) =~ /\s*(\d{5}(\-\d{4})?)\s*$/
+ or return gettext('illegal_zip'). " $field for country $country: ".
+ $self->getfield($field);
+ $self->setfield($field,$1);
+ } else {
+ if ( $self->getfield($field) =~ /^\s*$/ ) {
+ $self->setfield($field,'');
+ } else {
+ $self->getfield($field) =~ /^\s*(\w[\w\-\s]{2,8}\w)\s*$/
+ or return gettext('illegal_zip'). " $field: ". $self->getfield($field);
+ $self->setfield($field,$1);
+ }
+ }
+ '';
+}
+
+=item ut_country COLUMN
+
+Check/untaint country codes. Country names are changed to codes, if possible -
+see L<Locale::Country>.
+
+=cut
+
+sub ut_country {
+ my( $self, $field ) = @_;
+ unless ( $self->getfield($field) =~ /^(\w\w)$/ ) {
+ if ( $self->getfield($field) =~ /^([\w \,\.\(\)\']+)$/
+ && country2code($1) ) {
+ $self->setfield($field,uc(country2code($1)));
+ }
+ }
+ $self->getfield($field) =~ /^(\w\w)$/
+ or return "Illegal (country) $field: ". $self->getfield($field);
+ $self->setfield($field,uc($1));
+ '';
+}
+
+=item ut_anything COLUMN
+
+Untaints arbitrary data. Be careful.
+
+=cut
+
+sub ut_anything {
+ my( $self, $field ) = @_;
+ $self->getfield($field) =~ /^(.*)$/s
+ or return "Illegal $field: ". $self->getfield($field);
+ $self->setfield($field,$1);
+ '';
+}
+
+=item ut_enum COLUMN CHOICES_ARRAYREF
+
+Check/untaint a column, supplying all possible choices, like the "enum" type.
+
+=cut
+
+sub ut_enum {
+ my( $self, $field, $choices ) = @_;
+ foreach my $choice ( @$choices ) {
+ if ( $self->getfield($field) eq $choice ) {
+ $self->setfield($choice);
+ return '';
+ }
+ }
+ return "Illegal (enum) field $field: ". $self->getfield($field);
+}
+
+=item ut_foreign_key COLUMN FOREIGN_TABLE FOREIGN_COLUMN
+
+Check/untaint a foreign column key. Call a regular ut_ method (like ut_number)
+on the column first.
+
+=cut
+
+sub ut_foreign_key {
+ my( $self, $field, $table, $foreign ) = @_;
+ qsearchs($table, { $foreign => $self->getfield($field) })
+ or return "Can't find $field ". $self->getfield($field).
+ " in $table.$foreign";
+ '';
+}
+
+=item ut_foreign_keyn COLUMN FOREIGN_TABLE FOREIGN_COLUMN
+
+Like ut_foreign_key, except the null value is also allowed.
+
+=cut
+
+sub ut_foreign_keyn {
+ my( $self, $field, $table, $foreign ) = @_;
+ $self->getfield($field)
+ ? $self->ut_foreign_key($field, $table, $foreign)
+ : '';
+}
+
+
+=item virtual_fields [ TABLE ]
+
+Returns a list of virtual fields defined for the table. This should not
+be exported, and should only be called as an instance or class method.
+
+=cut
+
+sub virtual_fields {
+ my $self = shift;
+ my $table;
+ $table = $self->table or confess "virtual_fields called on non-table";
+
+ confess "Unknown table $table" unless $dbdef->table($table);
+
+ return () unless $self->dbdef->table('part_virtual_field');
+
+ unless ( $virtual_fields_cache{$table} ) {
+ my $query = 'SELECT name from part_virtual_field ' .
+ "WHERE dbtable = '$table'";
+ my $dbh = dbh;
+ my $result = $dbh->selectcol_arrayref($query);
+ confess $dbh->errstr if $dbh->err;
+ $virtual_fields_cache{$table} = $result;
+ }
+
+ @{$virtual_fields_cache{$table}};
+
+}
+
+
+=item fields [ TABLE ]
+
+This is a wrapper for real_fields and virtual_fields. Code that called
+fields before should probably continue to call fields.
+
+=cut
+
+sub fields {
+ my $something = shift;
+ my $table;
+ if($something->isa('FS::Record')) {
+ $table = $something->table;
+ } else {
+ $table = $something;
+ $something = "FS::$table";
+ }
+ return (real_fields($table), $something->virtual_fields());
+}
+
+=back
+
+=item pvf FIELD_NAME
+
+Returns the FS::part_virtual_field object corresponding to a field in the
+record (specified by FIELD_NAME).
+
+=cut
+
+sub pvf {
+ my ($self, $name) = (shift, shift);
+
+ if(grep /^$name$/, $self->virtual_fields) {
+ return qsearchs('part_virtual_field', { dbtable => $self->table,
+ name => $name } );
+ }
+ ''
+}
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item real_fields [ TABLE ]
+
+Returns a list of the real columns in the specified table. Called only by
+fields() and other subroutines elsewhere in FS::Record.
+
+=cut
+
+sub real_fields {
+ my $table = shift;
+
+ my($table_obj) = $dbdef->table($table);
+ confess "Unknown table $table" unless $table_obj;
+ $table_obj->columns;
+}
+
+=item reload_dbdef([FILENAME])
+
+Load a database definition (see L<DBIx::DBSchema>), optionally from a
+non-default filename. This command is executed at startup unless
+I<$FS::Record::setup_hack> is true. Returns a DBIx::DBSchema object.
+
+=cut
+
+sub reload_dbdef {
+ my $file = shift || $dbdef_file;
+
+ unless ( exists $dbdef_cache{$file} ) {
+ warn "[debug]$me loading dbdef for $file\n" if $DEBUG;
+ $dbdef_cache{$file} = DBIx::DBSchema->load( $file )
+ or die "can't load database schema from $file";
+ } else {
+ warn "[debug]$me re-using cached dbdef for $file\n" if $DEBUG;
+ }
+ $dbdef = $dbdef_cache{$file};
+}
+
+=item dbdef
+
+Returns the current database definition. See L<DBIx::DBSchema>.
+
+=cut
+
+sub dbdef { $dbdef; }
+
+=item _quote VALUE, TABLE, COLUMN
+
+This is an internal function used to construct SQL statements. It returns
+VALUE DBI-quoted (see L<DBI/"quote">) unless VALUE is a number and the column
+type (see L<DBIx::DBSchema::Column>) does not end in `char' or `binary'.
+
+=cut
+
+sub _quote {
+ my($value, $table, $column) = @_;
+ my $column_obj = $dbdef->table($table)->column($column);
+ my $column_type = $column_obj->type;
+
+ if ( $value eq '' && $column_type =~ /^int/ ) {
+ if ( $column_obj->null ) {
+ 'NULL';
+ } else {
+ cluck "WARNING: Attempting to set non-null integer $table.$column null; ".
+ "using 0 instead";
+ 0;
+ }
+ } elsif ( $value =~ /^\d+(\.\d+)?$/ &&
+ ! $column_type =~ /(char|binary|text)$/i ) {
+ $value;
+ } else {
+ dbh->quote($value);
+ }
+}
+
+=item vfieldpart_hashref TABLE
+
+Returns a hashref of virtual field names and vfieldparts applicable to the given
+TABLE.
+
+=cut
+
+sub vfieldpart_hashref {
+ my $self = shift;
+ my $table = $self->table;
+
+ return {} unless $self->dbdef->table('part_virtual_field');
+
+ my $dbh = dbh;
+ my $statement = "SELECT vfieldpart, name FROM part_virtual_field WHERE ".
+ "dbtable = '$table'";
+ my $sth = $dbh->prepare($statement);
+ $sth->execute or croak "Execution of '$statement' failed: ".$dbh->errstr;
+ return { map { $_->{name}, $_->{vfieldpart} }
+ @{$sth->fetchall_arrayref({})} };
+
+}
+
+
+=item hfields TABLE
+
+This is deprecated. Don't use it.
+
+It returns a hash-type list with the fields of this record's table set true.
+
+=cut
+
+sub hfields {
+ carp "warning: hfields is deprecated";
+ my($table)=@_;
+ my(%hash);
+ foreach (fields($table)) {
+ $hash{$_}=1;
+ }
+ \%hash;
+}
+
+sub _dump {
+ my($self)=@_;
+ join("\n", map {
+ "$_: ". $self->getfield($_). "|"
+ } (fields($self->table)) );
+}
+
+sub DESTROY { return; }
+
+#sub DESTROY {
+# my $self = shift;
+# #use Carp qw(cluck);
+# #cluck "DESTROYING $self";
+# warn "DESTROYING $self";
+#}
+
+#sub is_tainted {
+# return ! eval { join('',@_), kill 0; 1; };
+# }
+
+=back
+
+=head1 BUGS
+
+This module should probably be renamed, since much of the functionality is
+of general use. It is not completely unlike Adapter::DBI (see below).
+
+Exported qsearch and qsearchs should be deprecated in favor of method calls
+(against an FS::Record object like the old search and searchs that qsearch
+and qsearchs were on top of.)
+
+The whole fields / hfields mess should be removed.
+
+The various WHERE clauses should be subroutined.
+
+table string should be deprecated in favor of DBIx::DBSchema::Table.
+
+No doubt we could benefit from a Tied hash. Documenting how exists / defined
+true maps to the database (and WHERE clauses) would also help.
+
+The ut_ methods should ask the dbdef for a default length.
+
+ut_sqltype (like ut_varchar) should all be defined
+
+A fallback check method should be provided which uses the dbdef.
+
+The ut_money method assumes money has two decimal digits.
+
+The Pg money kludge in the new method only strips `$'.
+
+The ut_phonen method only checks US-style phone numbers.
+
+The _quote function should probably use ut_float instead of a regex.
+
+All the subroutines probably should be methods, here or elsewhere.
+
+Probably should borrow/use some dbdef methods where appropriate (like sub
+fields)
+
+As of 1.14, DBI fetchall_hashref( {} ) doesn't set fetchrow_hashref NAME_lc,
+or allow it to be set. Working around it is ugly any way around - DBI should
+be fixed. (only affects RDBMS which return uppercase column names)
+
+ut_zip should take an optional country like ut_phone.
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema>, L<FS::UID>, L<DBI>
+
+Adapter::DBI from Ch. 11 of Advanced Perl Programming by Sriram Srinivasan.
+
+=cut
+
+1;
+
diff --git a/FS/FS/Report.pm b/FS/FS/Report.pm
new file mode 100644
index 0000000..181fea2
--- /dev/null
+++ b/FS/FS/Report.pm
@@ -0,0 +1,46 @@
+package FS::Report;
+
+use strict;
+
+=head1 NAME
+
+FS::Report - Report data objects
+
+=head1 SYNOPSIS
+
+ #see the more speicific report objects, currently only FS::Report::Table
+
+=head1 DESCRIPTION
+
+See the more specific report objects, currently only FS::Report::Table
+
+=head1 METHODS
+
+=over 4
+
+=item new [ OPTION => VALUE ... ]
+
+Constructor. Takes a list of options and their values.
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = @_ ? ( ref($_[0]) ? shift : { @_ } ) : {};
+ bless( $self, $class );
+}
+
+=back
+
+=head1 BUGS
+
+Documentation.
+
+=head1 SEE ALSO
+
+L<FS::Report::Table>, reports in the web interface.
+
+=cut
+
+1;
diff --git a/FS/FS/Report/Table.pm b/FS/FS/Report/Table.pm
new file mode 100644
index 0000000..9f636fa
--- /dev/null
+++ b/FS/FS/Report/Table.pm
@@ -0,0 +1,27 @@
+package FS::Report::Table;
+
+use strict;
+use vars qw( @ISA );
+use FS::Report;
+
+@ISA = qw( FS::Report );
+
+=head1 NAME
+
+FS::Report::Table - Tables of report data
+
+=head1 SYNOPSIS
+
+See the more specific report objects, currently only FS::Report::Table::Monthly
+
+=head1 BUGS
+
+Documentation.
+
+=head1 SEE ALSO
+
+L<FS::Report::Table::Monthly>, reports in the web interface.
+
+=cut
+
+1;
diff --git a/FS/FS/Report/Table/Monthly.pm b/FS/FS/Report/Table/Monthly.pm
new file mode 100644
index 0000000..d3ff5d1
--- /dev/null
+++ b/FS/FS/Report/Table/Monthly.pm
@@ -0,0 +1,172 @@
+package FS::Report::Table::Monthly;
+
+use strict;
+use vars qw( @ISA $expenses_kludge );
+use Time::Local;
+use FS::UID qw( dbh );
+use FS::Report::Table;
+
+@ISA = qw( FS::Report::Table );
+
+$expenses_kludge = 0;
+
+=head1 NAME
+
+FS::Report::Table::Monthly - Tables of report data, indexed monthly
+
+=head1 SYNOPSIS
+
+ use FS::Report::Table::Monthly;
+
+ my $report = new FS::Report::Table::Monthly (
+ 'items' => [ 'invoiced', 'netsales', 'credits', 'receipts', ],
+ 'start_month' => 4,
+ 'start_year' => 2000,
+ 'end_month' => 4,
+ 'end_year' => 2020,
+ );
+
+ my $data = $report->data;
+
+=head1 METHODS
+
+=over 4
+
+=item data
+
+Returns a hashref of data (!! describe)
+
+=cut
+
+sub data {
+ my $self = shift;
+
+ my $smonth = $self->{'start_month'};
+ my $syear = $self->{'start_year'};
+ my $emonth = $self->{'end_month'};
+ my $eyear = $self->{'end_year'};
+
+ my %data;
+
+ while ( $syear < $eyear || ( $syear == $eyear && $smonth < $emonth+1 ) ) {
+
+ push @{$data{label}}, "$smonth/$syear";
+
+ my $speriod = timelocal(0,0,0,1,$smonth-1,$syear);
+ push @{$data{speriod}}, $speriod;
+ if ( ++$smonth == 13 ) { $syear++; $smonth=1; }
+ my $eperiod = timelocal(0,0,0,1,$smonth-1,$syear);
+ push @{$data{eperiod}}, $eperiod;
+
+ foreach my $item ( @{$self->{'items'}} ) {
+ push @{$data{$item}}, $self->$item($speriod, $eperiod);
+ }
+
+ }
+
+ \%data;
+
+}
+
+sub invoiced { #invoiced
+ my( $self, $speriod, $eperiod ) = ( shift, shift, shift );
+ $self->scalar_sql("
+ SELECT SUM(charged) FROM cust_bill
+ WHERE ". $self->in_time_period($speriod, $eperiod)
+ );
+}
+
+sub netsales { #net sales
+ my( $self, $speriod, $eperiod ) = ( shift, shift, shift );
+
+ my $credited = $self->scalar_sql("
+ SELECT SUM(cust_credit_bill.amount)
+ FROM cust_credit_bill, cust_bill
+ WHERE cust_bill.invnum = cust_credit_bill.invnum
+ AND ". $self->in_time_period($speriod, $eperiod, 'cust_bill')
+ );
+
+ #horrible local kludge
+ my $expenses = !$expenses_kludge ? 0 : $self->scalar_sql("
+ SELECT SUM(cust_bill_pkg.setup)
+ FROM cust_bill_pkg, cust_bill, cust_pkg, part_pkg
+ WHERE cust_bill.invnum = cust_bill_pkg.invnum
+ AND ". $self->in_time_period($speriod, $eperiod, 'cust_bill'). "
+ AND cust_pkg.pkgnum = cust_bill_pkg.pkgnum
+ AND cust_pkg.pkgpart = part_pkg.pkgpart
+ AND LOWER(part_pkg.pkg) LIKE 'expense _%'
+ ");
+
+ $self->invoiced($speriod,$eperiod) - $credited - $expenses;
+}
+
+#deferred revenue
+
+sub receipts { #cashflow
+ my( $self, $speriod, $eperiod ) = ( shift, shift, shift );
+
+ my $refunded = $self->scalar_sql("
+ SELECT SUM(refund) FROM cust_refund
+ WHERE ". $self->in_time_period($speriod, $eperiod)
+ );
+
+ #horrible local kludge that doesn't even really work right
+ my $expenses = !$expenses_kludge ? 0 : $self->scalar_sql("
+ SELECT SUM(cust_bill_pay.amount)
+ FROM cust_bill_pay, cust_bill
+ WHERE cust_bill_pay.invnum = cust_bill.invnum
+ AND ". $self->in_time_period($speriod, $eperiod, 'cust_bill_pay'). "
+ AND 0 < ( SELECT COUNT(*) from cust_bill_pkg, cust_pkg, part_pkg
+ WHERE cust_bill.invnum = cust_bill_pkg.invnum
+ AND cust_pkg.pkgnum = cust_bill_pkg.pkgnum
+ AND cust_pkg.pkgpart = part_pkg.pkgpart
+ AND LOWER(part_pkg.pkg) LIKE 'expense _%'
+ )
+ ");
+ # my $expenses_sql2 = "SELECT SUM(cust_bill_pay.amount) FROM cust_bill_pay, cust_bill_pkg, cust_bill, cust_pkg, part_pkg WHERE cust_bill_pay.invnum = cust_bill.invnum AND cust_bill.invnum = cust_bill_pkg.invnum AND cust_bill_pay._date >= $speriod AND cust_bill_pay._date < $eperiod AND cust_pkg.pkgnum = cust_bill_pkg.pkgnum AND cust_pkg.pkgpart = part_pkg.pkgpart AND LOWER(part_pkg.pkg) LIKE 'expense _%'";
+
+ $self->payments($speriod, $eperiod) - $refunded - $expenses;
+}
+
+sub payments {
+ my( $self, $speriod, $eperiod ) = ( shift, shift, shift );
+ $self->scalar_sql("
+ SELECT SUM(paid) FROM cust_pay
+ WHERE ". $self->in_time_period($speriod, $eperiod)
+ );
+}
+
+sub credits {
+ my( $self, $speriod, $eperiod ) = ( shift, shift, shift );
+ $self->scalar_sql("
+ SELECT SUM(amount) FROM cust_credit
+ WHERE ". $self->in_time_period($speriod, $eperiod)
+ );
+}
+
+sub in_time_period {
+ my( $self, $speriod, $eperiod ) = ( shift, shift, shift );
+ my $table = @_ ? shift().'.' : '';
+ "${table}_date >= $speriod AND ${table}_date < $eperiod";
+}
+
+sub scalar_sql {
+ my( $self, $sql ) = ( shift, shift );
+ my $sth = dbh->prepare($sql) or die dbh->errstr;
+ $sth->execute
+ or die "Unexpected error executing statement $sql: ". $sth->errstr;
+ $sth->fetchrow_arrayref->[0] || 0;
+}
+
+=back
+
+=head1 BUGS
+
+Documentation.
+
+=head1 SEE ALSO
+
+=cut
+
+1;
+
diff --git a/FS/FS/SearchCache.pm b/FS/FS/SearchCache.pm
new file mode 100644
index 0000000..4218acf
--- /dev/null
+++ b/FS/FS/SearchCache.pm
@@ -0,0 +1,96 @@
+package FS::SearchCache;
+
+use strict;
+use vars qw($DEBUG);
+#use Carp qw(carp cluck croak confess);
+
+$DEBUG = 0;
+
+=head1 NAME
+
+FS::SearchCache - cache
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+=head1 METHODS
+
+=over 4
+
+=item new
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my( $table, $key ) = @_;
+ warn "table $table\n" if $DEBUG > 1;
+ warn "key $key\n" if $DEBUG > 1;
+ my $self = { 'table' => $table,
+ 'key' => $key,
+ 'cache' => {},
+ 'subcache' => {},
+ };
+ bless ($self, $class);
+
+ $self;
+}
+
+=item table
+
+=cut
+
+sub table { my $self = shift; $self->{table}; }
+
+=item key
+
+=cut
+
+sub key { my $self = shift; $self->{key}; }
+
+=item cache
+
+=cut
+
+sub cache { my $self = shift; $self->{cache}; }
+
+=item subcache
+
+=cut
+
+sub subcache {
+ my $self = shift;
+ my $col = shift;
+ my $table = shift;
+ my $keyval = shift;
+ if ( exists $self->{subcache}->{$col}->{$keyval} ) {
+ warn "returning existing subcache for $keyval ($col)".
+ "$self->{subcache}->{$col}->{$keyval}\n" if $DEBUG;
+ return $self->{subcache}->{$col}->{$keyval};
+ } else {
+ #my $tablekey = @_ ? shift : $col;
+ my $tablekey = $col;
+ my $subcache = ref($self)->new( $table, $tablekey );
+ $self->{subcache}->{$col}->{$keyval} = $subcache;
+ warn "creating new subcache $table $tablekey: $subcache\n" if $DEBUG;
+ $subcache;
+ }
+}
+
+=back
+
+=head1 BUGS
+
+Dismal documentation.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_main>
+
+=cut
+
+1;
+
+
diff --git a/FS/FS/UI/Base.pm b/FS/FS/UI/Base.pm
new file mode 100644
index 0000000..bbeb9e1
--- /dev/null
+++ b/FS/FS/UI/Base.pm
@@ -0,0 +1,194 @@
+package FS::UI::Base;
+
+use strict;
+use vars qw ( @ISA );
+use FS::Record qw( fields qsearch );
+
+@ISA = ( $FS::UI::Base::_lock );
+
+=head1 NAME
+
+FS::UI::Base - Base class for all user-interface objects
+
+=head1 SYNOPSIS
+
+ use FS::UI::SomeInterface;
+ use FS::UI::some_table;
+
+ $interface = new FS::UI::some_table;
+
+ $error = $interface->browse;
+ $error = $interface->search;
+ $error = $interface->view;
+ $error = $interface->edit;
+ $error = $interface->process;
+
+=head1 DESCRIPTION
+
+An FS::UI::Base object represents a user interface object. FS::UI::Base
+is intended as a base class for table-specfic classes to inherit from, i.e.
+FS::UI::cust_main. The simplest case, which will provide a default UI for your
+new table, is as follows:
+
+ package FS::UI::table_name;
+ use vars qw ( @ISA );
+ use FS::UI::Base;
+ @ISA = qw( FS::UI::Base );
+ sub db_table { 'table_name'; }
+
+Currently available interfaces are:
+ FS::UI::Gtk, an X-Windows UI implemented using the Gtk+ toolkit
+ FS::UI::CGI, a web interface implemented using CGI.pm, etc.
+
+=head1 METHODS
+
+=over 4
+
+=item new
+
+=cut
+
+=item browse
+
+=cut
+
+sub browse {
+ my $self = shift;
+
+ my @fields = $self->list_fields;
+
+ #begin browse-specific stuff
+
+ $self->title( "Browse ". $self->db_names ) unless $self->title;
+ my @records = qsearch ( $self->db_table, {} );
+
+ #end browse-specific stuff
+
+ $self->addwidget ( new FS::UI::_Text ( $self->db_description ) );
+
+ my @header = $self->list_header;
+ my @headerspan = $self->list_headerspan;
+ my %callback = $self->db_callback;
+
+ my $columns;
+
+ my $table = new FS::UI::_Tableborder (
+ 'rows' => 1 + scalar(@records),
+ 'columns' => $columns || scalar(@fields),
+ );
+
+ my $c = 0;
+ foreach my $header ( @header ) {
+ my $headerspan = shift(@headerspan) || 1;
+ $table->attach(
+ 0, $c, new FS::UI::_Text ( $header ), 1, $headerspan
+ );
+ $c += $headerspan;
+ }
+
+ my $r = 1;
+
+ foreach my $record ( @records ) {
+ $c = 0;
+ foreach my $field ( @fields ) {
+ my $value = $record->getfield($field);
+ my $widget;
+ if ( $callback{$field} ) {
+ $widget = &{ $callback{$field} }( $value, $record );
+ } else {
+ $widget = new FS::UI::_Text ( $value );
+ }
+ $table->attach( $r, $c++, $widget, 1, 1 );
+ }
+ $r++;
+ }
+
+ $self->addwidget( $table );
+
+ $self->activate;
+
+}
+
+=item title
+
+=cut
+
+sub title {
+ my $self = shift;
+ my $value = shift;
+ if ( defined($value) ) {
+ $self->{'title'} = $value;
+ } else {
+ $self->{'title'};
+ }
+}
+
+=item addwidget
+
+=cut
+
+sub addwidget {
+ my $self = shift;
+ my $widget = shift;
+ push @{ $self->{'Widgets'} }, $widget;
+}
+
+#fallback methods
+
+sub db_description {}
+
+sub db_name {}
+
+sub db_names {
+ my $self = shift;
+ $self->db_name. 's';
+}
+
+sub list_fields {
+ my $self = shift;
+ fields( $self->db_table );
+}
+
+sub list_header {
+ my $self = shift;
+ $self->list_fields
+}
+
+sub list_headerspan {
+ my $self = shift;
+ map 1, $self->list_header;
+}
+
+sub db_callback {}
+
+=back
+
+=head1 VERSION
+
+$Id: Base.pm,v 1.1 1999-08-04 09:03:53 ivan Exp $
+
+=head1 BUGS
+
+This documentation is incomplete.
+
+There should be some sort of per-(freeside)-user preferences and the ability
+for specific FS::UI:: modules to put their own values there as well.
+
+=head1 SEE ALSO
+
+L<FS::UI::Gtk>, L<FS::UI::CGI>
+
+=head1 HISTORY
+
+$Log: Base.pm,v $
+Revision 1.1 1999-08-04 09:03:53 ivan
+initial checkin of module files for proper perl installation
+
+Revision 1.1 1999/01/20 09:30:36 ivan
+skeletal cross-UI UI code.
+
+
+=cut
+
+1;
+
diff --git a/FS/FS/UI/CGI.pm b/FS/FS/UI/CGI.pm
new file mode 100644
index 0000000..ae87d13
--- /dev/null
+++ b/FS/FS/UI/CGI.pm
@@ -0,0 +1,239 @@
+package FS::UI::CGI;
+
+use strict;
+use CGI;
+#use CGI::Switch; #when FS::UID user and preference callback stuff is fixed
+use CGI::Carp qw(fatalsToBrowser);
+use HTML::Table;
+use FS::UID qw(adminsuidsetup);
+#use FS::Record qw( qsearch fields );
+
+die "Can't initialize CGI interface; $FS::UI::Base::_lock used"
+ if $FS::UI::Base::_lock;
+$FS::UI::Base::_lock = "FS::UI::CGI";
+
+=head1 NAME
+
+FS::UI::CGI - Base class for CGI user-interface objects
+
+=head1 SYNOPSIS
+
+ use FS::UI::CGI;
+ use FS::UI::some_table;
+
+ $interface = new FS::UI::some_table;
+
+ $error = $interface->browse;
+ $error = $interface->search;
+ $error = $interface->view;
+ $error = $interface->edit;
+ $error = $interface->process;
+
+=head1 DESCRIPTION
+
+An FS::UI::CGI object represents a CGI interface object.
+
+=head1 METHODS
+
+=over 4
+
+=item new
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = { @_ };
+
+ $self->{'_cgi'} = new CGI;
+ $self->{'_user'} = $self->{'_cgi'}->remote_user;
+ $self->{'_dbh'} = FS::UID::adminsuidsetup $self->{'_user'};
+
+ bless ( $self, $class);
+}
+
+sub activate {
+ my $self = shift;
+ print $self->_header,
+ join ( "<BR>", map $_->sprint, @{ $self->{'Widgets'} } ),
+ $self->_footer,
+ ;
+}
+
+=item _header
+
+=cut
+
+sub _header {
+ my $self = shift;
+ my $cgi = $self->{'_cgi'};
+
+ $cgi->header( '-expires' => 'now' ), '<HTML>',
+ '<HEAD><TITLE>', $self->title, '</TITLE></HEAD>',
+ '<BODY BGCOLOR="#ffffff">',
+ '<FONT COLOR="#ff0000" SIZE=7>', $self->title, '</FONT><BR><BR>',
+ ;
+}
+
+=item _footer
+
+=cut
+
+sub _footer {
+ "</BODY></HTML>";
+}
+
+=item interface
+
+Returns the string `CGI'. Useful for the author of a table-specific UI class
+to conditionally specify certain behaviour.
+
+=cut
+
+sub interface { 'CGI'; }
+
+=back
+
+=cut
+
+package FS::UI::_Widget;
+
+use vars qw( $AUTOLOAD );
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = { @_ };
+ bless ( $self, $class );
+}
+
+sub AUTOLOAD {
+ my $self = shift;
+ my $value = shift;
+ my($field)=$AUTOLOAD;
+ $field =~ s/.*://;
+ if ( defined($value) ) {
+ $self->{$field} = $value;
+ } else {
+ $self->{$field};
+ }
+}
+
+package FS::UI::_Text;
+
+use vars qw ( @ISA );
+
+@ISA = qw ( FS::UI::_Widget);
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = {};
+ $self->{'_text'} = shift;
+ bless ( $self, $class );
+}
+
+sub sprint {
+ my $self = shift;
+ $self->{'_text'};
+}
+
+package FS::UI::_Link;
+
+use vars qw ( @ISA $BASE_URL );
+
+@ISA = qw ( FS::UI::_Widget);
+$BASE_URL = "http://rootwood.sisd.com/freeside";
+
+sub sprint {
+ my $self = shift;
+ my $table = $self->{'table'};
+ my $method = $self->{'method'};
+
+ # i will be cleaned up when we're done moving from the old webinterface!
+ my @arg = @{$self->{'arg'}};
+ my $yuck = join( "&", @arg);
+ qq(<A HREF="$BASE_URL/$method/$table.cgi?$yuck">). $self->{'text'}. "<\A>";
+}
+
+package FS::UI::_Table;
+
+use vars qw ( @ISA );
+
+@ISA = qw ( FS::UI::_Widget);
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = $class eq $proto ? { @_ } : $proto;
+ bless ( $self, $class );
+ $self->{'_table'} = new HTML::Table ( $self->rows, $self->columns );
+ $self;
+}
+
+sub attach {
+ my $self = shift;
+ my ( $row, $column, $widget, $rowspan, $colspan ) = @_;
+ $self->{"_table"}->setCell( $row+1, $column+1, $widget->sprint );
+ $self->{"_table"}->setCellRowSpan( $row+1, $column+1, $rowspan ) if $rowspan;
+ $self->{"_table"}->setCellColSpan( $row+1, $column+1, $colspan ) if $colspan;
+}
+
+sub sprint {
+ my $self = shift;
+ $self->{'_table'}->getTable;
+}
+
+package FS::UI::_Tableborder;
+
+use vars qw ( @ISA );
+
+@ISA = qw ( FS::UI::_Table );
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = $class eq $proto ? { @_ } : $proto;
+ bless ( $self, $class );
+ $self->SUPER::new(@_);
+ $self->{'_table'}->setBorder;
+ $self;
+}
+
+=head1 VERSION
+
+$Id: CGI.pm,v 1.1 1999-08-04 09:03:53 ivan Exp $
+
+=head1 BUGS
+
+This documentation is incomplete.
+
+In _Tableborder, headers should be links that sort on their fields.
+
+_Link uses a constant $BASE_URL
+
+_Link passes the arguments as a manually-constructed GET string instead
+of POSTing, for compatability while the web interface is upgraded. Once
+this is done it should pass arguements properly (i.e. as a POST, 8-bit clean)
+
+Still some small bits of widget code same as FS::UI::Gtk.
+
+=head1 SEE ALSO
+
+L<FS::UI::Base>
+
+=head1 HISTORY
+
+$Log: CGI.pm,v $
+Revision 1.1 1999-08-04 09:03:53 ivan
+initial checkin of module files for proper perl installation
+
+Revision 1.1 1999/01/20 09:30:36 ivan
+skeletal cross-UI UI code.
+
+
+=cut
+
+1;
+
diff --git a/FS/FS/UI/Gtk.pm b/FS/FS/UI/Gtk.pm
new file mode 100644
index 0000000..507a293
--- /dev/null
+++ b/FS/FS/UI/Gtk.pm
@@ -0,0 +1,224 @@
+package FS::UI::Gtk;
+
+use strict;
+use Gtk;
+use FS::UID qw(adminsuidsetup);
+
+die "Can't initialize Gtk interface; $FS::UI::Base::_lock used"
+ if $FS::UI::Base::_lock;
+$FS::UI::Base::_lock = "FS::UI::Gtk";
+
+=head1 NAME
+
+FS::UI::Gtk - Base class for Gtk user-interface objects
+
+=head1 SYNOPSIS
+
+ use FS::UI::Gtk;
+ use FS::UI::some_table;
+
+ $interface = new FS::UI::some_table;
+
+ $error = $interface->browse;
+ $error = $interface->search;
+ $error = $interface->view;
+ $error = $interface->edit;
+ $error = $interface->process;
+
+=head1 DESCRIPTION
+
+An FS::UI::Gtk object represents a Gtk user interface object.
+
+=head1 METHODS
+
+=over 4
+
+=item new
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = { @_ };
+
+ bless ( $self, $class );
+
+ $self->{'_user'} = 'ivan'; #Pop up login window?
+ $self->{'_dbh'} = FS::UID::adminsuidsetup $self->{'_user'};
+
+
+
+ $self;
+}
+
+sub activate {
+ my $self = shift;
+
+ my $vbox = new Gtk::VBox ( 0, 4 );
+
+ foreach my $widget ( @{ $self->{'Widgets'} } ) {
+ $widget->_gtk->show;
+ $vbox->pack_start ( $widget->_gtk, 1, 1, 4 );
+ }
+ $vbox->show;
+
+ my $window = new Gtk::Window "toplevel";
+ $self->{'_gtk'} = $window;
+ $window->set_title( $self->title );
+ $window->add ( $vbox );
+ $window->show;
+ main Gtk;
+}
+
+=item interface
+
+Returns the string `Gtk'. Useful for the author of a table-specific UI class
+to conditionally specify certain behaviour.
+
+=cut
+
+sub interface { 'Gtk'; }
+
+=back
+
+=cut
+
+package FS::UI::_Widget;
+
+use vars qw( $AUTOLOAD );
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = { @_ };
+ bless ( $self, $class );
+}
+
+sub _gtk {
+ my $self = shift;
+ $self->{'_gtk'};
+}
+
+sub AUTOLOAD {
+ my $self = shift;
+ my $value = shift;
+ my($field)=$AUTOLOAD;
+ $field =~ s/.*://;
+ if ( defined($value) ) {
+ $self->{$field} = $value;
+ } else {
+ $self->{$field};
+ }
+}
+
+package FS::UI::_Text;
+
+use vars qw ( @ISA );
+
+@ISA = qw ( FS::UI::_Widget );
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = {};
+ $self->{'_gtk'} = new Gtk::Label ( shift );
+ bless ( $self, $class );
+}
+
+package FS::UI::_Link;
+
+use vars qw ( @ISA );
+
+@ISA = qw ( FS::UI::_Widget );
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = { @_ };
+ $self->{'_gtk'} = new_with_label Gtk::Button ( $self->{'text'} );
+ $self->{'_gtk'}->signal_connect( 'clicked', sub {
+ print "STUB: (Gtk) FS::UI::_Link";
+ }, "hi", "there" );
+ bless ( $self, $class );
+}
+
+
+package FS::UI::_Table;
+
+use vars qw ( @ISA );
+
+@ISA = qw ( FS::UI::_Widget );
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = { @_ };
+ bless ( $self, $class );
+
+ $self->{'_gtk'} = new Gtk::Table (
+ $self->rows,
+ $self->columns,
+ 0, #homogeneous
+ );
+
+ $self;
+}
+
+sub attach {
+ my $self = shift;
+ my ( $row, $column, $widget, $rowspan, $colspan ) = @_;
+ $rowspan ||= 1;
+ $colspan ||= 1;
+ $self->_gtk->attach_defaults(
+ $widget->_gtk,
+ $column,
+ $column + $colspan,
+ $row,
+ $row + $rowspan,
+ );
+ $widget->_gtk->show;
+}
+
+package FS::UI::_Tableborder;
+
+use vars qw ( @ISA );
+
+@ISA = qw ( FS::UI::_Table );
+
+=head1 VERSION
+
+$Id: Gtk.pm,v 1.1 1999-08-04 09:03:53 ivan Exp $
+
+=head1 BUGS
+
+This documentation is incomplete.
+
+_Tableborder is just a _Table now. _Tableborders should scroll (but not the
+headers) and need and need more decoration. (data in white section ala gtksql
+and sliding field widths) headers should be buttons that callback to sort on
+their fields.
+
+There should be a persistant, per-(freeside)-user store for window positions
+and sizes and sort fields etc (see L<FS::UI::CGI/BUGS>.
+
+Still some small bits of widget code same as FS::UI::CGI.
+
+=head1 SEE ALSO
+
+L<FS::UI::Base>
+
+=head1 HISTORY
+
+$Log: Gtk.pm,v $
+Revision 1.1 1999-08-04 09:03:53 ivan
+initial checkin of module files for proper perl installation
+
+Revision 1.1 1999/01/20 09:30:36 ivan
+skeletal cross-UI UI code.
+
+
+=cut
+
+1;
+
diff --git a/FS/FS/UI/agent.pm b/FS/FS/UI/agent.pm
new file mode 100644
index 0000000..ce9744a
--- /dev/null
+++ b/FS/FS/UI/agent.pm
@@ -0,0 +1,62 @@
+package FS::UI::agent;
+
+use strict;
+use vars qw ( @ISA );
+use FS::UI::Base;
+use FS::Record qw( qsearchs );
+use FS::agent;
+use FS::agent_type;
+
+@ISA = qw ( FS::UI::Base );
+
+sub db_table { 'agent' };
+
+sub db_name { 'Agent' };
+
+sub db_description { <<END;
+Agents are resellers of your service. Agents may be limited to a subset of your
+full offerings (via their type).
+END
+}
+
+sub list_fields {
+ 'agentnum',
+ 'typenum',
+# 'freq',
+# 'prog',
+; }
+
+sub list_header {
+ 'Agent',
+ 'Type',
+# 'Freq (n/a)',
+# 'Prog (n/a)',
+; }
+
+sub db_callback {
+ 'agentnum' =>
+ sub {
+ my ( $agentnum, $record ) = @_;
+ my $agent = $record->agent;
+ new FS::UI::_Link (
+ 'table' => 'agent',
+ 'method' => 'edit',
+ 'arg' => [ $agentnum ],
+ 'text' => "$agentnum: $agent",
+ );
+ },
+ 'typenum' =>
+ sub {
+ my $typenum = shift;
+ my $agent_type = qsearchs( 'agent_type', { 'typenum' => $typenum } );
+ my $atype = $agent_type->atype;
+ new FS::UI::_Link (
+ 'table' => 'agent_type',
+ 'method' => 'edit',
+ 'arg' => [ $typenum ],
+ 'text' => "$typenum: $atype"
+ );
+ },
+}
+
+1;
diff --git a/FS/FS/UID.pm b/FS/FS/UID.pm
new file mode 100644
index 0000000..8271f89
--- /dev/null
+++ b/FS/FS/UID.pm
@@ -0,0 +1,316 @@
+package FS::UID;
+
+use strict;
+use vars qw(
+ @ISA @EXPORT_OK $cgi $dbh $freeside_uid $user
+ $conf_dir $secrets $datasrc $db_user $db_pass %callback @callback
+ $driver_name $AutoCommit
+);
+use subs qw(
+ getsecrets cgisetotaker
+);
+use Exporter;
+use Carp qw(carp croak cluck);
+use DBI;
+use FS::Conf;
+
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(checkeuid checkruid cgisuidsetup adminsuidsetup forksuidsetup
+ getotaker dbh datasrc getsecrets driver_name );
+
+$freeside_uid = scalar(getpwnam('freeside'));
+
+$conf_dir = "/usr/local/etc/freeside/";
+
+$AutoCommit = 1; #ours, not DBI
+
+=head1 NAME
+
+FS::UID - Subroutines for database login and assorted other stuff
+
+=head1 SYNOPSIS
+
+ use FS::UID qw(adminsuidsetup cgisuidsetup dbh datasrc getotaker
+ checkeuid checkruid);
+
+ adminsuidsetup $user;
+
+ $cgi = new CGI;
+ $dbh = cgisuidsetup($cgi);
+
+ $dbh = dbh;
+
+ $datasrc = datasrc;
+
+ $driver_name = driver_name;
+
+=head1 DESCRIPTION
+
+Provides a hodgepodge of subroutines.
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item adminsuidsetup USER
+
+Sets the user to USER (see config.html from the base documentation).
+Cleans the environment.
+Make sure the script is running as freeside, or setuid freeside.
+Opens a connection to the database.
+Swaps real and effective UIDs.
+Runs any defined callbacks (see below).
+Returns the DBI database handle (usually you don't need this).
+
+=cut
+
+sub adminsuidsetup {
+ $dbh->disconnect if $dbh;
+ &forksuidsetup(@_);
+}
+
+sub forksuidsetup {
+ $user = shift;
+ croak "fatal: adminsuidsetup called without arguements" unless $user;
+
+ $user =~ /^([\w\-\.]+)$/ or croak "fatal: illegal user $user";
+ $user = $1;
+
+ $ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
+ $ENV{'SHELL'} = '/bin/sh';
+ $ENV{'IFS'} = " \t\n";
+ $ENV{'CDPATH'} = '';
+ $ENV{'ENV'} = '';
+ $ENV{'BASH_ENV'} = '';
+
+ croak "Not running uid freeside!" unless checkeuid();
+ getsecrets;
+ $dbh = DBI->connect($datasrc,$db_user,$db_pass, {
+ 'AutoCommit' => 0,
+ 'ChopBlanks' => 1,
+ } ) or die "DBI->connect error: $DBI::errstr\n";
+
+ foreach ( keys %callback ) {
+ &{$callback{$_}};
+ # breaks multi-database installs # delete $callback{$_}; #run once
+ }
+
+ &{$_} foreach @callback;
+
+ $dbh;
+}
+
+=item install_callback
+
+A package can install a callback to be run in adminsuidsetup by passing
+a coderef to the FS::UID->install_callback class method. If adminsuidsetup has
+run already, the callback will also be run immediately.
+
+ $coderef = sub { warn "Hi, I'm returning your call!" };
+ FS::UID->install_callback($coderef);
+
+ install_callback FS::UID sub {
+ warn "Hi, I'm returning your call!"
+ };
+
+=cut
+
+sub install_callback {
+ my $class = shift;
+ my $callback = shift;
+ push @callback, $callback;
+ &{$callback} if $dbh;
+}
+
+=item cgisuidsetup CGI_object
+
+Takes a single argument, which is a CGI (see L<CGI>) or Apache (see L<Apache>)
+object (CGI::Base is depriciated). Runs cgisetotaker and then adminsuidsetup.
+
+=cut
+
+sub cgisuidsetup {
+ $cgi=shift;
+ if ( $cgi->isa('CGI::Base') ) {
+ carp "Use of CGI::Base is depriciated";
+ } elsif ( $cgi->isa('Apache') ) {
+
+ } elsif ( ! $cgi->isa('CGI') ) {
+ croak "fatal: unrecognized object $cgi";
+ }
+ cgisetotaker;
+ adminsuidsetup($user);
+}
+
+=item cgi
+
+Returns the CGI (see L<CGI>) object.
+
+=cut
+
+sub cgi {
+ carp "warning: \$FS::UID::cgi isa Apache" if $cgi->isa('Apache');
+ $cgi;
+}
+
+=item dbh
+
+Returns the DBI database handle.
+
+=cut
+
+sub dbh {
+ $dbh;
+}
+
+=item datasrc
+
+Returns the DBI data source.
+
+=cut
+
+sub datasrc {
+ $datasrc;
+}
+
+=item driver_name
+
+Returns just the driver name portion of the DBI data source.
+
+=cut
+
+sub driver_name {
+ return $driver_name if defined $driver_name;
+ $driver_name = ( split(':', $datasrc) )[1];
+}
+
+sub suidsetup {
+ croak "suidsetup depriciated";
+}
+
+=item getotaker
+
+Returns the current Freeside user.
+
+=cut
+
+sub getotaker {
+ $user;
+}
+
+=item cgisetotaker
+
+Sets and returns the CGI REMOTE_USER. $cgi should be defined as a CGI.pm
+object (see L<CGI>) or an Apache object (see L<Apache>). Support for CGI::Base
+and derived classes is depriciated.
+
+=cut
+
+sub cgisetotaker {
+ if ( $cgi && $cgi->isa('CGI::Base') && defined $cgi->var('REMOTE_USER')) {
+ carp "Use of CGI::Base is depriciated";
+ $user = lc ( $cgi->var('REMOTE_USER') );
+ } elsif ( $cgi && $cgi->isa('CGI') && defined $cgi->remote_user ) {
+ $user = lc ( $cgi->remote_user );
+ } elsif ( $cgi && $cgi->isa('Apache') ) {
+ $user = lc ( $cgi->connection->user );
+ } else {
+ die "fatal: Can't get REMOTE_USER! for cgi $cgi - you need to setup ".
+ "Apache user authentication as documented in httemplate/docs/install.html";
+ }
+ $user;
+}
+
+=item checkeuid
+
+Returns true if effective UID is that of the freeside user.
+
+=cut
+
+sub checkeuid {
+ ( $> == $freeside_uid );
+}
+
+=item checkruid
+
+Returns true if the real UID is that of the freeside user.
+
+=cut
+
+sub checkruid {
+ ( $< == $freeside_uid );
+}
+
+=item getsecrets [ USER ]
+
+Sets the user to USER, if supplied.
+Sets and returns the DBI datasource, username and password for this user from
+the `/usr/local/etc/freeside/mapsecrets' file.
+
+=cut
+
+sub getsecrets {
+ my($setuser) = shift;
+ $user = $setuser if $setuser;
+ die "No user!" unless $user;
+ my($conf) = new FS::Conf $conf_dir;
+ my($line) = grep /^\s*$user\s/, $conf->config('mapsecrets');
+ die "User $user not found in mapsecrets!" unless $line;
+ $line =~ /^\s*$user\s+(.*)$/;
+ $secrets = $1;
+ die "Illegal mapsecrets line for user?!" unless $secrets;
+ ($datasrc, $db_user, $db_pass) = $conf->config($secrets)
+ or die "Can't get secrets: $!";
+ $FS::Conf::default_dir = $conf_dir. "/conf.$datasrc";
+ undef $driver_name;
+ ($datasrc, $db_user, $db_pass);
+}
+
+=back
+
+=head1 CALLBACKS
+
+Warning: this interface is (still) likely to change in future releases.
+
+New (experimental) callback interface:
+
+A package can install a callback to be run in adminsuidsetup by passing
+a coderef to the FS::UID->install_callback class method. If adminsuidsetup has
+run already, the callback will also be run immediately.
+
+ $coderef = sub { warn "Hi, I'm returning your call!" };
+ FS::UID->install_callback($coderef);
+
+ install_callback FS::UID sub {
+ warn "Hi, I'm returning your call!"
+ };
+
+Old (deprecated) callback interface:
+
+A package can install a callback to be run in adminsuidsetup by putting a
+coderef into the hash %FS::UID::callback :
+
+ $coderef = sub { warn "Hi, I'm returning your call!" };
+ $FS::UID::callback{'Package::Name'} = $coderef;
+
+=head1 BUGS
+
+Too many package-global variables.
+
+Not OO.
+
+No capabilities yet. When mod_perl and Authen::DBI are implemented,
+cgisuidsetup will go away as well.
+
+Goes through contortions to support non-OO syntax with multiple datasrc's.
+
+Callbacks are (still) inelegant.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<CGI>, L<DBI>, config.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/acct_snarf.pm b/FS/FS/acct_snarf.pm
new file mode 100644
index 0000000..b4e88bf
--- /dev/null
+++ b/FS/FS/acct_snarf.pm
@@ -0,0 +1,128 @@
+package FS::acct_snarf;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::acct_snarf - Object methods for acct_snarf records
+
+=head1 SYNOPSIS
+
+ use FS::acct_snarf;
+
+ $record = new FS::acct_snarf \%hash;
+ $record = new FS::acct_snarf { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::svc_acct object represents an external mail account, typically for
+download of mail. FS::acct_snarf inherits from FS::Record. The following
+fields are currently supported:
+
+=over 4
+
+=item snarfnum - primary key
+
+=item svcnum - Account (see L<FS::svc_acct>)
+
+=item machine - external machine to download mail from
+
+=item protocol - protocol (pop3, imap, etc.)
+
+=item username - external login username
+
+=item _password - external login password
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record. To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'acct_snarf'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid external mail account. If
+there is an error, returns the error, otherwise returns false. Called by the
+insert and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+ my $error =
+ $self->ut_numbern('snarfnum')
+ || $self->ut_number('svcnum')
+ || $self->ut_foreign_key('svcnum', 'svc_acct', 'svcnum')
+ || $self->ut_domain('machine')
+ || $self->ut_alphan('protocol')
+ || $self->ut_textn('username')
+ ;
+ return $error if $error;
+
+ $self->_password =~ /^[^\t\n]*$/ or return "illegal password";
+ $self->_password($1);
+
+ ''; #no error
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/addr_block.pm b/FS/FS/addr_block.pm
new file mode 100755
index 0000000..1fb6060
--- /dev/null
+++ b/FS/FS/addr_block.pm
@@ -0,0 +1,331 @@
+package FS::addr_block;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs qsearch dbh );
+use FS::router;
+use FS::svc_broadband;
+use FS::Conf;
+use NetAddr::IP;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::addr_block - Object methods for addr_block records
+
+=head1 SYNOPSIS
+
+ use FS::addr_block;
+
+ $record = new FS::addr_block \%hash;
+ $record = new FS::addr_block { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::addr_block record describes an address block assigned for broadband
+access. FS::addr_block inherits from FS::Record. The following fields are
+currently supported:
+
+=over 4
+
+=item blocknum - primary key, used in FS::svc_broadband to associate
+services to the block.
+
+=item routernum - the router (see FS::router) to which this
+block is assigned.
+
+=item ip_gateway - the gateway address used by customers within this block.
+
+=item ip_netmask - the netmask of the block, expressed as an integer.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see "insert".
+
+=cut
+
+sub table { 'addr_block'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+sub delete {
+ my $self = shift;
+ return 'Block must be deallocated before deletion'
+ if $self->router;
+
+ $self->SUPER::delete;
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_number('routernum')
+ || $self->ut_ip('ip_gateway')
+ || $self->ut_number('ip_netmask')
+ ;
+ return $error if $error;
+
+
+ # A routernum of 0 indicates an unassigned block and is allowed
+ return "Unknown routernum"
+ if ($self->routernum and not $self->router);
+
+ my $self_addr = $self->NetAddr;
+ return "Cannot parse address: ". $self->ip_gateway . '/' . $self->ip_netmask
+ unless $self_addr;
+
+ if (not $self->blocknum) {
+ my @block = grep {
+ my $block_addr = $_->NetAddr;
+ if($block_addr->contains($self_addr)
+ or $self_addr->contains($block_addr)) { $_; };
+ } qsearch( 'addr_block', {});
+ foreach(@block) {
+ return "Block intersects existing block ".$_->ip_gateway."/".$_->ip_netmask;
+ }
+ }
+
+ $self->SUPER::check;
+}
+
+
+=item router
+
+Returns the FS::router object corresponding to this object. If the
+block is unassigned, returns undef.
+
+=cut
+
+sub router {
+ my $self = shift;
+ return qsearchs('router', { routernum => $self->routernum });
+}
+
+=item svc_broadband
+
+Returns a list of FS::svc_broadband objects associated
+with this object.
+
+=cut
+
+sub svc_broadband {
+ my $self = shift;
+ return qsearch('svc_broadband', { blocknum => $self->blocknum });
+}
+
+=item NetAddr
+
+Returns a NetAddr::IP object for this block's address and netmask.
+
+=cut
+
+sub NetAddr {
+ my $self = shift;
+
+ return new NetAddr::IP ($self->ip_gateway, $self->ip_netmask);
+}
+
+=item next_free_addr
+
+Returns a NetAddr::IP object corresponding to the first unassigned address
+in the block (other than the network, broadcast, or gateway address). If
+there are no free addresses, returns false.
+
+=cut
+
+sub next_free_addr {
+ my $self = shift;
+
+ my $conf = new FS::Conf;
+ my @excludeaddr = $conf->config('exclude_ip_addr');
+
+my @used =
+( (map { $_->NetAddr->addr }
+ ($self,
+ qsearch('svc_broadband', { blocknum => $self->blocknum }))
+ ), @excludeaddr
+);
+
+ my @free = $self->NetAddr->hostenum;
+ while (my $ip = shift @free) {
+ if (not grep {$_ eq $ip->addr;} @used) { return $ip; };
+ }
+
+ '';
+
+}
+
+=item allocate
+
+Allocates this address block to a router. Takes an FS::router object
+as an argument.
+
+At present it's not possible to reallocate a block to a different router
+except by deallocating it first, which requires that none of its addresses
+be assigned. This is probably as it should be.
+
+=cut
+
+sub allocate {
+ my ($self, $router) = @_;
+
+ return 'Block is already allocated'
+ if($self->router);
+
+ return 'Block must be allocated to a router'
+ unless(ref $router eq 'FS::router');
+
+ my @svc = $self->svc_broadband;
+ if (@svc) {
+ return 'Block has assigned addresses: '. join ', ', map {$_->ip_addr} @svc;
+ }
+
+ my $new = new FS::addr_block {$self->hash};
+ $new->routernum($router->routernum);
+ return $new->replace($self);
+
+}
+
+=item deallocate
+
+Deallocates the block (i.e. sets the routernum to 0). If any addresses in the
+block are assigned to services, it fails.
+
+=cut
+
+sub deallocate {
+ my $self = shift;
+
+ my @svc = $self->svc_broadband;
+ if (@svc) {
+ return 'Block has assigned addresses: '. join ', ', map {$_->ip_addr} @svc;
+ }
+
+ my $new = new FS::addr_block {$self->hash};
+ $new->routernum(0);
+ return $new->replace($self);
+}
+
+=item split_block
+
+Splits this address block into two equal blocks, occupying the same space as
+the original block. The first of the two will also have the same blocknum.
+The gateway address of each block will be set to the first usable address, i.e.
+(network address)+1. Since this method is designed for use on unallocated
+blocks, this is probably the correct behavior.
+
+(At present, splitting allocated blocks is disallowed. Anyone who wants to
+implement this is reminded that each split costs three addresses, and any
+customers who were using these addresses will have to be moved; depending on
+how full the block was before being split, they might have to be moved to a
+different block. Anyone who I<still> wants to implement it is asked to tie it
+to a configuration switch so that site admins can disallow it.)
+
+=cut
+
+sub split_block {
+
+ # We should consider using Attribute::Handlers/Aspect/Hook::LexWrap/
+ # something to atomicize functions, so that we can say
+ #
+ # sub split_block : atomic {
+ #
+ # instead of repeating all this AutoCommit verbage in every
+ # sub that does more than one database operation.
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $self = shift;
+ my $error;
+
+ if ($self->router) {
+ return 'Block is already allocated';
+ }
+
+ #TODO: Smallest allowed block should be a config option.
+ if ($self->NetAddr->masklen() ge 30) {
+ return 'Cannot split blocks with a mask length >= 30';
+ }
+
+ my (@new, @ip);
+ $ip[0] = $self->NetAddr;
+ @ip = map {$_->first()} $ip[0]->split($self->ip_netmask + 1);
+
+ foreach (0,1) {
+ $new[$_] = new FS::addr_block {$self->hash};
+ $new[$_]->ip_gateway($ip[$_]->addr);
+ $new[$_]->ip_netmask($ip[$_]->masklen);
+ }
+
+ $new[1]->blocknum('');
+
+ $error = $new[0]->replace($self);
+ if ($error) {
+ $dbh->rollback;
+ return $error;
+ }
+
+ $error = $new[1]->insert;
+ if ($error) {
+ $dbh->rollback;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ return '';
+}
+
+=item merge
+
+To be implemented.
+
+=back
+
+=head1 BUGS
+
+Minimum block size should be a config option. It's hardcoded at /30 right
+now because that's the smallest block that makes any sense at all.
+
+=cut
+
+1;
+
diff --git a/FS/FS/agent.pm b/FS/FS/agent.pm
new file mode 100644
index 0000000..7c69dfb
--- /dev/null
+++ b/FS/FS/agent.pm
@@ -0,0 +1,279 @@
+package FS::agent;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( dbh qsearch qsearchs );
+use FS::cust_main;
+use FS::agent_type;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::agent - Object methods for agent records
+
+=head1 SYNOPSIS
+
+ use FS::agent;
+
+ $record = new FS::agent \%hash;
+ $record = new FS::agent { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $agent_type = $record->agent_type;
+
+ $hashref = $record->pkgpart_hashref;
+ #may purchase $pkgpart if $hashref->{$pkgpart};
+
+=head1 DESCRIPTION
+
+An FS::agent object represents an agent. Every customer has an agent. Agents
+can be used to track things like resellers or salespeople. FS::agent inherits
+from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item agentnum - primary key (assigned automatically for new agents)
+
+=item agent - Text name of this agent
+
+=item typenum - Agent type. See L<FS::agent_type>
+
+=item prog - For future use.
+
+=item freq - For future use.
+
+=item disabled - Disabled flag, empty or 'Y'
+
+=item username - Username for the Agent interface
+
+=item _password - Password for the Agent interface
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new agent. To add the agent to the database, see L<"insert">.
+
+=cut
+
+sub table { 'agent'; }
+
+=item insert
+
+Adds this agent to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this agent from the database. Only agents with no customers can be
+deleted. If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ return "Can't delete an agent with customers!"
+ if qsearch( 'cust_main', { 'agentnum' => $self->agentnum } );
+
+ $self->SUPER::delete;
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid agent. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('agentnum')
+ || $self->ut_text('agent')
+ || $self->ut_number('typenum')
+ || $self->ut_numbern('freq')
+ || $self->ut_textn('prog')
+ ;
+ return $error if $error;
+
+ if ( $self->dbdef_table->column('disabled') ) {
+ $error = $self->ut_enum('disabled', [ '', 'Y' ] );
+ return $error if $error;
+ }
+
+ if ( $self->dbdef_table->column('username') ) {
+ $error = $self->ut_alphan('username');
+ return $error if $error;
+ if ( length($self->username) ) {
+ my $conflict = qsearchs('agent', { 'username' => $self->username } );
+ return 'duplicate agent username (with '. $conflict->agent. ')'
+ if $conflict;
+ $error = $self->ut_text('password'); # ut_text... arbitrary choice
+ } else {
+ $self->_password('');
+ }
+ }
+
+ return "Unknown typenum!"
+ unless $self->agent_type;
+
+ $self->SUPER::check;
+}
+
+=item agent_type
+
+Returns the FS::agent_type object (see L<FS::agent_type>) for this agent.
+
+=cut
+
+sub agent_type {
+ my $self = shift;
+ qsearchs( 'agent_type', { 'typenum' => $self->typenum } );
+}
+
+=item pkgpart_hashref
+
+Returns a hash reference. The keys of the hash are pkgparts. The value is
+true if this agent may purchase the specified package definition. See
+L<FS::part_pkg>.
+
+=cut
+
+sub pkgpart_hashref {
+ my $self = shift;
+ $self->agent_type->pkgpart_hashref;
+}
+
+=item num_prospect_cust_main
+
+Returns the number of prospects (customers with no packages ever ordered) for
+this agent.
+
+=cut
+
+sub num_prospect_cust_main {
+ shift->num_sql(FS::cust_main->prospect_sql);
+}
+
+sub num_sql {
+ my( $self, $sql ) = @_;
+ my $sth = dbh->prepare(
+ "SELECT COUNT(*) FROM cust_main WHERE agentnum = ? AND $sql"
+ ) or die dbh->errstr;
+ $sth->execute($self->agentnum) or die $sth->errstr;
+ $sth->fetchrow_arrayref->[0];
+}
+
+=item prospect_cust_main
+
+Returns the prospects (customers with no packages ever ordered) for this agent,
+as cust_main objects.
+
+=cut
+
+sub prospect_cust_main {
+ shift->cust_main_sql(FS::cust_main->prospect_sql);
+}
+
+sub cust_main_sql {
+ my( $self, $sql ) = @_;
+ qsearch( 'cust_main',
+ { 'agentnum' => $self->agentnum },
+ '',
+ " AND $sql"
+ );
+}
+
+=item num_active_cust_main
+
+Returns the number of active customers for this agent.
+
+=cut
+
+sub num_active_cust_main {
+ shift->num_sql(FS::cust_main->active_sql);
+}
+
+=item active_cust_main
+
+Returns the active customers for this agent, as cust_main objects.
+
+=cut
+
+sub active_cust_main {
+ shift->cust_main_sql(FS::cust_main->active_sql);
+}
+
+=item num_susp_cust_main
+
+Returns the number of suspended customers for this agent.
+
+=cut
+
+sub num_susp_cust_main {
+ shift->num_sql(FS::cust_main->susp_sql);
+}
+
+=item susp_cust_main
+
+Returns the suspended customers for this agent, as cust_main objects.
+
+=cut
+
+sub susp_cust_main {
+ shift->cust_main_sql(FS::cust_main->susp_sql);
+}
+
+=item num_cancel_cust_main
+
+Returns the number of cancelled customer for this agent.
+
+=cut
+
+sub num_cancel_cust_main {
+ shift->num_sql(FS::cust_main->cancel_sql);
+}
+
+=item cancel_cust_main
+
+Returns the cancelled customers for this agent, as cust_main objects.
+
+=cut
+
+sub cancel_cust_main {
+ shift->cust_main_sql(FS::cust_main->cancel_sql);
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::agent_type>, L<FS::cust_main>, L<FS::part_pkg>,
+schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/agent_type.pm b/FS/FS/agent_type.pm
new file mode 100644
index 0000000..5ba5ef2
--- /dev/null
+++ b/FS/FS/agent_type.pm
@@ -0,0 +1,166 @@
+package FS::agent_type;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch );
+use FS::agent;
+use FS::type_pkgs;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::agent_type - Object methods for agent_type records
+
+=head1 SYNOPSIS
+
+ use FS::agent_type;
+
+ $record = new FS::agent_type \%hash;
+ $record = new FS::agent_type { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $hashref = $record->pkgpart_hashref;
+ #may purchase $pkgpart if $hashref->{$pkgpart};
+
+ @type_pkgs = $record->type_pkgs;
+
+ @pkgparts = $record->pkgpart;
+
+=head1 DESCRIPTION
+
+An FS::agent_type object represents an agent type. Every agent (see
+L<FS::agent>) has an agent type. Agent types define which packages (see
+L<FS::part_pkg>) may be purchased by customers (see L<FS::cust_main>), via
+FS::type_pkgs records (see L<FS::type_pkgs>). FS::agent_type inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item typenum - primary key (assigned automatically for new agent types)
+
+=item atype - Text name of this agent type
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new agent type. To add the agent type to the database, see
+L<"insert">.
+
+=cut
+
+sub table { 'agent_type'; }
+
+=item insert
+
+Adds this agent type to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this agent type from the database. Only agent types with no agents
+can be deleted. If there is an error, returns the error, otherwise returns
+false.
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ return "Can't delete an agent_type with agents!"
+ if qsearch( 'agent', { 'typenum' => $self->typenum } );
+
+ $self->SUPER::delete;
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid agent type. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('typenum')
+ or $self->ut_text('atype')
+ or $self->SUPER::check;
+
+}
+
+=item pkgpart_hashref
+
+Returns a hash reference. The keys of the hash are pkgparts. The value is
+true iff this agent may purchase the specified package definition. See
+L<FS::part_pkg>.
+
+=cut
+
+sub pkgpart_hashref {
+ my $self = shift;
+ my %pkgpart;
+ #$pkgpart{$_}++ foreach $self->pkgpart;
+ # not compatible w/5.004_04 (fixed in 5.004_05)
+ foreach ( $self->pkgpart ) { $pkgpart{$_}++; }
+ \%pkgpart;
+}
+
+=item type_pkgs
+
+Returns all FS::type_pkgs objects (see L<FS::type_pkgs>) for this agent type.
+
+=cut
+
+sub type_pkgs {
+ my $self = shift;
+ qsearch('type_pkgs', { 'typenum' => $self->typenum } );
+}
+
+=item pkgpart
+
+Returns the pkgpart of all package definitions (see L<FS::part_pkg>) for this
+agent type.
+
+=cut
+
+sub pkgpart {
+ my $self = shift;
+ map $_->pkgpart, $self->type_pkgs;
+}
+
+=back
+
+=head1 VERSION
+
+$Id: agent_type.pm,v 1.2 2003-08-05 00:20:40 khoff Exp $
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::agent>, L<FS::type_pkgs>, L<FS::cust_main>,
+L<FS::part_pkg>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
new file mode 100644
index 0000000..49d53bc
--- /dev/null
+++ b/FS/FS/cust_bill.pm
@@ -0,0 +1,1479 @@
+package FS::cust_bill;
+
+use strict;
+use vars qw( @ISA $conf $money_char );
+use vars qw( $invoice_lines @buf ); #yuck
+use Date::Format;
+use Text::Template;
+use File::Temp 0.14;
+use FS::UID qw( datasrc );
+use FS::Record qw( qsearch qsearchs );
+use FS::Misc qw( send_email );
+use FS::cust_main;
+use FS::cust_bill_pkg;
+use FS::cust_credit;
+use FS::cust_pay;
+use FS::cust_pkg;
+use FS::cust_credit_bill;
+use FS::cust_pay_batch;
+use FS::cust_bill_event;
+
+@ISA = qw( FS::Record );
+
+#ask FS::UID to run this stuff for us later
+FS::UID->install_callback( sub {
+ $conf = new FS::Conf;
+ $money_char = $conf->config('money_char') || '$';
+} );
+
+=head1 NAME
+
+FS::cust_bill - Object methods for cust_bill records
+
+=head1 SYNOPSIS
+
+ use FS::cust_bill;
+
+ $record = new FS::cust_bill \%hash;
+ $record = new FS::cust_bill { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ ( $total_previous_balance, @previous_cust_bill ) = $record->previous;
+
+ @cust_bill_pkg_objects = $cust_bill->cust_bill_pkg;
+
+ ( $total_previous_credits, @previous_cust_credit ) = $record->cust_credit;
+
+ @cust_pay_objects = $cust_bill->cust_pay;
+
+ $tax_amount = $record->tax;
+
+ @lines = $cust_bill->print_text;
+ @lines = $cust_bill->print_text $time;
+
+=head1 DESCRIPTION
+
+An FS::cust_bill object represents an invoice; a declaration that a customer
+owes you money. The specific charges are itemized as B<cust_bill_pkg> records
+(see L<FS::cust_bill_pkg>). FS::cust_bill inherits from FS::Record. The
+following fields are currently supported:
+
+=over 4
+
+=item invnum - primary key (assigned automatically for new invoices)
+
+=item custnum - customer (see L<FS::cust_main>)
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=item charged - amount of this invoice
+
+=item printed - deprecated
+
+=item closed - books closed flag, empty or `Y'
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new invoice. To add the invoice to the database, see L<"insert">.
+Invoices are normally created by calling the bill method of a customer object
+(see L<FS::cust_main>).
+
+=cut
+
+sub table { 'cust_bill'; }
+
+=item insert
+
+Adds this invoice to the database ("Posts" the invoice). If there is an error,
+returns the error, otherwise returns false.
+
+=item delete
+
+Currently unimplemented. I don't remove invoices because there would then be
+no record you ever posted this invoice (which is bad, no?)
+
+=cut
+
+sub delete {
+ my $self = shift;
+ return "Can't delete closed invoice" if $self->closed =~ /^Y/i;
+ $self->SUPER::delete(@_);
+}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+Only printed may be changed. printed is normally updated by calling the
+collect method of a customer object (see L<FS::cust_main>).
+
+=cut
+
+sub replace {
+ my( $new, $old ) = ( shift, shift );
+ return "Can't change custnum!" unless $old->custnum == $new->custnum;
+ #return "Can't change _date!" unless $old->_date eq $new->_date;
+ return "Can't change _date!" unless $old->_date == $new->_date;
+ return "Can't change charged!" unless $old->charged == $new->charged;
+
+ $new->SUPER::replace($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid invoice. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('invnum')
+ || $self->ut_number('custnum')
+ || $self->ut_numbern('_date')
+ || $self->ut_money('charged')
+ || $self->ut_numbern('printed')
+ || $self->ut_enum('closed', [ '', 'Y' ])
+ ;
+ return $error if $error;
+
+ return "Unknown customer"
+ unless qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+
+ $self->_date(time) unless $self->_date;
+
+ $self->printed(0) if $self->printed eq '';
+
+ $self->SUPER::check;
+}
+
+=item previous
+
+Returns a list consisting of the total previous balance for this customer,
+followed by the previous outstanding invoices (as FS::cust_bill objects also).
+
+=cut
+
+sub previous {
+ my $self = shift;
+ my $total = 0;
+ my @cust_bill = sort { $a->_date <=> $b->_date }
+ grep { $_->owed != 0 && $_->_date < $self->_date }
+ qsearch( 'cust_bill', { 'custnum' => $self->custnum } )
+ ;
+ foreach ( @cust_bill ) { $total += $_->owed; }
+ $total, @cust_bill;
+}
+
+=item cust_bill_pkg
+
+Returns the line items (see L<FS::cust_bill_pkg>) for this invoice.
+
+=cut
+
+sub cust_bill_pkg {
+ my $self = shift;
+ qsearch( 'cust_bill_pkg', { 'invnum' => $self->invnum } );
+}
+
+=item cust_bill_event
+
+Returns the completed invoice events (see L<FS::cust_bill_event>) for this
+invoice.
+
+=cut
+
+sub cust_bill_event {
+ my $self = shift;
+ qsearch( 'cust_bill_event', { 'invnum' => $self->invnum } );
+}
+
+
+=item cust_main
+
+Returns the customer (see L<FS::cust_main>) for this invoice.
+
+=cut
+
+sub cust_main {
+ my $self = shift;
+ qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+}
+
+=item cust_credit
+
+Depreciated. See the cust_credited method.
+
+ #Returns a list consisting of the total previous credited (see
+ #L<FS::cust_credit>) and unapplied for this customer, followed by the previous
+ #outstanding credits (FS::cust_credit objects).
+
+=cut
+
+sub cust_credit {
+ use Carp;
+ croak "FS::cust_bill->cust_credit depreciated; see ".
+ "FS::cust_bill->cust_credit_bill";
+ #my $self = shift;
+ #my $total = 0;
+ #my @cust_credit = sort { $a->_date <=> $b->_date }
+ # grep { $_->credited != 0 && $_->_date < $self->_date }
+ # qsearch('cust_credit', { 'custnum' => $self->custnum } )
+ #;
+ #foreach (@cust_credit) { $total += $_->credited; }
+ #$total, @cust_credit;
+}
+
+=item cust_pay
+
+Depreciated. See the cust_bill_pay method.
+
+#Returns all payments (see L<FS::cust_pay>) for this invoice.
+
+=cut
+
+sub cust_pay {
+ use Carp;
+ croak "FS::cust_bill->cust_pay depreciated; see FS::cust_bill->cust_bill_pay";
+ #my $self = shift;
+ #sort { $a->_date <=> $b->_date }
+ # qsearch( 'cust_pay', { 'invnum' => $self->invnum } )
+ #;
+}
+
+=item cust_bill_pay
+
+Returns all payment applications (see L<FS::cust_bill_pay>) for this invoice.
+
+=cut
+
+sub cust_bill_pay {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_bill_pay', { 'invnum' => $self->invnum } );
+}
+
+=item cust_credited
+
+Returns all applied credits (see L<FS::cust_credit_bill>) for this invoice.
+
+=cut
+
+sub cust_credited {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_credit_bill', { 'invnum' => $self->invnum } )
+ ;
+}
+
+=item tax
+
+Returns the tax amount (see L<FS::cust_bill_pkg>) for this invoice.
+
+=cut
+
+sub tax {
+ my $self = shift;
+ my $total = 0;
+ my @taxlines = qsearch( 'cust_bill_pkg', { 'invnum' => $self->invnum ,
+ 'pkgnum' => 0 } );
+ foreach (@taxlines) { $total += $_->setup; }
+ $total;
+}
+
+=item owed
+
+Returns the amount owed (still outstanding) on this invoice, which is charged
+minus all payment applications (see L<FS::cust_bill_pay>) and credit
+applications (see L<FS::cust_credit_bill>).
+
+=cut
+
+sub owed {
+ my $self = shift;
+ my $balance = $self->charged;
+ $balance -= $_->amount foreach ( $self->cust_bill_pay );
+ $balance -= $_->amount foreach ( $self->cust_credited );
+ $balance = sprintf( "%.2f", $balance);
+ $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp
+ $balance;
+}
+
+=item send [ TEMPLATENAME [ , AGENTNUM [ , INVOICE_FROM ] ] ]
+
+Sends this invoice to the destinations configured for this customer: send
+emails or print. See L<FS::cust_main_invoice>.
+
+TEMPLATENAME, if specified, is the name of a suffix for alternate invoices.
+
+AGENTNUM, if specified, means that this invoice will only be sent for customers
+of the specified agent.
+
+INVOICE_FROM, if specified, overrides the default email invoice From: address.
+
+=cut
+
+sub send {
+ my $self = shift;
+ my $template = scalar(@_) ? shift : '';
+ return 'N/A' if scalar(@_) && $_[0] && $self->cust_main->agentnum != shift;
+ my $invoice_from =
+ scalar(@_)
+ ? shift
+ : ( $self->_agent_invoice_from || $conf->config('invoice_from') );
+
+ my @print_text = $self->print_text('', $template);
+ my @invoicing_list = $self->cust_main->invoicing_list;
+
+ if ( grep { $_ ne 'POST' } @invoicing_list or !@invoicing_list ) { #email
+
+ #better to notify this person than silence
+ @invoicing_list = ($invoice_from) unless @invoicing_list;
+
+ my $error = send_email(
+ 'from' => $invoice_from,
+ 'to' => [ grep { $_ ne 'POST' } @invoicing_list ],
+ 'subject' => 'Invoice',
+ 'body' => \@print_text,
+ );
+ die "can't email invoice: $error\n" if $error;
+
+ }
+
+ if ( $conf->config('invoice_latex') ) {
+ @print_text = $self->print_ps('', $template);
+ }
+
+ if ( grep { $_ eq 'POST' } @invoicing_list ) { #postal
+ my $lpr = $conf->config('lpr');
+ open(LPR, "|$lpr")
+ or die "Can't open pipe to $lpr: $!\n";
+ print LPR @print_text;
+ close LPR
+ or die $! ? "Error closing $lpr: $!\n"
+ : "Exit status $? from $lpr\n";
+ }
+
+ '';
+
+}
+
+=item send_csv OPTIONS
+
+Sends invoice as a CSV data-file to a remote host with the specified protocol.
+
+Options are:
+
+protocol - currently only "ftp"
+server
+username
+password
+dir
+
+The file will be named "N-YYYYMMDDHHMMSS.csv" where N is the invoice number
+and YYMMDDHHMMSS is a timestamp.
+
+The fields of the CSV file is as follows:
+
+record_type, invnum, custnum, _date, charged, first, last, company, address1, address2, city, state, zip, country, pkg, setup, recur, sdate, edate
+
+=over 4
+
+=item record type - B<record_type> is either C<cust_bill> or C<cust_bill_pkg>
+
+If B<record_type> is C<cust_bill>, this is a primary invoice record. The
+last five fields (B<pkg> through B<edate>) are irrelevant, and all other
+fields are filled in.
+
+If B<record_type> is C<cust_bill_pkg>, this is a line item record. Only the
+first two fields (B<record_type> and B<invnum>) and the last five fields
+(B<pkg> through B<edate>) are filled in.
+
+=item invnum - invoice number
+
+=item custnum - customer number
+
+=item _date - invoice date
+
+=item charged - total invoice amount
+
+=item first - customer first name
+
+=item last - customer first name
+
+=item company - company name
+
+=item address1 - address line 1
+
+=item address2 - address line 1
+
+=item city
+
+=item state
+
+=item zip
+
+=item country
+
+=item pkg - line item description
+
+=item setup - line item setup fee (one or both of B<setup> and B<recur> will be defined)
+
+=item recur - line item recurring fee (one or both of B<setup> and B<recur> will be defined)
+
+=item sdate - start date for recurring fee
+
+=item edate - end date for recurring fee
+
+=back
+
+=cut
+
+sub send_csv {
+ my($self, %opt) = @_;
+
+ #part one: create file
+
+ my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/cust_bill";
+ mkdir $spooldir, 0700 unless -d $spooldir;
+
+ my $file = $spooldir. '/'. $self->invnum. time2str('-%Y%m%d%H%M%S.csv', time);
+
+ open(CSV, ">$file") or die "can't open $file: $!";
+
+ eval "use Text::CSV_XS";
+ die $@ if $@;
+
+ my $csv = Text::CSV_XS->new({'always_quote'=>1});
+
+ my $cust_main = $self->cust_main;
+
+ $csv->combine(
+ 'cust_bill',
+ $self->invnum,
+ $self->custnum,
+ time2str("%x", $self->_date),
+ sprintf("%.2f", $self->charged),
+ ( map { $cust_main->getfield($_) }
+ qw( first last company address1 address2 city state zip country ) ),
+ map { '' } (1..5),
+ ) or die "can't create csv";
+ print CSV $csv->string. "\n";
+
+ #new charges (false laziness w/print_text)
+ foreach my $cust_bill_pkg ( $self->cust_bill_pkg ) {
+
+ my($pkg, $setup, $recur, $sdate, $edate);
+ if ( $cust_bill_pkg->pkgnum ) {
+
+ ($pkg, $setup, $recur, $sdate, $edate) = (
+ $cust_bill_pkg->cust_pkg->part_pkg->pkg,
+ ( $cust_bill_pkg->setup != 0
+ ? sprintf("%.2f", $cust_bill_pkg->setup )
+ : '' ),
+ ( $cust_bill_pkg->recur != 0
+ ? sprintf("%.2f", $cust_bill_pkg->recur )
+ : '' ),
+ time2str("%x", $cust_bill_pkg->sdate),
+ time2str("%x", $cust_bill_pkg->edate),
+ );
+
+ } else { #pkgnum tax
+ next unless $cust_bill_pkg->setup != 0;
+ my $itemdesc = defined $cust_bill_pkg->dbdef_table->column('itemdesc')
+ ? ( $cust_bill_pkg->itemdesc || 'Tax' )
+ : 'Tax';
+ ($pkg, $setup, $recur, $sdate, $edate) =
+ ( $itemdesc, sprintf("%10.2f",$cust_bill_pkg->setup), '', '', '' );
+ }
+
+ $csv->combine(
+ 'cust_bill_pkg',
+ $self->invnum,
+ ( map { '' } (1..11) ),
+ ($pkg, $setup, $recur, $sdate, $edate)
+ ) or die "can't create csv";
+ print CSV $csv->string. "\n";
+
+ }
+
+ close CSV or die "can't close CSV: $!";
+
+ #part two: upload it
+
+ my $net;
+ if ( $opt{protocol} eq 'ftp' ) {
+ eval "use Net::FTP;";
+ die $@ if $@;
+ $net = Net::FTP->new($opt{server}) or die @$;
+ } else {
+ die "unknown protocol: $opt{protocol}";
+ }
+
+ $net->login( $opt{username}, $opt{password} )
+ or die "can't FTP to $opt{username}\@$opt{server}: login error: $@";
+
+ $net->binary or die "can't set binary mode";
+
+ $net->cwd($opt{dir}) or die "can't cwd to $opt{dir}";
+
+ $net->put($file) or die "can't put $file: $!";
+
+ $net->quit;
+
+ unlink $file;
+
+}
+
+=item comp
+
+Pays this invoice with a compliemntary payment. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub comp {
+ my $self = shift;
+ my $cust_pay = new FS::cust_pay ( {
+ 'invnum' => $self->invnum,
+ 'paid' => $self->owed,
+ '_date' => '',
+ 'payby' => 'COMP',
+ 'payinfo' => $self->cust_main->payinfo,
+ 'paybatch' => '',
+ } );
+ $cust_pay->insert;
+}
+
+=item realtime_card
+
+Attempts to pay this invoice with a credit card payment via a
+Business::OnlinePayment realtime gateway. See
+http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment
+for supported processors.
+
+=cut
+
+sub realtime_card {
+ my $self = shift;
+ $self->realtime_bop( 'CC', @_ );
+}
+
+=item realtime_ach
+
+Attempts to pay this invoice with an electronic check (ACH) payment via a
+Business::OnlinePayment realtime gateway. See
+http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment
+for supported processors.
+
+=cut
+
+sub realtime_ach {
+ my $self = shift;
+ $self->realtime_bop( 'ECHECK', @_ );
+}
+
+=item realtime_lec
+
+Attempts to pay this invoice with phone bill (LEC) payment via a
+Business::OnlinePayment realtime gateway. See
+http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment
+for supported processors.
+
+=cut
+
+sub realtime_lec {
+ my $self = shift;
+ $self->realtime_bop( 'LEC', @_ );
+}
+
+sub realtime_bop {
+ my( $self, $method ) = @_;
+
+ my $cust_main = $self->cust_main;
+ my $balance = $cust_main->balance;
+ my $amount = ( $balance < $self->owed ) ? $balance : $self->owed;
+ $amount = sprintf("%.2f", $amount);
+ return "not run (balance $balance)" unless $amount > 0;
+
+ my $description = 'Internet Services';
+ if ( $conf->exists('business-onlinepayment-description') ) {
+ my $dtempl = $conf->config('business-onlinepayment-description');
+
+ my $agent_obj = $cust_main->agent
+ or die "can't retreive agent for $cust_main (agentnum ".
+ $cust_main->agentnum. ")";
+ my $agent = $agent_obj->agent;
+ my $pkgs = join(', ',
+ map { $_->cust_pkg->part_pkg->pkg }
+ grep { $_->pkgnum } $self->cust_bill_pkg
+ );
+ $description = eval qq("$dtempl");
+ }
+
+ $cust_main->realtime_bop($method, $amount,
+ 'description' => $description,
+ 'invnum' => $self->invnum,
+ );
+
+}
+
+=item batch_card
+
+Adds a payment for this invoice to the pending credit card batch (see
+L<FS::cust_pay_batch>).
+
+=cut
+
+sub batch_card {
+ my $self = shift;
+ my $cust_main = $self->cust_main;
+
+ my $cust_pay_batch = new FS::cust_pay_batch ( {
+ 'invnum' => $self->getfield('invnum'),
+ 'custnum' => $cust_main->getfield('custnum'),
+ 'last' => $cust_main->getfield('last'),
+ 'first' => $cust_main->getfield('first'),
+ 'address1' => $cust_main->getfield('address1'),
+ 'address2' => $cust_main->getfield('address2'),
+ 'city' => $cust_main->getfield('city'),
+ 'state' => $cust_main->getfield('state'),
+ 'zip' => $cust_main->getfield('zip'),
+ 'country' => $cust_main->getfield('country'),
+ 'cardnum' => $cust_main->getfield('payinfo'),
+ 'exp' => $cust_main->getfield('paydate'),
+ 'payname' => $cust_main->getfield('payname'),
+ 'amount' => $self->owed,
+ } );
+ my $error = $cust_pay_batch->insert;
+ die $error if $error;
+
+ '';
+}
+
+sub _agent_template {
+ my $self = shift;
+ $self->_agent_plandata('agent_templatename');
+}
+
+sub _agent_invoice_from {
+ my $self = shift;
+ $self->_agent_plandata('agent_invoice_from');
+}
+
+sub _agent_plandata {
+ my( $self, $option ) = @_;
+
+ my $cust_bill_event = qsearchs( 'part_bill_event',
+ {
+ 'payby' => $self->cust_main->payby,
+ 'plan' => 'send_agent',
+ 'plandata' => { 'op' => '~',
+ 'value' => "(^|\n)agentnum ".
+ $self->cust_main->agentnum.
+ "(\n|\$)",
+ },
+ },
+ '',
+ 'ORDER BY seconds LIMIT 1'
+ );
+
+ return '' unless $cust_bill_event;
+
+ if ( $cust_bill_event->plandata =~ /^$option (.*)$/m ) {
+ return $1;
+ } else {
+ warn "can't parse plandata for $1";
+ return '';
+ }
+
+}
+
+=item print_text [ TIME [ , TEMPLATE ] ]
+
+Returns an text invoice, as a list of lines.
+
+TIME an optional value used to control the printing of overdue messages. The
+default is now. It isn't the date of the invoice; that's the `_date' field.
+It is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=cut
+
+sub print_text {
+
+ my( $self, $today, $template ) = @_;
+ $today ||= time;
+# my $invnum = $self->invnum;
+ my $cust_main = qsearchs('cust_main', { 'custnum', $self->custnum } );
+ $cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') )
+ unless $cust_main->payname && $cust_main->payby ne 'CHEK';
+
+ my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance
+# my( $cr_total, @cr_cust_credit ) = $self->cust_credit; #credits
+ #my $balance_due = $self->owed + $pr_total - $cr_total;
+ my $balance_due = $self->owed + $pr_total;
+
+ #my @collect = ();
+ #my($description,$amount);
+ @buf = ();
+
+ #previous balance
+ foreach ( @pr_cust_bill ) {
+ push @buf, [
+ "Previous Balance, Invoice #". $_->invnum.
+ " (". time2str("%x",$_->_date). ")",
+ $money_char. sprintf("%10.2f",$_->owed)
+ ];
+ }
+ if (@pr_cust_bill) {
+ push @buf,['','-----------'];
+ push @buf,[ 'Total Previous Balance',
+ $money_char. sprintf("%10.2f",$pr_total ) ];
+ push @buf,['',''];
+ }
+
+ #new charges
+ foreach my $cust_bill_pkg (
+ ( grep { $_->pkgnum } $self->cust_bill_pkg ), #packages first
+ ( grep { ! $_->pkgnum } $self->cust_bill_pkg ), #then taxes
+ ) {
+
+ if ( $cust_bill_pkg->pkgnum ) {
+
+ my $cust_pkg = qsearchs('cust_pkg', { pkgnum =>$cust_bill_pkg->pkgnum } );
+ my $part_pkg = qsearchs('part_pkg', { pkgpart=>$cust_pkg->pkgpart } );
+ my $pkg = $part_pkg->pkg;
+
+ if ( $cust_bill_pkg->setup != 0 ) {
+ my $description = $pkg;
+ $description .= ' Setup' if $cust_bill_pkg->recur != 0;
+ push @buf, [ $description,
+ $money_char. sprintf("%10.2f", $cust_bill_pkg->setup) ];
+ push @buf,
+ map { [ " ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
+ }
+
+ if ( $cust_bill_pkg->recur != 0 ) {
+ push @buf, [
+ "$pkg (" . time2str("%x", $cust_bill_pkg->sdate) . " - " .
+ time2str("%x", $cust_bill_pkg->edate) . ")",
+ $money_char. sprintf("%10.2f", $cust_bill_pkg->recur)
+ ];
+ push @buf,
+ map { [ " ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
+ }
+
+ push @buf, map { [ " $_", '' ] } $cust_bill_pkg->details;
+
+ } else { #pkgnum tax or one-shot line item
+ my $itemdesc = defined $cust_bill_pkg->dbdef_table->column('itemdesc')
+ ? ( $cust_bill_pkg->itemdesc || 'Tax' )
+ : 'Tax';
+ if ( $cust_bill_pkg->setup != 0 ) {
+ push @buf, [ $itemdesc,
+ $money_char. sprintf("%10.2f", $cust_bill_pkg->setup) ];
+ }
+ if ( $cust_bill_pkg->recur != 0 ) {
+ push @buf, [ "$itemdesc (". time2str("%x", $cust_bill_pkg->sdate). " - "
+ . time2str("%x", $cust_bill_pkg->edate). ")",
+ $money_char. sprintf("%10.2f", $cust_bill_pkg->recur)
+ ];
+ }
+ }
+ }
+
+ push @buf,['','-----------'];
+ push @buf,['Total New Charges',
+ $money_char. sprintf("%10.2f",$self->charged) ];
+ push @buf,['',''];
+
+ push @buf,['','-----------'];
+ push @buf,['Total Charges',
+ $money_char. sprintf("%10.2f",$self->charged + $pr_total) ];
+ push @buf,['',''];
+
+ #credits
+ foreach ( $self->cust_credited ) {
+
+ #something more elaborate if $_->amount ne $_->cust_credit->credited ?
+
+ my $reason = substr($_->cust_credit->reason,0,32);
+ $reason .= '...' if length($reason) < length($_->cust_credit->reason);
+ $reason = " ($reason) " if $reason;
+ push @buf,[
+ "Credit #". $_->crednum. " (". time2str("%x",$_->cust_credit->_date) .")".
+ $reason,
+ $money_char. sprintf("%10.2f",$_->amount)
+ ];
+ }
+ #foreach ( @cr_cust_credit ) {
+ # push @buf,[
+ # "Credit #". $_->crednum. " (" . time2str("%x",$_->_date) .")",
+ # $money_char. sprintf("%10.2f",$_->credited)
+ # ];
+ #}
+
+ #get & print payments
+ foreach ( $self->cust_bill_pay ) {
+
+ #something more elaborate if $_->amount ne ->cust_pay->paid ?
+
+ push @buf,[
+ "Payment received ". time2str("%x",$_->cust_pay->_date ),
+ $money_char. sprintf("%10.2f",$_->amount )
+ ];
+ }
+
+ #balance due
+ my $balance_due_msg = $self->balance_due_msg;
+
+ push @buf,['','-----------'];
+ push @buf,[$balance_due_msg, $money_char.
+ sprintf("%10.2f", $balance_due ) ];
+
+ #create the template
+ $template ||= $self->_agent_template;
+ my $templatefile = 'invoice_template';
+ $templatefile .= "_$template" if length($template);
+ my @invoice_template = $conf->config($templatefile)
+ or die "cannot load config file $templatefile";
+ $invoice_lines = 0;
+ my $wasfunc = 0;
+ foreach ( grep /invoice_lines\(\d*\)/, @invoice_template ) { #kludgy
+ /invoice_lines\((\d*)\)/;
+ $invoice_lines += $1 || scalar(@buf);
+ $wasfunc=1;
+ }
+ die "no invoice_lines() functions in template?" unless $wasfunc;
+ my $invoice_template = new Text::Template (
+ TYPE => 'ARRAY',
+ SOURCE => [ map "$_\n", @invoice_template ],
+ ) or die "can't create new Text::Template object: $Text::Template::ERROR";
+ $invoice_template->compile()
+ or die "can't compile template: $Text::Template::ERROR";
+
+ #setup template variables
+ package FS::cust_bill::_template; #!
+ use vars qw( $invnum $date $page $total_pages @address $overdue @buf $agent );
+
+ $invnum = $self->invnum;
+ $date = $self->_date;
+ $page = 1;
+ $agent = $self->cust_main->agent->agent;
+
+ if ( $FS::cust_bill::invoice_lines ) {
+ $total_pages =
+ int( scalar(@FS::cust_bill::buf) / $FS::cust_bill::invoice_lines );
+ $total_pages++
+ if scalar(@FS::cust_bill::buf) % $FS::cust_bill::invoice_lines;
+ } else {
+ $total_pages = 1;
+ }
+
+ #format address (variable for the template)
+ my $l = 0;
+ @address = ( '', '', '', '', '', '' );
+ package FS::cust_bill; #!
+ $FS::cust_bill::_template::address[$l++] =
+ $cust_main->payname.
+ ( ( $cust_main->payby eq 'BILL' ) && $cust_main->payinfo
+ ? " (P.O. #". $cust_main->payinfo. ")"
+ : ''
+ )
+ ;
+ $FS::cust_bill::_template::address[$l++] = $cust_main->company
+ if $cust_main->company;
+ $FS::cust_bill::_template::address[$l++] = $cust_main->address1;
+ $FS::cust_bill::_template::address[$l++] = $cust_main->address2
+ if $cust_main->address2;
+ $FS::cust_bill::_template::address[$l++] =
+ $cust_main->city. ", ". $cust_main->state. " ". $cust_main->zip;
+ $FS::cust_bill::_template::address[$l++] = $cust_main->country
+ unless $cust_main->country eq 'US';
+
+ # #overdue? (variable for the template)
+ # $FS::cust_bill::_template::overdue = (
+ # $balance_due > 0
+ # && $today > $self->_date
+ ## && $self->printed > 1
+ # && $self->printed > 0
+ # );
+
+ #and subroutine for the template
+ sub FS::cust_bill::_template::invoice_lines {
+ my $lines = shift || scalar(@buf);
+ map {
+ scalar(@buf) ? shift @buf : [ '', '' ];
+ }
+ ( 1 .. $lines );
+ }
+
+ #and fill it in
+ $FS::cust_bill::_template::page = 1;
+ my $lines;
+ my @collect;
+ while (@buf) {
+ push @collect, split("\n",
+ $invoice_template->fill_in( PACKAGE => 'FS::cust_bill::_template' )
+ );
+ $FS::cust_bill::_template::page++;
+ }
+
+ map "$_\n", @collect;
+
+}
+
+=item print_latex [ TIME [ , TEMPLATE ] ]
+
+Internal method - returns a filename of a filled-in LaTeX template for this
+invoice (Note: add ".tex" to get the actual filename).
+
+See print_ps and print_pdf for methods that return PostScript and PDF output.
+
+TIME an optional value used to control the printing of overdue messages. The
+default is now. It isn't the date of the invoice; that's the `_date' field.
+It is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=cut
+
+#still some false laziness w/print_text
+sub print_latex {
+
+ my( $self, $today, $template ) = @_;
+ $today ||= time;
+
+# my $invnum = $self->invnum;
+ my $cust_main = $self->cust_main;
+ $cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') )
+ unless $cust_main->payname && $cust_main->payby ne 'CHEK';
+
+ my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance
+# my( $cr_total, @cr_cust_credit ) = $self->cust_credit; #credits
+ #my $balance_due = $self->owed + $pr_total - $cr_total;
+ my $balance_due = $self->owed + $pr_total;
+
+ #my @collect = ();
+ #my($description,$amount);
+ @buf = ();
+
+ #create the template
+ $template ||= $self->_agent_template;
+ my $templatefile = 'invoice_latex';
+ my $suffix = length($template) ? "_$template" : '';
+ $templatefile .= $suffix;
+ my @invoice_template = $conf->config($templatefile)
+ or die "cannot load config file $templatefile";
+
+ my %invoice_data = (
+ 'invnum' => $self->invnum,
+ 'date' => time2str('%b %o, %Y', $self->_date),
+ 'agent' => _latex_escape($cust_main->agent->agent),
+ 'payname' => _latex_escape($cust_main->payname),
+ 'company' => _latex_escape($cust_main->company),
+ 'address1' => _latex_escape($cust_main->address1),
+ 'address2' => _latex_escape($cust_main->address2),
+ 'city' => _latex_escape($cust_main->city),
+ 'state' => _latex_escape($cust_main->state),
+ 'zip' => _latex_escape($cust_main->zip),
+ 'country' => _latex_escape($cust_main->country),
+ 'footer' => join("\n", $conf->config('invoice_latexfooter') ),
+ 'smallfooter' => join("\n", $conf->config('invoice_latexsmallfooter') ),
+ 'quantity' => 1,
+ 'terms' => $conf->config('invoice_default_terms') || 'Payable upon receipt',
+ #'notes' => join("\n", $conf->config('invoice_latexnotes') ),
+ );
+
+ my $countrydefault = $conf->config('countrydefault') || 'US';
+ $invoice_data{'country'} = '' if $invoice_data{'country'} eq $countrydefault;
+
+ #do variable substitutions in notes
+ $invoice_data{'notes'} =
+ join("\n",
+ map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b }
+ $conf->config_orbase('invoice_latexnotes', $suffix)
+ );
+
+ $invoice_data{'footer'} =~ s/\n+$//;
+ $invoice_data{'smallfooter'} =~ s/\n+$//;
+ $invoice_data{'notes'} =~ s/\n+$//;
+
+ $invoice_data{'po_line'} =
+ ( $cust_main->payby eq 'BILL' && $cust_main->payinfo )
+ ? _latex_escape("Purchase Order #". $cust_main->payinfo)
+ : '~';
+
+ my @line_item = ();
+ my @total_item = ();
+ my @filled_in = ();
+ while ( @invoice_template ) {
+ my $line = shift @invoice_template;
+
+ if ( $line =~ /^%%Detail\s*$/ ) {
+
+ while ( ( my $line_item_line = shift @invoice_template )
+ !~ /^%%EndDetail\s*$/ ) {
+ push @line_item, $line_item_line;
+ }
+ foreach my $line_item ( $self->_items ) {
+ #foreach my $line_item ( $self->_items_pkg ) {
+ $invoice_data{'ref'} = $line_item->{'pkgnum'};
+ $invoice_data{'description'} = _latex_escape($line_item->{'description'});
+ if ( exists $line_item->{'ext_description'} ) {
+ $invoice_data{'description'} .=
+ "\\tabularnewline\n~~".
+ join("\\tabularnewline\n~~", map { _latex_escape($_) } @{$line_item->{'ext_description'}} );
+ }
+ $invoice_data{'amount'} = $line_item->{'amount'};
+ $invoice_data{'product_code'} = $line_item->{'pkgpart'} || 'N/A';
+ push @filled_in,
+ map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b } @line_item;
+ }
+
+ } elsif ( $line =~ /^%%TotalDetails\s*$/ ) {
+
+ while ( ( my $total_item_line = shift @invoice_template )
+ !~ /^%%EndTotalDetails\s*$/ ) {
+ push @total_item, $total_item_line;
+ }
+
+ my @total_fill = ();
+
+ my $taxtotal = 0;
+ foreach my $tax ( $self->_items_tax ) {
+ $invoice_data{'total_item'} = _latex_escape($tax->{'description'});
+ $taxtotal += ( $invoice_data{'total_amount'} = $tax->{'amount'} );
+ push @total_fill,
+ map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b }
+ @total_item;
+ }
+
+ if ( $taxtotal ) {
+ $invoice_data{'total_item'} = 'Sub-total';
+ $invoice_data{'total_amount'} =
+ '\dollar '. sprintf('%.2f', $self->charged - $taxtotal );
+ unshift @total_fill,
+ map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b }
+ @total_item;
+ }
+
+ $invoice_data{'total_item'} = '\textbf{Total}';
+ $invoice_data{'total_amount'} =
+ '\textbf{\dollar '. sprintf('%.2f', $self->charged + $pr_total ). '}';
+ push @total_fill,
+ map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b }
+ @total_item;
+
+ #foreach my $thing ( sort { $a->_date <=> $b->_date } $self->_items_credits, $self->_items_payments
+
+ # credits
+ foreach my $credit ( $self->_items_credits ) {
+ $invoice_data{'total_item'} = _latex_escape($credit->{'description'});
+ #$credittotal
+ $invoice_data{'total_amount'} = '-\dollar '. $credit->{'amount'};
+ push @total_fill,
+ map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b }
+ @total_item;
+ }
+
+ # payments
+ foreach my $payment ( $self->_items_payments ) {
+ $invoice_data{'total_item'} = _latex_escape($payment->{'description'});
+ #$paymenttotal
+ $invoice_data{'total_amount'} = '-\dollar '. $payment->{'amount'};
+ push @total_fill,
+ map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b }
+ @total_item;
+ }
+
+ $invoice_data{'total_item'} = '\textbf{'. $self->balance_due_msg. '}';
+ $invoice_data{'total_amount'} =
+ '\textbf{\dollar '. sprintf('%.2f', $self->owed + $pr_total ). '}';
+ push @total_fill,
+ map { my $b=$_; $b =~ s/\$(\w+)/$invoice_data{$1}/eg; $b }
+ @total_item;
+
+ push @filled_in, @total_fill;
+
+ } else {
+ #$line =~ s/\$(\w+)/$invoice_data{$1}/eg;
+ $line =~ s/\$(\w+)/exists($invoice_data{$1}) ? $invoice_data{$1} : nounder($1)/eg;
+ push @filled_in, $line;
+ }
+
+ }
+
+ sub nounder {
+ my $var = $1;
+ $var =~ s/_/\-/g;
+ $var;
+ }
+
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ my $fh = new File::Temp( TEMPLATE => 'invoice.'. $self->invnum. '.XXXXXXXX',
+ DIR => $dir,
+ SUFFIX => '.tex',
+ UNLINK => 0,
+ ) or die "can't open temp file: $!\n";
+ print $fh join("\n", @filled_in ), "\n";
+ close $fh;
+
+ $fh->filename =~ /^(.*).tex$/ or die "unparsable filename: ". $fh->filename;
+ return $1;
+
+}
+
+=item print_ps [ TIME [ , TEMPLATE ] ]
+
+Returns an postscript invoice, as a scalar.
+
+TIME an optional value used to control the printing of overdue messages. The
+default is now. It isn't the date of the invoice; that's the `_date' field.
+It is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=cut
+
+sub print_ps {
+ my $self = shift;
+
+ my $file = $self->print_latex(@_);
+
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ chdir($dir);
+
+ system("pslatex $file.tex >/dev/null 2>&1") == 0
+ or die "pslatex $file.tex failed: $!";
+ system("pslatex $file.tex >/dev/null 2>&1") == 0
+ or die "pslatex $file.tex failed: $!";
+
+ system('dvips', '-q', '-t', 'letter', "$file.dvi", '-o', "$file.ps" ) == 0
+ or die "dvips failed: $!";
+
+ open(POSTSCRIPT, "<$file.ps")
+ or die "can't open $file.ps: $! (error in LaTeX template?)\n";
+
+ unlink("$file.dvi", "$file.log", "$file.aux", "$file.ps", "$file.tex");
+
+ my $ps = '';
+ while (<POSTSCRIPT>) {
+ $ps .= $_;
+ }
+
+ close POSTSCRIPT;
+
+ return $ps;
+
+}
+
+=item print_pdf [ TIME [ , TEMPLATE ] ]
+
+Returns an PDF invoice, as a scalar.
+
+TIME an optional value used to control the printing of overdue messages. The
+default is now. It isn't the date of the invoice; that's the `_date' field.
+It is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=cut
+
+sub print_pdf {
+ my $self = shift;
+
+ my $file = $self->print_latex(@_);
+
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ chdir($dir);
+
+ #system('pdflatex', "$file.tex");
+ #system('pdflatex', "$file.tex");
+ #! LaTeX Error: Unknown graphics extension: .eps.
+
+ system("pslatex $file.tex >/dev/null 2>&1") == 0
+ or die "pslatex $file.tex failed: $!";
+ system("pslatex $file.tex >/dev/null 2>&1") == 0
+ or die "pslatex $file.tex failed: $!";
+
+ #system('dvipdf', "$file.dvi", "$file.pdf" );
+ system(
+ "dvips -q -t letter -f $file.dvi ".
+ "| gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$file.pdf ".
+ " -c save pop -"
+ ) == 0
+ or die "dvips | gs failed: $!";
+
+ open(PDF, "<$file.pdf")
+ or die "can't open $file.pdf: $! (error in LaTeX template?)\n";
+
+ unlink("$file.dvi", "$file.log", "$file.aux", "$file.pdf", "$file.tex");
+
+ my $pdf = '';
+ while (<PDF>) {
+ $pdf .= $_;
+ }
+
+ close PDF;
+
+ return $pdf;
+
+}
+
+# quick subroutine for print_latex
+#
+# There are ten characters that LaTeX treats as special characters, which
+# means that they do not simply typeset themselves:
+# # $ % & ~ _ ^ \ { }
+#
+# TeX ignores blanks following an escaped character; if you want a blank (as
+# in "10% of ..."), you have to "escape" the blank as well ("10\%\ of ...").
+
+sub _latex_escape {
+ my $value = shift;
+ $value =~ s/([#\$%&~_\^{}])( )?/"\\$1". ( length($2) ? "\\$2" : '' )/ge;
+ $value;
+}
+
+#utility methods for print_*
+
+sub balance_due_msg {
+ my $self = shift;
+ my $msg = 'Balance Due';
+ return $msg unless $conf->exists('invoice_default_terms');
+ if ( $conf->config('invoice_default_terms') =~ /^\s*Net\s*(\d+)\s*$/ ) {
+ $msg .= ' - Please pay by '. time2str("%x", $self->_date + ($1*86400) );
+ } elsif ( $conf->config('invoice_default_terms') ) {
+ $msg .= ' - '. $conf->config('invoice_default_terms');
+ }
+ $msg;
+}
+
+sub _items {
+ my $self = shift;
+ my @display = scalar(@_)
+ ? @_
+ : qw( _items_previous _items_pkg );
+ #: qw( _items_pkg );
+ #: qw( _items_previous _items_pkg _items_tax _items_credits _items_payments );
+ my @b = ();
+ foreach my $display ( @display ) {
+ push @b, $self->$display(@_);
+ }
+ @b;
+}
+
+sub _items_previous {
+ my $self = shift;
+ my $cust_main = $self->cust_main;
+ my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance
+ my @b = ();
+ foreach ( @pr_cust_bill ) {
+ push @b, {
+ 'description' => 'Previous Balance, Invoice #'. $_->invnum.
+ ' ('. time2str('%x',$_->_date). ')',
+ #'pkgpart' => 'N/A',
+ 'pkgnum' => 'N/A',
+ 'amount' => sprintf("%10.2f", $_->owed),
+ };
+ }
+ @b;
+
+ #{
+ # 'description' => 'Previous Balance',
+ # #'pkgpart' => 'N/A',
+ # 'pkgnum' => 'N/A',
+ # 'amount' => sprintf("%10.2f", $pr_total ),
+ # 'ext_description' => [ map {
+ # "Invoice ". $_->invnum.
+ # " (". time2str("%x",$_->_date). ") ".
+ # sprintf("%10.2f", $_->owed)
+ # } @pr_cust_bill ],
+
+ #};
+}
+
+sub _items_pkg {
+ my $self = shift;
+ my @cust_bill_pkg = grep { $_->pkgnum } $self->cust_bill_pkg;
+ $self->_items_cust_bill_pkg(\@cust_bill_pkg, @_);
+}
+
+sub _items_tax {
+ my $self = shift;
+ my @cust_bill_pkg = grep { ! $_->pkgnum } $self->cust_bill_pkg;
+ $self->_items_cust_bill_pkg(\@cust_bill_pkg, @_);
+}
+
+sub _items_cust_bill_pkg {
+ my $self = shift;
+ my $cust_bill_pkg = shift;
+
+ my @b = ();
+ foreach my $cust_bill_pkg ( @$cust_bill_pkg ) {
+
+ if ( $cust_bill_pkg->pkgnum ) {
+
+ my $cust_pkg = qsearchs('cust_pkg', { pkgnum =>$cust_bill_pkg->pkgnum } );
+ my $part_pkg = qsearchs('part_pkg', { pkgpart=>$cust_pkg->pkgpart } );
+ my $pkg = $part_pkg->pkg;
+
+ my %labels;
+ #tie %labels, 'Tie::IxHash';
+ push @{ $labels{$_->[0]} }, $_->[1] foreach $cust_pkg->labels;
+ my @ext_description;
+ foreach my $label ( keys %labels ) {
+ my @values = @{ $labels{$label} };
+ my $num = scalar(@values);
+ if ( $num > 5 ) {
+ push @ext_description, "$label ($num)";
+ } else {
+ push @ext_description, map { "$label: $_" } @values;
+ }
+ }
+
+ if ( $cust_bill_pkg->setup != 0 ) {
+ my $description = $pkg;
+ $description .= ' Setup' if $cust_bill_pkg->recur != 0;
+ my @d = @ext_description;
+ push @d, $cust_bill_pkg->details if $cust_bill_pkg->recur == 0;
+ push @b, {
+ 'description' => $description,
+ #'pkgpart' => $part_pkg->pkgpart,
+ 'pkgnum' => $cust_pkg->pkgnum,
+ 'amount' => sprintf("%10.2f", $cust_bill_pkg->setup),
+ 'ext_description' => \@d,
+ };
+ }
+
+ if ( $cust_bill_pkg->recur != 0 ) {
+ push @b, {
+ 'description' => "$pkg (" .
+ time2str('%x', $cust_bill_pkg->sdate). ' - '.
+ time2str('%x', $cust_bill_pkg->edate). ')',
+ #'pkgpart' => $part_pkg->pkgpart,
+ 'pkgnum' => $cust_pkg->pkgnum,
+ 'amount' => sprintf("%10.2f", $cust_bill_pkg->recur),
+ 'ext_description' => [ @ext_description,
+ $cust_bill_pkg->details,
+ ],
+ };
+ }
+
+ } else { #pkgnum tax or one-shot line item (??)
+
+ my $itemdesc = defined $cust_bill_pkg->dbdef_table->column('itemdesc')
+ ? ( $cust_bill_pkg->itemdesc || 'Tax' )
+ : 'Tax';
+ if ( $cust_bill_pkg->setup != 0 ) {
+ push @b, {
+ 'description' => $itemdesc,
+ 'amount' => sprintf("%10.2f", $cust_bill_pkg->setup),
+ };
+ }
+ if ( $cust_bill_pkg->recur != 0 ) {
+ push @b, {
+ 'description' => "$itemdesc (".
+ time2str("%x", $cust_bill_pkg->sdate). ' - '.
+ time2str("%x", $cust_bill_pkg->edate). ')',
+ 'amount' => sprintf("%10.2f", $cust_bill_pkg->recur),
+ };
+ }
+
+ }
+
+ }
+
+ @b;
+
+}
+
+sub _items_credits {
+ my $self = shift;
+
+ my @b;
+ #credits
+ foreach ( $self->cust_credited ) {
+
+ #something more elaborate if $_->amount ne $_->cust_credit->credited ?
+
+ my $reason = $_->cust_credit->reason;
+ #my $reason = substr($_->cust_credit->reason,0,32);
+ #$reason .= '...' if length($reason) < length($_->cust_credit->reason);
+ $reason = " ($reason) " if $reason;
+ push @b, {
+ #'description' => 'Credit ref\#'. $_->crednum.
+ # " (". time2str("%x",$_->cust_credit->_date) .")".
+ # $reason,
+ 'description' => 'Credit applied'.
+ time2str("%x",$_->cust_credit->_date). $reason,
+ 'amount' => sprintf("%10.2f",$_->amount),
+ };
+ }
+ #foreach ( @cr_cust_credit ) {
+ # push @buf,[
+ # "Credit #". $_->crednum. " (" . time2str("%x",$_->_date) .")",
+ # $money_char. sprintf("%10.2f",$_->credited)
+ # ];
+ #}
+
+ @b;
+
+}
+
+sub _items_payments {
+ my $self = shift;
+
+ my @b;
+ #get & print payments
+ foreach ( $self->cust_bill_pay ) {
+
+ #something more elaborate if $_->amount ne ->cust_pay->paid ?
+
+ push @b, {
+ 'description' => "Payment received ".
+ time2str("%x",$_->cust_pay->_date ),
+ 'amount' => sprintf("%10.2f", $_->amount )
+ };
+ }
+
+ @b;
+
+}
+
+=back
+
+=head1 BUGS
+
+The delete method.
+
+print_text formatting (and some logic :/) is in source, but needs to be
+slurped in from a file. Also number of lines ($=).
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_main>, L<FS::cust_bill_pay>, L<FS::cust_pay>,
+L<FS::cust_bill_pkg>, L<FS::cust_bill_credit>, schema.html from the base
+documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_bill_event.pm b/FS/FS/cust_bill_event.pm
new file mode 100644
index 0000000..ddd6762
--- /dev/null
+++ b/FS/FS/cust_bill_event.pm
@@ -0,0 +1,180 @@
+package FS::cust_bill_event;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+use FS::cust_bill;
+use FS::part_bill_event;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::cust_bill_event - Object methods for cust_bill_event records
+
+=head1 SYNOPSIS
+
+ use FS::cust_bill_event;
+
+ $record = new FS::cust_bill_event \%hash;
+ $record = new FS::cust_bill_event { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_bill_event object represents an complete invoice event.
+FS::cust_bill_event inherits from FS::Record. The following fields are
+currently supported:
+
+=over 4
+
+=item eventnum - primary key
+
+=item invnum - invoice (see L<FS::cust_bill>)
+
+=item eventpart - event definition (see L<FS::part_bill_event>)
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=item status - event status: B<done> or B<failed>
+
+=item statustext - additional status detail (i.e. error message)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new completed invoice event. To add the compelted invoice event to
+the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'cust_bill_event'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid completed invoice event. If
+there is an error, returns the error, otherwise returns false. Called by the
+insert and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ my $error = $self->ut_numbern('eventnum')
+ || $self->ut_number('invnum')
+ || $self->ut_number('eventpart')
+ || $self->ut_number('_date')
+ || $self->ut_enum('status', [qw( done failed )])
+ || $self->ut_textn('statustext')
+ ;
+
+ return "Unknown invnum ". $self->invnum
+ unless qsearchs( 'cust_bill' ,{ 'invnum' => $self->invnum } );
+
+ return "Unknown eventpart ". $self->eventpart
+ unless qsearchs( 'part_bill_event' ,{ 'eventpart' => $self->eventpart } );
+
+ $self->SUPER::check;
+}
+
+=item part_bill_event
+
+Returns the invoice event definition (see L<FS::part_bill_event>) for this
+completed invoice event.
+
+=cut
+
+sub part_bill_event {
+ my $self = shift;
+ qsearchs( 'part_bill_event', { 'eventpart' => $self->eventpart } );
+}
+
+=item cust_bill
+
+Returns the invoice (see L<FS::cust_bill>) for this completed invoice event.
+
+=cut
+
+sub cust_bill {
+ my $self = shift;
+ qsearchs( 'cust_bill', { 'invnum' => $self->invnum } );
+}
+
+=item retry
+
+Changes the status of this event from B<done> to B<failed>, allowing it to be
+retried.
+
+=cut
+
+sub retry {
+ my $self = shift;
+ return '' unless $self->status eq 'done';
+ my $old = ref($self)->new( { $self->hash } );
+ $self->status('failed');
+ $self->replace($old);
+}
+
+=back
+
+=head1 BUGS
+
+Far too early in the morning.
+
+=head1 SEE ALSO
+
+L<FS::part_bill_event>, L<FS::cust_bill>, L<FS::Record>, schema.html from the
+base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_bill_pay.pm b/FS/FS/cust_bill_pay.pm
new file mode 100644
index 0000000..c8b5525
--- /dev/null
+++ b/FS/FS/cust_bill_pay.pm
@@ -0,0 +1,226 @@
+package FS::cust_bill_pay;
+
+use strict;
+use vars qw( @ISA $conf );
+use FS::Record qw( qsearch qsearchs dbh );
+use FS::cust_bill;
+use FS::cust_pay;
+
+@ISA = qw( FS::Record );
+
+#ask FS::UID to run this stuff for us later
+FS::UID->install_callback( sub {
+ $conf = new FS::Conf;
+} );
+
+=head1 NAME
+
+FS::cust_bill_pay - Object methods for cust_bill_pay records
+
+=head1 SYNOPSIS
+
+ use FS::cust_bill_pay;
+
+ $record = new FS::cust_bill_pay \%hash;
+ $record = new FS::cust_bill_pay { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_bill_pay object represents the application of a payment to a
+specific invoice. FS::cust_bill_pay inherits from FS::Record. The following
+fields are currently supported:
+
+=over 4
+
+=item billpaynum - primary key (assigned automatically)
+
+=item invnum - Invoice (see L<FS::cust_bill>)
+
+=item paynum - Payment (see L<FS::cust_pay>)
+
+=item amount - Amount of the payment to apply to the specific invoice.
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'cust_bill_pay'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->check;
+ return $error if $error;
+
+ $error = $self->SUPER::insert;
+
+ my $cust_pay = qsearchs('cust_pay', { 'paynum' => $self->paynum } ) or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "unknown cust_pay.paynum: ". $self->paynum;
+ };
+
+ my $pay_total = 0;
+ $pay_total += $_ foreach map { $_->amount }
+ qsearch('cust_bill_pay', { 'paynum' => $self->paynum } );
+
+ if ( sprintf("%.2f", $pay_total) > sprintf("%.2f", $cust_pay->paid) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "total cust_bill_pay.amount $pay_total for paynum ". $self->paynum.
+ " greater than cust_pay.paid ". $cust_pay->paid;
+ }
+
+ my $cust_bill = $self->cust_bill;
+ unless ( $cust_bill ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "unknown cust_bill.invnum: ". $self->invnum;
+ };
+
+ my $bill_total = 0;
+ $bill_total += $_ foreach map { $_->amount }
+ qsearch('cust_bill_pay', { 'invnum' => $self->invnum } );
+ $bill_total += $_ foreach map { $_->amount }
+ qsearch('cust_credit_bill', { 'invnum' => $self->invnum } );
+ if ( sprintf("%.2f", $bill_total) > sprintf("%.2f", $cust_bill->charged) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "total cust_bill_pay.amount and cust_credit_bill.amount $bill_total".
+ " for invnum ". $self->invnum.
+ " greater than cust_bill.charged ". $cust_bill->charged;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ if ( $conf->exists('invoice_send_receipts') ) {
+ my $send_error = $cust_bill->send;
+ warn "Error sending receipt: $send_error\n" if $send_error;
+ }
+
+ '';
+}
+
+=item delete
+
+Deletes this payment application, unless the closed flag for the parent payment
+(see L<FS::cust_pay>) is set.
+
+=cut
+
+sub delete {
+ my $self = shift;
+ return "Can't delete application for closed payment"
+ if $self->cust_pay->closed =~ /^Y/i;
+ $self->SUPER::delete(@_);
+}
+
+=item replace OLD_RECORD
+
+Currently unimplemented (accounting reasons).
+
+=cut
+
+sub replace {
+ return "Can't (yet?) modify cust_bill_pay records!";
+}
+
+=item check
+
+Checks all fields to make sure this is a valid payment. If there is an error,
+returns the error, otherwise returns false. Called by the insert method.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('billpaynum')
+ || $self->ut_number('invnum')
+ || $self->ut_number('paynum')
+ || $self->ut_money('amount')
+ || $self->ut_numbern('_date')
+ ;
+ return $error if $error;
+
+ return "amount must be > 0" if $self->amount <= 0;
+
+ $self->_date(time) unless $self->_date;
+
+ $self->SUPER::check;
+}
+
+=item cust_pay
+
+Returns the payment (see L<FS::cust_pay>)
+
+=cut
+
+sub cust_pay {
+ my $self = shift;
+ qsearchs( 'cust_pay', { 'paynum' => $self->paynum } );
+}
+
+=item cust_bill
+
+Returns the invoice (see L<FS::cust_bill>)
+
+=cut
+
+sub cust_bill {
+ my $self = shift;
+ qsearchs( 'cust_bill', { 'invnum' => $self->invnum } );
+}
+
+=back
+
+=head1 BUGS
+
+Delete and replace methods.
+
+the checks for over-applied payments could be better done like the ones in
+cust_bill_credit
+
+=head1 SEE ALSO
+
+L<FS::cust_pay>, L<FS::cust_bill>, L<FS::Record>, schema.html from the
+base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm
new file mode 100644
index 0000000..6800707
--- /dev/null
+++ b/FS/FS/cust_bill_pkg.pm
@@ -0,0 +1,215 @@
+package FS::cust_bill_pkg;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs dbdef dbh );
+use FS::cust_pkg;
+use FS::cust_bill;
+use FS::cust_bill_pkg_detail;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::cust_bill_pkg - Object methods for cust_bill_pkg records
+
+=head1 SYNOPSIS
+
+ use FS::cust_bill_pkg;
+
+ $record = new FS::cust_bill_pkg \%hash;
+ $record = new FS::cust_bill_pkg { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_bill_pkg object represents an invoice line item.
+FS::cust_bill_pkg inherits from FS::Record. The following fields are currently
+supported:
+
+=over 4
+
+=item invnum - invoice (see L<FS::cust_bill>)
+
+=item pkgnum - package (see L<FS::cust_pkg>) or 0 for the special virtual sales tax package
+
+=item setup - setup fee
+
+=item recur - recurring fee
+
+=item sdate - starting date of recurring fee
+
+=item edate - ending date of recurring fee
+
+=item itemdesc - Line item description (currentlty used only when pkgnum is 0)
+
+=back
+
+sdate and edate are specified as UNIX timestamps; see L<perlfunc/"time">. Also
+see L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new line item. To add the line item to the database, see
+L<"insert">. Line items are normally created by calling the bill method of a
+customer object (see L<FS::cust_main>).
+
+=cut
+
+sub table { 'cust_bill_pkg'; }
+
+=item insert
+
+Adds this line item to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ unless ( defined dbdef->table('cust_bill_pkg_detail') && $self->get('details') ) {
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ return '';
+ }
+
+ foreach my $detail ( @{$self->get('details')} ) {
+ my $cust_bill_pkg_detail = new FS::cust_bill_pkg_detail {
+ 'pkgnum' => $self->pkgnum,
+ 'invnum' => $self->invnum,
+ 'detail' => $detail,
+ };
+ $error = $cust_bill_pkg_detail->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item delete
+
+Currently unimplemented. I don't remove line items because there would then be
+no record the items ever existed (which is bad, no?)
+
+=cut
+
+sub delete {
+ return "Can't delete cust_bill_pkg records!";
+}
+
+=item replace OLD_RECORD
+
+Currently unimplemented. This would be even more of an accounting nightmare
+than deleteing the items. Just don't do it.
+
+=cut
+
+sub replace {
+ return "Can't modify cust_bill_pkg records!";
+}
+
+=item check
+
+Checks all fields to make sure this is a valid line item. If there is an
+error, returns the error, otherwise returns false. Called by the insert
+method.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_number('pkgnum')
+ || $self->ut_number('invnum')
+ || $self->ut_money('setup')
+ || $self->ut_money('recur')
+ || $self->ut_numbern('sdate')
+ || $self->ut_numbern('edate')
+ || $self->ut_textn('itemdesc')
+ ;
+ return $error if $error;
+
+ if ( $self->pkgnum != 0 ) { #allow unchecked pkgnum 0 for tax! (add to part_pkg?)
+ return "Unknown pkgnum ". $self->pkgnum
+ unless qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } );
+ }
+
+ return "Unknown invnum"
+ unless qsearchs( 'cust_bill' ,{ 'invnum' => $self->invnum } );
+
+ $self->SUPER::check;
+}
+
+=item cust_pkg
+
+Returns the package (see L<FS::cust_pkg>) for this invoice line item.
+
+=cut
+
+sub cust_pkg {
+ my $self = shift;
+ qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } );
+}
+
+=item details
+
+Returns an array of detail information for the invoice line item.
+
+=cut
+
+sub details {
+ my $self = shift;
+ return () unless defined dbdef->table('cust_bill_pkg_detail');
+ map { $_->detail }
+ qsearch ( 'cust_bill_pkg_detail', { 'pkgnum' => $self->pkgnum,
+ 'invnum' => $self->invnum, } );
+ #qsearch ( 'cust_bill_pkg_detail', { 'lineitemnum' => $self->lineitemnum });
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_bill>, L<FS::cust_pkg>, L<FS::cust_main>, schema.html
+from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_bill_pkg_detail.pm b/FS/FS/cust_bill_pkg_detail.pm
new file mode 100644
index 0000000..261aa80
--- /dev/null
+++ b/FS/FS/cust_bill_pkg_detail.pm
@@ -0,0 +1,124 @@
+package FS::cust_bill_pkg_detail;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::cust_bill_pkg_detail - Object methods for cust_bill_pkg_detail records
+
+=head1 SYNOPSIS
+
+ use FS::cust_bill_pkg_detail;
+
+ $record = new FS::cust_bill_pkg_detail \%hash;
+ $record = new FS::cust_bill_pkg_detail { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_bill_pkg_detail object represents additional detail information for
+an invoice line item (see L<FS::cust_bill_pkg>). FS::cust_bill_pkg_detail
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item detailnum - primary key
+
+=item pkgnum -
+
+=item invnum -
+
+=item detail - detail description
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new line item detail. To add the line item detail to the database,
+see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'cust_bill_pkg_detail'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid line item detail. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('detailnum')
+ || $self->ut_foreign_key('pkgnum', 'cust_pkg', 'pkgnum')
+ || $self->ut_foreign_key('invnum', 'cust_pkg', 'invnum')
+ || $self->ut_text('detail')
+ || $self->SUPER::check
+ ;
+
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::cust_bill_pkg>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm
new file mode 100644
index 0000000..8ec255b
--- /dev/null
+++ b/FS/FS/cust_credit.pm
@@ -0,0 +1,330 @@
+package FS::cust_credit;
+
+use strict;
+use vars qw( @ISA $conf $unsuspendauto );
+use Date::Format;
+use FS::UID qw( dbh getotaker );
+use FS::Record qw( qsearch qsearchs );
+use FS::Misc qw(send_email);
+use FS::cust_main;
+use FS::cust_refund;
+use FS::cust_credit_bill;
+
+@ISA = qw( FS::Record );
+
+#ask FS::UID to run this stuff for us later
+$FS::UID::callback{'FS::cust_credit'} = sub {
+
+ $conf = new FS::Conf;
+ $unsuspendauto = $conf->exists('unsuspendauto');
+
+};
+
+=head1 NAME
+
+FS::cust_credit - Object methods for cust_credit records
+
+=head1 SYNOPSIS
+
+ use FS::cust_credit;
+
+ $record = new FS::cust_credit \%hash;
+ $record = new FS::cust_credit { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_credit object represents a credit; the equivalent of a negative
+B<cust_bill> record (see L<FS::cust_bill>). FS::cust_credit inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item crednum - primary key (assigned automatically for new credits)
+
+=item custnum - customer (see L<FS::cust_main>)
+
+=item amount - amount of the credit
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=item otaker - order taker (assigned automatically, see L<FS::UID>)
+
+=item reason - text
+
+=item closed - books closed flag, empty or `Y'
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new credit. To add the credit to the database, see L<"insert">.
+
+=cut
+
+sub table { 'cust_credit'; }
+
+=item insert
+
+Adds this credit to the database ("Posts" the credit). If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $cust_main = qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+ my $old_balance = $cust_main->balance;
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error inserting $self: $error";
+ }
+
+ #false laziness w/ cust_credit::insert
+ if ( $unsuspendauto && $old_balance && $cust_main->balance <= 0 ) {
+ my @errors = $cust_main->unsuspend;
+ #return
+ # side-fx with nested transactions? upstack rolls back?
+ warn "WARNING:Errors unsuspending customer ". $cust_main->custnum. ": ".
+ join(' / ', @errors)
+ if @errors;
+ }
+ #eslaf
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item delete
+
+Currently unimplemented.
+
+=cut
+
+sub delete {
+ my $self = shift;
+ return "Can't delete closed credit" if $self->closed =~ /^Y/i;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $cust_credit_bill ( $self->cust_credit_bill ) {
+ my $error = $cust_credit_bill->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ my $error = $self->SUPER::delete(@_);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ if ( $conf->config('deletecredits') ne '' ) {
+
+ my $cust_main = qsearchs('cust_main',{ 'custnum' => $self->custnum });
+
+ my $error = send_email(
+ 'from' => $conf->config('invoice_from'), #??? well as good as any
+ 'to' => $conf->config('deletecredits'),
+ 'subject' => 'FREESIDE NOTIFICATION: Credit deleted',
+ 'body' => [
+ "This is an automatic message from your Freeside installation\n",
+ "informing you that the following credit has been deleted:\n",
+ "\n",
+ 'crednum: '. $self->crednum. "\n",
+ 'custnum: '. $self->custnum.
+ " (". $cust_main->last. ", ". $cust_main->first. ")\n",
+ 'amount: $'. sprintf("%.2f", $self->amount). "\n",
+ 'date: '. time2str("%a %b %e %T %Y", $self->_date). "\n",
+ 'reason: '. $self->reason. "\n",
+ ],
+ );
+
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't send credit deletion notification: $error";
+ }
+
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item replace OLD_RECORD
+
+Credits may not be modified; there would then be no record the credit was ever
+posted.
+
+=cut
+
+sub replace {
+ #return "Can't modify credit!"
+ my $self = shift;
+ return "Can't modify closed credit" if $self->closed =~ /^Y/i;
+ $self->SUPER::replace(@_);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid credit. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('crednum')
+ || $self->ut_number('custnum')
+ || $self->ut_numbern('_date')
+ || $self->ut_money('amount')
+ || $self->ut_textn('reason')
+ || $self->ut_enum('closed', [ '', 'Y' ])
+ ;
+ return $error if $error;
+
+ return "amount must be > 0 " if $self->amount <= 0;
+
+ return "Unknown customer"
+ unless qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+
+ $self->_date(time) unless $self->_date;
+
+ $self->otaker(getotaker);
+
+ $self->SUPER::check;
+}
+
+=item cust_refund
+
+Depreciated. See the cust_credit_refund method.
+
+#Returns all refunds (see L<FS::cust_refund>) for this credit.
+
+=cut
+
+sub cust_refund {
+ use Carp;
+ croak "FS::cust_credit->cust_pay depreciated; see ".
+ "FS::cust_credit->cust_credit_refund";
+ #my $self = shift;
+ #sort { $a->_date <=> $b->_date }
+ # qsearch( 'cust_refund', { 'crednum' => $self->crednum } )
+ #;
+}
+
+=item cust_credit_refund
+
+Returns all refund applications (see L<FS::cust_credit_refund>) for this credit.
+
+=cut
+
+sub cust_credit_refund {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_credit_refund', { 'crednum' => $self->crednum } )
+ ;
+}
+
+=item cust_credit_bill
+
+Returns all application to invoices (see L<FS::cust_credit_bill>) for this
+credit.
+
+=cut
+
+sub cust_credit_bill {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_credit_bill', { 'crednum' => $self->crednum } )
+ ;
+}
+
+=item credited
+
+Returns the amount of this credit that is still outstanding; which is
+amount minus all refund applications (see L<FS::cust_credit_refund>) and
+applications to invoices (see L<FS::cust_credit_bill>).
+
+=cut
+
+sub credited {
+ my $self = shift;
+ my $amount = $self->amount;
+ $amount -= $_->amount foreach ( $self->cust_credit_refund );
+ $amount -= $_->amount foreach ( $self->cust_credit_bill );
+ sprintf( "%.2f", $amount );
+}
+
+=item cust_main
+
+Returns the customer (see L<FS::cust_main>) for this credit.
+
+=cut
+
+sub cust_main {
+ my $self = shift;
+ qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+}
+
+
+=back
+
+=head1 BUGS
+
+The delete method. The replace method.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_credit_refund>, L<FS::cust_refund>,
+L<FS::cust_credit_bill> L<FS::cust_bill>, schema.html from the base
+documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_credit_bill.pm b/FS/FS/cust_credit_bill.pm
new file mode 100644
index 0000000..bd76c2e
--- /dev/null
+++ b/FS/FS/cust_credit_bill.pm
@@ -0,0 +1,192 @@
+package FS::cust_credit_bill;
+
+use strict;
+use vars qw( @ISA $conf );
+use FS::UID qw( getotaker );
+use FS::Record qw( qsearch qsearchs );
+use FS::cust_main;
+#use FS::cust_refund;
+use FS::cust_credit;
+use FS::cust_bill;
+
+@ISA = qw( FS::Record );
+
+#ask FS::UID to run this stuff for us later
+FS::UID->install_callback( sub {
+ $conf = new FS::Conf;
+} );
+
+=head1 NAME
+
+FS::cust_credit_bill - Object methods for cust_credit_bill records
+
+=head1 SYNOPSIS
+
+ use FS::cust_credit_bill;
+
+ $record = new FS::cust_credit_bill \%hash;
+ $record = new FS::cust_credit_bill { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_credit_bill object represents application of a credit (see
+L<FS::cust_credit>) to an invoice (see L<FS::cust_bill>). FS::cust_credit
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item creditbillnum - primary key
+
+=item crednum - credit being applied
+
+=item invnum - invoice to which credit is applied (see L<FS::cust_bill>)
+
+=item amount - amount of the credit applied
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new cust_credit_bill. To add the cust_credit_bill to the database,
+see L<"insert">.
+
+=cut
+
+sub table { 'cust_credit_bill'; }
+
+=item insert
+
+Adds this cust_credit_bill to the database ("Posts" all or part of a credit).
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my $error = $self->SUPER::insert(@_);
+ return $error if $error;
+
+ if ( $conf->exists('invoice_send_receipts') ) {
+ my $send_error = $self->cust_bill->send;
+ warn "Error sending receipt: $send_error\n" if $send_error;
+ }
+
+ '';
+}
+
+=item delete
+
+Currently unimplemented.
+
+=cut
+
+sub delete {
+ my $self = shift;
+ return "Can't delete application for closed credit"
+ if $self->cust_credit->closed =~ /^Y/i;
+ $self->SUPER::delete(@_);
+}
+
+=item replace OLD_RECORD
+
+Application of credits may not be modified.
+
+=cut
+
+sub replace {
+ return "Can't modify application of credit!"
+}
+
+=item check
+
+Checks all fields to make sure this is a valid credit application. If there
+is an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('creditbillnum')
+ || $self->ut_number('crednum')
+ || $self->ut_number('invnum')
+ || $self->ut_numbern('_date')
+ || $self->ut_money('amount')
+ ;
+ return $error if $error;
+
+ return "amount must be > 0" if $self->amount <= 0;
+
+ return "Unknown credit"
+ unless my $cust_credit =
+ qsearchs( 'cust_credit', { 'crednum' => $self->crednum } );
+
+ return "Unknown invoice"
+ unless my $cust_bill =
+ qsearchs( 'cust_bill', { 'invnum' => $self->invnum } );
+
+ $self->_date(time) unless $self->_date;
+
+ return "Cannot apply more than remaining value of credit"
+ unless $self->amount <= $cust_credit->credited;
+
+ return "Cannot apply more than remaining value of invoice"
+ unless $self->amount <= $cust_bill->owed;
+
+ $self->SUPER::check;
+}
+
+=item sub cust_credit
+
+Returns the credit (see L<FS::cust_credit>)
+
+=cut
+
+sub cust_credit {
+ my $self = shift;
+ qsearchs( 'cust_credit', { 'crednum' => $self->crednum } );
+}
+
+=item cust_bill
+
+Returns the invoice (see L<FS::cust_bill>)
+
+=cut
+
+sub cust_bill {
+ my $self = shift;
+ qsearchs( 'cust_bill', { 'invnum' => $self->invnum } );
+}
+
+=back
+
+=head1 BUGS
+
+The delete method.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_refund>, L<FS::cust_bill>, L<FS::cust_credit>,
+schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_credit_refund.pm b/FS/FS/cust_credit_refund.pm
new file mode 100644
index 0000000..d0deae2
--- /dev/null
+++ b/FS/FS/cust_credit_refund.pm
@@ -0,0 +1,205 @@
+package FS::cust_credit_refund;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs dbh );
+#use FS::UID qw(getotaker);
+use FS::cust_credit;
+use FS::cust_refund;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::cust_credit_refund - Object methods for cust_bill_pay records
+
+=head1 SYNOPSIS
+
+ use FS::cust_credit_refund;
+
+ $record = new FS::cust_credit_refund \%hash;
+ $record = new FS::cust_credit_refund { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_credit_refund represents the application of a refund to a specific
+credit. FS::cust_credit_refund inherits from FS::Record. The following fields
+are currently supported:
+
+=over 4
+
+=item creditrefundnum - primary key (assigned automatically)
+
+=item crednum - Credit (see L<FS::cust_credit>)
+
+=item refundnum - Refund (see L<FS::cust_refund>)
+
+=item amount - Amount of the refund to apply to the specific credit.
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'cust_credit_refund'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->check;
+ return $error if $error;
+
+ $error = $self->SUPER::insert;
+
+ my $cust_refund =
+ qsearchs('cust_refund', { 'refundnum' => $self->refundnum } )
+ or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "unknown cust_refund.refundnum: ". $self->refundnum
+ };
+
+ my $refund_total = 0;
+ $refund_total += $_ foreach map { $_->amount }
+ qsearch('cust_credit_refund', { 'refundnum' => $self->refundnum } );
+
+ if ( $refund_total > $cust_refund->refund ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "total cust_credit_refund.amount $refund_total for refundnum ".
+ $self->refundnum.
+ " greater than cust_refund.refund ". $cust_refund->refund;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+}
+
+=item delete
+
+Currently unimplemented (accounting reasons).
+
+=cut
+
+sub delete {
+ return "Can't (yet?) delete cust_credit_refund records!";
+}
+
+=item replace OLD_RECORD
+
+Currently unimplemented (accounting reasons).
+
+=cut
+
+sub replace {
+ return "Can't (yet?) modify cust_credit_refund records!";
+}
+
+=item check
+
+Checks all fields to make sure this is a valid payment. If there is an error,
+returns the error, otherwise returns false. Called by the insert method.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('creditrefundnum')
+ || $self->ut_number('crednum')
+ || $self->ut_number('refundnum')
+ || $self->ut_money('amount')
+ || $self->ut_numbern('_date')
+ ;
+ return $error if $error;
+
+ return "amount must be > 0" if $self->amount <= 0;
+
+ $self->_date(time) unless $self->_date;
+
+ return "unknown cust_credit.crednum: ". $self->crednum
+ unless qsearchs( 'cust_credit', { 'crednum' => $self->crednum } );
+
+ $self->SUPER::check;
+}
+
+=item cust_refund
+
+Returns the refund (see L<FS::cust_refund>)
+
+=cut
+
+sub cust_refund {
+ my $self = shift;
+ qsearchs( 'cust_refund', { 'refundnum' => $self->refundnum } );
+}
+
+=item cust_credit
+
+Returns the credit (see L<FS::cust_credit>)
+
+=cut
+
+sub cust_credit {
+ my $self = shift;
+ qsearchs( 'cust_credit', { 'crednum' => $self->crednum } );
+}
+
+=back
+
+=head1 VERSION
+
+$Id: cust_credit_refund.pm,v 1.10 2003-08-05 00:20:41 khoff Exp $
+
+=head1 BUGS
+
+Delete and replace methods.
+
+the checks for over-applied refunds could be better done like the ones in
+cust_bill_credit
+
+=head1 SEE ALSO
+
+L<FS::cust_credit>, L<FS::cust_refund>, L<FS::Record>, schema.html from the
+base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
new file mode 100644
index 0000000..07f0a34
--- /dev/null
+++ b/FS/FS/cust_main.pm
@@ -0,0 +1,3033 @@
+package FS::cust_main;
+
+use strict;
+use vars qw( @ISA $conf $DEBUG $import );
+use vars qw( $realtime_bop_decline_quiet ); #ugh
+use Safe;
+use Carp;
+BEGIN {
+ eval "use Time::Local;";
+ die "Time::Local minimum version 1.05 required with Perl versions before 5.6"
+ if $] < 5.006 && !defined($Time::Local::VERSION);
+ eval "use Time::Local qw(timelocal timelocal_nocheck);";
+}
+use Date::Format;
+#use Date::Manip;
+use Business::CreditCard;
+use FS::UID qw( getotaker dbh );
+use FS::Record qw( qsearchs qsearch dbdef );
+use FS::Misc qw( send_email );
+use FS::cust_pkg;
+use FS::cust_bill;
+use FS::cust_bill_pkg;
+use FS::cust_pay;
+use FS::cust_credit;
+use FS::cust_refund;
+use FS::part_referral;
+use FS::cust_main_county;
+use FS::agent;
+use FS::cust_main_invoice;
+use FS::cust_credit_bill;
+use FS::cust_bill_pay;
+use FS::prepay_credit;
+use FS::queue;
+use FS::part_pkg;
+use FS::part_bill_event;
+use FS::cust_bill_event;
+use FS::cust_tax_exempt;
+use FS::type_pkgs;
+use FS::Msgcat qw(gettext);
+
+@ISA = qw( FS::Record );
+
+$realtime_bop_decline_quiet = 0;
+
+$DEBUG = 0;
+#$DEBUG = 1;
+
+$import = 0;
+
+#ask FS::UID to run this stuff for us later
+#$FS::UID::callback{'FS::cust_main'} = sub {
+install_callback FS::UID sub {
+ $conf = new FS::Conf;
+ #yes, need it for stuff below (prolly should be cached)
+};
+
+sub _cache {
+ my $self = shift;
+ my ( $hashref, $cache ) = @_;
+ if ( exists $hashref->{'pkgnum'} ) {
+# #@{ $self->{'_pkgnum'} } = ();
+ my $subcache = $cache->subcache( 'pkgnum', 'cust_pkg', $hashref->{custnum});
+ $self->{'_pkgnum'} = $subcache;
+ #push @{ $self->{'_pkgnum'} },
+ FS::cust_pkg->new_or_cached($hashref, $subcache) if $hashref->{pkgnum};
+ }
+}
+
+=head1 NAME
+
+FS::cust_main - Object methods for cust_main records
+
+=head1 SYNOPSIS
+
+ use FS::cust_main;
+
+ $record = new FS::cust_main \%hash;
+ $record = new FS::cust_main { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ @cust_pkg = $record->all_pkgs;
+
+ @cust_pkg = $record->ncancelled_pkgs;
+
+ @cust_pkg = $record->suspended_pkgs;
+
+ $error = $record->bill;
+ $error = $record->bill %options;
+ $error = $record->bill 'time' => $time;
+
+ $error = $record->collect;
+ $error = $record->collect %options;
+ $error = $record->collect 'invoice_time' => $time,
+ 'batch_card' => 'yes',
+ 'report_badcard' => 'yes',
+ ;
+
+=head1 DESCRIPTION
+
+An FS::cust_main object represents a customer. FS::cust_main inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item custnum - primary key (assigned automatically for new customers)
+
+=item agentnum - agent (see L<FS::agent>)
+
+=item refnum - Advertising source (see L<FS::part_referral>)
+
+=item first - name
+
+=item last - name
+
+=item ss - social security number (optional)
+
+=item company - (optional)
+
+=item address1
+
+=item address2 - (optional)
+
+=item city
+
+=item county - (optional, see L<FS::cust_main_county>)
+
+=item state - (see L<FS::cust_main_county>)
+
+=item zip
+
+=item country - (see L<FS::cust_main_county>)
+
+=item daytime - phone (optional)
+
+=item night - phone (optional)
+
+=item fax - phone (optional)
+
+=item ship_first - name
+
+=item ship_last - name
+
+=item ship_company - (optional)
+
+=item ship_address1
+
+=item ship_address2 - (optional)
+
+=item ship_city
+
+=item ship_county - (optional, see L<FS::cust_main_county>)
+
+=item ship_state - (see L<FS::cust_main_county>)
+
+=item ship_zip
+
+=item ship_country - (see L<FS::cust_main_county>)
+
+=item ship_daytime - phone (optional)
+
+=item ship_night - phone (optional)
+
+=item ship_fax - phone (optional)
+
+=item payby - I<CARD> (credit card - automatic), I<DCRD> (credit card - on-demand), I<CHEK> (electronic check - automatic), I<DCHK> (electronic check - on-demand), I<LECB> (Phone bill billing), I<BILL> (billing), I<COMP> (free), or I<PREPAY> (special billing type: applies a credit - see L<FS::prepay_credit> and sets billing type to I<BILL>)
+
+=item payinfo - card number, P.O., comp issuer (4-8 lowercase alphanumerics; think username) or prepayment identifier (see L<FS::prepay_credit>)
+
+=item paycvv - Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit number on the back (or front, for American Express) of the credit card
+
+=item paydate - expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy
+
+=item payname - name on card or billing name
+
+=item tax - tax exempt, empty or `Y'
+
+=item otaker - order taker (assigned automatically, see L<FS::UID>)
+
+=item comments - comments (optional)
+
+=item referral_custnum - referring customer number
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new customer. To add the customer to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'cust_main'; }
+
+=item insert [ CUST_PKG_HASHREF [ , INVOICING_LIST_ARYREF ] [ , OPTION => VALUE ... ] ]
+
+Adds this customer to the database. If there is an error, returns the error,
+otherwise returns false.
+
+CUST_PKG_HASHREF: If you pass a Tie::RefHash data structure to the insert
+method containing FS::cust_pkg and FS::svc_I<tablename> objects, all records
+are inserted atomicly, or the transaction is rolled back. Passing an empty
+hash reference is equivalent to not supplying this parameter. There should be
+a better explanation of this, but until then, here's an example:
+
+ use Tie::RefHash;
+ tie %hash, 'Tie::RefHash'; #this part is important
+ %hash = (
+ $cust_pkg => [ $svc_acct ],
+ ...
+ );
+ $cust_main->insert( \%hash );
+
+INVOICING_LIST_ARYREF: If you pass an arrarref to the insert method, it will
+be set as the invoicing list (see L<"invoicing_list">). Errors return as
+expected and rollback the entire transaction; it is not necessary to call
+check_invoicing_list first. The invoicing_list is set after the records in the
+CUST_PKG_HASHREF above are inserted, so it is now possible to set an
+invoicing_list destination to the newly-created svc_acct. Here's an example:
+
+ $cust_main->insert( {}, [ $email, 'POST' ] );
+
+Currently available options are: I<depend_jobnum> and I<noexport>.
+
+If I<depend_jobnum> is set, all provisioning jobs will have a dependancy
+on the supplied jobnum (they will not run until the specific job completes).
+This can be used to defer provisioning until some action completes (such
+as running the customer's credit card sucessfully).
+
+The I<noexport> option is deprecated. If I<noexport> is set true, no
+provisioning jobs (exports) are scheduled. (You can schedule them later with
+the B<reexport> method.)
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my $cust_pkgs = @_ ? shift : {};
+ my $invoicing_list = @_ ? shift : '';
+ my %options = @_;
+ warn "FS::cust_main::insert called with options ".
+ join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
+ if $DEBUG;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $amount = 0;
+ my $seconds = 0;
+ if ( $self->payby eq 'PREPAY' ) {
+ $self->payby('BILL');
+ my $prepay_credit = qsearchs(
+ 'prepay_credit',
+ { 'identifier' => $self->payinfo },
+ '',
+ 'FOR UPDATE'
+ );
+ warn "WARNING: can't find pre-found prepay_credit: ". $self->payinfo
+ unless $prepay_credit;
+ $amount = $prepay_credit->amount;
+ $seconds = $prepay_credit->seconds;
+ my $error = $prepay_credit->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "removing prepay_credit (transaction rolled back): $error";
+ }
+ }
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ #return "inserting cust_main record (transaction rolled back): $error";
+ return $error;
+ }
+
+ # invoicing list
+ if ( $invoicing_list ) {
+ $error = $self->check_invoicing_list( $invoicing_list );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "checking invoicing_list (transaction rolled back): $error";
+ }
+ $self->invoicing_list( $invoicing_list );
+ }
+
+ # packages
+ $error = $self->order_pkgs($cust_pkgs, \$seconds, %options);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ if ( $seconds ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "No svc_acct record to apply pre-paid time";
+ }
+
+ if ( $amount ) {
+ my $cust_credit = new FS::cust_credit {
+ 'custnum' => $self->custnum,
+ 'amount' => $amount,
+ };
+ $error = $cust_credit->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "inserting credit (transaction rolled back): $error";
+ }
+ }
+
+ $error = $self->queue_fuzzyfiles_update;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "updating fuzzy search cache: $error";
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item order_pkgs HASHREF, [ SECONDSREF, [ , OPTION => VALUE ... ] ]
+
+Like the insert method on an existing record, this method orders a package
+and included services atomicaly. Pass a Tie::RefHash data structure to this
+method containing FS::cust_pkg and FS::svc_I<tablename> objects. There should
+be a better explanation of this, but until then, here's an example:
+
+ use Tie::RefHash;
+ tie %hash, 'Tie::RefHash'; #this part is important
+ %hash = (
+ $cust_pkg => [ $svc_acct ],
+ ...
+ );
+ $cust_main->order_pkgs( \%hash, \'0', 'noexport'=>1 );
+
+Currently available options are: I<depend_jobnum> and I<noexport>.
+
+If I<depend_jobnum> is set, all provisioning jobs will have a dependancy
+on the supplied jobnum (they will not run until the specific job completes).
+This can be used to defer provisioning until some action completes (such
+as running the customer's credit card sucessfully).
+
+The I<noexport> option is deprecated. If I<noexport> is set true, no
+provisioning jobs (exports) are scheduled. (You can schedule them later with
+the B<reexport> method for each cust_pkg object. Using the B<reexport> method
+on the cust_main object is not recommended, as existing services will also be
+reexported.)
+
+=cut
+
+sub order_pkgs {
+ my $self = shift;
+ my $cust_pkgs = shift;
+ my $seconds = shift;
+ my %options = @_;
+ my %svc_options = ();
+ $svc_options{'depend_jobnum'} = $options{'depend_jobnum'}
+ if exists $options{'depend_jobnum'};
+ warn "FS::cust_main::order_pkgs called with options ".
+ join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
+ if $DEBUG;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ local $FS::svc_Common::noexport_hack = 1 if $options{'noexport'};
+
+ foreach my $cust_pkg ( keys %$cust_pkgs ) {
+ $cust_pkg->custnum( $self->custnum );
+ my $error = $cust_pkg->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "inserting cust_pkg (transaction rolled back): $error";
+ }
+ foreach my $svc_something ( @{$cust_pkgs->{$cust_pkg}} ) {
+ $svc_something->pkgnum( $cust_pkg->pkgnum );
+ if ( $seconds && $$seconds && $svc_something->isa('FS::svc_acct') ) {
+ $svc_something->seconds( $svc_something->seconds + $$seconds );
+ $$seconds = 0;
+ }
+ $error = $svc_something->insert(%svc_options);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ #return "inserting svc_ (transaction rolled back): $error";
+ return $error;
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ ''; #no error
+}
+
+=item reexport
+
+This method is deprecated. See the I<depend_jobnum> option to the insert and
+order_pkgs methods for a better way to defer provisioning.
+
+Re-schedules all exports by calling the B<reexport> method of all associated
+packages (see L<FS::cust_pkg>). If there is an error, returns the error;
+otherwise returns false.
+
+=cut
+
+sub reexport {
+ my $self = shift;
+
+ carp "warning: FS::cust_main::reexport is deprectated; ".
+ "use the depend_jobnum option to insert or order_pkgs to delay export";
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $cust_pkg ( $self->ncancelled_pkgs ) {
+ my $error = $cust_pkg->reexport;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item delete NEW_CUSTNUM
+
+This deletes the customer. If there is an error, returns the error, otherwise
+returns false.
+
+This will completely remove all traces of the customer record. This is not
+what you want when a customer cancels service; for that, cancel all of the
+customer's packages (see L</cancel>).
+
+If the customer has any uncancelled packages, you need to pass a new (valid)
+customer number for those packages to be transferred to. Cancelled packages
+will be deleted. Did I mention that this is NOT what you want when a customer
+cancels service and that you really should be looking see L<FS::cust_pkg/cancel>?
+
+You can't delete a customer with invoices (see L<FS::cust_bill>),
+or credits (see L<FS::cust_credit>), payments (see L<FS::cust_pay>) or
+refunds (see L<FS::cust_refund>).
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ if ( $self->cust_bill ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Can't delete a customer with invoices";
+ }
+ if ( $self->cust_credit ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Can't delete a customer with credits";
+ }
+ if ( $self->cust_pay ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Can't delete a customer with payments";
+ }
+ if ( $self->cust_refund ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Can't delete a customer with refunds";
+ }
+
+ my @cust_pkg = $self->ncancelled_pkgs;
+ if ( @cust_pkg ) {
+ my $new_custnum = shift;
+ unless ( qsearchs( 'cust_main', { 'custnum' => $new_custnum } ) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Invalid new customer number: $new_custnum";
+ }
+ foreach my $cust_pkg ( @cust_pkg ) {
+ my %hash = $cust_pkg->hash;
+ $hash{'custnum'} = $new_custnum;
+ my $new_cust_pkg = new FS::cust_pkg ( \%hash );
+ my $error = $new_cust_pkg->replace($cust_pkg);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+ my @cancelled_cust_pkg = $self->all_pkgs;
+ foreach my $cust_pkg ( @cancelled_cust_pkg ) {
+ my $error = $cust_pkg->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ foreach my $cust_main_invoice ( #(email invoice destinations, not invoices)
+ qsearch( 'cust_main_invoice', { 'custnum' => $self->custnum } )
+ ) {
+ my $error = $cust_main_invoice->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ my $error = $self->SUPER::delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item replace OLD_RECORD [ INVOICING_LIST_ARYREF ]
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+INVOICING_LIST_ARYREF: If you pass an arrarref to the insert method, it will
+be set as the invoicing list (see L<"invoicing_list">). Errors return as
+expected and rollback the entire transaction; it is not necessary to call
+check_invoicing_list first. Here's an example:
+
+ $new_cust_main->replace( $old_cust_main, [ $email, 'POST' ] );
+
+=cut
+
+sub replace {
+ my $self = shift;
+ my $old = shift;
+ my @param = @_;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ if ( $self->payby eq 'COMP' && $self->payby ne $old->payby
+ && $conf->config('users-allow_comp') ) {
+ return "You are not permitted to create complimentary accounts."
+ unless grep { $_ eq getotaker } $conf->config('users-allow_comp');
+ }
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::replace($old);
+
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ if ( @param ) { # INVOICING_LIST_ARYREF
+ my $invoicing_list = shift @param;
+ $error = $self->check_invoicing_list( $invoicing_list );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ $self->invoicing_list( $invoicing_list );
+ }
+
+ if ( $self->payby =~ /^(CARD|CHEK|LECB)$/ &&
+ grep { $self->get($_) ne $old->get($_) } qw(payinfo paydate payname) ) {
+ # card/check/lec info has changed, want to retry realtime_ invoice events
+ my $error = $self->retry_realtime;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $error = $self->queue_fuzzyfiles_update;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "updating fuzzy search cache: $error";
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item queue_fuzzyfiles_update
+
+Used by insert & replace to update the fuzzy search cache
+
+=cut
+
+sub queue_fuzzyfiles_update {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $queue = new FS::queue { 'job' => 'FS::cust_main::append_fuzzyfiles' };
+ my $error = $queue->insert($self->getfield('last'), $self->company);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "queueing job (transaction rolled back): $error";
+ }
+
+ if ( defined $self->dbdef_table->column('ship_last') && $self->ship_last ) {
+ $queue = new FS::queue { 'job' => 'FS::cust_main::append_fuzzyfiles' };
+ $error = $queue->insert($self->getfield('ship_last'), $self->ship_company);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "queueing job (transaction rolled back): $error";
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item check
+
+Checks all fields to make sure this is a valid customer record. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and repalce methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ #warn "BEFORE: \n". $self->_dump;
+
+ my $error =
+ $self->ut_numbern('custnum')
+ || $self->ut_number('agentnum')
+ || $self->ut_number('refnum')
+ || $self->ut_name('last')
+ || $self->ut_name('first')
+ || $self->ut_textn('company')
+ || $self->ut_text('address1')
+ || $self->ut_textn('address2')
+ || $self->ut_text('city')
+ || $self->ut_textn('county')
+ || $self->ut_textn('state')
+ || $self->ut_country('country')
+ || $self->ut_anything('comments')
+ || $self->ut_numbern('referral_custnum')
+ ;
+ #barf. need message catalogs. i18n. etc.
+ $error .= "Please select an advertising source."
+ if $error =~ /^Illegal or empty \(numeric\) refnum: /;
+ return $error if $error;
+
+ return "Unknown agent"
+ unless qsearchs( 'agent', { 'agentnum' => $self->agentnum } );
+
+ return "Unknown refnum"
+ unless qsearchs( 'part_referral', { 'refnum' => $self->refnum } );
+
+ return "Unknown referring custnum ". $self->referral_custnum
+ unless ! $self->referral_custnum
+ || qsearchs( 'cust_main', { 'custnum' => $self->referral_custnum } );
+
+ if ( $self->ss eq '' ) {
+ $self->ss('');
+ } else {
+ my $ss = $self->ss;
+ $ss =~ s/\D//g;
+ $ss =~ /^(\d{3})(\d{2})(\d{4})$/
+ or return "Illegal social security number: ". $self->ss;
+ $self->ss("$1-$2-$3");
+ }
+
+
+# bad idea to disable, causes billing to fail because of no tax rates later
+# unless ( $import ) {
+ unless ( qsearch('cust_main_county', {
+ 'country' => $self->country,
+ 'state' => '',
+ } ) ) {
+ return "Unknown state/county/country: ".
+ $self->state. "/". $self->county. "/". $self->country
+ unless qsearch('cust_main_county',{
+ 'state' => $self->state,
+ 'county' => $self->county,
+ 'country' => $self->country,
+ } );
+ }
+# }
+
+ $error =
+ $self->ut_phonen('daytime', $self->country)
+ || $self->ut_phonen('night', $self->country)
+ || $self->ut_phonen('fax', $self->country)
+ || $self->ut_zip('zip', $self->country)
+ ;
+ return $error if $error;
+
+ my @addfields = qw(
+ last first company address1 address2 city county state zip
+ country daytime night fax
+ );
+
+ if ( defined $self->dbdef_table->column('ship_last') ) {
+ if ( scalar ( grep { $self->getfield($_) ne $self->getfield("ship_$_") }
+ @addfields )
+ && scalar ( grep { $self->getfield("ship_$_") ne '' } @addfields )
+ )
+ {
+ my $error =
+ $self->ut_name('ship_last')
+ || $self->ut_name('ship_first')
+ || $self->ut_textn('ship_company')
+ || $self->ut_text('ship_address1')
+ || $self->ut_textn('ship_address2')
+ || $self->ut_text('ship_city')
+ || $self->ut_textn('ship_county')
+ || $self->ut_textn('ship_state')
+ || $self->ut_country('ship_country')
+ ;
+ return $error if $error;
+
+ #false laziness with above
+ unless ( qsearchs('cust_main_county', {
+ 'country' => $self->ship_country,
+ 'state' => '',
+ } ) ) {
+ return "Unknown ship_state/ship_county/ship_country: ".
+ $self->ship_state. "/". $self->ship_county. "/". $self->ship_country
+ unless qsearchs('cust_main_county',{
+ 'state' => $self->ship_state,
+ 'county' => $self->ship_county,
+ 'country' => $self->ship_country,
+ } );
+ }
+ #eofalse
+
+ $error =
+ $self->ut_phonen('ship_daytime', $self->ship_country)
+ || $self->ut_phonen('ship_night', $self->ship_country)
+ || $self->ut_phonen('ship_fax', $self->ship_country)
+ || $self->ut_zip('ship_zip', $self->ship_country)
+ ;
+ return $error if $error;
+
+ } else { # ship_ info eq billing info, so don't store dup info in database
+ $self->setfield("ship_$_", '')
+ foreach qw( last first company address1 address2 city county state zip
+ country daytime night fax );
+ }
+ }
+
+ $self->payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP|PREPAY)$/
+ or return "Illegal payby: ". $self->payby;
+ $self->payby($1);
+
+ if ( $self->payby eq 'CARD' || $self->payby eq 'DCRD' ) {
+
+ my $payinfo = $self->payinfo;
+ $payinfo =~ s/\D//g;
+ $payinfo =~ /^(\d{13,16})$/
+ or return gettext('invalid_card'); # . ": ". $self->payinfo;
+ $payinfo = $1;
+ $self->payinfo($payinfo);
+ validate($payinfo)
+ or return gettext('invalid_card'); # . ": ". $self->payinfo;
+ return gettext('unknown_card_type')
+ if cardtype($self->payinfo) eq "Unknown";
+ if ( defined $self->dbdef_table->column('paycvv') ) {
+ if ( length($self->paycvv) ) {
+ if ( cardtype($self->payinfo) eq 'American Express card' ) {
+ $self->paycvv =~ /^(\d{4})$/
+ or return "CVV2 (CID) for American Express cards is four digits.";
+ $self->paycvv($1);
+ } else {
+ $self->paycvv =~ /^(\d{3})$/
+ or return "CVV2 (CVC2/CID) is three digits.";
+ $self->paycvv($1);
+ }
+ } else {
+ $self->paycvv('');
+ }
+ }
+
+ } elsif ( $self->payby eq 'CHEK' || $self->payby eq 'DCHK' ) {
+
+ my $payinfo = $self->payinfo;
+ $payinfo =~ s/[^\d\@]//g;
+ $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba';
+ $payinfo = "$1\@$2";
+ $self->payinfo($payinfo);
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
+
+ } elsif ( $self->payby eq 'LECB' ) {
+
+ my $payinfo = $self->payinfo;
+ $payinfo =~ s/\D//g;
+ $payinfo =~ /^1?(\d{10})$/ or return 'invalid btn billing telephone number';
+ $payinfo = $1;
+ $self->payinfo($payinfo);
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
+
+ } elsif ( $self->payby eq 'BILL' ) {
+
+ $error = $self->ut_textn('payinfo');
+ return "Illegal P.O. number: ". $self->payinfo if $error;
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
+
+ } elsif ( $self->payby eq 'COMP' ) {
+
+ if ( !$self->custnum && $conf->config('users-allow_comp') ) {
+ return "You are not permitted to create complimentary accounts."
+ unless grep { $_ eq getotaker } $conf->config('users-allow_comp');
+ }
+
+ $error = $self->ut_textn('payinfo');
+ return "Illegal comp account issuer: ". $self->payinfo if $error;
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
+
+ } elsif ( $self->payby eq 'PREPAY' ) {
+
+ my $payinfo = $self->payinfo;
+ $payinfo =~ s/\W//g; #anything else would just confuse things
+ $self->payinfo($payinfo);
+ $error = $self->ut_alpha('payinfo');
+ return "Illegal prepayment identifier: ". $self->payinfo if $error;
+ return "Unknown prepayment identifier"
+ unless qsearchs('prepay_credit', { 'identifier' => $self->payinfo } );
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
+
+ }
+
+ if ( $self->paydate eq '' || $self->paydate eq '-' ) {
+ return "Expriation date required"
+ unless $self->payby =~ /^(BILL|PREPAY|CHEK|LECB)$/;
+ $self->paydate('');
+ } else {
+ my( $m, $y );
+ if ( $self->paydate =~ /^(\d{1,2})[\/\-](\d{2}(\d{2})?)$/ ) {
+ ( $m, $y ) = ( $1, length($2) == 4 ? $2 : "20$2" );
+ } elsif ( $self->paydate =~ /^(20)?(\d{2})[\/\-](\d{1,2})[\/\-]\d+$/ ) {
+ ( $m, $y ) = ( $3, "20$2" );
+ } else {
+ return "Illegal expiration date: ". $self->paydate;
+ }
+ $self->paydate("$y-$m-01");
+ my($nowm,$nowy)=(localtime(time))[4,5]; $nowm++; $nowy+=1900;
+ return gettext('expired_card')
+ if !$import && ( $y<$nowy || ( $y==$nowy && $1<$nowm ) );
+ }
+
+ if ( $self->payname eq '' && $self->payby !~ /^(CHEK|DCHK)$/ &&
+ ( ! $conf->exists('require_cardname')
+ || $self->payby !~ /^(CARD|DCRD)$/ )
+ ) {
+ $self->payname( $self->first. " ". $self->getfield('last') );
+ } else {
+ $self->payname =~ /^([\w \,\.\-\']+)$/
+ or return gettext('illegal_name'). " payname: ". $self->payname;
+ $self->payname($1);
+ }
+
+ $self->tax =~ /^(Y?)$/ or return "Illegal tax: ". $self->tax;
+ $self->tax($1);
+
+ $self->otaker(getotaker) unless $self->otaker;
+
+ #warn "AFTER: \n". $self->_dump;
+
+ $self->SUPER::check;
+}
+
+=item all_pkgs
+
+Returns all packages (see L<FS::cust_pkg>) for this customer.
+
+=cut
+
+sub all_pkgs {
+ my $self = shift;
+ if ( $self->{'_pkgnum'} ) {
+ values %{ $self->{'_pkgnum'}->cache };
+ } else {
+ qsearch( 'cust_pkg', { 'custnum' => $self->custnum });
+ }
+}
+
+=item ncancelled_pkgs
+
+Returns all non-cancelled packages (see L<FS::cust_pkg>) for this customer.
+
+=cut
+
+sub ncancelled_pkgs {
+ my $self = shift;
+ if ( $self->{'_pkgnum'} ) {
+ grep { ! $_->getfield('cancel') } values %{ $self->{'_pkgnum'}->cache };
+ } else {
+ @{ [ # force list context
+ qsearch( 'cust_pkg', {
+ 'custnum' => $self->custnum,
+ 'cancel' => '',
+ }),
+ qsearch( 'cust_pkg', {
+ 'custnum' => $self->custnum,
+ 'cancel' => 0,
+ }),
+ ] };
+ }
+}
+
+=item suspended_pkgs
+
+Returns all suspended packages (see L<FS::cust_pkg>) for this customer.
+
+=cut
+
+sub suspended_pkgs {
+ my $self = shift;
+ grep { $_->susp } $self->ncancelled_pkgs;
+}
+
+=item unflagged_suspended_pkgs
+
+Returns all unflagged suspended packages (see L<FS::cust_pkg>) for this
+customer (thouse packages without the `manual_flag' set).
+
+=cut
+
+sub unflagged_suspended_pkgs {
+ my $self = shift;
+ return $self->suspended_pkgs
+ unless dbdef->table('cust_pkg')->column('manual_flag');
+ grep { ! $_->manual_flag } $self->suspended_pkgs;
+}
+
+=item unsuspended_pkgs
+
+Returns all unsuspended (and uncancelled) packages (see L<FS::cust_pkg>) for
+this customer.
+
+=cut
+
+sub unsuspended_pkgs {
+ my $self = shift;
+ grep { ! $_->susp } $self->ncancelled_pkgs;
+}
+
+=item unsuspend
+
+Unsuspends all unflagged suspended packages (see L</unflagged_suspended_pkgs>
+and L<FS::cust_pkg>) for this customer. Always returns a list: an empty list
+on success or a list of errors.
+
+=cut
+
+sub unsuspend {
+ my $self = shift;
+ grep { $_->unsuspend } $self->suspended_pkgs;
+}
+
+=item suspend
+
+Suspends all unsuspended packages (see L<FS::cust_pkg>) for this customer.
+Always returns a list: an empty list on success or a list of errors.
+
+=cut
+
+sub suspend {
+ my $self = shift;
+ grep { $_->suspend } $self->unsuspended_pkgs;
+}
+
+=item suspend_if_pkgpart PKGPART [ , PKGPART ... ]
+
+Suspends all unsuspended packages (see L<FS::cust_pkg>) matching the listed
+PKGPARTs (see L<FS::part_pkg>). Always returns a list: an empty list on
+success or a list of errors.
+
+=cut
+
+sub suspend_if_pkgpart {
+ my $self = shift;
+ my @pkgparts = @_;
+ grep { $_->suspend }
+ grep { my $pkgpart = $_->pkgpart; grep { $pkgpart eq $_ } @pkgparts }
+ $self->unsuspended_pkgs;
+}
+
+=item suspend_unless_pkgpart PKGPART [ , PKGPART ... ]
+
+Suspends all unsuspended packages (see L<FS::cust_pkg>) unless they match the
+listed PKGPARTs (see L<FS::part_pkg>). Always returns a list: an empty list
+on success or a list of errors.
+
+=cut
+
+sub suspend_unless_pkgpart {
+ my $self = shift;
+ my @pkgparts = @_;
+ grep { $_->suspend }
+ grep { my $pkgpart = $_->pkgpart; ! grep { $pkgpart eq $_ } @pkgparts }
+ $self->unsuspended_pkgs;
+}
+
+=item cancel [ OPTION => VALUE ... ]
+
+Cancels all uncancelled packages (see L<FS::cust_pkg>) for this customer.
+
+Available options are: I<quiet>
+
+I<quiet> can be set true to supress email cancellation notices.
+
+Always returns a list: an empty list on success or a list of errors.
+
+=cut
+
+sub cancel {
+ my $self = shift;
+ grep { $_ } map { $_->cancel(@_) } $self->ncancelled_pkgs;
+}
+
+=item agent
+
+Returns the agent (see L<FS::agent>) for this customer.
+
+=cut
+
+sub agent {
+ my $self = shift;
+ qsearchs( 'agent', { 'agentnum' => $self->agentnum } );
+}
+
+=item bill OPTIONS
+
+Generates invoices (see L<FS::cust_bill>) for this customer. Usually used in
+conjunction with the collect method.
+
+Options are passed as name-value pairs.
+
+Currently available options are:
+
+resetup - if set true, re-charges setup fees.
+
+time - bills the customer as if it were that time. Specified as a UNIX
+timestamp; see L<perlfunc/"time">). Also see L<Time::Local> and
+L<Date::Parse> for conversion functions. For example:
+
+ use Date::Parse;
+ ...
+ $cust_main->bill( 'time' => str2time('April 20th, 2001') );
+
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub bill {
+ my( $self, %options ) = @_;
+ my $time = $options{'time'} || time;
+
+ my $error;
+
+ #put below somehow?
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ $self->select_for_update; #mutex
+
+ # find the packages which are due for billing, find out how much they are
+ # & generate invoice database.
+
+ my( $total_setup, $total_recur ) = ( 0, 0 );
+ #my( $taxable_setup, $taxable_recur ) = ( 0, 0 );
+ my @cust_bill_pkg = ();
+ #my $tax = 0;##
+ #my $taxable_charged = 0;##
+ #my $charged = 0;##
+
+ my %tax;
+
+ foreach my $cust_pkg (
+ qsearch('cust_pkg', { 'custnum' => $self->custnum } )
+ ) {
+
+ #NO!! next if $cust_pkg->cancel;
+ next if $cust_pkg->getfield('cancel');
+
+ #? to avoid use of uninitialized value errors... ?
+ $cust_pkg->setfield('bill', '')
+ unless defined($cust_pkg->bill);
+
+ my $part_pkg = $cust_pkg->part_pkg;
+
+ #so we don't modify cust_pkg record unnecessarily
+ my $cust_pkg_mod_flag = 0;
+ my %hash = $cust_pkg->hash;
+ my $old_cust_pkg = new FS::cust_pkg \%hash;
+
+ my @details = ();
+
+ # bill setup
+ my $setup = 0;
+ if ( !$cust_pkg->setup || $options{'resetup'} ) {
+ my $setup_prog = $part_pkg->getfield('setup');
+ $setup_prog =~ /^(.*)$/ or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "Illegal setup for pkgpart ". $part_pkg->pkgpart.
+ ": $setup_prog";
+ };
+ $setup_prog = $1;
+ $setup_prog = '0' if $setup_prog =~ /^\s*$/;
+
+ #my $cpt = new Safe;
+ ##$cpt->permit(); #what is necessary?
+ #$cpt->share(qw( $cust_pkg )); #can $cpt now use $cust_pkg methods?
+ #$setup = $cpt->reval($setup_prog);
+ $setup = eval $setup_prog;
+ unless ( defined($setup) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Error eval-ing part_pkg->setup pkgpart ". $part_pkg->pkgpart.
+ "(expression $setup_prog): $@";
+ }
+ $cust_pkg->setfield('setup', $time) unless $cust_pkg->setup;
+ $cust_pkg_mod_flag=1;
+ }
+
+ #bill recurring fee
+ my $recur = 0;
+ my $sdate;
+ if ( $part_pkg->getfield('freq') ne '0' &&
+ ! $cust_pkg->getfield('susp') &&
+ ( $cust_pkg->getfield('bill') || 0 ) <= $time
+ ) {
+ my $recur_prog = $part_pkg->getfield('recur');
+ $recur_prog =~ /^(.*)$/ or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "Illegal recur for pkgpart ". $part_pkg->pkgpart.
+ ": $recur_prog";
+ };
+ $recur_prog = $1;
+ $recur_prog = '0' if $recur_prog =~ /^\s*$/;
+
+ # shared with $recur_prog
+ $sdate = $cust_pkg->bill || $cust_pkg->setup || $time;
+
+ #my $cpt = new Safe;
+ ##$cpt->permit(); #what is necessary?
+ #$cpt->share(qw( $cust_pkg )); #can $cpt now use $cust_pkg methods?
+ #$recur = $cpt->reval($recur_prog);
+ $recur = eval $recur_prog;
+ unless ( defined($recur) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Error eval-ing part_pkg->recur pkgpart ". $part_pkg->pkgpart.
+ "(expression $recur_prog): $@";
+ }
+ #change this bit to use Date::Manip? CAREFUL with timezones (see
+ # mailing list archive)
+ my ($sec,$min,$hour,$mday,$mon,$year) =
+ (localtime($sdate) )[0,1,2,3,4,5];
+
+ #pro-rating magic - if $recur_prog fiddles $sdate, want to use that
+ # only for figuring next bill date, nothing else, so, reset $sdate again
+ # here
+ $sdate = $cust_pkg->bill || $cust_pkg->setup || $time;
+ $cust_pkg->last_bill($sdate)
+ if $cust_pkg->dbdef_table->column('last_bill');
+
+ if ( $part_pkg->freq =~ /^\d+$/ ) {
+ $mon += $part_pkg->freq;
+ until ( $mon < 12 ) { $mon -= 12; $year++; }
+ } elsif ( $part_pkg->freq =~ /^(\d+)w$/ ) {
+ my $weeks = $1;
+ $mday += $weeks * 7;
+ } elsif ( $part_pkg->freq =~ /^(\d+)d$/ ) {
+ my $days = $1;
+ $mday += $days;
+ } else {
+ $dbh->rollback if $oldAutoCommit;
+ return "unparsable frequency: ". $part_pkg->freq;
+ }
+ $cust_pkg->setfield('bill',
+ timelocal_nocheck($sec,$min,$hour,$mday,$mon,$year));
+ $cust_pkg_mod_flag = 1;
+ }
+
+ warn "\$setup is undefined" unless defined($setup);
+ warn "\$recur is undefined" unless defined($recur);
+ warn "\$cust_pkg->bill is undefined" unless defined($cust_pkg->bill);
+
+ if ( $cust_pkg_mod_flag ) {
+ $error=$cust_pkg->replace($old_cust_pkg);
+ if ( $error ) { #just in case
+ $dbh->rollback if $oldAutoCommit;
+ return "Error modifying pkgnum ". $cust_pkg->pkgnum. ": $error";
+ }
+ $setup = sprintf( "%.2f", $setup );
+ $recur = sprintf( "%.2f", $recur );
+ if ( $setup < 0 && ! $conf->exists('allow_negative_charges') ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "negative setup $setup for pkgnum ". $cust_pkg->pkgnum;
+ }
+ if ( $recur < 0 && ! $conf->exists('allow_negative_charges') ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "negative recur $recur for pkgnum ". $cust_pkg->pkgnum;
+ }
+ if ( $setup != 0 || $recur != 0 ) {
+ my $cust_bill_pkg = new FS::cust_bill_pkg ({
+ 'pkgnum' => $cust_pkg->pkgnum,
+ 'setup' => $setup,
+ 'recur' => $recur,
+ 'sdate' => $sdate,
+ 'edate' => $cust_pkg->bill,
+ 'details' => \@details,
+ });
+ push @cust_bill_pkg, $cust_bill_pkg;
+ $total_setup += $setup;
+ $total_recur += $recur;
+
+ unless ( $self->tax =~ /Y/i || $self->payby eq 'COMP' ) {
+
+ my @taxes = qsearch( 'cust_main_county', {
+ 'state' => $self->state,
+ 'county' => $self->county,
+ 'country' => $self->country,
+ 'taxclass' => $part_pkg->taxclass,
+ } );
+ unless ( @taxes ) {
+ @taxes = qsearch( 'cust_main_county', {
+ 'state' => $self->state,
+ 'county' => $self->county,
+ 'country' => $self->country,
+ 'taxclass' => '',
+ } );
+ }
+
+ #one more try at a whole-country tax rate
+ unless ( @taxes ) {
+ @taxes = qsearch( 'cust_main_county', {
+ 'state' => '',
+ 'county' => '',
+ 'country' => $self->country,
+ 'taxclass' => '',
+ } );
+ }
+
+ # maybe eliminate this entirely, along with all the 0% records
+ unless ( @taxes ) {
+ $dbh->rollback if $oldAutoCommit;
+ return
+ "fatal: can't find tax rate for state/county/country/taxclass ".
+ join('/', ( map $self->$_(), qw(state county country) ),
+ $part_pkg->taxclass ). "\n";
+ }
+
+ foreach my $tax ( @taxes ) {
+
+ my $taxable_charged = 0;
+ $taxable_charged += $setup
+ unless $part_pkg->setuptax =~ /^Y$/i
+ || $tax->setuptax =~ /^Y$/i;
+ $taxable_charged += $recur
+ unless $part_pkg->recurtax =~ /^Y$/i
+ || $tax->recurtax =~ /^Y$/i;
+ next unless $taxable_charged;
+
+ if ( $tax->exempt_amount > 0 ) {
+ my ($mon,$year) = (localtime($sdate) )[4,5];
+ $mon++;
+ my $freq = $part_pkg->freq || 1;
+ if ( $freq !~ /(\d+)$/ ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "daily/weekly package definitions not (yet?)".
+ " compatible with monthly tax exemptions";
+ }
+ my $taxable_per_month = sprintf("%.2f", $taxable_charged / $freq );
+ foreach my $which_month ( 1 .. $freq ) {
+ my %hash = (
+ 'custnum' => $self->custnum,
+ 'taxnum' => $tax->taxnum,
+ 'year' => 1900+$year,
+ 'month' => $mon++,
+ );
+ #until ( $mon < 12 ) { $mon -= 12; $year++; }
+ until ( $mon < 13 ) { $mon -= 12; $year++; }
+ my $cust_tax_exempt =
+ qsearchs('cust_tax_exempt', \%hash)
+ || new FS::cust_tax_exempt( { %hash, 'amount' => 0 } );
+ my $remaining_exemption = sprintf("%.2f",
+ $tax->exempt_amount - $cust_tax_exempt->amount );
+ if ( $remaining_exemption > 0 ) {
+ my $addl = $remaining_exemption > $taxable_per_month
+ ? $taxable_per_month
+ : $remaining_exemption;
+ $taxable_charged -= $addl;
+ my $new_cust_tax_exempt = new FS::cust_tax_exempt ( {
+ $cust_tax_exempt->hash,
+ 'amount' =>
+ sprintf("%.2f", $cust_tax_exempt->amount + $addl),
+ } );
+ $error = $new_cust_tax_exempt->exemptnum
+ ? $new_cust_tax_exempt->replace($cust_tax_exempt)
+ : $new_cust_tax_exempt->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "fatal: can't update cust_tax_exempt: $error";
+ }
+
+ } # if $remaining_exemption > 0
+
+ } #foreach $which_month
+
+ } #if $tax->exempt_amount
+
+ $taxable_charged = sprintf( "%.2f", $taxable_charged);
+
+ #$tax += $taxable_charged * $cust_main_county->tax / 100
+ $tax{ $tax->taxname || 'Tax' } +=
+ $taxable_charged * $tax->tax / 100
+
+ } #foreach my $tax ( @taxes )
+
+ } #unless $self->tax =~ /Y/i || $self->payby eq 'COMP'
+
+ } #if $setup != 0 || $recur != 0
+
+ } #if $cust_pkg_mod_flag
+
+ } #foreach my $cust_pkg
+
+ my $charged = sprintf( "%.2f", $total_setup + $total_recur );
+# my $taxable_charged = sprintf( "%.2f", $taxable_setup + $taxable_recur );
+
+ unless ( @cust_bill_pkg ) { #don't create invoices with no line items
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ return '';
+ }
+
+# unless ( $self->tax =~ /Y/i
+# || $self->payby eq 'COMP'
+# || $taxable_charged == 0 ) {
+# my $cust_main_county = qsearchs('cust_main_county',{
+# 'state' => $self->state,
+# 'county' => $self->county,
+# 'country' => $self->country,
+# } ) or die "fatal: can't find tax rate for state/county/country ".
+# $self->state. "/". $self->county. "/". $self->country. "\n";
+# my $tax = sprintf( "%.2f",
+# $taxable_charged * ( $cust_main_county->getfield('tax') / 100 )
+# );
+
+ if ( dbdef->table('cust_bill_pkg')->column('itemdesc') ) { #1.5 schema
+
+ foreach my $taxname ( grep { $tax{$_} > 0 } keys %tax ) {
+ my $tax = sprintf("%.2f", $tax{$taxname} );
+ $charged = sprintf( "%.2f", $charged+$tax );
+
+ my $cust_bill_pkg = new FS::cust_bill_pkg ({
+ 'pkgnum' => 0,
+ 'setup' => $tax,
+ 'recur' => 0,
+ 'sdate' => '',
+ 'edate' => '',
+ 'itemdesc' => $taxname,
+ });
+ push @cust_bill_pkg, $cust_bill_pkg;
+ }
+
+ } else { #1.4 schema
+
+ my $tax = 0;
+ foreach ( values %tax ) { $tax += $_ };
+ $tax = sprintf("%.2f", $tax);
+ if ( $tax > 0 ) {
+ $charged = sprintf( "%.2f", $charged+$tax );
+
+ my $cust_bill_pkg = new FS::cust_bill_pkg ({
+ 'pkgnum' => 0,
+ 'setup' => $tax,
+ 'recur' => 0,
+ 'sdate' => '',
+ 'edate' => '',
+ });
+ push @cust_bill_pkg, $cust_bill_pkg;
+ }
+
+ }
+
+ my $cust_bill = new FS::cust_bill ( {
+ 'custnum' => $self->custnum,
+ '_date' => $time,
+ 'charged' => $charged,
+ } );
+ $error = $cust_bill->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't create invoice for customer #". $self->custnum. ": $error";
+ }
+
+ my $invnum = $cust_bill->invnum;
+ my $cust_bill_pkg;
+ foreach $cust_bill_pkg ( @cust_bill_pkg ) {
+ #warn $invnum;
+ $cust_bill_pkg->invnum($invnum);
+ $error = $cust_bill_pkg->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't create invoice line item for customer #". $self->custnum.
+ ": $error";
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ ''; #no error
+}
+
+=item collect OPTIONS
+
+(Attempt to) collect money for this customer's outstanding invoices (see
+L<FS::cust_bill>). Usually used after the bill method.
+
+Depending on the value of `payby', this may print or email an invoice (I<BILL>,
+I<DCRD>, or I<DCHK>), charge a credit card (I<CARD>), charge via electronic
+check/ACH (I<CHEK>), or just add any necessary (pseudo-)payment (I<COMP>).
+
+Most actions are now triggered by invoice events; see L<FS::part_bill_event>
+and the invoice events web interface.
+
+If there is an error, returns the error, otherwise returns false.
+
+Options are passed as name-value pairs.
+
+Currently available options are:
+
+invoice_time - Use this time when deciding when to print invoices and
+late notices on those invoices. The default is now. It is specified as a UNIX timestamp; see L<perlfunc/"time">). Also see L<Time::Local> and L<Date::Parse>
+for conversion functions.
+
+retry - Retry card/echeck/LEC transactions even when not scheduled by invoice
+events.
+
+retry_card - Deprecated alias for 'retry'
+
+batch_card - This option is deprecated. See the invoice events web interface
+to control whether cards are batched or run against a realtime gateway.
+
+report_badcard - This option is deprecated.
+
+force_print - This option is deprecated; see the invoice events web interface.
+
+quiet - set true to surpress email card/ACH decline notices.
+
+=cut
+
+sub collect {
+ my( $self, %options ) = @_;
+ my $invoice_time = $options{'invoice_time'} || time;
+
+ #put below somehow?
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ $self->select_for_update; #mutex
+
+ my $balance = $self->balance;
+ warn "collect customer". $self->custnum. ": balance $balance" if $DEBUG;
+ unless ( $balance > 0 ) { #redundant?????
+ $dbh->rollback if $oldAutoCommit; #hmm
+ return '';
+ }
+
+ if ( exists($options{'retry_card'}) ) {
+ carp 'retry_card option passed to collect is deprecated; use retry';
+ $options{'retry'} ||= $options{'retry_card'};
+ }
+ if ( exists($options{'retry'}) && $options{'retry'} ) {
+ my $error = $self->retry_realtime;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ foreach my $cust_bill ( $self->open_cust_bill ) {
+
+ # don't try to charge for the same invoice if it's already in a batch
+ #next if qsearchs( 'cust_pay_batch', { 'invnum' => $cust_bill->invnum } );
+
+ last if $self->balance <= 0;
+
+ warn "invnum ". $cust_bill->invnum. " (owed ". $cust_bill->owed. ")"
+ if $DEBUG;
+
+ foreach my $part_bill_event (
+ sort { $a->seconds <=> $b->seconds
+ || $a->weight <=> $b->weight
+ || $a->eventpart <=> $b->eventpart }
+ grep { $_->seconds <= ( $invoice_time - $cust_bill->_date )
+ && ! qsearch( 'cust_bill_event', {
+ 'invnum' => $cust_bill->invnum,
+ 'eventpart' => $_->eventpart,
+ 'status' => 'done',
+ } )
+ }
+ qsearch('part_bill_event', { 'payby' => $self->payby,
+ 'disabled' => '', } )
+ ) {
+
+ last if $cust_bill->owed <= 0 # don't run subsequent events if owed<=0
+ || $self->balance <= 0; # or if balance<=0
+
+ warn "calling invoice event (". $part_bill_event->eventcode. ")\n"
+ if $DEBUG;
+ my $cust_main = $self; #for callback
+
+ my $error;
+ {
+ local $realtime_bop_decline_quiet = 1 if $options{'quiet'};
+ $error = eval $part_bill_event->eventcode;
+ }
+
+ my $status = '';
+ my $statustext = '';
+ if ( $@ ) {
+ $status = 'failed';
+ $statustext = $@;
+ } elsif ( $error ) {
+ $status = 'done';
+ $statustext = $error;
+ } else {
+ $status = 'done'
+ }
+
+ #add cust_bill_event
+ my $cust_bill_event = new FS::cust_bill_event {
+ 'invnum' => $cust_bill->invnum,
+ 'eventpart' => $part_bill_event->eventpart,
+ #'_date' => $invoice_time,
+ '_date' => time,
+ 'status' => $status,
+ 'statustext' => $statustext,
+ };
+ $error = $cust_bill_event->insert;
+ if ( $error ) {
+ #$dbh->rollback if $oldAutoCommit;
+ #return "error: $error";
+
+ # gah, even with transactions.
+ $dbh->commit if $oldAutoCommit; #well.
+ my $e = 'WARNING: Event run but database not updated - '.
+ 'error inserting cust_bill_event, invnum #'. $cust_bill->invnum.
+ ', eventpart '. $part_bill_event->eventpart.
+ ": $error";
+ warn $e;
+ return $e;
+ }
+
+
+ }
+
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item retry_realtime
+
+Schedules realtime credit card / electronic check / LEC billing events for
+for retry. Useful if card information has changed or manual retry is desired.
+The 'collect' method must be called to actually retry the transaction.
+
+Implementation details: For each of this customer's open invoices, changes
+the status of the first "done" (with statustext error) realtime processing
+event to "failed".
+
+=cut
+
+sub retry_realtime {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $cust_bill (
+ grep { $_->cust_bill_event }
+ $self->open_cust_bill
+ ) {
+ my @cust_bill_event =
+ sort { $a->part_bill_event->seconds <=> $b->part_bill_event->seconds }
+ grep {
+ #$_->part_bill_event->plan eq 'realtime-card'
+ $_->part_bill_event->eventcode =~
+ /\$cust_bill\->realtime_(card|ach|lec)/
+ && $_->status eq 'done'
+ && $_->statustext
+ }
+ $cust_bill->cust_bill_event;
+ next unless @cust_bill_event;
+ my $error = $cust_bill_event[0]->retry;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error scheduling invoice event for retry: $error";
+ }
+
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item realtime_bop METHOD AMOUNT [ OPTION => VALUE ... ]
+
+Runs a realtime credit card, ACH (electronic check) or phone bill transaction
+via a Business::OnlinePayment realtime gateway. See
+L<http://420.am/business-onlinepayment> for supported gateways.
+
+Available methods are: I<CC>, I<ECHECK> and I<LEC>
+
+Available options are: I<description>, I<invnum>, I<quiet>
+
+The additional options I<payname>, I<address1>, I<address2>, I<city>, I<state>,
+I<zip>, I<payinfo> and I<paydate> are also available. Any of these options,
+if set, will override the value from the customer record.
+
+I<description> is a free-text field passed to the gateway. It defaults to
+"Internet services".
+
+If an I<invnum> is specified, this payment (if sucessful) is applied to the
+specified invoice. If you don't specify an I<invnum> you might want to
+call the B<apply_payments> method.
+
+I<quiet> can be set true to surpress email decline notices.
+
+(moved from cust_bill) (probably should get realtime_{card,ach,lec} here too)
+
+=cut
+
+sub realtime_bop {
+ my( $self, $method, $amount, %options ) = @_;
+ if ( $DEBUG ) {
+ warn "$self $method $amount\n";
+ warn " $_ => $options{$_}\n" foreach keys %options;
+ }
+
+ $options{'description'} ||= 'Internet services';
+
+ #pre-requisites
+ die "Real-time processing not enabled\n"
+ unless $conf->exists('business-onlinepayment');
+ eval "use Business::OnlinePayment";
+ die $@ if $@;
+
+ #overrides
+ $self->set( $_ => $options{$_} )
+ foreach grep { exists($options{$_}) }
+ qw( payname address1 address2 city state zip payinfo paydate paycvv);
+
+ #load up config
+ my $bop_config = 'business-onlinepayment';
+ $bop_config .= '-ach'
+ if $method eq 'ECHECK' && $conf->exists($bop_config. '-ach');
+ my ( $processor, $login, $password, $action, @bop_options ) =
+ $conf->config($bop_config);
+ $action ||= 'normal authorization';
+ pop @bop_options if scalar(@bop_options) % 2 && $bop_options[-1] =~ /^\s*$/;
+ die "No real-time processor is enabled - ".
+ "did you set the business-onlinepayment configuration value?\n"
+ unless $processor;
+
+ #massage data
+
+ my $address = $self->address1;
+ $address .= ", ". $self->address2 if $self->address2;
+
+ my($payname, $payfirst, $paylast);
+ if ( $self->payname && $method ne 'ECHECK' ) {
+ $payname = $self->payname;
+ $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/
+ or return "Illegal payname $payname";
+ ($payfirst, $paylast) = ($1, $2);
+ } else {
+ $payfirst = $self->getfield('first');
+ $paylast = $self->getfield('last');
+ $payname = "$payfirst $paylast";
+ }
+
+ my @invoicing_list = grep { $_ ne 'POST' } $self->invoicing_list;
+ if ( $conf->exists('emailinvoiceauto')
+ || ( $conf->exists('emailinvoiceonly') && ! @invoicing_list ) ) {
+ push @invoicing_list, $self->all_emails;
+ }
+ my $email = $invoicing_list[0];
+
+ my %content;
+ if ( $method eq 'CC' ) {
+
+ $content{card_number} = $self->payinfo;
+ $self->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
+ $content{expiration} = "$2/$1";
+
+ $content{cvv2} = $self->paycvv
+ if defined $self->dbdef_table->column('paycvv')
+ && length($self->paycvv);
+
+ $content{recurring_billing} = 'YES'
+ if qsearch('cust_pay', { 'custnum' => $self->custnum,
+ 'payby' => 'CARD',
+ 'payinfo' => $self->payinfo, } );
+
+ } elsif ( $method eq 'ECHECK' ) {
+ my($account_number,$routing_code) = $self->payinfo;
+ ( $content{account_number}, $content{routing_code} ) =
+ split('@', $self->payinfo);
+ $content{bank_name} = $self->payname;
+ $content{account_type} = 'CHECKING';
+ $content{account_name} = $payname;
+ $content{customer_org} = $self->company ? 'B' : 'I';
+ $content{customer_ssn} = $self->ss;
+ } elsif ( $method eq 'LEC' ) {
+ $content{phone} = $self->payinfo;
+ }
+
+ #transaction(s)
+
+ my( $action1, $action2 ) = split(/\s*\,\s*/, $action );
+
+ my $transaction =
+ new Business::OnlinePayment( $processor, @bop_options );
+ $transaction->content(
+ 'type' => $method,
+ 'login' => $login,
+ 'password' => $password,
+ 'action' => $action1,
+ 'description' => $options{'description'},
+ 'amount' => $amount,
+ 'invoice_number' => $options{'invnum'},
+ 'customer_id' => $self->custnum,
+ 'last_name' => $paylast,
+ 'first_name' => $payfirst,
+ 'name' => $payname,
+ 'address' => $address,
+ 'city' => $self->city,
+ 'state' => $self->state,
+ 'zip' => $self->zip,
+ 'country' => $self->country,
+ 'referer' => 'http://cleanwhisker.420.am/',
+ 'email' => $email,
+ 'phone' => $self->daytime || $self->night,
+ %content, #after
+ );
+ $transaction->submit();
+
+ if ( $transaction->is_success() && $action2 ) {
+ my $auth = $transaction->authorization;
+ my $ordernum = $transaction->can('order_number')
+ ? $transaction->order_number
+ : '';
+
+ my $capture =
+ new Business::OnlinePayment( $processor, @bop_options );
+
+ my %capture = (
+ %content,
+ type => $method,
+ action => $action2,
+ login => $login,
+ password => $password,
+ order_number => $ordernum,
+ amount => $amount,
+ authorization => $auth,
+ description => $options{'description'},
+ );
+
+ foreach my $field (qw( authorization_source_code returned_ACI transaction_identifier validation_code
+ transaction_sequence_num local_transaction_date
+ local_transaction_time AVS_result_code )) {
+ $capture{$field} = $transaction->$field() if $transaction->can($field);
+ }
+
+ $capture->content( %capture );
+
+ $capture->submit();
+
+ unless ( $capture->is_success ) {
+ my $e = "Authorization sucessful but capture failed, custnum #".
+ $self->custnum. ': '. $capture->result_code.
+ ": ". $capture->error_message;
+ warn $e;
+ return $e;
+ }
+
+ }
+
+ #remove paycvv after initial transaction
+ #false laziness w/misc/process/payment.cgi - check both to make sure working
+ # correctly
+ if ( defined $self->dbdef_table->column('paycvv')
+ && length($self->paycvv)
+ && ! grep { $_ eq cardtype($self->payinfo) } $conf->config('cvv-save')
+ && ! length($options{'paycvv'})
+ ) {
+ my $new = new FS::cust_main { $self->hash };
+ $new->paycvv('');
+ my $error = $new->replace($self);
+ if ( $error ) {
+ warn "error removing cvv: $error\n";
+ }
+ }
+
+ #result handling
+ if ( $transaction->is_success() ) {
+
+ my %method2payby = (
+ 'CC' => 'CARD',
+ 'ECHECK' => 'CHEK',
+ 'LEC' => 'LECB',
+ );
+
+ my $cust_pay = new FS::cust_pay ( {
+ 'custnum' => $self->custnum,
+ 'invnum' => $options{'invnum'},
+ 'paid' => $amount,
+ '_date' => '',
+ 'payby' => $method2payby{$method},
+ 'payinfo' => $self->payinfo,
+ 'paybatch' => "$processor:". $transaction->authorization,
+ } );
+ my $error = $cust_pay->insert;
+ if ( $error ) {
+ $cust_pay->invnum(''); #try again with no specific invnum
+ my $error2 = $cust_pay->insert;
+ if ( $error2 ) {
+ # gah, even with transactions.
+ my $e = 'WARNING: Card/ACH debited but database not updated - '.
+ "error inserting payment ($processor): $error2".
+ " (previously tried insert with invnum #$options{'invnum'}" .
+ ": $error )";
+ warn $e;
+ return $e;
+ }
+ }
+ return ''; #no error
+
+ } else {
+
+ my $perror = "$processor error: ". $transaction->error_message;
+
+ if ( !$options{'quiet'} && !$realtime_bop_decline_quiet
+ && $conf->exists('emaildecline')
+ && grep { $_ ne 'POST' } $self->invoicing_list
+ && ! grep { $transaction->error_message =~ /$_/ }
+ $conf->config('emaildecline-exclude')
+ ) {
+ my @templ = $conf->config('declinetemplate');
+ my $template = new Text::Template (
+ TYPE => 'ARRAY',
+ SOURCE => [ map "$_\n", @templ ],
+ ) or return "($perror) can't create template: $Text::Template::ERROR";
+ $template->compile()
+ or return "($perror) can't compile template: $Text::Template::ERROR";
+
+ my $templ_hash = { error => $transaction->error_message };
+
+ my $error = send_email(
+ 'from' => $conf->config('invoice_from'),
+ 'to' => [ grep { $_ ne 'POST' } $self->invoicing_list ],
+ 'subject' => 'Your payment could not be processed',
+ 'body' => [ $template->fill_in(HASH => $templ_hash) ],
+ );
+
+ $perror .= " (also received error sending decline notification: $error)"
+ if $error;
+
+ }
+
+ return $perror;
+ }
+
+}
+
+=item total_owed
+
+Returns the total owed for this customer on all invoices
+(see L<FS::cust_bill/owed>).
+
+=cut
+
+sub total_owed {
+ my $self = shift;
+ $self->total_owed_date(2145859200); #12/31/2037
+}
+
+=item total_owed_date TIME
+
+Returns the total owed for this customer on all invoices with date earlier than
+TIME. TIME is specified as a UNIX timestamp; see L<perlfunc/"time">). Also
+see L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=cut
+
+sub total_owed_date {
+ my $self = shift;
+ my $time = shift;
+ my $total_bill = 0;
+ foreach my $cust_bill (
+ grep { $_->_date <= $time }
+ qsearch('cust_bill', { 'custnum' => $self->custnum, } )
+ ) {
+ $total_bill += $cust_bill->owed;
+ }
+ sprintf( "%.2f", $total_bill );
+}
+
+=item apply_credits
+
+Applies (see L<FS::cust_credit_bill>) unapplied credits (see L<FS::cust_credit>)
+to outstanding invoice balances in chronological order and returns the value
+of any remaining unapplied credits available for refund
+(see L<FS::cust_refund>).
+
+=cut
+
+sub apply_credits {
+ my $self = shift;
+
+ return 0 unless $self->total_credited;
+
+ my @credits = sort { $b->_date <=> $a->_date} (grep { $_->credited > 0 }
+ qsearch('cust_credit', { 'custnum' => $self->custnum } ) );
+
+ my @invoices = sort { $a->_date <=> $b->_date} (grep { $_->owed > 0 }
+ qsearch('cust_bill', { 'custnum' => $self->custnum } ) );
+
+ my $credit;
+
+ foreach my $cust_bill ( @invoices ) {
+ my $amount;
+
+ if ( !defined($credit) || $credit->credited == 0) {
+ $credit = pop @credits or last;
+ }
+
+ if ($cust_bill->owed >= $credit->credited) {
+ $amount=$credit->credited;
+ }else{
+ $amount=$cust_bill->owed;
+ }
+
+ my $cust_credit_bill = new FS::cust_credit_bill ( {
+ 'crednum' => $credit->crednum,
+ 'invnum' => $cust_bill->invnum,
+ 'amount' => $amount,
+ } );
+ my $error = $cust_credit_bill->insert;
+ die $error if $error;
+
+ redo if ($cust_bill->owed > 0);
+
+ }
+
+ return $self->total_credited;
+}
+
+=item apply_payments
+
+Applies (see L<FS::cust_bill_pay>) unapplied payments (see L<FS::cust_pay>)
+to outstanding invoice balances in chronological order.
+
+ #and returns the value of any remaining unapplied payments.
+
+=cut
+
+sub apply_payments {
+ my $self = shift;
+
+ #return 0 unless
+
+ my @payments = sort { $b->_date <=> $a->_date } ( grep { $_->unapplied > 0 }
+ qsearch('cust_pay', { 'custnum' => $self->custnum } ) );
+
+ my @invoices = sort { $a->_date <=> $b->_date} (grep { $_->owed > 0 }
+ qsearch('cust_bill', { 'custnum' => $self->custnum } ) );
+
+ my $payment;
+
+ foreach my $cust_bill ( @invoices ) {
+ my $amount;
+
+ if ( !defined($payment) || $payment->unapplied == 0 ) {
+ $payment = pop @payments or last;
+ }
+
+ if ( $cust_bill->owed >= $payment->unapplied ) {
+ $amount = $payment->unapplied;
+ } else {
+ $amount = $cust_bill->owed;
+ }
+
+ my $cust_bill_pay = new FS::cust_bill_pay ( {
+ 'paynum' => $payment->paynum,
+ 'invnum' => $cust_bill->invnum,
+ 'amount' => $amount,
+ } );
+ my $error = $cust_bill_pay->insert;
+ die $error if $error;
+
+ redo if ( $cust_bill->owed > 0);
+
+ }
+
+ return $self->total_unapplied_payments;
+}
+
+=item total_credited
+
+Returns the total outstanding credit (see L<FS::cust_credit>) for this
+customer. See L<FS::cust_credit/credited>.
+
+=cut
+
+sub total_credited {
+ my $self = shift;
+ my $total_credit = 0;
+ foreach my $cust_credit ( qsearch('cust_credit', {
+ 'custnum' => $self->custnum,
+ } ) ) {
+ $total_credit += $cust_credit->credited;
+ }
+ sprintf( "%.2f", $total_credit );
+}
+
+=item total_unapplied_payments
+
+Returns the total unapplied payments (see L<FS::cust_pay>) for this customer.
+See L<FS::cust_pay/unapplied>.
+
+=cut
+
+sub total_unapplied_payments {
+ my $self = shift;
+ my $total_unapplied = 0;
+ foreach my $cust_pay ( qsearch('cust_pay', {
+ 'custnum' => $self->custnum,
+ } ) ) {
+ $total_unapplied += $cust_pay->unapplied;
+ }
+ sprintf( "%.2f", $total_unapplied );
+}
+
+=item balance
+
+Returns the balance for this customer (total_owed minus total_credited
+minus total_unapplied_payments).
+
+=cut
+
+sub balance {
+ my $self = shift;
+ sprintf( "%.2f",
+ $self->total_owed - $self->total_credited - $self->total_unapplied_payments
+ );
+}
+
+=item balance_date TIME
+
+Returns the balance for this customer, only considering invoices with date
+earlier than TIME (total_owed_date minus total_credited minus
+total_unapplied_payments). TIME is specified as a UNIX timestamp; see
+L<perlfunc/"time">). Also see L<Time::Local> and L<Date::Parse> for conversion
+functions.
+
+=cut
+
+sub balance_date {
+ my $self = shift;
+ my $time = shift;
+ sprintf( "%.2f",
+ $self->total_owed_date($time)
+ - $self->total_credited
+ - $self->total_unapplied_payments
+ );
+}
+
+=item paydate_monthyear
+
+Returns a two-element list consisting of the month and year of this customer's
+paydate (credit card expiration date for CARD customers)
+
+=cut
+
+sub paydate_monthyear {
+ my $self = shift;
+ if ( $self->paydate =~ /^(\d{4})-(\d{2})-\d{2}$/ ) { #Pg date format
+ ( $2, $1 );
+ } elsif ( $self->paydate =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) {
+ ( $1, $3 );
+ } else {
+ ('', '');
+ }
+}
+
+=item payinfo_masked
+
+Returns a "masked" payinfo field with all but the last four characters replaced
+by 'x'es. Useful for displaying credit cards.
+
+=cut
+
+sub payinfo_masked {
+ my $self = shift;
+ my $payinfo = $self->payinfo;
+ 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4));
+}
+
+=item invoicing_list [ ARRAYREF ]
+
+If an arguement is given, sets these email addresses as invoice recipients
+(see L<FS::cust_main_invoice>). Errors are not fatal and are not reported
+(except as warnings), so use check_invoicing_list first.
+
+Returns a list of email addresses (with svcnum entries expanded).
+
+Note: You can clear the invoicing list by passing an empty ARRAYREF. You can
+check it without disturbing anything by passing nothing.
+
+This interface may change in the future.
+
+=cut
+
+sub invoicing_list {
+ my( $self, $arrayref ) = @_;
+ if ( $arrayref ) {
+ my @cust_main_invoice;
+ if ( $self->custnum ) {
+ @cust_main_invoice =
+ qsearch( 'cust_main_invoice', { 'custnum' => $self->custnum } );
+ } else {
+ @cust_main_invoice = ();
+ }
+ foreach my $cust_main_invoice ( @cust_main_invoice ) {
+ #warn $cust_main_invoice->destnum;
+ unless ( grep { $cust_main_invoice->address eq $_ } @{$arrayref} ) {
+ #warn $cust_main_invoice->destnum;
+ my $error = $cust_main_invoice->delete;
+ warn $error if $error;
+ }
+ }
+ if ( $self->custnum ) {
+ @cust_main_invoice =
+ qsearch( 'cust_main_invoice', { 'custnum' => $self->custnum } );
+ } else {
+ @cust_main_invoice = ();
+ }
+ my %seen = map { $_->address => 1 } @cust_main_invoice;
+ foreach my $address ( @{$arrayref} ) {
+ next if exists $seen{$address} && $seen{$address};
+ $seen{$address} = 1;
+ my $cust_main_invoice = new FS::cust_main_invoice ( {
+ 'custnum' => $self->custnum,
+ 'dest' => $address,
+ } );
+ my $error = $cust_main_invoice->insert;
+ warn $error if $error;
+ }
+ }
+ if ( $self->custnum ) {
+ map { $_->address }
+ qsearch( 'cust_main_invoice', { 'custnum' => $self->custnum } );
+ } else {
+ ();
+ }
+}
+
+=item check_invoicing_list ARRAYREF
+
+Checks these arguements as valid input for the invoicing_list method. If there
+is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub check_invoicing_list {
+ my( $self, $arrayref ) = @_;
+ foreach my $address ( @{$arrayref} ) {
+ my $cust_main_invoice = new FS::cust_main_invoice ( {
+ 'custnum' => $self->custnum,
+ 'dest' => $address,
+ } );
+ my $error = $self->custnum
+ ? $cust_main_invoice->check
+ : $cust_main_invoice->checkdest
+ ;
+ return $error if $error;
+ }
+ '';
+}
+
+=item set_default_invoicing_list
+
+Sets the invoicing list to all accounts associated with this customer,
+overwriting any previous invoicing list.
+
+=cut
+
+sub set_default_invoicing_list {
+ my $self = shift;
+ $self->invoicing_list($self->all_emails);
+}
+
+=item all_emails
+
+Returns the email addresses of all accounts provisioned for this customer.
+
+=cut
+
+sub all_emails {
+ my $self = shift;
+ my %list;
+ foreach my $cust_pkg ( $self->all_pkgs ) {
+ my @cust_svc = qsearch('cust_svc', { 'pkgnum' => $cust_pkg->pkgnum } );
+ my @svc_acct =
+ map { qsearchs('svc_acct', { 'svcnum' => $_->svcnum } ) }
+ grep { qsearchs('svc_acct', { 'svcnum' => $_->svcnum } ) }
+ @cust_svc;
+ $list{$_}=1 foreach map { $_->email } @svc_acct;
+ }
+ keys %list;
+}
+
+=item invoicing_list_addpost
+
+Adds postal invoicing to this customer. If this customer is already configured
+to receive postal invoices, does nothing.
+
+=cut
+
+sub invoicing_list_addpost {
+ my $self = shift;
+ return if grep { $_ eq 'POST' } $self->invoicing_list;
+ my @invoicing_list = $self->invoicing_list;
+ push @invoicing_list, 'POST';
+ $self->invoicing_list(\@invoicing_list);
+}
+
+=item referral_cust_main [ DEPTH [ EXCLUDE_HASHREF ] ]
+
+Returns an array of customers referred by this customer (referral_custnum set
+to this custnum). If DEPTH is given, recurses up to the given depth, returning
+customers referred by customers referred by this customer and so on, inclusive.
+The default behavior is DEPTH 1 (no recursion).
+
+=cut
+
+sub referral_cust_main {
+ my $self = shift;
+ my $depth = @_ ? shift : 1;
+ my $exclude = @_ ? shift : {};
+
+ my @cust_main =
+ map { $exclude->{$_->custnum}++; $_; }
+ grep { ! $exclude->{ $_->custnum } }
+ qsearch( 'cust_main', { 'referral_custnum' => $self->custnum } );
+
+ if ( $depth > 1 ) {
+ push @cust_main,
+ map { $_->referral_cust_main($depth-1, $exclude) }
+ @cust_main;
+ }
+
+ @cust_main;
+}
+
+=item referral_cust_main_ncancelled
+
+Same as referral_cust_main, except only returns customers with uncancelled
+packages.
+
+=cut
+
+sub referral_cust_main_ncancelled {
+ my $self = shift;
+ grep { scalar($_->ncancelled_pkgs) } $self->referral_cust_main;
+}
+
+=item referral_cust_pkg [ DEPTH ]
+
+Like referral_cust_main, except returns a flat list of all unsuspended (and
+uncancelled) packages for each customer. The number of items in this list may
+be useful for comission calculations (perhaps after a C<grep { my $pkgpart = $_->pkgpart; grep { $_ == $pkgpart } @commission_worthy_pkgparts> } $cust_main-> ).
+
+=cut
+
+sub referral_cust_pkg {
+ my $self = shift;
+ my $depth = @_ ? shift : 1;
+
+ map { $_->unsuspended_pkgs }
+ grep { $_->unsuspended_pkgs }
+ $self->referral_cust_main($depth);
+}
+
+=item credit AMOUNT, REASON
+
+Applies a credit to this customer. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub credit {
+ my( $self, $amount, $reason ) = @_;
+ my $cust_credit = new FS::cust_credit {
+ 'custnum' => $self->custnum,
+ 'amount' => $amount,
+ 'reason' => $reason,
+ };
+ $cust_credit->insert;
+}
+
+=item charge AMOUNT [ PKG [ COMMENT [ TAXCLASS ] ] ]
+
+Creates a one-time charge for this customer. If there is an error, returns
+the error, otherwise returns false.
+
+=cut
+
+sub charge {
+ my ( $self, $amount ) = ( shift, shift );
+ my $pkg = @_ ? shift : 'One-time charge';
+ my $comment = @_ ? shift : '$'. sprintf("%.2f",$amount);
+ my $taxclass = @_ ? shift : '';
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $part_pkg = new FS::part_pkg ( {
+ 'pkg' => $pkg,
+ 'comment' => $comment,
+ 'setup' => $amount,
+ 'freq' => 0,
+ 'recur' => '0',
+ 'disabled' => 'Y',
+ 'taxclass' => $taxclass,
+ } );
+
+ my $error = $part_pkg->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ my $pkgpart = $part_pkg->pkgpart;
+ my %type_pkgs = ( 'typenum' => $self->agent->typenum, 'pkgpart' => $pkgpart );
+ unless ( qsearchs('type_pkgs', \%type_pkgs ) ) {
+ my $type_pkgs = new FS::type_pkgs \%type_pkgs;
+ $error = $type_pkgs->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ my $cust_pkg = new FS::cust_pkg ( {
+ 'custnum' => $self->custnum,
+ 'pkgpart' => $pkgpart,
+ } );
+
+ $error = $cust_pkg->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item cust_bill
+
+Returns all the invoices (see L<FS::cust_bill>) for this customer.
+
+=cut
+
+sub cust_bill {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch('cust_bill', { 'custnum' => $self->custnum, } )
+}
+
+=item open_cust_bill
+
+Returns all the open (owed > 0) invoices (see L<FS::cust_bill>) for this
+customer.
+
+=cut
+
+sub open_cust_bill {
+ my $self = shift;
+ grep { $_->owed > 0 } $self->cust_bill;
+}
+
+=item cust_credit
+
+Returns all the credits (see L<FS::cust_credit>) for this customer.
+
+=cut
+
+sub cust_credit {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_credit', { 'custnum' => $self->custnum } )
+}
+
+=item cust_pay
+
+Returns all the payments (see L<FS::cust_pay>) for this customer.
+
+=cut
+
+sub cust_pay {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_pay', { 'custnum' => $self->custnum } )
+}
+
+=item cust_refund
+
+Returns all the refunds (see L<FS::cust_refund>) for this customer.
+
+=cut
+
+sub cust_refund {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_refund', { 'custnum' => $self->custnum } )
+}
+
+=item select_for_update
+
+Selects this record with the SQL "FOR UPDATE" command. This can be useful as
+a mutex.
+
+=cut
+
+sub select_for_update {
+ my $self = shift;
+ qsearch('cust_main', { 'custnum' => $self->custnum }, '*', 'FOR UPDATE' );
+}
+
+=item name
+
+Returns a name string for this customer, either "Company (Last, First)" or
+"Last, First".
+
+=cut
+
+sub name {
+ my $self = shift;
+ my $name = $self->get('last'). ', '. $self->first;
+ $name = $self->company. " ($name)" if $self->company;
+ $name;
+}
+
+=item status
+
+Returns a status string for this customer, currently:
+
+=over 4
+
+=item prospect - No packages have ever been ordered
+
+=item active - One or more recurring packages is active
+
+=item suspended - All non-cancelled recurring packages are suspended
+
+=item cancelled - All recurring packages are cancelled
+
+=back
+
+=cut
+
+sub status {
+ my $self = shift;
+ for my $status (qw( prospect active suspended cancelled )) {
+ my $method = $status.'_sql';
+ my $numnum = ( my $sql = $self->$method() ) =~ s/cust_main\.custnum/?/g;
+ my $sth = dbh->prepare("SELECT $sql") or die dbh->errstr;
+ $sth->execute( ($self->custnum) x $numnum ) or die $sth->errstr;
+ return $status if $sth->fetchrow_arrayref->[0];
+ }
+}
+
+=item statuscolor
+
+Returns a hex triplet color string for this customer's status.
+
+=cut
+
+my %statuscolor = (
+ 'prospect' => '000000',
+ 'active' => '00CC00',
+ 'suspended' => 'FF9900',
+ 'cancelled' => 'FF0000',
+);
+sub statuscolor {
+ my $self = shift;
+ $statuscolor{$self->status};
+}
+
+=back
+
+=head1 CLASS METHODS
+
+=over 4
+
+=item prospect_sql
+
+Returns an SQL expression identifying prospective cust_main records (customers
+with no packages ever ordered)
+
+=cut
+
+sub prospect_sql { "
+ 0 = ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ )
+"; }
+
+=item active_sql
+
+Returns an SQL expression identifying active cust_main records.
+
+=cut
+
+sub active_sql { "
+ 0 < ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
+ AND ( cust_pkg.susp IS NULL OR cust_pkg.susp = 0 )
+ )
+"; }
+
+=item susp_sql
+=item suspended_sql
+
+Returns an SQL expression identifying suspended cust_main records.
+
+=cut
+
+sub suspended_sql { susp_sql(@_); }
+sub susp_sql { "
+ 0 < ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
+ )
+ AND 0 = ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ AND ( cust_pkg.susp IS NULL OR cust_pkg.susp = 0 )
+ )
+"; }
+
+=item cancel_sql
+=item cancelled_sql
+
+Returns an SQL expression identifying cancelled cust_main records.
+
+=cut
+
+sub cancelled_sql { cancel_sql(@_); }
+sub cancel_sql { "
+ 0 < ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ )
+ AND 0 = ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
+ )
+"; }
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item check_and_rebuild_fuzzyfiles
+
+=cut
+
+sub check_and_rebuild_fuzzyfiles {
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ -e "$dir/cust_main.last" && -e "$dir/cust_main.company"
+ or &rebuild_fuzzyfiles;
+}
+
+=item rebuild_fuzzyfiles
+
+=cut
+
+sub rebuild_fuzzyfiles {
+
+ use Fcntl qw(:flock);
+
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+
+ #last
+
+ open(LASTLOCK,">>$dir/cust_main.last")
+ or die "can't open $dir/cust_main.last: $!";
+ flock(LASTLOCK,LOCK_EX)
+ or die "can't lock $dir/cust_main.last: $!";
+
+ my @all_last = map $_->getfield('last'), qsearch('cust_main', {});
+ push @all_last,
+ grep $_, map $_->getfield('ship_last'), qsearch('cust_main',{})
+ if defined dbdef->table('cust_main')->column('ship_last');
+
+ open (LASTCACHE,">$dir/cust_main.last.tmp")
+ or die "can't open $dir/cust_main.last.tmp: $!";
+ print LASTCACHE join("\n", @all_last), "\n";
+ close LASTCACHE or die "can't close $dir/cust_main.last.tmp: $!";
+
+ rename "$dir/cust_main.last.tmp", "$dir/cust_main.last";
+ close LASTLOCK;
+
+ #company
+
+ open(COMPANYLOCK,">>$dir/cust_main.company")
+ or die "can't open $dir/cust_main.company: $!";
+ flock(COMPANYLOCK,LOCK_EX)
+ or die "can't lock $dir/cust_main.company: $!";
+
+ my @all_company = grep $_ ne '', map $_->company, qsearch('cust_main',{});
+ push @all_company,
+ grep $_ ne '', map $_->ship_company, qsearch('cust_main', {})
+ if defined dbdef->table('cust_main')->column('ship_last');
+
+ open (COMPANYCACHE,">$dir/cust_main.company.tmp")
+ or die "can't open $dir/cust_main.company.tmp: $!";
+ print COMPANYCACHE join("\n", @all_company), "\n";
+ close COMPANYCACHE or die "can't close $dir/cust_main.company.tmp: $!";
+
+ rename "$dir/cust_main.company.tmp", "$dir/cust_main.company";
+ close COMPANYLOCK;
+
+}
+
+=item all_last
+
+=cut
+
+sub all_last {
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ open(LASTCACHE,"<$dir/cust_main.last")
+ or die "can't open $dir/cust_main.last: $!";
+ my @array = map { chomp; $_; } <LASTCACHE>;
+ close LASTCACHE;
+ \@array;
+}
+
+=item all_company
+
+=cut
+
+sub all_company {
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ open(COMPANYCACHE,"<$dir/cust_main.company")
+ or die "can't open $dir/cust_main.last: $!";
+ my @array = map { chomp; $_; } <COMPANYCACHE>;
+ close COMPANYCACHE;
+ \@array;
+}
+
+=item append_fuzzyfiles LASTNAME COMPANY
+
+=cut
+
+sub append_fuzzyfiles {
+ my( $last, $company ) = @_;
+
+ &check_and_rebuild_fuzzyfiles;
+
+ use Fcntl qw(:flock);
+
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+
+ if ( $last ) {
+
+ open(LAST,">>$dir/cust_main.last")
+ or die "can't open $dir/cust_main.last: $!";
+ flock(LAST,LOCK_EX)
+ or die "can't lock $dir/cust_main.last: $!";
+
+ print LAST "$last\n";
+
+ flock(LAST,LOCK_UN)
+ or die "can't unlock $dir/cust_main.last: $!";
+ close LAST;
+ }
+
+ if ( $company ) {
+
+ open(COMPANY,">>$dir/cust_main.company")
+ or die "can't open $dir/cust_main.company: $!";
+ flock(COMPANY,LOCK_EX)
+ or die "can't lock $dir/cust_main.company: $!";
+
+ print COMPANY "$company\n";
+
+ flock(COMPANY,LOCK_UN)
+ or die "can't unlock $dir/cust_main.company: $!";
+
+ close COMPANY;
+ }
+
+ 1;
+}
+
+=item batch_import
+
+=cut
+
+sub batch_import {
+ my $param = shift;
+ #warn join('-',keys %$param);
+ my $fh = $param->{filehandle};
+ my $agentnum = $param->{agentnum};
+ my $refnum = $param->{refnum};
+ my $pkgpart = $param->{pkgpart};
+ my @fields = @{$param->{fields}};
+
+ eval "use Date::Parse;";
+ die $@ if $@;
+ eval "use Text::CSV_XS;";
+ die $@ if $@;
+
+ my $csv = new Text::CSV_XS;
+ #warn $csv;
+ #warn $fh;
+
+ my $imported = 0;
+ #my $columns;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ #while ( $columns = $csv->getline($fh) ) {
+ my $line;
+ while ( defined($line=<$fh>) ) {
+
+ $csv->parse($line) or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't parse: ". $csv->error_input();
+ };
+
+ my @columns = $csv->fields();
+ #warn join('-',@columns);
+
+ my %cust_main = (
+ agentnum => $agentnum,
+ refnum => $refnum,
+ country => $conf->config('countrydefault') || 'US',
+ payby => 'BILL', #default
+ paydate => '12/2037', #default
+ );
+ my $billtime = time;
+ my %cust_pkg = ( pkgpart => $pkgpart );
+ foreach my $field ( @fields ) {
+ if ( $field =~ /^cust_pkg\.(setup|bill|susp|expire|cancel)$/ ) {
+ #$cust_pkg{$1} = str2time( shift @$columns );
+ if ( $1 eq 'setup' ) {
+ $billtime = str2time(shift @columns);
+ } else {
+ $cust_pkg{$1} = str2time( shift @columns );
+ }
+ } else {
+ #$cust_main{$field} = shift @$columns;
+ $cust_main{$field} = shift @columns;
+ }
+ }
+
+ my $cust_pkg = new FS::cust_pkg ( \%cust_pkg ) if $pkgpart;
+ my $cust_main = new FS::cust_main ( \%cust_main );
+ use Tie::RefHash;
+ tie my %hash, 'Tie::RefHash'; #this part is important
+ $hash{$cust_pkg} = [] if $pkgpart;
+ my $error = $cust_main->insert( \%hash );
+
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't insert customer for $line: $error";
+ }
+
+ #false laziness w/bill.cgi
+ $error = $cust_main->bill( 'time' => $billtime );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't bill customer for $line: $error";
+ }
+
+ $cust_main->apply_payments;
+ $cust_main->apply_credits;
+
+ $error = $cust_main->collect();
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't collect customer for $line: $error";
+ }
+
+ $imported++;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ return "Empty file!" unless $imported;
+
+ ''; #no error
+
+}
+
+=item batch_charge
+
+=cut
+
+sub batch_charge {
+ my $param = shift;
+ #warn join('-',keys %$param);
+ my $fh = $param->{filehandle};
+ my @fields = @{$param->{fields}};
+
+ eval "use Date::Parse;";
+ die $@ if $@;
+ eval "use Text::CSV_XS;";
+ die $@ if $@;
+
+ my $csv = new Text::CSV_XS;
+ #warn $csv;
+ #warn $fh;
+
+ my $imported = 0;
+ #my $columns;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ #while ( $columns = $csv->getline($fh) ) {
+ my $line;
+ while ( defined($line=<$fh>) ) {
+
+ $csv->parse($line) or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't parse: ". $csv->error_input();
+ };
+
+ my @columns = $csv->fields();
+ #warn join('-',@columns);
+
+ my %row = ();
+ foreach my $field ( @fields ) {
+ $row{$field} = shift @columns;
+ }
+
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $row{'custnum'} } );
+ unless ( $cust_main ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "unknown custnum $row{'custnum'}";
+ }
+
+ if ( $row{'amount'} > 0 ) {
+ my $error = $cust_main->charge($row{'amount'}, $row{'pkg'});
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ $imported++;
+ } elsif ( $row{'amount'} < 0 ) {
+ my $error = $cust_main->credit( sprintf( "%.2f", 0-$row{'amount'} ),
+ $row{'pkg'} );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ $imported++;
+ } else {
+ #hmm?
+ }
+
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ return "Empty file!" unless $imported;
+
+ ''; #no error
+
+}
+
+=back
+
+=head1 BUGS
+
+The delete method.
+
+The delete method should possibly take an FS::cust_main object reference
+instead of a scalar customer number.
+
+Bill and collect options should probably be passed as references instead of a
+list.
+
+There should probably be a configuration file with a list of allowed credit
+card types.
+
+No multiple currency support (probably a larger project than just this module).
+
+payinfo_masked false laziness with cust_pay.pm and cust_refund.pm
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_pkg>, L<FS::cust_bill>, L<FS::cust_credit>
+L<FS::agent>, L<FS::part_referral>, L<FS::cust_main_county>,
+L<FS::cust_main_invoice>, L<FS::UID>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_main_county.pm b/FS/FS/cust_main_county.pm
new file mode 100644
index 0000000..ef2793a
--- /dev/null
+++ b/FS/FS/cust_main_county.pm
@@ -0,0 +1,290 @@
+package FS::cust_main_county;
+
+use strict;
+use vars qw( @ISA @EXPORT_OK $conf
+ @cust_main_county %cust_main_county $countyflag );
+use Exporter;
+use FS::Record qw( qsearch );
+
+@ISA = qw( FS::Record );
+@EXPORT_OK = qw( regionselector );
+
+@cust_main_county = ();
+$countyflag = '';
+
+#ask FS::UID to run this stuff for us later
+$FS::UID::callback{'FS::cust_main_county'} = sub {
+ $conf = new FS::Conf;
+};
+
+=head1 NAME
+
+FS::cust_main_county - Object methods for cust_main_county objects
+
+=head1 SYNOPSIS
+
+ use FS::cust_main_county;
+
+ $record = new FS::cust_main_county \%hash;
+ $record = new FS::cust_main_county { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ ($county_html, $state_html, $country_html) =
+ FS::cust_main_county::regionselector( $county, $state, $country );
+
+=head1 DESCRIPTION
+
+An FS::cust_main_county object represents a tax rate, defined by locale.
+FS::cust_main_county inherits from FS::Record. The following fields are
+currently supported:
+
+=over 4
+
+=item taxnum - primary key (assigned automatically for new tax rates)
+
+=item state
+
+=item county
+
+=item country
+
+=item tax - percentage
+
+=item taxclass
+
+=item exempt_amount
+
+=item taxname - if defined, printed on invoices instead of "Tax"
+
+=item setuptax - if 'Y', this tax does not apply to setup fees
+
+=item recurtax - if 'Y', this tax does not apply to recurring fees
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new tax rate. To add the tax rate to the database, see L<"insert">.
+
+=cut
+
+sub table { 'cust_main_county'; }
+
+=item insert
+
+Adds this tax rate to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this tax rate from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid tax rate. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ $self->exempt_amount(0) unless $self->exempt_amount;
+
+ $self->ut_numbern('taxnum')
+ || $self->ut_anything('state')
+ || $self->ut_textn('county')
+ || $self->ut_text('country')
+ || $self->ut_float('tax')
+ || $self->ut_textn('taxclass') # ...
+ || $self->ut_money('exempt_amount')
+ || $self->ut_textn('taxname')
+ || $self->ut_enum('setuptax', [ '', 'Y' ] )
+ || $self->ut_enum('recurtax', [ '', 'Y' ] )
+ || $self->SUPER::check
+ ;
+
+}
+
+sub taxname {
+ my $self = shift;
+ if ( $self->dbdef_table->column('taxname') ) {
+ return $self->setfield('taxname', $_[0]) if @_;
+ return $self->getfield('taxname');
+ }
+ return '';
+}
+
+sub setuptax {
+ my $self = shift;
+ if ( $self->dbdef_table->column('setuptax') ) {
+ return $self->setfield('setuptax', $_[0]) if @_;
+ return $self->getfield('setuptax');
+ }
+ return '';
+}
+
+sub recurtax {
+ my $self = shift;
+ if ( $self->dbdef_table->column('recurtax') ) {
+ return $self->setfield('recurtax', $_[0]) if @_;
+ return $self->getfield('recurtax');
+ }
+ return '';
+}
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item regionselector [ COUNTY STATE COUNTRY [ PREFIX [ ONCHANGE ] ] ]
+
+=cut
+
+sub regionselector {
+ my ( $selected_county, $selected_state, $selected_country,
+ $prefix, $onchange ) = @_;
+
+ $prefix = '' unless defined $prefix;
+
+ $countyflag = 0;
+
+# unless ( @cust_main_county ) { #cache
+ @cust_main_county = qsearch('cust_main_county', {} );
+ foreach my $c ( @cust_main_county ) {
+ $countyflag=1 if $c->county;
+ #push @{$cust_main_county{$c->country}{$c->state}}, $c->county;
+ $cust_main_county{$c->country}{$c->state}{$c->county} = 1;
+ }
+# }
+ $countyflag=1 if $selected_county;
+
+ my $script_html = <<END;
+ <SCRIPT>
+ function opt(what,value,text) {
+ var optionName = new Option(text, value, false, false);
+ var length = what.length;
+ what.options[length] = optionName;
+ }
+ function ${prefix}country_changed(what) {
+ country = what.options[what.selectedIndex].text;
+ for ( var i = what.form.${prefix}state.length; i >= 0; i-- )
+ what.form.${prefix}state.options[i] = null;
+END
+ #what.form.${prefix}state.options[0] = new Option('', '', false, true);
+
+ foreach my $country ( sort keys %cust_main_county ) {
+ $script_html .= "\nif ( country == \"$country\" ) {\n";
+ foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
+ my $text = $state || '(n/a)';
+ $script_html .= qq!opt(what.form.${prefix}state, "$state", "$text");\n!;
+ }
+ $script_html .= "}\n";
+ }
+
+ $script_html .= <<END;
+ }
+ function ${prefix}state_changed(what) {
+END
+
+ if ( $countyflag ) {
+ $script_html .= <<END;
+ state = what.options[what.selectedIndex].text;
+ country = what.form.${prefix}country.options[what.form.${prefix}country.selectedIndex].text;
+ for ( var i = what.form.${prefix}county.length; i >= 0; i-- )
+ what.form.${prefix}county.options[i] = null;
+END
+
+ foreach my $country ( sort keys %cust_main_county ) {
+ $script_html .= "\nif ( country == \"$country\" ) {\n";
+ foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
+ $script_html .= "\nif ( state == \"$state\" ) {\n";
+ #foreach my $county ( sort @{$cust_main_county{$country}{$state}} ) {
+ foreach my $county ( sort keys %{$cust_main_county{$country}{$state}} ) {
+ my $text = $county || '(n/a)';
+ $script_html .=
+ qq!opt(what.form.${prefix}county, "$county", "$text");\n!;
+ }
+ $script_html .= "}\n";
+ }
+ $script_html .= "}\n";
+ }
+ }
+
+ $script_html .= <<END;
+ }
+ </SCRIPT>
+END
+
+ my $county_html = $script_html;
+ if ( $countyflag ) {
+ $county_html .= qq!<SELECT NAME="${prefix}county" onChange="$onchange">!;
+ $county_html .= '</SELECT>';
+ } else {
+ $county_html .=
+ qq!<INPUT TYPE="hidden" NAME="${prefix}county" VALUE="$selected_county">!;
+ }
+
+ my $state_html = qq!<SELECT NAME="${prefix}state" !.
+ qq!onChange="${prefix}state_changed(this); $onchange">!;
+ foreach my $state ( sort keys %{ $cust_main_county{$selected_country} } ) {
+ my $text = $state || '(n/a)';
+ my $selected = $state eq $selected_state ? 'SELECTED' : '';
+ $state_html .= "\n<OPTION $selected VALUE=$state>$text</OPTION>"
+ }
+ $state_html .= '</SELECT>';
+
+ $state_html .= '</SELECT>';
+
+ my $country_html = qq!<SELECT NAME="${prefix}country" !.
+ qq!onChange="${prefix}country_changed(this); $onchange">!;
+ my $countrydefault = $conf->config('countrydefault') || 'US';
+ foreach my $country (
+ sort { ($b eq $countrydefault) <=> ($a eq $countrydefault) or $a cmp $b }
+ keys %cust_main_county
+ ) {
+ my $selected = $country eq $selected_country ? ' SELECTED' : '';
+ $country_html .= "\n<OPTION$selected>$country</OPTION>"
+ }
+ $country_html .= '</SELECT>';
+
+ ($county_html, $state_html, $country_html);
+
+}
+
+=back
+
+=head1 BUGS
+
+regionselector? putting web ui components in here? they should probably live
+somewhere else...
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_main>, L<FS::cust_bill>, schema.html from the base
+documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_main_invoice.pm b/FS/FS/cust_main_invoice.pm
new file mode 100644
index 0000000..add0cca
--- /dev/null
+++ b/FS/FS/cust_main_invoice.pm
@@ -0,0 +1,177 @@
+package FS::cust_main_invoice;
+
+use strict;
+use vars qw(@ISA $conf);
+use Exporter;
+use FS::Record qw( qsearchs );
+use FS::Conf;
+use FS::cust_main;
+use FS::svc_acct;
+use FS::Msgcat qw(gettext);
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::cust_main_invoice - Object methods for cust_main_invoice records
+
+=head1 SYNOPSIS
+
+ use FS::cust_main_invoice;
+
+ $record = new FS::cust_main_invoice \%hash;
+ $record = new FS::cust_main_invoice { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $email_address = $record->address;
+
+=head1 DESCRIPTION
+
+An FS::cust_main_invoice object represents an invoice destination. FS::cust_main_invoice inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item destnum - primary key
+
+=item custnum - customer (see L<FS::cust_main>)
+
+=item dest - Invoice destination: If numeric, a svcnum (see L<FS::svc_acct>), if string, a literal email address, or `POST' to enable mailing (the default if no cust_main_invoice records exist)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new invoice destination. To add the invoice destination to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'cust_main_invoice'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+
+ return "Can't change custnum!" unless $old->custnum == $new->custnum;
+
+ $new->SUPER::replace($old);
+}
+
+
+=item check
+
+Checks all fields to make sure this is a valid invoice destination. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and repalce methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error = $self->ut_numbern('destnum')
+ || $self->ut_number('custnum')
+ || $self->checkdest;
+ ;
+ return $error if $error;
+
+ return "Unknown customer"
+ unless qsearchs('cust_main',{ 'custnum' => $self->custnum });
+
+ $self->SUPER::check;
+}
+
+=item checkdest
+
+Checks the dest field only.
+
+#If it finds that the account ends in the
+#same domain configured as the B<domain> configuration file, it will change the
+#invoice destination from an email address to a service number (see
+#L<FS::svc_acct>).
+
+=cut
+
+sub checkdest {
+ my $self = shift;
+
+ my $error = $self->ut_text('dest');
+ return $error if $error;
+
+ if ( $self->dest eq 'POST' ) {
+ #contemplate our navel
+ } elsif ( $self->dest =~ /^(\d+)$/ ) {
+ return "Unknown local account (specified by svcnum: ". $self->dest. ")"
+ unless qsearchs( 'svc_acct', { 'svcnum' => $self->dest } );
+ } elsif ( $self->dest =~ /^([\w\.\-\&\+]+)\@(([\w\.\-]+\.)+\w+)$/ ) {
+ my($user, $domain) = ($1, $2);
+ $self->dest("$1\@$2");
+ } else {
+ return gettext("illegal_email_invoice_address");
+ }
+
+ ''; #no error
+}
+
+=item address
+
+Returns the literal email address for this record (or `POST').
+
+=cut
+
+sub address {
+ my $self = shift;
+ if ( $self->dest =~ /^(\d+)$/ ) {
+ my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $1 } )
+ or return undef;
+ $svc_acct->email;
+ } else {
+ $self->dest;
+ }
+}
+
+=back
+
+=head1 VERSION
+
+$Id: cust_main_invoice.pm,v 1.14 2003-08-05 00:20:42 khoff Exp $
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_main>
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm
new file mode 100644
index 0000000..ba9924f
--- /dev/null
+++ b/FS/FS/cust_pay.pm
@@ -0,0 +1,427 @@
+package FS::cust_pay;
+
+use strict;
+use vars qw( @ISA $conf $unsuspendauto );
+use Date::Format;
+use Business::CreditCard;
+use FS::UID qw( dbh );
+use FS::Record qw( dbh qsearch qsearchs dbh );
+use FS::Misc qw(send_email);
+use FS::cust_bill;
+use FS::cust_bill_pay;
+use FS::cust_main;
+
+@ISA = qw( FS::Record );
+
+#ask FS::UID to run this stuff for us later
+FS::UID->install_callback( sub {
+ $conf = new FS::Conf;
+ $unsuspendauto = $conf->exists('unsuspendauto');
+} );
+
+=head1 NAME
+
+FS::cust_pay - Object methods for cust_pay objects
+
+=head1 SYNOPSIS
+
+ use FS::cust_pay;
+
+ $record = new FS::cust_pay \%hash;
+ $record = new FS::cust_pay { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_pay object represents a payment; the transfer of money from a
+customer. FS::cust_pay inherits from FS::Record. The following fields are
+currently supported:
+
+=over 4
+
+=item paynum - primary key (assigned automatically for new payments)
+
+=item custnum - customer (see L<FS::cust_main>)
+
+=item paid - Amount of this payment
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH),
+`LECB' (phone bill billing), `BILL' (billing), or `COMP' (free)
+
+=item payinfo - card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively
+
+=item paybatch - text field for tracking card processing
+
+=item closed - books closed flag, empty or `Y'
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new payment. To add the payment to the databse, see L<"insert">.
+
+=cut
+
+sub table { 'cust_pay'; }
+
+=item insert
+
+Adds this payment to the database.
+
+For backwards-compatibility and convenience, if the additional field invnum
+is defined, an FS::cust_bill_pay record for the full amount of the payment
+will be created. In this case, custnum is optional.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ if ( $self->invnum ) {
+ my $cust_bill = qsearchs('cust_bill', { 'invnum' => $self->invnum } )
+ or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "Unknown cust_bill.invnum: ". $self->invnum;
+ };
+ $self->custnum($cust_bill->custnum );
+ }
+
+ my $cust_main = qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+ my $old_balance = $cust_main->balance;
+
+ my $error = $self->check;
+ return $error if $error;
+
+ $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error inserting $self: $error";
+ }
+
+ if ( $self->invnum ) {
+ my $cust_bill_pay = new FS::cust_bill_pay {
+ 'invnum' => $self->invnum,
+ 'paynum' => $self->paynum,
+ 'amount' => $self->paid,
+ '_date' => $self->_date,
+ };
+ $error = $cust_bill_pay->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error inserting $cust_bill_pay: $error";
+ }
+ }
+
+ if ( $self->paybatch =~ /^webui-/ ) {
+ my @cust_pay = qsearch('cust_pay', {
+ 'custnum' => $self->custnum,
+ 'paybatch' => $self->paybatch,
+ } );
+ if ( scalar(@cust_pay) > 1 ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "a payment with webui token ". $self->paybatch. " already exists";
+ }
+ }
+
+ #false laziness w/ cust_credit::insert
+ if ( $unsuspendauto && $old_balance && $cust_main->balance <= 0 ) {
+ my @errors = $cust_main->unsuspend;
+ #return
+ # side-fx with nested transactions? upstack rolls back?
+ warn "WARNING:Errors unsuspending customer ". $cust_main->custnum. ": ".
+ join(' / ', @errors)
+ if @errors;
+ }
+ #eslaf
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+sub upgrade_replace { #1.3.x->1.4.x
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->check;
+ return $error if $error;
+
+ my %new = $self->hash;
+ my $new = FS::cust_pay->new(\%new);
+
+ if ( $self->invnum ) {
+ my $cust_bill_pay = new FS::cust_bill_pay {
+ 'invnum' => $self->invnum,
+ 'paynum' => $self->paynum,
+ 'amount' => $self->paid,
+ '_date' => $self->_date,
+ };
+ $error = $cust_bill_pay->insert;
+ if ( $error =~
+ /total cust_bill_pay.amount and cust_credit_bill.amount .* for invnum .* greater than cust_bill.charged/ ) {
+ #warn $error;
+ my $cust_bill = qsearchs( 'cust_bill', { 'invnum' => $self->invnum } );
+ $new->custnum($cust_bill->custnum);
+ } elsif ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ } else {
+ $new->custnum($cust_bill_pay->cust_bill->custnum);
+ }
+ } else {
+ die;
+ }
+
+ $error = $new->SUPER::replace($self);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+
+}
+
+=item delete
+
+Deletes this payment and all associated applications (see L<FS::cust_bill_pay>),
+unless the closed flag is set.
+
+=cut
+
+sub delete {
+ my $self = shift;
+ return "Can't delete closed payment" if $self->closed =~ /^Y/i;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $cust_bill_pay ( $self->cust_bill_pay ) {
+ my $error = $cust_bill_pay->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ my $error = $self->SUPER::delete(@_);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ if ( $conf->config('deletepayments') ne '' ) {
+
+ my $cust_main = qsearchs('cust_main',{ 'custnum' => $self->custnum });
+
+ my $error = send_email(
+ 'from' => $conf->config('invoice_from'), #??? well as good as any
+ 'to' => $conf->config('deletepayments'),
+ 'subject' => 'FREESIDE NOTIFICATION: Payment deleted',
+ 'body' => [
+ "This is an automatic message from your Freeside installation\n",
+ "informing you that the following payment has been deleted:\n",
+ "\n",
+ 'paynum: '. $self->paynum. "\n",
+ 'custnum: '. $self->custnum.
+ " (". $cust_main->last. ", ". $cust_main->first. ")\n",
+ 'paid: $'. sprintf("%.2f", $self->paid). "\n",
+ 'date: '. time2str("%a %b %e %T %Y", $self->_date). "\n",
+ 'payby: '. $self->payby. "\n",
+ 'payinfo: '. $self->payinfo. "\n",
+ 'paybatch: '. $self->paybatch. "\n",
+ ],
+ );
+
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't send payment deletion notification: $error";
+ }
+
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item replace OLD_RECORD
+
+Currently unimplemented (accounting reasons).
+
+=cut
+
+sub replace {
+ return "Can't (yet?) modify cust_pay records!";
+}
+
+=item check
+
+Checks all fields to make sure this is a valid payment. If there is an error,
+returns the error, otherwise returns false. Called by the insert method.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('paynum')
+ || $self->ut_numbern('custnum')
+ || $self->ut_money('paid')
+ || $self->ut_numbern('_date')
+ || $self->ut_textn('paybatch')
+ || $self->ut_enum('closed', [ '', 'Y' ])
+ ;
+ return $error if $error;
+
+ return "paid must be > 0 " if $self->paid <= 0;
+
+ return "unknown cust_main.custnum: ". $self->custnum
+ unless $self->invnum
+ || qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+
+ $self->_date(time) unless $self->_date;
+
+ $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP)$/ or return "Illegal payby";
+ $self->payby($1);
+
+ #false laziness with cust_refund::check
+ if ( $self->payby eq 'CARD' ) {
+ my $payinfo = $self->payinfo;
+ $payinfo =~ s/\D//g;
+ $self->payinfo($payinfo);
+ if ( $self->payinfo ) {
+ $self->payinfo =~ /^(\d{13,16})$/
+ or return "Illegal (mistyped?) credit card number (payinfo)";
+ $self->payinfo($1);
+ validate($self->payinfo) or return "Illegal credit card number";
+ return "Unknown card type" if cardtype($self->payinfo) eq "Unknown";
+ } else {
+ $self->payinfo('N/A');
+ }
+
+ } else {
+ $error = $self->ut_textn('payinfo');
+ return $error if $error;
+ }
+
+ $self->SUPER::check;
+}
+
+=item cust_bill_pay
+
+Returns all applications to invoices (see L<FS::cust_bill_pay>) for this
+payment.
+
+=cut
+
+sub cust_bill_pay {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_bill_pay', { 'paynum' => $self->paynum } )
+ ;
+}
+
+=item unapplied
+
+Returns the amount of this payment that is still unapplied; which is
+paid minus all payment applications (see L<FS::cust_bill_pay>).
+
+=cut
+
+sub unapplied {
+ my $self = shift;
+ my $amount = $self->paid;
+ $amount -= $_->amount foreach ( $self->cust_bill_pay );
+ sprintf("%.2f", $amount );
+}
+
+=item cust_main
+
+Returns the parent customer object (see L<FS::cust_main>).
+
+=cut
+
+sub cust_main {
+ my $self = shift;
+ qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+}
+
+=item payinfo_masked
+
+Returns a "masked" payinfo field with all but the last four characters replaced
+by 'x'es. Useful for displaying credit cards.
+
+=cut
+
+sub payinfo_masked {
+ my $self = shift;
+ my $payinfo = $self->payinfo;
+ 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4));
+}
+
+=back
+
+=head1 BUGS
+
+Delete and replace methods. payinfo_masked false laziness with cust_main.pm
+and cust_refund.pm
+
+=head1 SEE ALSO
+
+L<FS::cust_bill_pay>, L<FS::cust_bill>, L<FS::Record>, schema.html from the
+base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_pay_batch.pm b/FS/FS/cust_pay_batch.pm
new file mode 100644
index 0000000..8059f1c
--- /dev/null
+++ b/FS/FS/cust_pay_batch.pm
@@ -0,0 +1,397 @@
+package FS::cust_pay_batch;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw(dbh qsearchs);
+use Business::CreditCard;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::cust_pay_batch - Object methods for batch cards
+
+=head1 SYNOPSIS
+
+ use FS::cust_pay_batch;
+
+ $record = new FS::cust_pay_batch \%hash;
+ $record = new FS::cust_pay_batch { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_pay_batch object represents a credit card transaction ready to be
+batched (sent to a processor). FS::cust_pay_batch inherits from FS::Record.
+Typically called by the collect method of an FS::cust_main object. The
+following fields are currently supported:
+
+=over 4
+
+=item paybatchnum - primary key (automatically assigned)
+
+=item cardnum
+
+=item exp - card expiration
+
+=item amount
+
+=item invnum - invoice
+
+=item custnum - customer
+
+=item payname - name on card
+
+=item first - name
+
+=item last - name
+
+=item address1
+
+=item address2
+
+=item city
+
+=item state
+
+=item zip
+
+=item country
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record. To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'cust_pay_batch'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item replace OLD_RECORD
+
+#inactive
+#
+#Replaces the OLD_RECORD with this one in the database. If there is an error,
+#returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ return "Can't (yet?) replace batched transactions!";
+}
+
+=item check
+
+Checks all fields to make sure this is a valid transaction. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and repalce methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('paybatchnum')
+ || $self->ut_numbern('trancode') #depriciated
+ || $self->ut_number('cardnum')
+ || $self->ut_money('amount')
+ || $self->ut_number('invnum')
+ || $self->ut_number('custnum')
+ || $self->ut_text('address1')
+ || $self->ut_textn('address2')
+ || $self->ut_text('city')
+ || $self->ut_textn('state')
+ ;
+
+ return $error if $error;
+
+ $self->getfield('last') =~ /^([\w \,\.\-\']+)$/ or return "Illegal last name";
+ $self->setfield('last',$1);
+
+ $self->first =~ /^([\w \,\.\-\']+)$/ or return "Illegal first name";
+ $self->first($1);
+
+ my $cardnum = $self->cardnum;
+ $cardnum =~ s/\D//g;
+ $cardnum =~ /^(\d{13,16})$/
+ or return "Illegal credit card number";
+ $cardnum = $1;
+ $self->cardnum($cardnum);
+ validate($cardnum) or return "Illegal credit card number";
+ return "Unknown card type" if cardtype($cardnum) eq "Unknown";
+
+ if ( $self->exp eq '' ) {
+ return "Expriation date required"; #unless
+ $self->exp('');
+ } else {
+ if ( $self->exp =~ /^(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})$/ ) {
+ $self->exp("$1-$2-$3");
+ } elsif ( $self->exp =~ /^(\d{1,2})[\/\-](\d{2}(\d{2})?)$/ ) {
+ if ( length($2) == 4 ) {
+ $self->exp("$2-$1-01");
+ } elsif ( $2 > 98 ) { #should pry change to check for "this year"
+ $self->exp("19$2-$1-01");
+ } else {
+ $self->exp("20$2-$1-01");
+ }
+ } else {
+ return "Illegal expiration date";
+ }
+ }
+
+ if ( $self->payname eq '' ) {
+ $self->payname( $self->first. " ". $self->getfield('last') );
+ } else {
+ $self->payname =~ /^([\w \,\.\-\']+)$/
+ or return "Illegal billing name";
+ $self->payname($1);
+ }
+
+ #$self->zip =~ /^\s*(\w[\w\-\s]{3,8}\w)\s*$/
+ # or return "Illegal zip: ". $self->zip;
+ #$self->zip($1);
+
+ $self->country =~ /^(\w\w)$/ or return "Illegal country: ". $self->country;
+ $self->country($1);
+
+ $error = $self->ut_zip('zip', $self->country);
+ return $error if $error;
+
+ #check invnum, custnum, ?
+
+ $self->SUPER::check;
+}
+
+=item cust_main
+
+Returns the customer (see L<FS::cust_main>) for this batched credit card
+payment.
+
+=cut
+
+sub cust_main {
+ my $self = shift;
+ qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+}
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item import_results
+
+=cut
+
+sub import_results {
+ use Time::Local;
+ use FS::cust_pay;
+ eval "use Text::CSV_XS;";
+ die $@ if $@;
+#
+ my $param = shift;
+ my $fh = $param->{'filehandle'};
+ my $format = $param->{'format'};
+ my $paybatch = $param->{'paybatch'};
+
+ my @fields;
+ my $end_condition;
+ my $end_hook;
+ my $hook;
+ my $approved_condition;
+ my $declined_condition;
+
+ if ( $format eq 'csv-td_canada_trust-merchant_pc_batch' ) {
+
+ @fields = (
+ 'paybatchnum', # Reference#: Invoice number of the transaction
+ 'paid', # Amount: Amount of the transaction. Dollars and cents
+ # with no decimal entered.
+ '', # Card Type: 0 - MCrd, 1 - Visa, 2 - AMEX, 3 - Discover,
+ # 4 - Insignia, 5 - Diners/EnRoute, 6 - JCB
+ '_date', # Transaction Date: Date the Transaction was processed
+ 'time', # Transaction Time: Time the transaction was processed
+ 'payinfo', # Card Number: Card number for the transaction
+ '', # Expiry Date: Expiry date of the card
+ '', # Auth#: Authorization number entered for force post
+ # transaction
+ 'type', # Transaction Type: 0 - purchase, 40 - refund,
+ # 20 - force post
+ 'result', # Processing Result: 3 - Approval,
+ # 4 - Declined/Amount over limit,
+ # 5 - Invalid/Expired/stolen card,
+ # 6 - Comm Error
+ '', # Terminal ID: Terminal ID used to process the transaction
+ );
+
+ $end_condition = sub {
+ my $hash = shift;
+ $hash->{'type'} eq '0BC';
+ };
+
+ $end_hook = sub {
+ my( $hash, $total) = @_;
+ $total = sprintf("%.2f", $total);
+ my $batch_total = sprintf("%.2f", $hash->{'paybatchnum'} / 100 );
+ return "Our total $total does not match bank total $batch_total!"
+ if $total != $batch_total;
+ '';
+ };
+
+ $hook = sub {
+ my $hash = shift;
+ $hash->{'paid'} = sprintf("%.2f", $hash->{'paid'} / 100 );
+ $hash->{'_date'} = timelocal( substr($hash->{'time'}, 4, 2),
+ substr($hash->{'time'}, 2, 2),
+ substr($hash->{'time'}, 0, 2),
+ substr($hash->{'_date'}, 6, 2),
+ substr($hash->{'_date'}, 4, 2)-1,
+ substr($hash->{'_date'}, 0, 4)-1900, );
+ };
+
+ $approved_condition = sub {
+ my $hash = shift;
+ $hash->{'type'} eq '0' && $hash->{'result'} == 3;
+ };
+
+ $declined_condition = sub {
+ my $hash = shift;
+ $hash->{'type'} eq '0' && ( $hash->{'result'} == 4
+ || $hash->{'result'} == 5 );
+ };
+
+
+ } else {
+ return "Unknown format $format";
+ }
+
+ my $csv = new Text::CSV_XS;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $total = 0;
+ my $line;
+ while ( defined($line=<$fh>) ) {
+
+ next if $line =~ /^\s*$/; #skip blank lines
+
+ $csv->parse($line) or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't parse: ". $csv->error_input();
+ };
+
+ my @values = $csv->fields();
+ my %hash;
+ foreach my $field ( @fields ) {
+ my $value = shift @values;
+ next unless $field;
+ $hash{$field} = $value;
+ }
+
+ if ( &{$end_condition}(\%hash) ) {
+ my $error = &{$end_hook}(\%hash, $total);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ last;
+ }
+
+ my $cust_pay_batch =
+ qsearchs('cust_pay_batch', { 'paybatchnum' => $hash{'paybatchnum'} } );
+ unless ( $cust_pay_batch ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "unknown paybatchnum $hash{'paybatchnum'}\n";
+ }
+ my $custnum = $cust_pay_batch->custnum,
+
+ my $error = $cust_pay_batch->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error removing paybatchnum $hash{'paybatchnum'}: $error\n";
+ }
+
+ &{$hook}(\%hash);
+
+ if ( &{$approved_condition}(\%hash) ) {
+
+ my $cust_pay = new FS::cust_pay ( {
+ 'custnum' => $custnum,
+ 'payby' => 'CARD',
+ 'paybatch' => $paybatch,
+ map { $_ => $hash{$_} } (qw( paid _date payinfo )),
+ } );
+ $error = $cust_pay->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error adding payment paybatchnum $hash{'paybatchnum'}: $error\n";
+ }
+ $total += $hash{'paid'};
+
+ $cust_pay->cust_main->apply_payments;
+
+ } elsif ( &{$declined_condition}(\%hash) ) {
+
+ #this should be configurable... if anybody else ever uses batches
+ $cust_pay_batch->cust_main->suspend;
+
+ }
+
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=back
+
+=head1 BUGS
+
+There should probably be a configuration file with a list of allowed credit
+card types.
+
+=head1 SEE ALSO
+
+L<FS::cust_main>, L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
new file mode 100644
index 0000000..db0f7d4
--- /dev/null
+++ b/FS/FS/cust_pkg.pm
@@ -0,0 +1,926 @@
+package FS::cust_pkg;
+
+use strict;
+use vars qw(@ISA $disable_agentcheck @SVCDB_CANCEL_SEQ $DEBUG);
+use FS::UID qw( getotaker dbh );
+use FS::Record qw( qsearch qsearchs );
+use FS::Misc qw( send_email );
+use FS::cust_svc;
+use FS::part_pkg;
+use FS::cust_main;
+use FS::type_pkgs;
+use FS::pkg_svc;
+use FS::cust_bill_pkg;
+
+# need to 'use' these instead of 'require' in sub { cancel, suspend, unsuspend,
+# setup }
+# because they load configuraion by setting FS::UID::callback (see TODO)
+use FS::svc_acct;
+use FS::svc_domain;
+use FS::svc_www;
+use FS::svc_forward;
+
+# for sending cancel emails in sub cancel
+use FS::Conf;
+
+@ISA = qw( FS::Record );
+
+$DEBUG = 0;
+
+$disable_agentcheck = 0;
+
+# The order in which to unprovision services.
+@SVCDB_CANCEL_SEQ = qw( svc_external
+ svc_www
+ svc_forward
+ svc_acct
+ svc_domain
+ svc_broadband );
+
+sub _cache {
+ my $self = shift;
+ my ( $hashref, $cache ) = @_;
+ #if ( $hashref->{'pkgpart'} ) {
+ if ( $hashref->{'pkg'} ) {
+ # #@{ $self->{'_pkgnum'} } = ();
+ # my $subcache = $cache->subcache('pkgpart', 'part_pkg');
+ # $self->{'_pkgpart'} = $subcache;
+ # #push @{ $self->{'_pkgnum'} },
+ # FS::part_pkg->new_or_cached($hashref, $subcache);
+ $self->{'_pkgpart'} = FS::part_pkg->new($hashref);
+ }
+ if ( exists $hashref->{'svcnum'} ) {
+ #@{ $self->{'_pkgnum'} } = ();
+ my $subcache = $cache->subcache('svcnum', 'cust_svc', $hashref->{pkgnum});
+ $self->{'_svcnum'} = $subcache;
+ #push @{ $self->{'_pkgnum'} },
+ FS::cust_svc->new_or_cached($hashref, $subcache) if $hashref->{svcnum};
+ }
+}
+
+=head1 NAME
+
+FS::cust_pkg - Object methods for cust_pkg objects
+
+=head1 SYNOPSIS
+
+ use FS::cust_pkg;
+
+ $record = new FS::cust_pkg \%hash;
+ $record = new FS::cust_pkg { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->cancel;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $part_pkg = $record->part_pkg;
+
+ @labels = $record->labels;
+
+ $seconds = $record->seconds_since($timestamp);
+
+ $error = FS::cust_pkg::order( $custnum, \@pkgparts );
+ $error = FS::cust_pkg::order( $custnum, \@pkgparts, \@remove_pkgnums ] );
+
+=head1 DESCRIPTION
+
+An FS::cust_pkg object represents a customer billing item. FS::cust_pkg
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item pkgnum - primary key (assigned automatically for new billing items)
+
+=item custnum - Customer (see L<FS::cust_main>)
+
+=item pkgpart - Billing item definition (see L<FS::part_pkg>)
+
+=item setup - date
+
+=item bill - date (next bill date)
+
+=item last_bill - last bill date
+
+=item susp - date
+
+=item expire - date
+
+=item cancel - date
+
+=item otaker - order taker (assigned automatically if null, see L<FS::UID>)
+
+=item manual_flag - If this field is set to 1, disables the automatic
+unsuspension of this package when using the B<unsuspendauto> config file.
+
+=back
+
+Note: setup, bill, susp, expire and cancel are specified as UNIX timestamps;
+see L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for
+conversion functions.
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new billing item. To add the item to the database, see L<"insert">.
+
+=cut
+
+sub table { 'cust_pkg'; }
+
+=item insert
+
+Adds this billing item to the database ("Orders" the item). If there is an
+error, returns the error, otherwise returns false.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ # custnum might not have have been defined in sub check (for one-shot new
+ # customers), so check it here instead
+ # (is this still necessary with transactions?)
+
+ my $error = $self->ut_number('custnum');
+ return $error if $error;
+
+ my $cust_main = $self->cust_main;
+ return "Unknown custnum: ". $self->custnum unless $cust_main;
+
+ unless ( $disable_agentcheck ) {
+ my $agent = qsearchs( 'agent', { 'agentnum' => $cust_main->agentnum } );
+ my $pkgpart_href = $agent->pkgpart_hashref;
+ return "agent ". $agent->agentnum.
+ " can't purchase pkgpart ". $self->pkgpart
+ unless $pkgpart_href->{ $self->pkgpart };
+ }
+
+ $self->SUPER::insert;
+
+}
+
+=item delete
+
+This method now works but you probably shouldn't use it.
+
+You don't want to delete billing items, because there would then be no record
+the customer ever purchased the item. Instead, see the cancel method.
+
+=cut
+
+#sub delete {
+# return "Can't delete cust_pkg records!";
+#}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+Currently, custnum, setup, bill, susp, expire, and cancel may be changed.
+
+Changing pkgpart may have disasterous effects. See the order subroutine.
+
+setup and bill are normally updated by calling the bill method of a customer
+object (see L<FS::cust_main>).
+
+suspend is normally updated by the suspend and unsuspend methods.
+
+cancel is normally updated by the cancel method (and also the order subroutine
+in some cases).
+
+=cut
+
+sub replace {
+ my( $new, $old ) = ( shift, shift );
+
+ #return "Can't (yet?) change pkgpart!" if $old->pkgpart != $new->pkgpart;
+ return "Can't change otaker!" if $old->otaker ne $new->otaker;
+
+ #allow this *sigh*
+ #return "Can't change setup once it exists!"
+ # if $old->getfield('setup') &&
+ # $old->getfield('setup') != $new->getfield('setup');
+
+ #some logic for bill, susp, cancel?
+
+ $new->SUPER::replace($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid billing item. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('pkgnum')
+ || $self->ut_numbern('custnum')
+ || $self->ut_number('pkgpart')
+ || $self->ut_numbern('setup')
+ || $self->ut_numbern('bill')
+ || $self->ut_numbern('susp')
+ || $self->ut_numbern('cancel')
+ ;
+ return $error if $error;
+
+ if ( $self->custnum ) {
+ return "Unknown customer ". $self->custnum unless $self->cust_main;
+ }
+
+ return "Unknown pkgpart: ". $self->pkgpart
+ unless qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
+
+ $self->otaker(getotaker) unless $self->otaker;
+ $self->otaker =~ /^([\w\.\-]{0,16})$/ or return "Illegal otaker";
+ $self->otaker($1);
+
+ if ( $self->dbdef_table->column('manual_flag') ) {
+ $self->manual_flag('') if $self->manual_flag eq ' ';
+ $self->manual_flag =~ /^([01]?)$/
+ or return "Illegal manual_flag ". $self->manual_flag;
+ $self->manual_flag($1);
+ }
+
+ $self->SUPER::check;
+}
+
+=item cancel [ OPTION => VALUE ... ]
+
+Cancels and removes all services (see L<FS::cust_svc> and L<FS::part_svc>)
+in this package, then cancels the package itself (sets the cancel field to
+now).
+
+Available options are: I<quiet>
+
+I<quiet> can be set true to supress email cancellation notices.
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub cancel {
+ my( $self, %options ) = @_;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my %svc;
+ foreach my $cust_svc (
+ qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } )
+ ) {
+ push @{ $svc{$cust_svc->part_svc->svcdb} }, $cust_svc;
+ }
+
+ foreach my $svcdb (@SVCDB_CANCEL_SEQ) {
+ foreach my $cust_svc (@{ $svc{$svcdb} }) {
+ my $error = $cust_svc->cancel;
+
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Error cancelling cust_svc: $error";
+ }
+ }
+ }
+
+ unless ( $self->getfield('cancel') ) {
+ my %hash = $self->hash;
+ $hash{'cancel'} = time;
+ my $new = new FS::cust_pkg ( \%hash );
+ $error = $new->replace($self);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ my $conf = new FS::Conf;
+ my @invoicing_list = grep { $_ ne 'POST' } $self->cust_main->invoicing_list;
+ if ( !$options{'quiet'} && $conf->exists('emailcancel') && @invoicing_list ) {
+ my $conf = new FS::Conf;
+ my $error = send_email(
+ 'from' => $conf->config('invoice_from'),
+ 'to' => \@invoicing_list,
+ 'subject' => $conf->config('cancelsubject'),
+ 'body' => [ map "$_\n", $conf->config('cancelmessage') ],
+ );
+ #should this do something on errors?
+ }
+
+ ''; #no errors
+
+}
+
+=item suspend
+
+Suspends all services (see L<FS::cust_svc> and L<FS::part_svc>) in this
+package, then suspends the package itself (sets the susp field to now).
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub suspend {
+ my $self = shift;
+ my $error ;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $cust_svc (
+ qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } )
+ ) {
+ my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $cust_svc->svcpart } );
+
+ $part_svc->svcdb =~ /^([\w\-]+)$/ or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "Illegal svcdb value in part_svc!";
+ };
+ my $svcdb = $1;
+ require "FS/$svcdb.pm";
+
+ my $svc = qsearchs( $svcdb, { 'svcnum' => $cust_svc->svcnum } );
+ if ($svc) {
+ $error = $svc->suspend;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ }
+
+ unless ( $self->getfield('susp') ) {
+ my %hash = $self->hash;
+ $hash{'susp'} = time;
+ my $new = new FS::cust_pkg ( \%hash );
+ $error = $new->replace($self);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ ''; #no errors
+}
+
+=item unsuspend
+
+Unsuspends all services (see L<FS::cust_svc> and L<FS::part_svc>) in this
+package, then unsuspends the package itself (clears the susp field).
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub unsuspend {
+ my $self = shift;
+ my($error);
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $cust_svc (
+ qsearch('cust_svc',{'pkgnum'=> $self->pkgnum } )
+ ) {
+ my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $cust_svc->svcpart } );
+
+ $part_svc->svcdb =~ /^([\w\-]+)$/ or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "Illegal svcdb value in part_svc!";
+ };
+ my $svcdb = $1;
+ require "FS/$svcdb.pm";
+
+ my $svc = qsearchs( $svcdb, { 'svcnum' => $cust_svc->svcnum } );
+ if ($svc) {
+ $error = $svc->unsuspend;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ }
+
+ unless ( ! $self->getfield('susp') ) {
+ my %hash = $self->hash;
+ $hash{'susp'} = '';
+ my $new = new FS::cust_pkg ( \%hash );
+ $error = $new->replace($self);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ ''; #no errors
+}
+
+=item last_bill
+
+Returns the last bill date, or if there is no last bill date, the setup date.
+Useful for billing metered services.
+
+=cut
+
+sub last_bill {
+ my $self = shift;
+ if ( $self->dbdef_table->column('last_bill') ) {
+ return $self->setfield('last_bill', $_[0]) if @_;
+ return $self->getfield('last_bill') if $self->getfield('last_bill');
+ }
+ my $cust_bill_pkg = qsearchs('cust_bill_pkg', { 'pkgnum' => $self->pkgnum,
+ 'edate' => $self->bill, } );
+ $cust_bill_pkg ? $cust_bill_pkg->sdate : $self->setup || 0;
+}
+
+=item part_pkg
+
+Returns the definition for this billing item, as an FS::part_pkg object (see
+L<FS::part_pkg>).
+
+=cut
+
+sub part_pkg {
+ my $self = shift;
+ #exists( $self->{'_pkgpart'} )
+ $self->{'_pkgpart'}
+ ? $self->{'_pkgpart'}
+ : qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
+}
+
+=item cust_svc
+
+Returns the services for this package, as FS::cust_svc objects (see
+L<FS::cust_svc>)
+
+=cut
+
+sub cust_svc {
+ my $self = shift;
+ #if ( $self->{'_svcnum'} ) {
+ # values %{ $self->{'_svcnum'}->cache };
+ #} else {
+ map { $_->[0] }
+ sort { $b->[1] cmp $a->[1] or $a->[2] <=> $b->[2] }
+ map {
+ my $pkg_svc = qsearchs( 'pkg_svc', { 'pkgpart' => $self->pkgpart,
+ 'svcpart' => $_->svcpart } );
+ [ $_,
+ $pkg_svc ? $pkg_svc->primary_svc : '',
+ $pkg_svc ? $pkg_svc->quantity : 0,
+ ];
+ }
+ qsearch ( 'cust_svc', { 'pkgnum' => $self->pkgnum } );
+ #}
+}
+
+=item labels
+
+Returns a list of lists, calling the label method for all services
+(see L<FS::cust_svc>) of this billing item.
+
+=cut
+
+sub labels {
+ my $self = shift;
+ map { [ $_->label ] } $self->cust_svc;
+}
+
+=item cust_main
+
+Returns the parent customer object (see L<FS::cust_main>).
+
+=cut
+
+sub cust_main {
+ my $self = shift;
+ qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+}
+
+=item seconds_since TIMESTAMP
+
+Returns the number of seconds all accounts (see L<FS::svc_acct>) in this
+package have been online since TIMESTAMP, according to the session monitor.
+
+TIMESTAMP is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=cut
+
+sub seconds_since {
+ my($self, $since) = @_;
+ my $seconds = 0;
+
+ foreach my $cust_svc (
+ grep { $_->part_svc->svcdb eq 'svc_acct' } $self->cust_svc
+ ) {
+ $seconds += $cust_svc->seconds_since($since);
+ }
+
+ $seconds;
+
+}
+
+=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END
+
+Returns the numbers of seconds all accounts (see L<FS::svc_acct>) in this
+package have been online between TIMESTAMP_START (inclusive) and TIMESTAMP_END
+(exclusive).
+
+TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see
+L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for conversion
+functions.
+
+
+=cut
+
+sub seconds_since_sqlradacct {
+ my($self, $start, $end) = @_;
+
+ my $seconds = 0;
+
+ foreach my $cust_svc (
+ grep {
+ my $part_svc = $_->part_svc;
+ $part_svc->svcdb eq 'svc_acct'
+ && scalar($part_svc->part_export('sqlradius'));
+ } $self->cust_svc
+ ) {
+ $seconds += $cust_svc->seconds_since_sqlradacct($start, $end);
+ }
+
+ $seconds;
+
+}
+
+=item attribute_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ATTRIBUTE
+
+Returns the sum of the given attribute for all accounts (see L<FS::svc_acct>)
+in this package for sessions ending between TIMESTAMP_START (inclusive) and
+TIMESTAMP_END
+(exclusive).
+
+TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see
+L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for conversion
+functions.
+
+=cut
+
+sub attribute_since_sqlradacct {
+ my($self, $start, $end, $attrib) = @_;
+
+ my $sum = 0;
+
+ foreach my $cust_svc (
+ grep {
+ my $part_svc = $_->part_svc;
+ $part_svc->svcdb eq 'svc_acct'
+ && scalar($part_svc->part_export('sqlradius'));
+ } $self->cust_svc
+ ) {
+ $sum += $cust_svc->attribute_since_sqlradacct($start, $end, $attrib);
+ }
+
+ $sum;
+
+}
+
+=item transfer DEST_PKGNUM | DEST_CUST_PKG, [ OPTION => VALUE ... ]
+
+Transfers as many services as possible from this package to another package.
+
+The destination package can be specified by pkgnum by passing an FS::cust_pkg
+object. The destination package must already exist.
+
+Services are moved only if the destination allows services with the correct
+I<svcpart> (not svcdb), unless the B<change_svcpart> option is set true. Use
+this option with caution! No provision is made for export differences
+between the old and new service definitions. Probably only should be used
+when your exports for all service definitions of a given svcdb are identical.
+(attempt a transfer without it first, to move all possible svcpart-matching
+services)
+
+Any services that can't be moved remain in the original package.
+
+Returns an error, if there is one; otherwise, returns the number of services
+that couldn't be moved.
+
+=cut
+
+sub transfer {
+ my ($self, $dest_pkgnum, %opt) = @_;
+
+ my $remaining = 0;
+ my $dest;
+ my %target;
+
+ if (ref ($dest_pkgnum) eq 'FS::cust_pkg') {
+ $dest = $dest_pkgnum;
+ $dest_pkgnum = $dest->pkgnum;
+ } else {
+ $dest = qsearchs('cust_pkg', { pkgnum => $dest_pkgnum });
+ }
+
+ return ('Package does not exist: '.$dest_pkgnum) unless $dest;
+
+ foreach my $pkg_svc ( $dest->part_pkg->pkg_svc ) {
+ $target{$pkg_svc->svcpart} = $pkg_svc->quantity;
+ }
+
+ foreach my $cust_svc ($dest->cust_svc) {
+ $target{$cust_svc->svcpart}--;
+ }
+
+ my %svcpart2svcparts = ();
+ if ( exists $opt{'change_svcpart'} && $opt{'change_svcpart'} ) {
+ warn "change_svcpart option received, creating alternates list\n" if $DEBUG;
+ foreach my $svcpart ( map { $_->svcpart } $self->cust_svc ) {
+ next if exists $svcpart2svcparts{$svcpart};
+ my $part_svc = qsearchs('part_svc', { 'svcpart' => $svcpart } );
+ $svcpart2svcparts{$svcpart} = [
+ map { $_->[0] }
+ sort { $b->[1] cmp $a->[1] or $a->[2] <=> $b->[2] }
+ map {
+ my $pkg_svc = qsearchs( 'pkg_svc', { 'pkgpart' => $dest->pkgpart,
+ 'svcpart' => $_ } );
+ [ $_,
+ $pkg_svc ? $pkg_svc->primary_svc : '',
+ $pkg_svc ? $pkg_svc->quantity : 0,
+ ];
+ }
+
+ grep { $_ != $svcpart }
+ map { $_->svcpart }
+ qsearch('part_svc', { 'svcdb' => $part_svc->svcdb } )
+ ];
+ warn "alternates for svcpart $svcpart: ".
+ join(', ', @{$svcpart2svcparts{$svcpart}}). "\n"
+ if $DEBUG;
+ }
+ }
+
+ foreach my $cust_svc ($self->cust_svc) {
+ if($target{$cust_svc->svcpart} > 0) {
+ $target{$cust_svc->svcpart}--;
+ my $new = new FS::cust_svc {
+ svcnum => $cust_svc->svcnum,
+ svcpart => $cust_svc->svcpart,
+ pkgnum => $dest_pkgnum,
+ };
+ my $error = $new->replace($cust_svc);
+ return $error if $error;
+ } elsif ( exists $opt{'change_svcpart'} && $opt{'change_svcpart'} ) {
+ if ( $DEBUG ) {
+ warn "looking for alternates for svcpart ". $cust_svc->svcpart. "\n";
+ warn "alternates to consider: ".
+ join(', ', @{$svcpart2svcparts{$cust_svc->svcpart}}). "\n";
+ }
+ my @alternate = grep {
+ warn "considering alternate svcpart $_: ".
+ "$target{$_} available in new package\n"
+ if $DEBUG;
+ $target{$_} > 0;
+ } @{$svcpart2svcparts{$cust_svc->svcpart}};
+ if ( @alternate ) {
+ warn "alternate(s) found\n" if $DEBUG;
+ my $change_svcpart = $alternate[0];
+ $target{$change_svcpart}--;
+ my $new = new FS::cust_svc {
+ svcnum => $cust_svc->svcnum,
+ svcpart => $change_svcpart,
+ pkgnum => $dest_pkgnum,
+ };
+ my $error = $new->replace($cust_svc);
+ return $error if $error;
+ } else {
+ $remaining++;
+ }
+ } else {
+ $remaining++
+ }
+ }
+ return $remaining;
+}
+
+=item reexport
+
+This method is deprecated. See the I<depend_jobnum> option to the insert and
+order_pkgs methods in FS::cust_main for a better way to defer provisioning.
+
+=cut
+
+sub reexport {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $cust_svc ( $self->cust_svc ) {
+ #false laziness w/svc_Common::insert
+ my $svc_x = $cust_svc->svc_x;
+ foreach my $part_export ( $cust_svc->part_svc->part_export ) {
+ my $error = $part_export->export_insert($svc_x);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item order CUSTNUM, PKGPARTS_ARYREF, [ REMOVE_PKGNUMS_ARYREF [ RETURN_CUST_PKG_ARRAYREF ] ]
+
+CUSTNUM is a customer (see L<FS::cust_main>)
+
+PKGPARTS is a list of pkgparts specifying the the billing item definitions (see
+L<FS::part_pkg>) to order for this customer. Duplicates are of course
+permitted.
+
+REMOVE_PKGNUMS is an optional list of pkgnums specifying the billing items to
+remove for this customer. The services (see L<FS::cust_svc>) are moved to the
+new billing items. An error is returned if this is not possible (see
+L<FS::pkg_svc>). An empty arrayref is equivalent to not specifying this
+parameter.
+
+RETURN_CUST_PKG_ARRAYREF, if specified, will be filled in with the
+newly-created cust_pkg objects.
+
+=cut
+
+sub order {
+ my ($custnum, $pkgparts, $remove_pkgnum, $return_cust_pkg) = @_;
+
+ my $conf = new FS::Conf;
+
+ # Transactionize this whole mess
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error;
+ my $cust_main = qsearchs('cust_main', { custnum => $custnum });
+ return "Customer not found: $custnum" unless $cust_main;
+
+ # Create the new packages.
+ my $cust_pkg;
+ foreach (@$pkgparts) {
+ $cust_pkg = new FS::cust_pkg { custnum => $custnum,
+ pkgpart => $_ };
+ $error = $cust_pkg->insert;
+ if ($error) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ push @$return_cust_pkg, $cust_pkg;
+ }
+ # $return_cust_pkg now contains refs to all of the newly
+ # created packages.
+
+ # Transfer services and cancel old packages.
+ foreach my $old_pkgnum (@$remove_pkgnum) {
+ my $old_pkg = qsearchs ('cust_pkg', { pkgnum => $old_pkgnum });
+
+ foreach my $new_pkg (@$return_cust_pkg) {
+ $error = $old_pkg->transfer($new_pkg);
+ if ($error and $error == 0) {
+ # $old_pkg->transfer failed.
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ if ( $error > 0 && $conf->exists('cust_pkg-change_svcpart') ) {
+ warn "trying transfer again with change_svcpart option\n" if $DEBUG;
+ foreach my $new_pkg (@$return_cust_pkg) {
+ $error = $old_pkg->transfer($new_pkg, 'change_svcpart'=>1 );
+ if ($error and $error == 0) {
+ # $old_pkg->transfer failed.
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ if ($error > 0) {
+ # Transfers were successful, but we went through all of the
+ # new packages and still had services left on the old package.
+ # We can't cancel the package under the circumstances, so abort.
+ $dbh->rollback if $oldAutoCommit;
+ return "Unable to transfer all services from package ".$old_pkg->pkgnum;
+ }
+ $error = $old_pkg->cancel;
+ if ($error) {
+ $dbh->rollback;
+ return $error;
+ }
+ }
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+}
+
+=back
+
+=head1 BUGS
+
+sub order is not OO. Perhaps it should be moved to FS::cust_main and made so?
+
+In sub order, the @pkgparts array (passed by reference) is clobbered.
+
+Also in sub order, no money is adjusted. Once FS::part_pkg defines a standard
+method to pass dates to the recur_prog expression, it should do so.
+
+FS::svc_acct, FS::svc_domain, FS::svc_www, FS::svc_ip and FS::svc_forward are
+loaded via 'use' at compile time, rather than via 'require' in sub { setup,
+suspend, unsuspend, cancel } because they use %FS::UID::callback to load
+configuration values. Probably need a subroutine which decides what to do
+based on whether or not we've fetched the user yet, rather than a hash. See
+FS::UID and the TODO.
+
+Now that things are transactional should the check in the insert method be
+moved to check ?
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_main>, L<FS::part_pkg>, L<FS::cust_svc>,
+L<FS::pkg_svc>, schema.html from the base documentation
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_refund.pm b/FS/FS/cust_refund.pm
new file mode 100644
index 0000000..d60c010
--- /dev/null
+++ b/FS/FS/cust_refund.pm
@@ -0,0 +1,295 @@
+package FS::cust_refund;
+
+use strict;
+use vars qw( @ISA );
+use Business::CreditCard;
+use FS::Record qw( qsearchs dbh );
+use FS::UID qw(getotaker);
+use FS::cust_credit;
+use FS::cust_credit_refund;
+use FS::cust_main;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::cust_refund - Object method for cust_refund objects
+
+=head1 SYNOPSIS
+
+ use FS::cust_refund;
+
+ $record = new FS::cust_refund \%hash;
+ $record = new FS::cust_refund { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_refund represents a refund: the transfer of money to a customer;
+equivalent to a negative payment (see L<FS::cust_pay>). FS::cust_refund
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item refundnum - primary key (assigned automatically for new refunds)
+
+=item custnum - customer (see L<FS::cust_main>)
+
+=item refund - Amount of the refund
+
+=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH),
+`LECB' (Phone bill billing), `BILL' (billing), or `COMP' (free)
+
+=item payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username)
+
+=item paybatch - text field for tracking card processing
+
+=item otaker - order taker (assigned automatically, see L<FS::UID>)
+
+=item closed - books closed flag, empty or `Y'
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new refund. To add the refund to the database, see L<"insert">.
+
+=cut
+
+sub table { 'cust_refund'; }
+
+=item insert
+
+Adds this refund to the database.
+
+For backwards-compatibility and convenience, if the additional field crednum is
+defined, an FS::cust_credit_refund record for the full amount of the refund
+will be created. In this case, custnum is optional.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ if ( $self->crednum ) {
+ my $cust_credit = qsearchs('cust_credit', { 'crednum' => $self->crednum } )
+ or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "Unknown cust_credit.crednum: ". $self->crednum;
+ };
+ $self->custnum($cust_credit->custnum);
+ }
+
+ my $error = $self->check;
+ return $error if $error;
+
+ $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ if ( $self->crednum ) {
+ my $cust_credit_refund = new FS::cust_credit_refund {
+ 'crednum' => $self->crednum,
+ 'refundnum' => $self->refundnum,
+ 'amount' => $self->refund,
+ '_date' => $self->_date,
+ };
+ $error = $cust_credit_refund->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ #$self->custnum($cust_credit_refund->cust_credit->custnum);
+ }
+
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+sub upgrade_replace { #1.3.x->1.4.x
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->check;
+ return $error if $error;
+
+ my %new = $self->hash;
+ my $new = FS::cust_refund->new(\%new);
+
+ if ( $self->crednum ) {
+ my $cust_credit_refund = new FS::cust_credit_refund {
+ 'crednum' => $self->crednum,
+ 'refundnum' => $self->refundnum,
+ 'amount' => $self->refund,
+ '_date' => $self->_date,
+ };
+ $error = $cust_credit_refund->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ $new->custnum($cust_credit_refund->cust_credit->custnum);
+ } else {
+ die;
+ }
+
+ $error = $new->SUPER::replace($self);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item delete
+
+Currently unimplemented (accounting reasons).
+
+=cut
+
+sub delete {
+ my $self = shift;
+ return "Can't delete closed refund" if $self->closed =~ /^Y/i;
+ $self->SUPER::delete(@_);
+}
+
+=item replace OLD_RECORD
+
+Currently unimplemented (accounting reasons).
+
+=cut
+
+sub replace {
+ return "Can't (yet?) modify cust_refund records!";
+}
+
+=item check
+
+Checks all fields to make sure this is a valid refund. If there is an error,
+returns the error, otherwise returns false. Called by the insert method.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('refundnum')
+ || $self->ut_numbern('custnum')
+ || $self->ut_money('refund')
+ || $self->ut_numbern('_date')
+ || $self->ut_textn('paybatch')
+ || $self->ut_enum('closed', [ '', 'Y' ])
+ ;
+ return $error if $error;
+
+ return "refund must be > 0 " if $self->refund <= 0;
+
+ $self->_date(time) unless $self->_date;
+
+ return "unknown cust_main.custnum: ". $self->custnum
+ unless $self->crednum
+ || qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+
+ $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP)$/ or return "Illegal payby";
+ $self->payby($1);
+
+ #false laziness with cust_pay::check
+ if ( $self->payby eq 'CARD' ) {
+ my $payinfo = $self->payinfo;
+ $payinfo =~ s/\D//g;
+ $self->payinfo($payinfo);
+ if ( $self->payinfo ) {
+ $self->payinfo =~ /^(\d{13,16})$/
+ or return "Illegal (mistyped?) credit card number (payinfo)";
+ $self->payinfo($1);
+ validate($self->payinfo) or return "Illegal credit card number";
+ return "Unknown card type" if cardtype($self->payinfo) eq "Unknown";
+ } else {
+ $self->payinfo('N/A');
+ }
+
+ } else {
+ $error = $self->ut_textn('payinfo');
+ return $error if $error;
+ }
+
+ $self->otaker(getotaker);
+
+ $self->SUPER::check;
+}
+
+=item payinfo_masked
+
+Returns a "masked" payinfo field with all but the last four characters replaced
+by 'x'es. Useful for displaying credit cards.
+
+=cut
+
+
+sub payinfo_masked {
+ my $self = shift;
+ my $payinfo = $self->payinfo;
+ 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4));
+}
+
+
+=back
+
+=head1 BUGS
+
+Delete and replace methods. payinfo_masked false laziness with cust_main.pm
+and cust_pay.pm
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_credit>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm
new file mode 100644
index 0000000..fae265d
--- /dev/null
+++ b/FS/FS/cust_svc.pm
@@ -0,0 +1,633 @@
+package FS::cust_svc;
+
+use strict;
+use vars qw( @ISA $ignore_quantity );
+use Carp qw( cluck );
+use FS::Record qw( qsearch qsearchs dbh );
+use FS::cust_pkg;
+use FS::part_pkg;
+use FS::part_svc;
+use FS::pkg_svc;
+use FS::svc_acct;
+use FS::svc_domain;
+use FS::svc_forward;
+use FS::svc_broadband;
+use FS::domain_record;
+use FS::part_export;
+
+@ISA = qw( FS::Record );
+
+$ignore_quantity = 0;
+
+sub _cache {
+ my $self = shift;
+ my ( $hashref, $cache ) = @_;
+ if ( $hashref->{'username'} ) {
+ $self->{'_svc_acct'} = FS::svc_acct->new($hashref, '');
+ }
+ if ( $hashref->{'svc'} ) {
+ $self->{'_svcpart'} = FS::part_svc->new($hashref);
+ }
+}
+
+=head1 NAME
+
+FS::cust_svc - Object method for cust_svc objects
+
+=head1 SYNOPSIS
+
+ use FS::cust_svc;
+
+ $record = new FS::cust_svc \%hash
+ $record = new FS::cust_svc { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ ($label, $value) = $record->label;
+
+=head1 DESCRIPTION
+
+An FS::cust_svc represents a service. FS::cust_svc inherits from FS::Record.
+The following fields are currently supported:
+
+=over 4
+
+=item svcnum - primary key (assigned automatically for new services)
+
+=item pkgnum - Package (see L<FS::cust_pkg>)
+
+=item svcpart - Service definition (see L<FS::part_svc>)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new service. To add the refund to the database, see L<"insert">.
+Services are normally created by creating FS::svc_ objects (see
+L<FS::svc_acct>, L<FS::svc_domain>, and L<FS::svc_forward>, among others).
+
+=cut
+
+sub table { 'cust_svc'; }
+
+=item insert
+
+Adds this service to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this service from the database. If there is an error, returns the
+error, otherwise returns false. Note that this only removes the cust_svc
+record - you should probably use the B<cancel> method instead.
+
+=item cancel
+
+Cancels the relevant service by calling the B<cancel> method of the associated
+FS::svc_XXX object (i.e. an FS::svc_acct object or FS::svc_domain object),
+deleting the FS::svc_XXX record and then deleting this record.
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub cancel {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $part_svc = $self->part_svc;
+
+ $part_svc->svcdb =~ /^([\w\-]+)$/ or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "Illegal svcdb value in part_svc!";
+ };
+ my $svcdb = $1;
+ require "FS/$svcdb.pm";
+
+ my $svc = $self->svc_x;
+ if ($svc) {
+ my $error = $svc->cancel;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Error canceling service: $error";
+ }
+ $error = $svc->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Error deleting service: $error";
+ }
+ }
+
+ my $error = $self->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Error deleting cust_svc: $error";
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ ''; #no errors
+
+}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $new->SUPER::replace($old);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error if $error;
+ }
+
+ if ( $new->svcpart != $old->svcpart ) {
+ my $svc_x = $new->svc_x;
+ my $new_svc_x = ref($svc_x)->new({$svc_x->hash});
+ my $error = $new_svc_x->replace($svc_x);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error if $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ ''; #no error
+
+}
+
+=item check
+
+Checks all fields to make sure this is a valid service. If there is an error,
+returns the error, otehrwise returns false. Called by the insert and
+replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('svcnum')
+ || $self->ut_numbern('pkgnum')
+ || $self->ut_number('svcpart')
+ ;
+ return $error if $error;
+
+ my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
+ return "Unknown svcpart" unless $part_svc;
+
+ if ( $self->pkgnum ) {
+ my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } );
+ return "Unknown pkgnum" unless $cust_pkg;
+ my $pkg_svc = qsearchs( 'pkg_svc', {
+ 'pkgpart' => $cust_pkg->pkgpart,
+ 'svcpart' => $self->svcpart,
+ });
+ # or new FS::pkg_svc ( { 'pkgpart' => $cust_pkg->pkgpart,
+ # 'svcpart' => $self->svcpart,
+ # 'quantity' => 0 } );
+ my $quantity = $pkg_svc ? $pkg_svc->quantity : 0;
+
+ my @cust_svc = qsearch('cust_svc', {
+ 'pkgnum' => $self->pkgnum,
+ 'svcpart' => $self->svcpart,
+ });
+ return "Already ". scalar(@cust_svc). " ". $part_svc->svc.
+ " services for pkgnum ". $self->pkgnum
+ if scalar(@cust_svc) >= $quantity && !$ignore_quantity;
+ }
+
+ $self->SUPER::check;
+}
+
+=item part_svc
+
+Returns the definition for this service, as a FS::part_svc object (see
+L<FS::part_svc>).
+
+=cut
+
+sub part_svc {
+ my $self = shift;
+ $self->{'_svcpart'}
+ ? $self->{'_svcpart'}
+ : qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
+}
+
+=item cust_pkg
+
+Returns the definition for this service, as a FS::part_svc object (see
+L<FS::part_svc>).
+
+=cut
+
+sub cust_pkg {
+ my $self = shift;
+ qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } );
+}
+
+=item label
+
+Returns a list consisting of:
+- The name of this service (from part_svc)
+- A meaningful identifier (username, domain, or mail alias)
+- The table name (i.e. svc_domain) for this service
+
+=cut
+
+sub label {
+ my $self = shift;
+ my $svcdb = $self->part_svc->svcdb;
+ my $svc_x = $self->svc_x
+ or die "can't find $svcdb.svcnum ". $self->svcnum;
+ my $tag;
+ if ( $svcdb eq 'svc_acct' ) {
+ $tag = $svc_x->email;
+ } elsif ( $svcdb eq 'svc_forward' ) {
+ if ( $svc_x->srcsvc ) {
+ my $svc_acct = $svc_x->srcsvc_acct;
+ $tag = $svc_acct->email;
+ } else {
+ $tag = $svc_x->src;
+ }
+ $tag .= '->';
+ if ( $svc_x->dstsvc ) {
+ my $svc_acct = $svc_x->dstsvc_acct;
+ $tag .= $svc_acct->email;
+ } else {
+ $tag .= $svc_x->dst;
+ }
+ } elsif ( $svcdb eq 'svc_domain' ) {
+ $tag = $svc_x->getfield('domain');
+ } elsif ( $svcdb eq 'svc_www' ) {
+ my $domain = qsearchs( 'domain_record', { 'recnum' => $svc_x->recnum } );
+ $tag = $domain->zone;
+ } elsif ( $svcdb eq 'svc_broadband' ) {
+ $tag = $svc_x->ip_addr;
+ } elsif ( $svcdb eq 'svc_external' ) {
+ $tag = $svc_x->id. ': '. $svc_x->title;
+ } else {
+ cluck "warning: asked for label of unsupported svcdb; using svcnum";
+ $tag = $svc_x->getfield('svcnum');
+ }
+ $self->part_svc->svc, $tag, $svcdb;
+}
+
+=item svc_x
+
+Returns the FS::svc_XXX object for this service (i.e. an FS::svc_acct object or
+FS::svc_domain object, etc.)
+
+=cut
+
+sub svc_x {
+ my $self = shift;
+ my $svcdb = $self->part_svc->svcdb;
+ if ( $svcdb eq 'svc_acct' && $self->{'_svc_acct'} ) {
+ $self->{'_svc_acct'};
+ } else {
+ qsearchs( $svcdb, { 'svcnum' => $self->svcnum } );
+ }
+}
+
+=item seconds_since TIMESTAMP
+
+See L<FS::svc_acct/seconds_since>. Equivalent to
+$cust_svc->svc_x->seconds_since, but more efficient. Meaningless for records
+where B<svcdb> is not "svc_acct".
+
+=cut
+
+#note: implementation here, POD in FS::svc_acct
+sub seconds_since {
+ my($self, $since) = @_;
+ my $dbh = dbh;
+ my $sth = $dbh->prepare(' SELECT SUM(logout-login) FROM session
+ WHERE svcnum = ?
+ AND login >= ?
+ AND logout IS NOT NULL'
+ ) or die $dbh->errstr;
+ $sth->execute($self->svcnum, $since) or die $sth->errstr;
+ $sth->fetchrow_arrayref->[0];
+}
+
+=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END
+
+See L<FS::svc_acct/seconds_since_sqlradacct>. Equivalent to
+$cust_svc->svc_x->seconds_since_sqlradacct, but more efficient. Meaningless
+for records where B<svcdb> is not "svc_acct".
+
+=cut
+
+#note: implementation here, POD in FS::svc_acct
+sub seconds_since_sqlradacct {
+ my($self, $start, $end) = @_;
+
+ my $svc_x = $self->svc_x;
+
+ my @part_export = $self->part_svc->part_export('sqlradius');
+ push @part_export, $self->part_svc->part_export('sqlradius_withdomain');
+ die "no sqlradius or sqlradius_withdomain export configured for this".
+ "service type"
+ unless @part_export;
+ #or return undef;
+
+ my $seconds = 0;
+ foreach my $part_export ( @part_export ) {
+
+ next if $part_export->option('ignore_accounting');
+
+ my $dbh = DBI->connect( map { $part_export->option($_) }
+ qw(datasrc username password) )
+ or die "can't connect to sqlradius database: ". $DBI::errstr;
+
+ #select a unix time conversion function based on database type
+ my $str2time;
+ if ( $dbh->{Driver}->{Name} =~ /^mysql(PP)?$/ ) {
+ $str2time = 'UNIX_TIMESTAMP(';
+ } elsif ( $dbh->{Driver}->{Name} eq 'Pg' ) {
+ $str2time = 'EXTRACT( EPOCH FROM ';
+ } else {
+ warn "warning: unknown database type ". $dbh->{Driver}->{Name}.
+ "; guessing how to convert to UNIX timestamps";
+ $str2time = 'extract(epoch from ';
+ }
+
+ my $username;
+ if ( $part_export->exporttype eq 'sqlradius' ) {
+ $username = $svc_x->username;
+ } elsif ( $part_export->exporttype eq 'sqlradius_withdomain' ) {
+ $username = $svc_x->email;
+ } else {
+ die 'unknown exporttype '. $part_export->exporttype;
+ }
+
+ my $query;
+
+ #find closed sessions completely within the given range
+ my $sth = $dbh->prepare("SELECT SUM(acctsessiontime)
+ FROM radacct
+ WHERE UserName = ?
+ AND $str2time AcctStartTime) >= ?
+ AND $str2time AcctStopTime ) < ?
+ AND $str2time AcctStopTime ) > 0
+ AND AcctStopTime IS NOT NULL"
+ ) or die $dbh->errstr;
+ $sth->execute($username, $start, $end) or die $sth->errstr;
+ my $regular = $sth->fetchrow_arrayref->[0];
+
+ #find open sessions which start in the range, count session start->range end
+ $query = "SELECT SUM( ? - $str2time AcctStartTime ) )
+ FROM radacct
+ WHERE UserName = ?
+ AND $str2time AcctStartTime ) >= ?
+ AND $str2time AcctStartTime ) < ?
+ AND ( ? - $str2time AcctStartTime ) ) < 86400
+ AND ( $str2time AcctStopTime ) = 0
+ OR AcctStopTime IS NULL )";
+ $sth = $dbh->prepare($query) or die $dbh->errstr;
+ $sth->execute($end, $username, $start, $end, $end)
+ or die $sth->errstr. " executing query $query";
+ my $start_during = $sth->fetchrow_arrayref->[0];
+
+ #find closed sessions which start before the range but stop during,
+ #count range start->session end
+ $sth = $dbh->prepare("SELECT SUM( $str2time AcctStopTime ) - ? )
+ FROM radacct
+ WHERE UserName = ?
+ AND $str2time AcctStartTime ) < ?
+ AND $str2time AcctStopTime ) >= ?
+ AND $str2time AcctStopTime ) < ?
+ AND $str2time AcctStopTime ) > 0
+ AND AcctStopTime IS NOT NULL"
+ ) or die $dbh->errstr;
+ $sth->execute($start, $username, $start, $start, $end ) or die $sth->errstr;
+ my $end_during = $sth->fetchrow_arrayref->[0];
+
+ #find closed (not anymore - or open) sessions which start before the range
+ # but stop after, or are still open, count range start->range end
+ # don't count open sessions (probably missing stop record)
+ $sth = $dbh->prepare("SELECT COUNT(*)
+ FROM radacct
+ WHERE UserName = ?
+ AND $str2time AcctStartTime ) < ?
+ AND ( $str2time AcctStopTime ) >= ?
+ )"
+ # OR AcctStopTime = 0
+ # OR AcctStopTime IS NULL )"
+ ) or die $dbh->errstr;
+ $sth->execute($username, $start, $end ) or die $sth->errstr;
+ my $entire_range = ($end-$start) * $sth->fetchrow_arrayref->[0];
+
+ $seconds += $regular + $end_during + $start_during + $entire_range;
+
+ }
+
+ $seconds;
+
+}
+
+=item attribute_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ATTRIBUTE
+
+See L<FS::svc_acct/attribute_since_sqlradacct>. Equivalent to
+$cust_svc->svc_x->attribute_since_sqlradacct, but more efficient. Meaningless
+for records where B<svcdb> is not "svc_acct".
+
+=cut
+
+#note: implementation here, POD in FS::svc_acct
+#(false laziness w/seconds_since_sqlradacct above)
+sub attribute_since_sqlradacct {
+ my($self, $start, $end, $attrib) = @_;
+
+ my $svc_x = $self->svc_x;
+
+ my @part_export = $self->part_svc->part_export('sqlradius');
+ push @part_export, $self->part_svc->part_export('sqlradius_withdomain');
+ die "no sqlradius or sqlradius_withdomain export configured for this".
+ "service type"
+ unless @part_export;
+ #or return undef;
+
+ my $sum = 0;
+
+ foreach my $part_export ( @part_export ) {
+
+ next if $part_export->option('ignore_accounting');
+
+ my $dbh = DBI->connect( map { $part_export->option($_) }
+ qw(datasrc username password) )
+ or die "can't connect to sqlradius database: ". $DBI::errstr;
+
+ #select a unix time conversion function based on database type
+ my $str2time;
+ if ( $dbh->{Driver}->{Name} =~ /^mysql(PP)?$/ ) {
+ $str2time = 'UNIX_TIMESTAMP(';
+ } elsif ( $dbh->{Driver}->{Name} eq 'Pg' ) {
+ $str2time = 'EXTRACT( EPOCH FROM ';
+ } else {
+ warn "warning: unknown database type ". $dbh->{Driver}->{Name}.
+ "; guessing how to convert to UNIX timestamps";
+ $str2time = 'extract(epoch from ';
+ }
+
+ my $username;
+ if ( $part_export->exporttype eq 'sqlradius' ) {
+ $username = $svc_x->username;
+ } elsif ( $part_export->exporttype eq 'sqlradius_withdomain' ) {
+ $username = $svc_x->email;
+ } else {
+ die 'unknown exporttype '. $part_export->exporttype;
+ }
+
+ my $sth = $dbh->prepare("SELECT SUM($attrib)
+ FROM radacct
+ WHERE UserName = ?
+ AND $str2time AcctStopTime ) >= ?
+ AND $str2time AcctStopTime ) < ?
+ AND AcctStopTime IS NOT NULL"
+ ) or die $dbh->errstr;
+ $sth->execute($username, $start, $end) or die $sth->errstr;
+
+ $sum += $sth->fetchrow_arrayref->[0];
+
+ }
+
+ $sum;
+
+}
+
+=item get_session_history_sqlradacct TIMESTAMP_START TIMESTAMP_END
+
+See L<FS::svc_acct/get_session_history_sqlradacct>. Equivalent to
+$cust_svc->svc_x->get_session_history_sqlradacct, but more efficient.
+Meaningless for records where B<svcdb> is not "svc_acct".
+
+=cut
+
+sub get_session_history {
+ my($self, $start, $end, $attrib) = @_;
+
+ my $username = $self->svc_x->username;
+
+ my @part_export = $self->part_svc->part_export('sqlradius')
+ or die "no sqlradius export configured for this service type";
+ #or return undef;
+
+ my @sessions = ();
+
+ foreach my $part_export ( @part_export ) {
+
+ my $dbh = DBI->connect( map { $part_export->option($_) }
+ qw(datasrc username password) )
+ or die "can't connect to sqlradius database: ". $DBI::errstr;
+
+ #select a unix time conversion function based on database type
+ my $str2time;
+ if ( $dbh->{Driver}->{Name} =~ /^mysql(PP)?$/ ) {
+ $str2time = 'UNIX_TIMESTAMP(';
+ } elsif ( $dbh->{Driver}->{Name} eq 'Pg' ) {
+ $str2time = 'EXTRACT( EPOCH FROM ';
+ } else {
+ warn "warning: unknown database type ". $dbh->{Driver}->{Name}.
+ "; guessing how to convert to UNIX timestamps";
+ $str2time = 'extract(epoch from ';
+ }
+
+ my @fields = qw( acctstarttime acctstoptime acctsessiontime
+ acctinputoctets acctoutputoctets framedipaddress );
+
+ my $sth = $dbh->prepare('SELECT '. join(', ', @fields).
+ " FROM radacct
+ WHERE UserName = ?
+ AND $str2time AcctStopTime ) >= ?
+ AND $str2time AcctStopTime ) <= ?
+ ORDER BY AcctStartTime DESC
+ ") or die $dbh->errstr;
+ $sth->execute($username, $start, $end) or die $sth->errstr;
+
+ push @sessions, map { { %$_ } } @{ $sth->fetchall_arrayref({}) };
+
+ }
+ \@sessions
+
+}
+
+=item pkg_svc
+
+Returns the pkg_svc record for for this service, if applicable.
+
+=cut
+
+sub pkg_svc {
+ my $self = shift;
+ my $cust_pkg = $self->cust_pkg;
+ return undef unless $cust_pkg;
+
+ qsearchs( 'pkg_svc', { 'svcpart' => $self->svcpart,
+ 'pkgpart' => $cust_pkg->pkgpart,
+ }
+ );
+}
+
+=back
+
+=head1 BUGS
+
+Behaviour of changing the svcpart of cust_svc records is undefined and should
+possibly be prohibited, and pkg_svc records are not checked.
+
+pkg_svc records are not checked in general (here).
+
+Deleting this record doesn't check or delete the svc_* record associated
+with this record.
+
+In seconds_since_sqlradacct, specifying a DATASRC/USERNAME/PASSWORD instead of
+a DBI database handle is not yet implemented.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_pkg>, L<FS::part_svc>, L<FS::pkg_svc>,
+schema.html from the base documentation
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_tax_exempt.pm b/FS/FS/cust_tax_exempt.pm
new file mode 100644
index 0000000..da0de00
--- /dev/null
+++ b/FS/FS/cust_tax_exempt.pm
@@ -0,0 +1,132 @@
+package FS::cust_tax_exempt;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::cust_tax_exempt - Object methods for cust_tax_exempt records
+
+=head1 SYNOPSIS
+
+ use FS::cust_tax_exempt;
+
+ $record = new FS::cust_tax_exempt \%hash;
+ $record = new FS::cust_tax_exempt { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_tax_exempt object represents a historical record of a customer tax
+exemption. Currently this is only used for "texas tax". FS::cust_tax_exempt
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item exemptnum - primary key
+
+=item custnum - customer (see L<FS::cust_main>)
+
+=item taxnum - tax rate (see L<FS::cust_main_county>)
+
+=item year
+
+=item month
+
+=item amount
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new exemption record. To add the example to the database, see
+L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'cust_tax_exempt'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid example. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('exemptnum')
+ || $self->ut_foreign_key('custnum', 'cust_main', 'custnum')
+ || $self->ut_foreign_key('taxnum', 'cust_main_county', 'taxnum')
+ || $self->ut_number('year') #check better
+ || $self->ut_number('month') #check better
+ || $self->ut_money('amount')
+ || $self->SUPER::check
+ ;
+}
+
+=back
+
+=head1 BUGS
+
+Texas tax is a royal pain in the ass.
+
+=head1 SEE ALSO
+
+L<FS::cust_main_county>, L<FS::cust_main>, L<FS::Record>, schema.html from the
+base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/domain_record.pm b/FS/FS/domain_record.pm
new file mode 100644
index 0000000..2a30594
--- /dev/null
+++ b/FS/FS/domain_record.pm
@@ -0,0 +1,417 @@
+package FS::domain_record;
+
+use strict;
+use vars qw( @ISA $noserial_hack $DEBUG );
+use FS::Conf;
+#use FS::Record qw( qsearch qsearchs );
+use FS::Record qw( qsearchs dbh );
+use FS::svc_domain;
+use FS::svc_www;
+
+@ISA = qw(FS::Record);
+
+$DEBUG = 1;
+
+=head1 NAME
+
+FS::domain_record - Object methods for domain_record records
+
+=head1 SYNOPSIS
+
+ use FS::domain_record;
+
+ $record = new FS::domain_record \%hash;
+ $record = new FS::domain_record { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::domain_record object represents an entry in a DNS zone.
+FS::domain_record inherits from FS::Record. The following fields are currently
+supported:
+
+=over 4
+
+=item recnum - primary key
+
+=item svcnum - Domain (see L<FS::svc_domain>) of this entry
+
+=item reczone - partial (or full) zone for this entry
+
+=item recaf - address family for this entry, currently only `IN' is recognized.
+
+=item rectype - record type for this entry (A, MX, etc.)
+
+=item recdata - data for this entry
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new entry. To add the example to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'domain_record'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ if ( $self->rectype eq '_mstr' ) { #delete all other records
+ foreach my $domain_record ( reverse $self->svc_domain->domain_record ) {
+ my $error = $domain_record->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ unless ( $self->rectype =~ /^(SOA|_mstr)$/ ) {
+ my $error = $self->increment_serial;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ my $conf = new FS::Conf;
+ if ( $self->rectype =~ /^A$/ && ! $conf->exists('disable_autoreverse') ) {
+ my $reverse = $self->reverse_record;
+ if ( $reverse && ! $reverse->recnum ) {
+ my $error = $reverse->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error adding corresponding reverse-ARPA record: $error";
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ return "Can't delete a domain record which has a website!"
+ if qsearchs( 'svc_www', { 'recnum' => $self->recnum } );
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ unless ( $self->rectype =~ /^(SOA|_mstr)$/ ) {
+ my $error = $self->increment_serial;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ my $conf = new FS::Conf;
+ if ( $self->rectype =~ /^A$/ && ! $conf->exists('disable_autoreverse') ) {
+ my $reverse = $self->reverse_record;
+ if ( $reverse && $reverse->recnum && $reverse->recdata eq $self->zone.'.' ){
+ my $error = $reverse->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error removing corresponding reverse-ARPA record: $error";
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::replace(@_);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ unless ( $self->rectype eq 'SOA' ) {
+ my $error = $self->increment_serial;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item check
+
+Checks all fields to make sure this is a valid example. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('recnum')
+ || $self->ut_number('svcnum')
+ ;
+ return $error if $error;
+
+ return "Unknown svcnum (in svc_domain)"
+ unless qsearchs('svc_domain', { 'svcnum' => $self->svcnum } );
+
+ $self->reczone =~ /^(@|[a-z0-9\.\-\*]+)$/i
+ or return "Illegal reczone: ". $self->reczone;
+ $self->reczone($1);
+
+ $self->recaf =~ /^(IN)$/ or return "Illegal recaf: ". $self->recaf;
+ $self->recaf($1);
+
+ $self->rectype =~ /^(SOA|NS|MX|A|PTR|CNAME|_mstr)$/
+ or return "Illegal rectype (only SOA NS MX A PTR CNAME recognized): ".
+ $self->rectype;
+ $self->rectype($1);
+
+ return "Illegal reczone for ". $self->rectype. ": ". $self->reczone
+ if $self->rectype !~ /^MX$/i && $self->reczone =~ /\*/;
+
+ if ( $self->rectype eq 'SOA' ) {
+ my $recdata = $self->recdata;
+ $recdata =~ s/\s+/ /g;
+ $recdata =~ /^([a-z0-9\.\-]+ [\w\-\+]+\.[a-z0-9\.\-]+ \( ((\d+|((\d+[WDHMS])+)) ){5}\))$/i
+ or return "Illegal data for SOA record: $recdata";
+ $self->recdata($1);
+ } elsif ( $self->rectype eq 'NS' ) {
+ $self->recdata =~ /^([a-z0-9\.\-]+)$/i
+ or return "Illegal data for NS record: ". $self->recdata;
+ $self->recdata($1);
+ } elsif ( $self->rectype eq 'MX' ) {
+ $self->recdata =~ /^(\d+)\s+([a-z0-9\.\-]+)$/i
+ or return "Illegal data for MX record: ". $self->recdata;
+ $self->recdata("$1 $2");
+ } elsif ( $self->rectype eq 'A' ) {
+ $self->recdata =~ /^((\d{1,3}\.){3}\d{1,3})$/
+ or return "Illegal data for A record: ". $self->recdata;
+ $self->recdata($1);
+ } elsif ( $self->rectype eq 'PTR' ) {
+ $self->recdata =~ /^([a-z0-9\.\-]+)$/i
+ or return "Illegal data for PTR record: ". $self->recdata;
+ $self->recdata($1);
+ } elsif ( $self->rectype eq 'CNAME' ) {
+ $self->recdata =~ /^([a-z0-9\.\-]+|\@)$/i
+ or return "Illegal data for CNAME record: ". $self->recdata;
+ $self->recdata($1);
+ } elsif ( $self->rectype eq '_mstr' ) {
+ $self->recdata =~ /^((\d{1,3}\.){3}\d{1,3})$/
+ or return "Illegal data for _master pseudo-record: ". $self->recdata;
+ } else {
+ die "ack!";
+ }
+
+ $self->SUPER::check;
+}
+
+=item increment_serial
+
+=cut
+
+sub increment_serial {
+ return '' if $noserial_hack;
+ my $self = shift;
+
+ my $soa = qsearchs('domain_record', {
+ svcnum => $self->svcnum,
+ reczone => '@',
+ recaf => 'IN',
+ rectype => 'SOA', } )
+ || qsearchs('domain_record', {
+ svcnum => $self->svcnum,
+ reczone => $self->svc_domain->domain.'.',
+ recaf => 'IN',
+ rectype => 'SOA',
+ } )
+ or return "soa record not found; can't increment serial";
+
+ my $data = $soa->recdata;
+ $data =~ s/(\(\D*)(\d+)/$1.($2+1)/e; #well, it works.
+
+ my %hash = $soa->hash;
+ $hash{recdata} = $data;
+ my $new = new FS::domain_record \%hash;
+ $new->replace($soa);
+}
+
+=item svc_domain
+
+Returns the domain (see L<FS::svc_domain>) for this record.
+
+=cut
+
+sub svc_domain {
+ my $self = shift;
+ qsearchs('svc_domain', { svcnum => $self->svcnum } );
+}
+
+=item zone
+
+Returns the canonical zone name.
+
+=cut
+
+sub zone {
+ my $self = shift;
+ my $zone = $self->reczone; # or die ?
+ if ( $zone =~ /\.$/ ) {
+ $zone =~ s/\.$//;
+ } else {
+ my $svc_domain = $self->svc_domain; # or die ?
+ $zone .= '.'. $svc_domain->domain;
+ $zone =~ s/^\@\.//;
+ }
+ $zone;
+}
+
+=item reverse_record
+
+Returns the corresponding reverse-ARPA record as another FS::domain_record
+object. If the specific record does not exist in the database but the
+reverse-ARPA zone itself does, an appropriate new record is created. If no
+reverse-ARPA zone is available at all, returns false.
+
+(You can test whether or not record itself exists in the database or is a new
+object that might need to be inserted by checking the recnum field)
+
+Mostly used by the insert and delete methods - probably should see them for
+examples.
+
+=cut
+
+sub reverse_record {
+ my $self = shift;
+ warn "reverse_record called\n" if $DEBUG;
+ #should support classless reverse-ARPA ala rfc2317 too
+ $self->recdata =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
+ or return '';
+ my $domain = "$3.$2.$1.in-addr.arpa";
+ my $ptr_reczone = $4;
+ warn "reverse_record: searching for domain: $domain\n" if $DEBUG;
+ my $svc_domain = qsearchs('svc_domain', { 'domain' => $domain } )
+ or return '';
+ warn "reverse_record: found domain: $domain\n" if $DEBUG;
+ my %hash = (
+ 'svcnum' => $svc_domain->svcnum,
+ 'reczone' => $ptr_reczone,
+ 'recaf' => 'IN',
+ 'rectype' => 'PTR',
+ );
+ qsearchs('domain_record', \%hash )
+ or new FS::domain_record { %hash, 'recdata' => $self->zone.'.' };
+}
+
+=back
+
+=head1 BUGS
+
+The data validation doesn't check everything it could. In particular,
+there is no protection against bad data that passes the regex, duplicate
+SOA records, forgetting the trailing `.', impossible IP addersses, etc. Of
+course, it's still better than editing the zone files directly. :)
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/export_svc.pm b/FS/FS/export_svc.pm
new file mode 100644
index 0000000..c104e45
--- /dev/null
+++ b/FS/FS/export_svc.pm
@@ -0,0 +1,124 @@
+package FS::export_svc;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+use FS::part_export;
+use FS::part_svc;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::export_svc - Object methods for export_svc records
+
+=head1 SYNOPSIS
+
+ use FS::export_svc;
+
+ $record = new FS::export_svc \%hash;
+ $record = new FS::export_svc { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::export_svc object links a service definition (see L<FS::part_svc>) to
+an export (see L<FS::part_export>). FS::export_svc inherits from FS::Record.
+The following fields are currently supported:
+
+=over 4
+
+=item exportsvcnum - primary key
+
+=item exportnum - export (see L<FS::part_export>)
+
+=item svcpart - service definition (see L<FS::part_svc>)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record. To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'export_svc'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('exportsvcnum')
+ || $self->ut_number('exportnum')
+ || $self->ut_foreign_key('exportnum', 'part_export', 'exportnum')
+ || $self->ut_number('svcpart')
+ || $self->ut_foreign_key('svcpart', 'part_svc', 'svcpart')
+ || $self->SUPER::check
+ ;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::part_export>, L<FS::part_svc>, L<FS::Record>, schema.html from the base
+documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/msgcat.pm b/FS/FS/msgcat.pm
new file mode 100644
index 0000000..855b8b2
--- /dev/null
+++ b/FS/FS/msgcat.pm
@@ -0,0 +1,132 @@
+package FS::msgcat;
+
+use strict;
+use vars qw( @ISA );
+use Exporter;
+use FS::UID;
+use FS::Record qw( qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::msgcat - Object methods for message catalog entries
+
+=head1 SYNOPSIS
+
+ use FS::msgcat;
+
+ $record = new FS::msgcat \%hash;
+ $record = new FS::msgcat { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::msgcat object represents an message catalog entry. FS::msgcat inherits
+from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item msgnum - primary key
+
+=item msgcode - Error code
+
+=item locale - Locale
+
+=item msg - Message
+
+=back
+
+If you just want to B<use> message catalogs, see L<FS::Msgcat>.
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'msgcat'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid example. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('msgnum')
+ || $self->ut_text('msgcode')
+ || $self->ut_text('msg')
+ ;
+ return $error if $error;
+
+ $self->locale =~ /^([\w\@]+)$/ or return "illegal locale: ". $self->locale;
+ $self->locale($1);
+
+ $self->SUPER::check
+}
+
+=back
+
+=head1 BUGS
+
+i18n/l10n, eek
+
+=head1 SEE ALSO
+
+L<FS::Msgcat>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/nas.pm b/FS/FS/nas.pm
new file mode 100644
index 0000000..2d17df8
--- /dev/null
+++ b/FS/FS/nas.pm
@@ -0,0 +1,154 @@
+package FS::nas;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw(qsearchs); #qsearch);
+use FS::UID qw( dbh );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::nas - Object methods for nas records
+
+=head1 SYNOPSIS
+
+ use FS::nas;
+
+ $record = new FS::nas \%hash;
+ $record = new FS::nas {
+ 'nasnum' => 1,
+ 'nasip' => '10.4.20.23',
+ 'nasfqdn' => 'box1.brc.nv.us.example.net',
+ };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->heartbeat($timestamp);
+
+=head1 DESCRIPTION
+
+An FS::nas object represents an Network Access Server on your network, such as
+a terminal server or equivalent. FS::nas inherits from FS::Record. The
+following fields are currently supported:
+
+=over 4
+
+=item nasnum - primary key
+
+=item nas - NAS name
+
+=item nasip - NAS ip address
+
+=item nasfqdn - NAS fully-qualified domain name
+
+=item last - timestamp indicating the last instant the NAS was in a known
+ state (used by the session monitoring).
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new NAS. To add the NAS to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'nas'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid example. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('nasnum')
+ || $self->ut_text('nas')
+ || $self->ut_ip('nasip')
+ || $self->ut_domain('nasfqdn')
+ || $self->ut_numbern('last')
+ || $self->SUPER::check
+ ;
+}
+
+=item heartbeat TIMESTAMP
+
+Updates the timestamp for this nas
+
+=cut
+
+sub heartbeat {
+ my($self, $timestamp) = @_;
+ my $dbh = dbh;
+ my $sth =
+ $dbh->prepare("UPDATE nas SET last = ? WHERE nasnum = ? AND last < ?");
+ $sth->execute($timestamp, $self->nasnum, $timestamp) or die $sth->errstr;
+ $self->last($timestamp);
+}
+
+=back
+
+=head1 VERSION
+
+$Id: nas.pm,v 1.7 2003-08-05 00:20:43 khoff Exp $
+
+=head1 BUGS
+
+heartbeat method uses SQL directly and doesn't update history tables.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_bill_event.pm b/FS/FS/part_bill_event.pm
new file mode 100644
index 0000000..4774b8d
--- /dev/null
+++ b/FS/FS/part_bill_event.pm
@@ -0,0 +1,186 @@
+package FS::part_bill_event;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+use FS::Conf;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::part_bill_event - Object methods for part_bill_event records
+
+=head1 SYNOPSIS
+
+ use FS::part_bill_event;
+
+ $record = new FS::part_bill_event \%hash;
+ $record = new FS::part_bill_event { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_bill_event object represents an invoice event definition -
+a callback which is triggered when an invoice is a certain amount of time
+overdue. FS::part_bill_event inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item eventpart - primary key
+
+=item payby - CARD, DCRD, CHEK, DCHK, LECB, BILL, or COMP
+
+=item event - event name
+
+=item eventcode - event action
+
+=item seconds - how long after the invoice date events of this type are triggered
+
+=item weight - ordering for events with identical seconds
+
+=item plan - eventcode plan
+
+=item plandata - additional plan data
+
+=item disabled - Disabled flag, empty or `Y'
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new invoice event definition. To add the example to the database,
+see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'part_bill_event'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid invoice event definition. If
+there is an error, returns the error, otherwise returns false. Called by the
+insert and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ $self->weight(0) unless $self->weight;
+
+ my $conf = new FS::Conf;
+ if ( $conf->exists('safe-part_bill_event') ) {
+ my $error = $self->ut_anything('eventcode');
+ return $error if $error;
+
+ my $c = $self->eventcode;
+
+ $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/
+
+ or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|realtime_card_cybercash|batch_card|send)\(\);\s*$/
+
+ or $c =~ /^\s*\$cust_bill\->send\(\'\w+\'\);\s*$/
+
+ or $c =~ /^\s*\$cust_main\->apply_payments; \$cust_main->apply_credits; "";\s*$/
+
+ or $c =~ /^\s*\$cust_main\->charge\( \s*\d*\.?\d*\s*,\s*\'[\w \!\@\#\$\%\&\(\)\-\+\;\:\"\,\.\?\/]*\'\s*\);\s*$/
+
+ or do {
+ #log
+ return "illegal eventcode: $c";
+ };
+
+ }
+
+ my $error = $self->ut_numbern('eventpart')
+ || $self->ut_enum('payby', [qw( CARD DCRD CHEK DCHK LECB BILL COMP )] )
+ || $self->ut_text('event')
+ || $self->ut_anything('eventcode')
+ || $self->ut_number('seconds')
+ || $self->ut_enum('disabled', [ '', 'Y' ] )
+ || $self->ut_number('weight')
+ || $self->ut_textn('plan')
+ || $self->ut_anything('plandata')
+ ;
+ #|| $self->ut_snumber('seconds')
+ return $error if $error;
+
+ #quelle kludge
+ if ( $self->plandata =~ /^(agent_)?templatename\s+(.*)$/m ) {
+ my $name= $2;
+
+ foreach my $file (qw( template latex latexnotes )) {
+ unless ( $conf->exists("invoice_${file}_$name") ) {
+ $conf->set(
+ "invoice_${file}_$name" =>
+ join("\n", $conf->config("invoice_$file") )
+ );
+ }
+ }
+ }
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+Alas.
+
+=head1 SEE ALSO
+
+L<FS::cust_bill>, L<FS::cust_bill_event>, L<FS::Record>, schema.html from the
+base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm
new file mode 100644
index 0000000..bd12389
--- /dev/null
+++ b/FS/FS/part_export.pm
@@ -0,0 +1,590 @@
+package FS::part_export;
+
+use strict;
+use vars qw( @ISA @EXPORT_OK $DEBUG %exports );
+use Exporter;
+use Tie::IxHash;
+use FS::Record qw( qsearch qsearchs dbh );
+use FS::part_svc;
+use FS::part_export_option;
+use FS::export_svc;
+
+@ISA = qw(FS::Record);
+@EXPORT_OK = qw(export_info);
+
+$DEBUG = 0;
+
+=head1 NAME
+
+FS::part_export - Object methods for part_export records
+
+=head1 SYNOPSIS
+
+ use FS::part_export;
+
+ $record = new FS::part_export \%hash;
+ $record = new FS::part_export { 'column' => 'value' };
+
+ #($new_record, $options) = $template_recored->clone( $svcpart );
+
+ $error = $record->insert( { 'option' => 'value' } );
+ $error = $record->insert( \%options );
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_export object represents an export of Freeside data to an external
+provisioning system. FS::part_export inherits from FS::Record. The following
+fields are currently supported:
+
+=over 4
+
+=item exportnum - primary key
+
+=item machine - Machine name
+
+=item exporttype - Export type
+
+=item nodomain - blank or "Y" : usernames are exported to this service with no domain
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new export. To add the export to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'part_export'; }
+
+=cut
+
+#=item clone SVCPART
+#
+#An alternate constructor. Creates a new export by duplicating an existing
+#export. The given svcpart is assigned to the new export.
+#
+#Returns a list consisting of the new export object and a hashref of options.
+#
+#=cut
+#
+#sub clone {
+# my $self = shift;
+# my $class = ref($self);
+# my %hash = $self->hash;
+# $hash{'exportnum'} = '';
+# $hash{'svcpart'} = shift;
+# ( $class->new( \%hash ),
+# { map { $_->optionname => $_->optionvalue }
+# qsearch('part_export_option', { 'exportnum' => $self->exportnum } )
+# }
+# );
+#}
+
+=item insert HASHREF
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+If a hash reference of options is supplied, part_export_option records are
+created (see L<FS::part_export_option>).
+
+=cut
+
+#false laziness w/queue.pm
+sub insert {
+ my $self = shift;
+ my $options = shift;
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ foreach my $optionname ( keys %{$options} ) {
+ my $part_export_option = new FS::part_export_option ( {
+ 'exportnum' => $self->exportnum,
+ 'optionname' => $optionname,
+ 'optionvalue' => $options->{$optionname},
+ } );
+ $error = $part_export_option->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+#foreign keys would make this much less tedious... grr dumb mysql
+sub delete {
+ my $self = shift;
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ foreach my $part_export_option ( $self->part_export_option ) {
+ my $error = $part_export_option->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ foreach my $export_svc ( $self->export_svc ) {
+ my $error = $export_svc->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item replace OLD_RECORD HASHREF
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+If a hash reference of options is supplied, part_export_option records are
+created or modified (see L<FS::part_export_option>).
+
+=cut
+
+sub replace {
+ my $self = shift;
+ my $old = shift;
+ my $options = shift;
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::replace($old);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ foreach my $optionname ( keys %{$options} ) {
+ my $old = qsearchs( 'part_export_option', {
+ 'exportnum' => $self->exportnum,
+ 'optionname' => $optionname,
+ } );
+ my $new = new FS::part_export_option ( {
+ 'exportnum' => $self->exportnum,
+ 'optionname' => $optionname,
+ 'optionvalue' => $options->{$optionname},
+ } );
+ $new->optionnum($old->optionnum) if $old;
+ my $error = $old ? $new->replace($old) : $new->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ #remove extraneous old options
+ foreach my $opt (
+ grep { !exists $options->{$_->optionname} } $old->part_export_option
+ ) {
+ my $error = $opt->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+};
+
+=item check
+
+Checks all fields to make sure this is a valid export. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+ my $error =
+ $self->ut_numbern('exportnum')
+ || $self->ut_domain('machine')
+ || $self->ut_alpha('exporttype')
+ ;
+ return $error if $error;
+
+ $self->nodomain =~ /^(Y?)$/ or return "Illegal nodomain: ". $self->nodomain;
+ $self->nodomain($1);
+
+ $self->deprecated(1); #BLAH
+
+ #check exporttype?
+
+ $self->SUPER::check;
+}
+
+#=item part_svc
+#
+#Returns the service definition (see L<FS::part_svc>) for this export.
+#
+#=cut
+#
+#sub part_svc {
+# my $self = shift;
+# qsearchs('part_svc', { svcpart => $self->svcpart } );
+#}
+
+sub part_svc {
+ use Carp;
+ croak "FS::part_export::part_svc deprecated";
+ #confess "FS::part_export::part_svc deprecated";
+}
+
+=item svc_x
+
+Returns a list of associated FS::svc_* records.
+
+=cut
+
+sub svc_x {
+ my $self = shift;
+ map { $_->svc_x } $self->cust_svc;
+}
+
+=item cust_svc
+
+Returns a list of associated FS::cust_svc records.
+
+=cut
+
+sub cust_svc {
+ my $self = shift;
+ map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
+ grep { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
+ $self->export_svc;
+}
+
+=item export_svc
+
+Returns a list of associated FS::export_svc records.
+
+=cut
+
+sub export_svc {
+ my $self = shift;
+ qsearch('export_svc', { 'exportnum' => $self->exportnum } );
+}
+
+=item part_export_option
+
+Returns all options as FS::part_export_option objects (see
+L<FS::part_export_option>).
+
+=cut
+
+sub part_export_option {
+ my $self = shift;
+ qsearch('part_export_option', { 'exportnum' => $self->exportnum } );
+}
+
+=item options
+
+Returns a list of option names and values suitable for assigning to a hash.
+
+=cut
+
+sub options {
+ my $self = shift;
+ map { $_->optionname => $_->optionvalue } $self->part_export_option;
+}
+
+=item option OPTIONNAME
+
+Returns the option value for the given name, or the empty string.
+
+=cut
+
+sub option {
+ my $self = shift;
+ my $part_export_option =
+ qsearchs('part_export_option', {
+ exportnum => $self->exportnum,
+ optionname => shift,
+ } );
+ $part_export_option ? $part_export_option->optionvalue : '';
+}
+
+=item rebless
+
+Reblesses the object into the FS::part_export::EXPORTTYPE class, where
+EXPORTTYPE is the object's I<exporttype> field. There should be better docs
+on how to create new exports (and they should live in their own files and be
+autoloaded-on-demand), but until then, see L</NEW EXPORT CLASSES>.
+
+=cut
+
+sub rebless {
+ my $self = shift;
+ my $exporttype = $self->exporttype;
+ my $class = ref($self). "::$exporttype";
+ eval "use $class;";
+ die $@ if $@;
+ bless($self, $class);
+}
+
+=item export_insert SVC_OBJECT
+
+=cut
+
+sub export_insert {
+ my $self = shift;
+ $self->rebless;
+ $self->_export_insert(@_);
+}
+
+#sub AUTOLOAD {
+# my $self = shift;
+# $self->rebless;
+# my $method = $AUTOLOAD;
+# #$method =~ s/::(\w+)$/::_$1/; #infinite loop prevention
+# $method =~ s/::(\w+)$/_$1/; #infinite loop prevention
+# $self->$method(@_);
+#}
+
+=item export_replace NEW OLD
+
+=cut
+
+sub export_replace {
+ my $self = shift;
+ $self->rebless;
+ $self->_export_replace(@_);
+}
+
+=item export_delete
+
+=cut
+
+sub export_delete {
+ my $self = shift;
+ $self->rebless;
+ $self->_export_delete(@_);
+}
+
+=item export_suspend
+
+=cut
+
+sub export_suspend {
+ my $self = shift;
+ $self->rebless;
+ $self->_export_suspend(@_);
+}
+
+=item export_unsuspend
+
+=cut
+
+sub export_unsuspend {
+ my $self = shift;
+ $self->rebless;
+ $self->_export_unsuspend(@_);
+}
+
+#fallbacks providing useful error messages intead of infinite loops
+sub _export_insert {
+ my $self = shift;
+ return "_export_insert: unknown export type ". $self->exporttype;
+}
+
+sub _export_replace {
+ my $self = shift;
+ return "_export_replace: unknown export type ". $self->exporttype;
+}
+
+sub _export_delete {
+ my $self = shift;
+ return "_export_delete: unknown export type ". $self->exporttype;
+}
+
+#call svcdb-specific fallbacks
+
+sub _export_suspend {
+ my $self = shift;
+ #warn "warning: _export_suspened unimplemented for". ref($self);
+ my $svc_x = shift;
+ my $new = $svc_x->clone_suspended;
+ $self->_export_replace( $new, $svc_x );
+}
+
+sub _export_unsuspend {
+ my $self = shift;
+ #warn "warning: _export_unsuspend unimplemented for ". ref($self);
+ my $svc_x = shift;
+ my $old = $svc_x->clone_kludge_unsuspend;
+ $self->_export_replace( $svc_x, $old );
+}
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item export_info [ SVCDB ]
+
+Returns a hash reference of the exports for the given I<svcdb>, or if no
+I<svcdb> is specified, for all exports. The keys of the hash are
+I<exporttype>s and the values are again hash references containing information
+on the export:
+
+ 'desc' => 'Description',
+ 'options' => {
+ 'option' => { label=>'Option Label' },
+ 'option2' => { label=>'Another label' },
+ },
+ 'nodomain' => 'Y', #or ''
+ 'notes' => 'Additional notes',
+
+=cut
+
+sub export_info {
+ #warn $_[0];
+ return $exports{$_[0]} || {} if @_;
+ #{ map { %{$exports{$_}} } keys %exports };
+ my $r = { map { %{$exports{$_}} } keys %exports };
+}
+
+#=item exporttype2svcdb EXPORTTYPE
+#
+#Returns the applicable I<svcdb> for an I<exporttype>.
+#
+#=cut
+#
+#sub exporttype2svcdb {
+# my $exporttype = $_[0];
+# foreach my $svcdb ( keys %exports ) {
+# return $svcdb if grep { $exporttype eq $_ } keys %{$exports{$svcdb}};
+# }
+# '';
+#}
+
+foreach my $INC ( @INC ) {
+ foreach my $file ( glob("$INC/FS/part_export/*.pm") ) {
+ warn "attempting to load export info from $file\n" if $DEBUG;
+ $file =~ /\/(\w+)\.pm$/ or do {
+ warn "unrecognized file in $INC/FS/part_export/: $file\n";
+ next;
+ };
+ my $mod = $1;
+ my $info = eval "use FS::part_export::$mod; ".
+ "\\%FS::part_export::$mod\::info;";
+ if ( $@ ) {
+ die "error using FS::part_export::$mod (skipping): $@\n" if $@;
+ next;
+ }
+ unless ( keys %$info ) {
+ warn "no %info hash found in FS::part_export::$mod, skipping\n"
+ unless $mod =~ /^(passwdfile|null)$/; #hack but what the heck
+ next;
+ }
+ warn "got export info from FS::part_export::$mod: $info\n" if $DEBUG;
+ no strict 'refs';
+ foreach my $svc (
+ ref($info->{'svc'}) ? @{$info->{'svc'}} : $info->{'svc'}
+ ) {
+ unless ( $svc ) {
+ warn "blank svc for FS::part_export::$mod (skipping)\n";
+ next;
+ }
+ $exports{$svc}->{$mod} = $info;
+ }
+ }
+}
+
+=back
+
+=head1 NEW EXPORT CLASSES
+
+A module should be added in FS/FS/part_export/ (an example may be found in
+eg/export_template.pm)
+
+=head1 BUGS
+
+Hmm... cust_export class (not necessarily a database table...) ... ?
+
+deprecated column...
+
+=head1 SEE ALSO
+
+L<FS::part_export_option>, L<FS::export_svc>, L<FS::svc_acct>,
+L<FS::svc_domain>,
+L<FS::svc_forward>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_export/acct_sql.pm b/FS/FS/part_export/acct_sql.pm
new file mode 100644
index 0000000..dfc37d0
--- /dev/null
+++ b/FS/FS/part_export/acct_sql.pm
@@ -0,0 +1,177 @@
+package FS::part_export::acct_sql;
+
+use vars qw(@ISA %info @saltset);
+use Tie::IxHash;
+#use Digest::MD5 qw(md5_hex);
+use FS::Record; #qw(qsearchs);
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'datasrc' => { label => 'DBI data source' },
+ 'username' => { label => 'Database username' },
+ 'password' => { label => 'Database password' },
+ 'table' => { label => 'Database table' },
+ 'schema' => { label =>
+ 'Database schema mapping to Freeside methods.',
+ type => 'textarea',
+ },
+ 'primary_key' => { label => 'Database primary key' },
+;
+
+tie my %postfix_courierimap_mailbox_map, 'Tie::IxHash',
+ 'username' => 'email',
+ 'password' => '_password',
+ 'crypt' => 'crypt_password',
+ 'name' => 'finger',
+ 'maildir' => 'virtual_maildir',
+ 'domain' => 'domain',
+ 'svcnum' => 'svcnum',
+;
+my $postfix_courierimap_mailbox_map =
+ join('\n', map "$_ $postfix_courierimap_mailbox_map{$_}",
+ keys %postfix_courierimap_mailbox_map );
+
+tie my %postfix_courierimap_alias_map, 'Tie::IxHash',
+ 'address' => 'email',
+ 'goto' => 'email',
+ 'domain' => 'domain',
+ 'svcnum' => 'svcnum',
+;
+my $postfix_courierimap_alias_map =
+ join('\n', map "$_ $postfix_courierimap_alias_map{$_}",
+ keys %postfix_courierimap_alias_map );
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export of accounts to SQL databases '.
+ '(Postfix+Courier IMAP, others?)',
+ 'options' => \%options,
+ 'nodomain' => '',
+ 'notes' => <<END
+Export accounts (svc_acct records) to SQL databases. Written for
+Postfix+Courier IMAP but intended to be generally useful for generic SQL
+exports, eventually.
+
+<BR><BR>In contrast to sqlmail, this is newer and less well tested, and
+currently less flexible. It is intended to export just svc_acct records only,
+rather than a single export for svc_acct, svc_forward and svc_domain records,
+to export in "default" formats rather than configure the MTA or POP/IMAP server
+for a Freeside-specific schema, and possibly to be configured for different
+mail server setups through some subclassing rather than options.
+
+<BR><BR>Use these buttons for some useful presets:
+<UL>
+ <LI><INPUT TYPE="button" VALUE="postfix_courierimap_mailbox" onClick='
+ this.form.table.value = "mailbox";
+ this.form.schema.value = "$postfix_courierimap_mailbox_map";
+ this.form.primary_key.value = "username";
+ '>
+ <LI><INPUT TYPE="button" VALUE="postfix_courierimap_alias" onClick='
+ this.form.table.value = "alias";
+ this.form.schema.value = "$postfix_courierimap_alias_map";
+ this.form.primary_key.value = "address";
+ '>
+</UL>
+END
+);
+
+sub _map {
+ my $self = shift;
+ map { /^\s*(\S+)\s*(\S+)\s*$/ } split("\n", $self->option('schema') );
+}
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self, $svc_acct) = (shift, shift);
+
+ my %map = $self->_map;
+
+ my %record = map { my $value = $map{$_};
+ $_ => $svc_acct->$value();
+ } keys %map;
+
+ my $err_or_queue =
+ $self->acct_sql_queue(
+ $svc_acct->svcnum,
+ 'insert',
+ $self->option('table'),
+ %record
+ );
+ return $err_or_queue unless ref($err_or_queue);
+
+ '';
+
+}
+
+sub _export_replace {
+}
+
+sub _export_delete {
+ my ( $self, $svc_acct ) = (shift, shift);
+ my %map = $self->_map;
+ my $keymap = $map{$self->option('primary_key')};
+ my $err_or_queue = $self->acct_sql_queue(
+ $svc_acct->svcnum,
+ 'delete',
+ $self->option('table'),
+ $self->option('primary_key') => $svc_acct->$keymap(),
+ );
+ return $err_or_queue unless ref($err_or_queue);
+ '';
+}
+
+sub acct_sql_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::acct_sql::acct_sql_$method",
+ };
+ $queue->insert(
+ $self->option('datasrc'),
+ $self->option('username'),
+ $self->option('password'),
+ @_,
+ ) or $queue;
+}
+
+sub acct_sql_insert { #subroutine, not method
+ my $dbh = acct_sql_connect(shift, shift, shift);
+ my( $table, %record ) = @_;
+
+ my $sth = $dbh->prepare(
+ "INSERT INTO $table ( ". join(", ", keys %record).
+ " ) VALUES ( ". join(", ", map '?', keys %record ). " )"
+ ) or die $dbh->errstr;
+
+ $sth->execute( map $record{$_}, keys %record )
+ or die "can't insert into $table table: ". $sth->errstr;
+
+ $dbh->disconnect;
+}
+
+sub acct_sql_delete { #subroutine, not method
+ my $dbh = acct_sql_connect(shift, shift, shift);
+ my( $table, %record ) = @_;
+
+ my $sth = $dbh->prepare(
+ "DELETE FROM $table WHERE ". join(' AND ', map "$_ = ? ", keys %record )
+ ) or die $dbh->errstr;
+
+ $sth->execute( map $record{$_}, keys %record )
+ or die "can't delete from $table table: ". $sth->errstr;
+
+ $dbh->disconnect;
+}
+
+sub acct_sql_connect {
+ #my($datasrc, $username, $password) = @_;
+ #DBI->connect($datasrc, $username, $password) or die $DBI::errstr;
+ DBI->connect(@_) or die $DBI::errstr;
+}
+
+1;
+
+
diff --git a/FS/FS/part_export/apache.pm b/FS/FS/part_export/apache.pm
new file mode 100644
index 0000000..35b00cc
--- /dev/null
+++ b/FS/FS/part_export/apache.pm
@@ -0,0 +1,47 @@
+package FS::part_export::apache;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export::null;
+
+@ISA = qw(FS::part_export::null);
+
+tie my %options, 'Tie::IxHash',
+ 'user' => { label=>'Remote username', default=>'root' },
+ 'httpd_conf' => { label=>'httpd.conf snippet location',
+ default=>'/etc/apache/httpd-freeside.conf', },
+ 'restart' => { label=>'Apache restart command',
+ default=>'apachectl graceful',
+ },
+ 'template' => {
+ label => 'Template',
+ type => 'textarea',
+ default => <<'END',
+<VirtualHost $domain> #generic
+#<VirtualHost ip.addr> #preferred, http://httpd.apache.org/docs/dns-caveats.html
+DocumentRoot /var/www/$zone
+ServerName $zone
+ServerAlias *.$zone
+#BandWidthModule On
+#LargeFileLimit 4096 12288
+#FrontpageEnable on
+</VirtualHost>
+
+END
+ },
+;
+
+%info = (
+ 'svc' => 'svc_www',
+ 'desc' => 'Export an Apache httpd.conf file snippet.',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Batch export of an httpd.conf snippet from a template. Typically used with
+something like <code>Include /etc/apache/httpd-freeside.conf</code> in
+httpd.conf. <a href="http://search.cpan.org/dist/File-Rsync">File::Rsync</a>
+must be installed. Run bin/apache.export to export the files.
+END
+);
+
+1;
+
diff --git a/FS/FS/part_export/bind.pm b/FS/FS/part_export/bind.pm
new file mode 100644
index 0000000..1ef7b65
--- /dev/null
+++ b/FS/FS/part_export/bind.pm
@@ -0,0 +1,35 @@
+package FS::part_export::bind;
+
+use vars qw(@ISA %info %options);
+use Tie::IxHash;
+use FS::part_export::null;
+
+@ISA = qw(FS::part_export::null);
+
+tie %options, 'Tie::IxHash',
+ 'named_conf' => { label => 'named.conf location',
+ default=> '/etc/bind/named.conf' },
+ 'zonepath' => { label => 'path to zone files',
+ default=> '/etc/bind/', },
+ 'bind_release' => { label => 'ISC BIND Release',
+ type => 'select',
+ options => [qw(BIND8 BIND9)],
+ default => 'BIND8' },
+ 'bind9_minttl' => { label => 'The minttl required by bind9 and RFC1035.',
+ default => '1D' },
+ 'reload' => { label => 'Optional reload command. If not specified, defaults to "ndc" under BIND8 and "rndc" under BIND9.', },
+;
+
+%info = (
+ 'svc' => 'svc_domain',
+ 'desc' => 'Batch export to BIND named',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Batch export of BIND zone and configuration files to a primary nameserver.
+<a href="http://search.cpan.org/search?dist=File-Rsync">File::Rsync</a>
+must be installed. Run bin/bind.export to export the files.
+END
+);
+
+1;
+
diff --git a/FS/FS/part_export/bind_slave.pm b/FS/FS/part_export/bind_slave.pm
new file mode 100644
index 0000000..c89325f
--- /dev/null
+++ b/FS/FS/part_export/bind_slave.pm
@@ -0,0 +1,28 @@
+package FS::part_export::bind_slave;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export::null;
+
+@ISA = qw(FS::part_export::null);
+
+tie my %options, 'Tie::IxHash',
+ 'master' => { label=> 'Master IP address(s) (semicolon-separated)' },
+ %FS::part_export::bind::options,
+;
+delete $options{'zonepath'};
+
+%info = (
+ 'svc' => 'svc_domain',
+ 'desc' =>'Batch export to slave BIND named',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Batch export of BIND configuration file to a secondary nameserver. Zones are
+slaved from the listed masters.
+<a href="http://search.cpan.org/dist/File-Rsync">File::Rsync</a>
+must be installed. Run bin/bind.export to export the files.
+END
+);
+
+1;
+
diff --git a/FS/FS/part_export/bsdshell.pm b/FS/FS/part_export/bsdshell.pm
new file mode 100644
index 0000000..7b5feb2
--- /dev/null
+++ b/FS/FS/part_export/bsdshell.pm
@@ -0,0 +1,25 @@
+package FS::part_export::bsdshell;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export::passwdfile;
+
+@ISA = qw(FS::part_export::passwdfile);
+
+tie my %options, 'Tie::IxHash', %FS::part_export::passwdfile::options;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' =>
+ 'Batch export of /etc/passwd and /etc/master.passwd files (BSD)',
+ 'options' => \%options,
+ 'nodomain' => 'Y',
+ 'notes' => <<'END'
+MD5 crypt requires installation of
+<a href="http://search.cpan.org/dist/Crypt-PasswdMD5">Crypt::PasswdMD5</a>
+from CPAN. Run bin/bsdshell.export to export the files.
+END
+);
+
+1;
+
diff --git a/FS/FS/part_export/communigate_pro.pm b/FS/FS/part_export/communigate_pro.pm
new file mode 100644
index 0000000..6da2017
--- /dev/null
+++ b/FS/FS/part_export/communigate_pro.pm
@@ -0,0 +1,178 @@
+package FS::part_export::communigate_pro;
+
+use vars qw(@ISA %info %options);
+use Tie::IxHash;
+use FS::part_export;
+use FS::queue;
+
+@ISA = qw(FS::part_export);
+
+tie %options, 'Tie::IxHash',
+ 'port' => { label=>'Port number', default=>'106', },
+ 'login' => { label=>'The administrator account name. The name can contain a domain part.', },
+ 'password' => { label=>'The administrator account password.', },
+ 'accountType' => { label=>'Type for newly-created accounts',
+ type=>'select',
+ options=>[qw( MultiMailbox TextMailbox MailDirMailbox )],
+ default=>'MultiMailbox',
+ },
+ 'externalFlag' => { label=> 'Create accounts with an external (visible for legacy mailers) INBOX.',
+ type=>'checkbox',
+ },
+ 'AccessModes' => { label=>'Access modes',
+ default=>'Mail POP IMAP PWD WebMail WebSite',
+ },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export to a CommuniGate Pro mail server',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Real time export to a
+<a href="http://www.stalker.com/CommuniGatePro/">CommuniGate Pro</a>
+mail server. The
+<a href="http://www.stalker.com/CGPerl/">CommuniGate Pro Perl Interface</a>
+must be installed as CGP::CLI.
+END
+);
+
+sub rebless { shift; }
+
+sub export_username {
+ my($self, $svc_acct) = (shift, shift);
+ $svc_acct->email;
+}
+
+sub _export_insert {
+ my( $self, $svc_acct ) = (shift, shift);
+ my @options = ( $svc_acct->svcnum, 'CreateAccount',
+ 'accountName' => $self->export_username($svc_acct),
+ 'accountType' => $self->option('accountType'),
+ 'AccessModes' => $self->option('AccessModes'),
+ 'RealName' => $svc_acct->finger,
+ 'Password' => $svc_acct->_password,
+ );
+ push @options, 'MaxAccountSize' => $svc_acct->quota if $svc_acct->quota;
+ push @options, 'externalFlag' => $self->option('externalFlag')
+ if $self->option('externalFlag');
+
+ $self->communigate_pro_queue( @options );
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+ return "can't (yet) change username with CommuniGate Pro"
+ if $old->username ne $new->username;
+ return "can't (yet) change domain with CommuniGate Pro"
+ if $self->export_username($old) ne $self->export_username($new);
+ return "can't (yet) change GECOS with CommuniGate Pro"
+ if $old->finger ne $new->finger;
+ return "can't (yet) change quota with CommuniGate Pro"
+ if $old->quota ne $new->quota;
+ return '' unless $old->username ne $new->username
+ || $old->_password ne $new->_password
+ || $old->finger ne $new->finger
+ || $old->quota ne $new->quota;
+
+ return '' if '*SUSPENDED* '. $old->_password eq $new->_password;
+
+ #my $err_or_queue = $self->communigate_pro_queue( $new->svcnum,'RenameAccount',
+ # $old->email, $new->email );
+ #return $err_or_queue unless ref($err_or_queue);
+ #my $jobnum = $err_or_queue->jobnum;
+
+ $self->communigate_pro_queue( $new->svcnum, 'SetAccountPassword',
+ $self->export_username($new), $new->_password )
+ if $new->_password ne $old->_password;
+
+}
+
+sub _export_delete {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->communigate_pro_queue( $svc_acct->svcnum, 'DeleteAccount',
+ $self->export_username($svc_acct),
+ );
+}
+
+sub _export_suspend {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->communigate_pro_queue( $svc_acct->svcnum, 'UpdateAccountSettings',
+ 'accountName' => $self->export_username($svc_acct),
+ 'AccessModes' => 'Mail',
+ );
+}
+
+sub _export_unsuspend {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->communigate_pro_queue( $svc_acct->svcnum, 'UpdateAccountSettings',
+ 'accountName' => $self->export_username($svc_acct),
+ 'AccessModes' => $self->option('AccessModes'),
+ );
+}
+
+sub communigate_pro_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my @kludge_methods = qw(CreateAccount UpdateAccountSettings);
+ my $sub = 'communigate_pro_command';
+ $sub = $method if grep { $method eq $_ } @kludge_methods;
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::communigate_pro::$sub",
+ };
+ $queue->insert(
+ $self->machine,
+ $self->option('port'),
+ $self->option('login'),
+ $self->option('password'),
+ $method,
+ @_,
+ );
+
+}
+
+sub CreateAccount {
+ my( $machine, $port, $login, $password, $method, %args ) = @_;
+ my $accountName = delete $args{'accountName'};
+ my $accountType = delete $args{'accountType'};
+ my $externalFlag = delete $args{'externalFlag'};
+ $args{'AccessModes'} = [ split(' ', $args{'AccessModes'}) ];
+ my @args = ( accountName => $accountName,
+ accountType => $accountType,
+ settings => \%args,
+ );
+ #externalFlag => $externalFlag,
+ push @args, externalFlag => $externalFlag if $externalFlag;
+
+ communigate_pro_command( $machine, $port, $login, $password, $method, @args );
+
+}
+
+sub UpdateAccountSettings {
+ my( $machine, $port, $login, $password, $method, %args ) = @_;
+ my $accountName = delete $args{'accountName'};
+ $args{'AccessModes'} = [ split(' ', $args{'AccessModes'}) ];
+ @args = ( $accountName, \%args );
+ communigate_pro_command( $machine, $port, $login, $password, $method, @args );
+}
+
+sub communigate_pro_command { #subroutine, not method
+ my( $machine, $port, $login, $password, $method, @args ) = @_;
+
+ eval "use CGP::CLI";
+
+ my $cli = new CGP::CLI( {
+ 'PeerAddr' => $machine,
+ 'PeerPort' => $port,
+ 'login' => $login,
+ 'password' => $password,
+ } ) or die "Can't login to CGPro: $CGP::ERR_STRING\n";
+
+ $cli->$method(@args) or die "CGPro error: ". $cli->getErrMessage;
+
+ $cli->Logout or die "Can't logout of CGPro: $CGP::ERR_STRING\n";
+
+}
+
+1;
+
diff --git a/FS/FS/part_export/communigate_pro_singledomain.pm b/FS/FS/part_export/communigate_pro_singledomain.pm
new file mode 100644
index 0000000..6a1bf60
--- /dev/null
+++ b/FS/FS/part_export/communigate_pro_singledomain.pm
@@ -0,0 +1,37 @@
+package FS::part_export::communigate_pro_singledomain;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export::communigate_pro;
+
+@ISA = qw(FS::part_export::communigate_pro);
+
+tie my %options, 'Tie::IxHash', %FS::part_export::communigate_pro::options,
+ 'domain' => { label=>'Domain', },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' =>
+ 'Real-time export to a CommuniGate Pro mail server, one domain only',
+ 'options' => \%options,
+ 'nodomain' => 'Y',
+ 'notes' => <<'END'
+Real time export to a
+<a href="http://www.stalker.com/CommuniGatePro/">CommuniGate Pro</a>
+mail server. This is an unusual export to CommuniGate Pro that forces all
+accounts into a single domain. As CommuniGate Pro supports multipledomains,
+unless you have a specific reason for using this export, you probably want to
+use the communigate_pro export instead. The
+<a href="http://www.stalker.com/CGPerl/">CommuniGate Pro Perl Interface</a>
+must be installed as CGP::CLI.
+END
+);
+
+sub export_username {
+ my($self, $svc_acct) = (shift, shift);
+ $svc_acct->username. '@'. $self->option('domain');
+}
+
+1;
+
diff --git a/FS/FS/part_export/cp.pm b/FS/FS/part_export/cp.pm
new file mode 100644
index 0000000..a295c57
--- /dev/null
+++ b/FS/FS/part_export/cp.pm
@@ -0,0 +1,160 @@
+package FS::part_export::cp;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'port' => { label=>'Port number' },
+ 'username' => { label=>'Username' },
+ 'password' => { label=>'Password' },
+ 'domain' => { label=>'Domain' },
+ 'workgroup' => { label=>'Default Workgroup' },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export to Critical Path Account Provisioning Protocol',
+ 'options'=> \%options,
+ 'notes' => <<'END'
+Real-time export to
+<a href="http://www.cp.net/">Critial Path Account Provisioning Protocol</a>.
+Requires installation of
+<a href="http://search.cpan.org/dist/Net-APP">Net::APP</a>
+from CPAN.
+END
+);
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->cp_queue( $svc_acct->svcnum, 'create_mailbox',
+ 'Mailbox' => $svc_acct->username,
+ 'Password' => $svc_acct->_password,
+ 'Workgroup' => $self->option('workgroup'),
+ 'Domain' => $svc_acct->domain,
+ );
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+ return "can't change domain with Critical Path"
+ if $old->domain ne $new->domain;
+ return '' unless $old->username ne $new->username
+ || $old->_password ne $new->_password;
+ $self->cp_queue( $new->svcnum, 'replace', $new->domain,
+ $old->username, $new->username, $old->_password, $new->_password );
+}
+
+sub _export_delete {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->cp_queue( $svc_acct->svcnum, 'delete_mailbox',
+ 'Mailbox' => $svc_acct->username,
+ 'Domain' => $svc_acct->domain,
+ );
+}
+
+sub _export_suspend {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->cp_queue( $svc_acct->svcnum, 'set_mailbox_status',
+ 'Mailbox' => $svc_acct->username,
+ 'Domain' => $svc_acct->domain,
+ 'OTHER' => 'T',
+ 'OTHER_SUSPEND' => 'T',
+ );
+}
+
+sub _export_unsuspend {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->cp_queue( $svc_acct->svcnum, 'set_mailbox_status',
+ 'Mailbox' => $svc_acct->username,
+ 'Domain' => $svc_acct->domain,
+ 'PAYMENT' => 'F',
+ 'OTHER' => 'F',
+ 'OTHER_SUSPEND' => 'F',
+ 'OTHER_BOUNCE' => 'F',
+ );
+}
+
+sub cp_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => 'FS::part_export::cp::cp_command',
+ };
+ $queue->insert(
+ $self->machine,
+ $self->option('port'),
+ $self->option('username'),
+ $self->option('password'),
+ $self->option('domain'),
+ $method,
+ @_,
+ );
+}
+
+sub cp_command { #subroutine, not method
+ my($host, $port, $username, $password, $login_domain, $method, @args) = @_;
+
+ #quelle hack
+ if ( $method eq 'replace' ) {
+
+ my( $domain, $old_username, $new_username, $old_password, $new_password)
+ = @args;
+
+ if ( $old_username ne $new_username ) {
+ cp_command($host, $port, $username, $password, 'rename_mailbox',
+ Domain => $domain,
+ Old_Mailbox => $old_username,
+ New_Mailbox => $new_username,
+ );
+ }
+
+ #my $other = 'F';
+ if ( $new_password =~ /^\*SUSPENDED\* (.*)$/ ) {
+ $new_password = $1;
+ # $other = 'T';
+ }
+ #cp_command($host, $port, $username, $password, $login_domain,
+ # 'set_mailbox_status',
+ # Domain => $domain,
+ # Mailbox => $new_username,
+ # Other => $other,
+ # Other_Bounce => $other,
+ #);
+
+ if ( $old_password ne $new_password ) {
+ cp_command($host, $port, $username, $password, $login_domain,
+ 'change_mailbox',
+ Domain => $domain,
+ Mailbox => $new_username,
+ Password => $new_password,
+ );
+ }
+
+ return;
+ }
+ #eof quelle hack
+
+ eval "use Net::APP;";
+
+ my $app = new Net::APP (
+ "$host:$port",
+ User => $username,
+ Password => $password,
+ Domain => $login_domain,
+ Timeout => 60,
+ #Debug => 1,
+ ) or die "$@\n";
+
+ $app->$method( @args );
+
+ die $app->message."\n" unless $app->ok;
+
+}
+
+1;
+
diff --git a/FS/FS/part_export/cyrus.pm b/FS/FS/part_export/cyrus.pm
new file mode 100644
index 0000000..84c9e5a
--- /dev/null
+++ b/FS/FS/part_export/cyrus.pm
@@ -0,0 +1,120 @@
+package FS::part_export::cyrus;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'server' => { label=>'IMAP server' },
+ 'username' => { label=>'Admin username' },
+ 'password' => { label=>'Admin password' },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export to Cyrus IMAP server',
+ 'options' => \%options,
+ 'nodomain' => 'Y',
+ 'notes' => <<'END'
+Integration with
+<a href="http://asg.web.cmu.edu/cyrus/imapd/">Cyrus IMAP Server</a>.
+Cyrus::IMAP::Admin should be installed locally and the connection to the
+server secured. <B>svc_acct.quota</B>, if available, is used to set the
+Cyrus quota.
+END
+);
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self, $svc_acct) = (shift, shift);
+ $self->cyrus_queue( $svc_acct->svcnum, 'insert',
+ $svc_acct->username, $svc_acct->quota );
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+ return "can't change username using Cyrus"
+ if $old->username ne $new->username;
+ return '';
+# #return '' unless $old->_password ne $new->_password;
+# $self->cyrus_queue( $new->svcnum,
+# 'replace', $new->username, $new->_password );
+}
+
+sub _export_delete {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->cyrus_queue( $svc_acct->svcnum, 'delete',
+ $svc_acct->username );
+}
+
+#a good idea to queue anything that could fail or take any time
+sub cyrus_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::cyrus::cyrus_$method",
+ };
+ $queue->insert(
+ $self->option('server'),
+ $self->option('username'),
+ $self->option('password'),
+ @_
+ );
+}
+
+sub cyrus_insert { #subroutine, not method
+ my $client = cyrus_connect(shift, shift, shift);
+ my( $username, $quota ) = @_;
+ my $rc = $client->create("user.$username");
+ my $error = $client->error;
+ die "creating user.$username: $error" if $error;
+
+ $rc = $client->setacl("user.$username", $username => 'all' );
+ $error = $client->error;
+ die "setacl user.$username: $error" if $error;
+
+ if ( $quota ) {
+ $rc = $client->setquota("user.$username", 'STORAGE' => $quota );
+ $error = $client->error;
+ die "setquota user.$username: $error" if $error;
+ }
+
+}
+
+sub cyrus_delete { #subroutine, not method
+ my ( $server, $admin_username, $password_username, $username ) = @_;
+ my $client = cyrus_connect($server, $admin_username, $password_username);
+
+ my $rc = $client->setacl("user.$username", $admin_username => 'all' );
+ my $error = $client->error;
+ die $error if $error;
+
+ $rc = $client->delete("user.$username");
+ $error = $client->error;
+ die $error if $error;
+}
+
+sub cyrus_connect {
+
+ my( $server, $admin_username, $admin_password ) = @_;
+
+ eval "use Cyrus::IMAP::Admin;";
+
+ my $client = Cyrus::IMAP::Admin->new($server);
+ $client->authenticate(
+ -user => $admin_username,
+ -mechanism => "login",
+ -password => $admin_password,
+ );
+ $client;
+
+}
+
+#sub cyrus_replace { #subroutine, not method
+#}
+
+1;
+
diff --git a/FS/FS/part_export/domain_shellcommands.pm b/FS/FS/part_export/domain_shellcommands.pm
new file mode 100644
index 0000000..0ba5617
--- /dev/null
+++ b/FS/FS/part_export/domain_shellcommands.pm
@@ -0,0 +1,161 @@
+package FS::part_export::domain_shellcommands;
+
+use strict;
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'user' => { label=>'Remote username', default=>'root' },
+ 'useradd' => { label=>'Insert command',
+ default=>'',
+ },
+ 'userdel' => { label=>'Delete command',
+ default=>'',
+ },
+ 'usermod' => { label=>'Modify command',
+ default=>'',
+ },
+;
+
+%info = (
+ 'svc' => 'svc_domain',
+ 'desc' => 'Run remote commands via SSH, for domains (qmail, ISPMan).',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Run remote commands via SSH, for domains. You will need to
+<a href="../docs/ssh.html">setup SSH for unattended operation</a>.
+<BR><BR>Use these buttons for some useful presets:
+<UL>
+ <LI>
+ <INPUT TYPE="button" VALUE="qmail catchall .qmail-domain-default maintenance" onClick='
+ this.form.useradd.value = "[ \"$uid\" -a \"$gid\" -a \"$dir\" -a \"$qdomain\" ] && [ -e $dir/.qmail-$qdomain-default ] || { touch $dir/.qmail-$qdomain-default; chown $uid:$gid $dir/.qmail-$qdomain-default; }";
+ this.form.userdel.value = "";
+ this.form.usermod.value = "";
+ '>
+ <LI>
+ <INPUT TYPE="button" VALUE="ISPMan CLI" onClick='
+ this.form.useradd.value = "/usr/local/ispman/bin/ispman.addDomain -d $domain changeme";
+ this.form.userdel.value = "/usr/local/ispman/bin/ispman.deleteDomain -d $domain";
+ this.form.usermod.value = "";
+ '>
+</UL>
+The following variables are available for interpolation (prefixed with <code>new_</code> or <code>old_</code> for replace operations):
+<UL>
+ <LI><code>$domain</code>
+ <LI><code>$qdomain</code> - domain with periods replaced by colons
+ <LI><code>$uid</code> - of catchall account
+ <LI><code>$gid</code> - of catchall account
+ <LI><code>$dir</code> - home directory of catchall account
+ <LI>All other fields in
+ <a href="../docs/schema.html#svc_domain">svc_domain</a> are also available.
+</UL>
+END
+);
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self) = shift;
+ $self->_export_command('useradd', @_);
+}
+
+sub _export_delete {
+ my($self) = shift;
+ $self->_export_command('userdel', @_);
+}
+
+sub _export_command {
+ my ( $self, $action, $svc_domain) = (shift, shift, shift);
+ my $command = $self->option($action);
+
+ #set variable for the command
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${$_} = $svc_domain->getfield($_) foreach $svc_domain->fields;
+ }
+ ( $qdomain = $domain ) =~ s/\./:/g; #see dot-qmail(5): EXTENSION ADDRESSES
+
+ if ( $svc_domain->catchall ) {
+ no strict 'refs';
+ my $svc_acct = $svc_domain->catchall_svc_acct;
+ ${$_} = $svc_acct->getfield($_) foreach qw(uid gid dir);
+ } else {
+ no strict 'refs';
+ ${$_} = '' foreach qw(uid gid dir);
+ }
+
+ #done setting variables for the command
+
+ $self->shellcommands_queue( $svc_domain->svcnum,
+ user => $self->option('user')||'root',
+ host => $self->machine,
+ command => eval(qq("$command")),
+ );
+}
+
+sub _export_replace {
+ my($self, $new, $old ) = (shift, shift, shift);
+ my $command = $self->option('usermod');
+
+ #set variable for the command
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${"old_$_"} = $old->getfield($_) foreach $old->fields;
+ ${"new_$_"} = $new->getfield($_) foreach $new->fields;
+ }
+ ( $old_qdomain = $old_domain ) =~ s/\./:/g; #see dot-qmail(5): EXTENSION ADDRESSES
+ ( $new_qdomain = $new_domain ) =~ s/\./:/g; #see dot-qmail(5): EXTENSION ADDRESSES
+
+ if ( $old->catchall ) {
+ no strict 'refs';
+ my $svc_acct = $old->catchall_svc_acct;
+ ${"old_$_"} = $svc_acct->getfield($_) foreach qw(uid gid dir);
+ } else {
+ ${"old_$_"} = '' foreach qw(uid gid dir);
+ }
+ if ( $new->catchall ) {
+ no strict 'refs';
+ my $svc_acct = $new->catchall_svc_acct;
+ ${"new_$_"} = $svc_acct->getfield($_) foreach qw(uid gid dir);
+ } else {
+ ${"new_$_"} = '' foreach qw(uid gid dir);
+ }
+
+ #done setting variables for the command
+
+ $self->shellcommands_queue( $new->svcnum,
+ user => $self->option('user')||'root',
+ host => $self->machine,
+ command => eval(qq("$command")),
+ );
+}
+
+#a good idea to queue anything that could fail or take any time
+sub shellcommands_queue {
+ my( $self, $svcnum ) = (shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::domain_shellcommands::ssh_cmd",
+ };
+ $queue->insert( @_ );
+}
+
+sub ssh_cmd { #subroutine, not method
+ use Net::SSH '0.08';
+ &Net::SSH::ssh_cmd( { @_ } );
+}
+
+#sub shellcommands_insert { #subroutine, not method
+#}
+#sub shellcommands_replace { #subroutine, not method
+#}
+#sub shellcommands_delete { #subroutine, not method
+#}
+
+1;
+
diff --git a/FS/FS/part_export/forward_shellcommands.pm b/FS/FS/part_export/forward_shellcommands.pm
new file mode 100644
index 0000000..fe30435
--- /dev/null
+++ b/FS/FS/part_export/forward_shellcommands.pm
@@ -0,0 +1,159 @@
+package FS::part_export::forward_shellcommands;
+
+use strict;
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'user' => { label=>'Remote username', default=>'root' },
+ 'useradd' => { label=>'Insert command',
+ default=>'',
+ },
+ 'userdel' => { label=>'Delete command',
+ default=>'',
+ },
+ 'usermod' => { label=>'Modify command',
+ default=>'',
+ },
+;
+
+%info = (
+ 'svc' => 'svc_forward',
+ 'desc' => 'Run remote commands via SSH, for forwards',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Run remote commands via SSH, for forwards. You will need to
+<a href="../docs/ssh.html">setup SSH for unattended operation</a>.
+<BR><BR>Use these buttons for some useful presets:
+<UL>
+ <LI>
+ <INPUT TYPE="button" VALUE="text vpopmail maintenance" onClick='
+ this.form.useradd.value = "[ -d /home/vpopmail/domains/$domain/$username ] && { echo \"$destination\" > /home/vpopmail/domains/$domain/$username/.qmail; chown vpopmail:vchkpw /home/vpopmail/domains/$domain/$username/.qmail; }";
+ this.form.userdel.value = "rm /home/vpopmail/domains/$domain/$username/.qmail";
+ this.form.usermod.value = "mv /home/vpopmail/domains/$old_domain/$old_username/.qmail /home/vpopmail/domains/$new_domain/$new_username; [ \"$old_destination\" != \"$new_destination\" ] && { echo \"$new_destination\" > /home/vpopmail/domains/$new_domain/$new_username/.qmail; chown vpopmail:vchkpw /home/vpopmail/domains/$new_domain/$new_username/.qmail; }";
+ '>
+ <LI>
+ <INPUT TYPE="button" VALUE="ISPMan CLI" onClick='
+ this.form.useradd.value = "";
+ this.form.userdel.value = "";
+ this.form.usermod.value = "";
+ '>
+</UL>
+The following variables are available for interpolation (prefixed with
+<code>new_</code> or <code>old_</code> for replace operations):
+<UL>
+ <LI><code>$username</code>
+ <LI><code>$domain</code>
+ <LI><code>$destination</code> - forward destination
+ <LI>All other fields in <a href="../docs/schema.html#svc_forward">svc_forward</a> are also available.
+</UL>
+END
+);
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self) = shift;
+ $self->_export_command('useradd', @_);
+}
+
+sub _export_delete {
+ my($self) = shift;
+ $self->_export_command('userdel', @_);
+}
+
+sub _export_command {
+ my ( $self, $action, $svc_forward ) = (shift, shift, shift);
+ my $command = $self->option($action);
+
+ #set variable for the command
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${$_} = $svc_forward->getfield($_) foreach $svc_forward->fields;
+ }
+
+ my $svc_acct = $svc_forward->srcsvc_acct;
+ $username = $svc_acct->username;
+ $domain = $svc_acct->domain;
+ if ($svc_forward->dstsvc_acct) {
+ $destination = $svc_forward->dstsvc_acct->email;
+ } else {
+ $destination = $svc_forward->dst;
+ }
+
+ #done setting variables for the command
+
+ $self->shellcommands_queue( $svc_forward->svcnum,
+ user => $self->option('user')||'root',
+ host => $self->machine,
+ command => eval(qq("$command")),
+ );
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+ my $command = $self->option('usermod');
+
+ #set variable for the command
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${"old_$_"} = $old->getfield($_) foreach $old->fields;
+ ${"new_$_"} = $new->getfield($_) foreach $new->fields;
+ }
+
+ my $old_svc_acct = $old->srcsvc_acct;
+ $old_username = $old_svc_acct->username;
+ $old_domain = $old_svc_acct->domain;
+ if ($old->dstsvc_acct) {
+ $old_destination = $old->dstsvc_acct->email;
+ } else {
+ $old_destination = $old->dst;
+ }
+
+ my $new_svc_acct = $new->srcsvc_acct;
+ $new_username = $new_svc_acct->username;
+ $new_domain = $new_svc_acct->domain;
+ if ($new->dstsvc) {
+ $new_destination = $new->dstsvc_acct->email;
+ } else {
+ $new_destination = $new->dst;
+ }
+
+ #done setting variables for the command
+
+ $self->shellcommands_queue( $new->svcnum,
+ user => $self->option('user')||'root',
+ host => $self->machine,
+ command => eval(qq("$command")),
+ );
+}
+
+#a good idea to queue anything that could fail or take any time
+sub shellcommands_queue {
+ my( $self, $svcnum ) = (shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::forward_shellcommands::ssh_cmd",
+ };
+ $queue->insert( @_ );
+}
+
+sub ssh_cmd { #subroutine, not method
+ use Net::SSH '0.08';
+ &Net::SSH::ssh_cmd( { @_ } );
+}
+
+#sub shellcommands_insert { #subroutine, not method
+#}
+#sub shellcommands_replace { #subroutine, not method
+#}
+#sub shellcommands_delete { #subroutine, not method
+#}
+
+1;
+
diff --git a/FS/FS/part_export/http.pm b/FS/FS/part_export/http.pm
new file mode 100644
index 0000000..0be2a0f
--- /dev/null
+++ b/FS/FS/part_export/http.pm
@@ -0,0 +1,134 @@
+package FS::part_export::http;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'method' => { label =>'Method',
+ type =>'select',
+ #options =>[qw(POST GET)],
+ options =>[qw(POST)],
+ default =>'POST' },
+ 'url' => { label => 'URL', default => 'http://', },
+ 'insert_data' => {
+ label => 'Insert data',
+ type => 'textarea',
+ default => join("\n",
+ 'DomainName $svc_x->domain',
+ 'Email ( grep { $_ ne "POST" } $svc_x->cust_svc->cust_pkg->cust_main->invoicing_list)[0]',
+ 'test 1',
+ 'reseller $svc_x->cust_svc->cust_pkg->part_pkg->pkg =~ /reseller/i',
+ ),
+ },
+ 'delete_data' => {
+ label => 'Delete data',
+ type => 'textarea',
+ default => join("\n",
+ ),
+ },
+ 'replace_data' => {
+ label => 'Replace data',
+ type => 'textarea',
+ default => join("\n",
+ ),
+ },
+;
+
+%info = (
+ 'svc' => 'svc_domain',
+ 'desc' => 'Send an HTTP or HTTPS GET or POST request',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Send an HTTP or HTTPS GET or POST to the specified URL. For HTTPS support,
+<a href="http://search.cpan.org/dist/Crypt-SSLeay">Crypt::SSLeay</a>
+or <a href="http://search.cpan.org/dist/IO-Socket-SSL">IO::Socket::SSL</a>
+is required.
+END
+);
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my $self = shift;
+ $self->_export_command('insert', @_);
+}
+
+sub _export_delete {
+ my $self = shift;
+ $self->_export_command('delete', @_);
+}
+
+sub _export_command {
+ my( $self, $action, $svc_x ) = ( shift, shift, shift );
+
+ return unless $self->option("${action}_data");
+
+ $self->http_queue( $svc_x->svcnum,
+ $self->option('method'),
+ $self->option('url'),
+ map {
+ /^\s*(\S+)\s+(.*)$/ or /()()/;
+ my( $field, $value_expression ) = ( $1, $2 );
+ my $value = eval $value_expression;
+ die $@ if $@;
+ ( $field, $value );
+ } split(/\n/, $self->option("${action}_data") )
+ );
+
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = ( shift, shift, shift );
+
+ return unless $self->option('replace_data');
+
+ $self->http_queue( $svc_x->svcnum,
+ $self->option('method'),
+ $self->option('url'),
+ map {
+ /^\s*(\S+)\s+(.*)$/ or /()()/;
+ my( $field, $value_expression ) = ( $1, $2 );
+ die $@ if $@;
+ ( $field, $value );
+ } split(/\n/, $self->option('replace_data') )
+ );
+
+}
+
+sub http_queue {
+ my($self, $svcnum) = (shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::http::http",
+ };
+ $queue->insert( @_ );
+}
+
+sub http {
+ my($method, $url, @data) = @_;
+
+ $method = lc($method);
+
+ eval "use LWP::UserAgent;";
+ die "using LWP::UserAgent: $@" if $@;
+ eval "use HTTP::Request::Common;";
+ die "using HTTP::Request::Common: $@" if $@;
+
+ my $ua = LWP::UserAgent->new;
+
+ #my $response = $ua->$method(
+ # $url, \%data,
+ # 'Content-Type'=>'application/x-www-form-urlencoded'
+ #);
+ my $req = HTTP::Request::Common::POST( $url, \@data );
+ my $response = $ua->request($req);
+
+ die $response->error_as_HTML if $response->is_error;
+
+}
+
+1;
+
diff --git a/FS/FS/part_export/infostreet.pm b/FS/FS/part_export/infostreet.pm
new file mode 100644
index 0000000..309e7ce
--- /dev/null
+++ b/FS/FS/part_export/infostreet.pm
@@ -0,0 +1,277 @@
+package FS::part_export::infostreet;
+
+use vars qw(@ISA %info %infostreet2cust_main $DEBUG);
+use Tie::IxHash;
+use FS::UID qw(dbh);
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'url' => { label=>'XML-RPC Access URL', },
+ 'login' => { label=>'InfoStreet login', },
+ 'password' => { label=>'InfoStreet password', },
+ 'groupID' => { label=>'InfoStreet groupID', },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export to InfoStreet streetSmartAPI',
+ 'options' => \%options,
+ 'nodomain' => 'Y',
+ 'notes' => <<'END'
+Real-time export to
+<a href="http://www.infostreet.com/">InfoStreet</a> streetSmartAPI.
+Requires installation of
+<a href="http://search.cpan.org/dist/Frontier-Client">Frontier::Client</a> from CPAN.
+END
+);
+
+$DEBUG = 0;
+
+%infostreet2cust_main = (
+ 'firstName' => 'first',
+ 'lastName' => 'last',
+ 'address1' => 'address1',
+ 'address2' => 'address2',
+ 'city' => 'city',
+ 'state' => 'state',
+ 'zipCode' => 'zip',
+ 'country' => 'country',
+ 'phoneNumber' => 'daytime',
+ 'faxNumber' => 'night', #noment-request...
+);
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my( $self, $svc_acct ) = (shift, shift);
+ my $cust_main = $svc_acct->cust_svc->cust_pkg->cust_main;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $err_or_queue = $self->infostreet_err_or_queue( $svc_acct->svcnum,
+ 'createUser', $svc_acct->username, $svc_acct->_password );
+ return $err_or_queue unless ref($err_or_queue);
+ my $jobnum = $err_or_queue->jobnum;
+
+ my %contact_info = ( map {
+ $_ => $cust_main->getfield( $infostreet2cust_main{$_} );
+ } keys %infostreet2cust_main );
+
+ my @emails = grep { $_ ne 'POST' } $cust_main->invoicing_list;
+ $contact_info{'email'} = $emails[0] if @emails;
+
+ #this one is kinda noment-specific
+ $contact_info{'organization'} = $cust_main->agent->agent;
+
+ $err_or_queue = $self->infostreet_queueContact( $svc_acct->svcnum,
+ $svc_acct->username, %contact_info );
+ return $err_or_queue unless ref($err_or_queue);
+
+ # If a quota has been specified set the quota because it is not the default
+ $err_or_queue = $self->infostreet_queueSetQuota( $svc_acct->svcnum,
+ $svc_acct->username, $svc_acct->quota ) if $svc_acct->quota;
+ return $err_or_queue unless ref($err_or_queue);
+
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ return $error if $error;
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+ return "can't change username with InfoStreet"
+ if $old->username ne $new->username;
+
+ # If the quota has changed then do the export to setQuota
+ my $err_or_queue = $self->infostreet_queueSetQuota( $new->svcnum, $new->username, $new->quota )
+ if ( $old->quota != $new->quota );
+ return $err_or_queue unless ref($err_or_queue);
+
+
+ return '' unless $old->_password ne $new->_password;
+ $self->infostreet_queue( $new->svcnum,
+ 'passwd', $new->username, $new->_password );
+}
+
+sub _export_delete {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->infostreet_queue( $svc_acct->svcnum,
+ 'purgeAccount,releaseUsername', $svc_acct->username );
+}
+
+sub _export_suspend {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->infostreet_queue( $svc_acct->svcnum,
+ 'setStatus', $svc_acct->username, 'DISABLED' );
+}
+
+sub _export_unsuspend {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->infostreet_queue( $svc_acct->svcnum,
+ 'setStatus', $svc_acct->username, 'ACTIVE' );
+}
+
+sub infostreet_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => 'FS::part_export::infostreet::infostreet_command',
+ };
+ $queue->insert(
+ $self->option('url'),
+ $self->option('login'),
+ $self->option('password'),
+ $self->option('groupID'),
+ $method,
+ @_,
+ );
+}
+
+#ick false laziness
+sub infostreet_err_or_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => 'FS::part_export::infostreet::infostreet_command',
+ };
+ $queue->insert(
+ $self->option('url'),
+ $self->option('login'),
+ $self->option('password'),
+ $self->option('groupID'),
+ $method,
+ @_,
+ ) or $queue;
+}
+
+sub infostreet_queueContact {
+ my( $self, $svcnum ) = (shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => 'FS::part_export::infostreet::infostreet_setContact',
+ };
+ $queue->insert(
+ $self->option('url'),
+ $self->option('login'),
+ $self->option('password'),
+ $self->option('groupID'),
+ @_,
+ ) or $queue;
+}
+
+sub infostreet_setContact {
+ my($url, $is_username, $is_password, $groupID, $username, %contact_info) = @_;
+ my $accountID = infostreet_command($url, $is_username, $is_password, $groupID,
+ 'getAccountID', $username);
+ foreach my $field ( keys %contact_info ) {
+ infostreet_command($url, $is_username, $is_password, $groupID,
+ 'setContactField', [ 'int'=>$accountID ], $field, $contact_info{$field} );
+ }
+
+}
+
+sub infostreet_queueSetQuota {
+
+ my( $self, $svcnum) = (shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => 'FS::part_export::infostreet::infostreet_setQuota',
+ };
+
+ $queue->insert(
+ $self->option('url'),
+ $self->option('login'),
+ $self->option('password'),
+ $self->option('groupID'),
+ @_,
+ ) or $queue;
+
+}
+
+sub infostreet_setQuota {
+ my($url, $is_username, $is_password, $groupID, $username, $quota) = @_;
+ infostreet_command($url, $is_username, $is_password, $groupID, 'setQuota', $username, [ 'int'=> $quota ] );
+}
+
+
+sub infostreet_command { #subroutine, not method
+ my($url, $username, $password, $groupID, $method, @args) = @_;
+
+ warn "[FS::part_export::infostreet] $method ".join(' ', @args)."\n" if $DEBUG;
+
+ #quelle hack
+ if ( $method =~ /,/ ) {
+ foreach my $part ( split(/,\s*/, $method) ) {
+ infostreet_command($url, $username, $password, $groupID, $part, @args);
+ }
+ return;
+ }
+
+ eval "use Frontier::Client;";
+ die $@ if $@;
+
+ eval 'sub Frontier::RPC2::String::repr {
+ my $self = shift;
+ my $value = $$self;
+ $value =~ s/([&<>\"])/$Frontier::RPC2::char_entities{$1}/ge;
+ $value;
+ }';
+ die $@ if $@;
+
+ my $conn = Frontier::Client->new( url => $url );
+ my $key_result = $conn->call( 'authenticate', $username, $password, $groupID);
+ my %key_result = _infostreet_parse($key_result);
+ die $key_result{error} unless $key_result{success};
+ my $key = $key_result{data};
+
+ #my $result = $conn->call($method, $key, @args);
+ my $result = $conn->call( $method, $key,
+ map {
+ if ( ref($_) ) {
+ my( $type, $value) = @{$_};
+ $conn->$type($value);
+ } else {
+ $conn->string($_);
+ }
+ } @args );
+ my %result = _infostreet_parse($result);
+ die $result{error} unless $result{success};
+
+ $result->{data};
+
+}
+
+#sub infostreet_command_byid { #subroutine, not method;
+# my($url, $username, $password, $groupID, $method, @args ) = @_;
+#
+# infostreet_command
+#
+#}
+
+sub _infostreet_parse { #subroutine, not method
+ my $arg = shift;
+ map {
+ my $value = $arg->{$_};
+ #warn ref($value);
+ $value = $value->value()
+ if ref($value) && $value->isa('Frontier::RPC2::DataType');
+ $_=>$value;
+ } keys %$arg;
+}
+
+1;
+
diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm
new file mode 100644
index 0000000..823d99d
--- /dev/null
+++ b/FS/FS/part_export/ldap.pm
@@ -0,0 +1,294 @@
+package FS::part_export::ldap;
+
+use vars qw(@ISA %info @saltset);
+use Tie::IxHash;
+use FS::Record qw( dbh );
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'dn' => { label=>'Root DN' },
+ 'password' => { label=>'Root DN password' },
+ 'userdn' => { label=>'User DN' },
+ 'attributes' => { label=>'Attributes',
+ type=>'textarea',
+ default=>join("\n",
+ 'uid $username',
+ 'mail $username\@$domain',
+ 'uidno $uid',
+ 'gidno $gid',
+ 'cn $first',
+ 'sn $last',
+ 'mailquota $quota',
+ 'vmail',
+ 'location',
+ 'mailtag',
+ 'mailhost',
+ 'mailmessagestore $dir',
+ 'userpassword $crypt_password',
+ 'hint',
+ 'answer $sec_phrase',
+ 'objectclass top,person,inetOrgPerson',
+ ),
+ },
+ 'radius' => { label=>'Export RADIUS attributes', type=>'checkbox', },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export to LDAP',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Real-time export to arbitrary LDAP attributes. Requires installation of
+<a href="http://search.cpan.org/dist/Net-LDAP">Net::LDAP</a> from CPAN.
+END
+);
+
+@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self, $svc_acct) = (shift, shift);
+
+ #false laziness w/shellcommands.pm
+ {
+ no strict 'refs';
+ ${$_} = $svc_acct->getfield($_) foreach $svc_acct->fields;
+ ${$_} = $svc_acct->$_() foreach qw( domain );
+ my $cust_pkg = $svc_acct->cust_svc->cust_pkg;
+ if ( $cust_pkg ) {
+ my $cust_main = $cust_pkg->cust_main;
+ ${$_} = $cust_main->getfield($_) foreach qw(first last);
+ }
+ }
+ $crypt_password = ''; #surpress "used only once" warnings
+ $crypt_password = '{crypt}'. crypt( $svc_acct->_password,
+ $saltset[int(rand(64))].$saltset[int(rand(64))] );
+
+ my $username_attrib;
+ my %attrib = map { /^\s*(\w+)\s+(.*\S)\s*$/;
+ $username_attrib = $1 if $2 eq '$username';
+ ( $1 => eval(qq("$2")) ); }
+ grep { /^\s*(\w+)\s+(.*\S)\s*$/ }
+ split("\n", $self->option('attributes'));
+
+ if ( $self->option('radius') ) {
+ foreach my $table (qw(reply check)) {
+ my $method = "radius_$table";
+ my %radius = $svc_acct->$method();
+ foreach my $radius ( keys %radius ) {
+ ( my $ldap = $radius ) =~ s/\-//g;
+ $attrib{$ldap} = $radius{$radius};
+ }
+ }
+ }
+
+ my $err_or_queue = $self->ldap_queue( $svc_acct->svcnum, 'insert',
+ #$svc_acct->username,
+ $username_attrib,
+ %attrib );
+ return $err_or_queue unless ref($err_or_queue);
+
+ #groups with LDAP?
+ #my @groups = $svc_acct->radius_groups;
+ #if ( @groups ) {
+ # my $err_or_queue = $self->ldap_queue(
+ # $svc_acct->svcnum, 'usergroup_insert',
+ # $svc_acct->username, @groups );
+ # return $err_or_queue unless ref($err_or_queue);
+ #}
+
+ '';
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ return "can't (yet?) change username with ldap"
+ if $old->username ne $new->username;
+
+ return "ldap replace unimplemented";
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $jobnum = '';
+ #if ( $old->username ne $new->username ) {
+ # my $err_or_queue = $self->ldap_queue( $new->svcnum, 'rename',
+ # $new->username, $old->username );
+ # unless ( ref($err_or_queue) ) {
+ # $dbh->rollback if $oldAutoCommit;
+ # return $err_or_queue;
+ # }
+ # $jobnum = $err_or_queue->jobnum;
+ #}
+
+ foreach my $table (qw(reply check)) {
+ my $method = "radius_$table";
+ my %new = $new->$method();
+ my %old = $old->$method();
+ if ( grep { !exists $old{$_} #new attributes
+ || $new{$_} ne $old{$_} #changed
+ } keys %new
+ ) {
+ my $err_or_queue = $self->ldap_queue( $new->svcnum, 'insert',
+ $table, $new->username, %new );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ my @del = grep { !exists $new{$_} } keys %old;
+ if ( @del ) {
+ my $err_or_queue = $self->ldap_queue( $new->svcnum, 'attrib_delete',
+ $table, $new->username, @del );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+ }
+
+ # (sorta) false laziness with FS::svc_acct::replace
+ my @oldgroups = @{$old->usergroup}; #uuuh
+ my @newgroups = $new->radius_groups;
+ my @delgroups = ();
+ foreach my $oldgroup ( @oldgroups ) {
+ if ( grep { $oldgroup eq $_ } @newgroups ) {
+ @newgroups = grep { $oldgroup ne $_ } @newgroups;
+ next;
+ }
+ push @delgroups, $oldgroup;
+ }
+
+ if ( @delgroups ) {
+ my $err_or_queue = $self->ldap_queue( $new->svcnum, 'usergroup_delete',
+ $new->username, @delgroups );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ if ( @newgroups ) {
+ my $err_or_queue = $self->ldap_queue( $new->svcnum, 'usergroup_insert',
+ $new->username, @newgroups );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+}
+
+sub _export_delete {
+ my( $self, $svc_acct ) = (shift, shift);
+ return "ldap delete unimplemented";
+ my $err_or_queue = $self->ldap_queue( $svc_acct->svcnum, 'delete',
+ $svc_acct->username );
+ ref($err_or_queue) ? '' : $err_or_queue;
+}
+
+sub ldap_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::ldap::ldap_$method",
+ };
+ $queue->insert(
+ $self->machine,
+ $self->option('dn'),
+ $self->option('password'),
+ $self->option('userdn'),
+ @_,
+ ) or $queue;
+}
+
+sub ldap_insert { #subroutine, not method
+ my $ldap = ldap_connect(shift, shift, shift);
+ my( $userdn, $username_attrib, %attrib ) = @_;
+
+ $userdn = "$username_attrib=$attrib{$username_attrib}, $userdn"
+ if $username_attrib;
+ #icky hack, but should be unsurprising to the LDAPers
+ foreach my $key ( grep { $attrib{$_} =~ /,/ } keys %attrib ) {
+ $attrib{$key} = [ split(/,/, $attrib{$key}) ];
+ }
+
+ my $status = $ldap->add( $userdn, attrs => [ %attrib ] );
+ die 'LDAP error: '. $status->error. "\n" if $status->is_error;
+
+ $ldap->unbind;
+}
+
+#sub ldap_delete { #subroutine, not method
+# my $dbh = ldap_connect(shift, shift, shift);
+# my $username = shift;
+#
+# foreach my $table (qw( radcheck radreply usergroup )) {
+# my $sth = $dbh->prepare( "DELETE FROM $table WHERE UserName = ?" );
+# $sth->execute($username)
+# or die "can't delete from $table table: ". $sth->errstr;
+# }
+# $dbh->disconnect;
+#}
+
+sub ldap_connect {
+ my( $machine, $dn, $password ) = @_;
+ my %bind_options;
+ $bind_options{password} = $password if length($password);
+
+ eval "use Net::LDAP";
+ die $@ if $@;
+
+ my $ldap = Net::LDAP->new($machine) or die $@;
+ my $status = $ldap->bind( $dn, %bind_options );
+ die 'LDAP error: '. $status->error. "\n" if $status->is_error;
+
+ $ldap;
+}
+
+1;
+
diff --git a/FS/FS/part_export/null.pm b/FS/FS/part_export/null.pm
new file mode 100644
index 0000000..0145af3
--- /dev/null
+++ b/FS/FS/part_export/null.pm
@@ -0,0 +1,13 @@
+package FS::part_export::null;
+
+use vars qw(@ISA);
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+sub rebless { shift; }
+
+sub _export_insert {}
+sub _export_replace {}
+sub _export_delete {}
+
diff --git a/FS/FS/part_export/passwdfile.pm b/FS/FS/part_export/passwdfile.pm
new file mode 100644
index 0000000..2978d25
--- /dev/null
+++ b/FS/FS/part_export/passwdfile.pm
@@ -0,0 +1,18 @@
+package FS::part_export::passwdfile;
+
+use strict;
+use vars qw(@ISA %options);
+use Tie::IxHash;
+use FS::part_export::null;
+
+@ISA = qw(FS::part_export::null);
+
+tie %options, 'Tie::IxHash',
+ 'crypt' => { label=>'Password encryption',
+ type=>'select', options=>[qw(crypt md5)],
+ default=>'crypt',
+ },
+;
+
+1;
+
diff --git a/FS/FS/part_export/postfix.pm b/FS/FS/part_export/postfix.pm
new file mode 100644
index 0000000..4fd19ee
--- /dev/null
+++ b/FS/FS/part_export/postfix.pm
@@ -0,0 +1,32 @@
+package FS::part_export::postfix;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export::null;
+
+@ISA = qw(FS::part_export::null);
+
+tie my %options, 'Tie::IxHash',
+ 'user' => { label=>'Remote username', default=>'root' },
+ 'aliases' => { label=>'aliases file location', default=>'/etc/aliases' },
+ 'virtual' => { label=>'virtual file location', default=>'/etc/postfix/virtual' },
+ 'mydomain' => { label=>'local domain', default=>'' },
+ 'newaliases' => { label=>'newaliases command', default=>'newaliases' },
+ 'postmap' => { label=>'postmap command',
+ default=>'postmap hash:/etc/postfix/virtual', },
+ 'reload' => { label=>'reload command',
+ default=>'postfix reload' },
+;
+
+%info = (
+ 'svc' => 'svc_forward',
+ 'desc' => 'Postfix text files',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Batch export of Postfix aliases and virtual files.
+<a href="http://search.cpan.org/dist/File-Rsync">File::Rsync</a>
+must be installed. Run bin/postfix.export to export the files.
+END
+);
+
+1;
diff --git a/FS/FS/part_export/router.pm b/FS/FS/part_export/router.pm
new file mode 100644
index 0000000..648a437
--- /dev/null
+++ b/FS/FS/part_export/router.pm
@@ -0,0 +1,190 @@
+package FS::part_export::router;
+
+=head1 FS::part_export::router
+
+This export connects to a router and transmits commands via telnet or SSH.
+It requires the following custom router fields:
+
+=over 4
+
+=item admin_address - IP address (or hostname) to connect
+
+=item admin_user - username for admin access
+
+=item admin_password - password for admin access
+
+=back
+
+The export itself needs the following options:
+
+=over 4
+
+=item insert, replace, delete - command strings (to be interpolated)
+
+=item Prompt - prompt string to expect from router after successful login
+
+=item Timeout - time to wait for prompt string
+
+=back
+
+(Prompt and Timeout are required only for telnet connections.)
+
+=cut
+
+use vars qw(@ISA %info @saltset);
+use Tie::IxHash;
+use String::ShellQuote;
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'protocol' => {
+ label=>'Protocol',
+ type =>'select',
+ options => [qw(telnet ssh)],
+ default => 'telnet'},
+ 'insert' => {label=>'Insert command', default=>'' },
+ 'delete' => {label=>'Delete command', default=>'' },
+ 'replace' => {label=>'Replace command', default=>'' },
+ 'Timeout' => {label=>'Time to wait for prompt', default=>'20' },
+ 'Prompt' => {label=>'Prompt string', default=>'#' }
+;
+
+%info = (
+ 'svc' => 'svc_broadband',
+ 'desc' => 'Send a command to a router.',
+ 'options' => \%options,
+ 'notes' => 'Installation of Net::Telnet from CPAN is required for telnet connections. ( more detailed description from Kristian / fire2wire? )',
+);
+
+@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self) = shift;
+ $self->_export_command('insert', @_);
+}
+
+sub _export_delete {
+ my($self) = shift;
+ $self->_export_command('delete', @_);
+}
+
+sub _export_suspend {
+ my($self) = shift;
+ $self->_export_command('suspend', @_);
+}
+
+sub _export_unsuspend {
+ my($self) = shift;
+ $self->_export_command('unsuspend', @_);
+}
+
+sub _export_command {
+ my ( $self, $action, $svc_broadband) = (shift, shift, shift);
+ my $command = $self->option($action);
+ return '' if $command =~ /^\s*$/;
+
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${$_} = $svc_broadband->getfield($_) foreach $svc_broadband->fields;
+ }
+ # fetch router info
+ my $router = $svc_broadband->addr_block->router;
+ my %r;
+ $r{$_} = $router->getfield($_) foreach $router->virtual_fields;
+ #warn qq("$command");
+ #warn eval(qq("$command"));
+
+ warn "admin_address: '$r{admin_address}'";
+
+ if ($r{admin_address} ne '') {
+ $self->router_queue( $svc_broadband->svcnum, $self->option('protocol'),
+ user => $r{admin_user},
+ password => $r{admin_password},
+ host => $r{admin_address},
+ Timeout => $self->option('Timeout'),
+ Prompt => $self->option('Prompt'),
+ command => eval(qq("$command")),
+ );
+ } else {
+ return '';
+ }
+}
+
+sub _export_replace {
+
+ # We don't handle the case of a svc_broadband moving between routers.
+ # If you want to do that, reprovision the service.
+
+ my($self, $new, $old ) = (shift, shift, shift);
+ my $command = $self->option('replace');
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${"old_$_"} = $old->getfield($_) foreach $old->fields;
+ ${"new_$_"} = $new->getfield($_) foreach $new->fields;
+ }
+
+ my $router = $new->addr_block->router;
+ my %r;
+ $r{$_} = $router->getfield($_) foreach $router->virtual_fields;
+
+ if ($r{admin_address} ne '') {
+ $self->router_queue( $new->svcnum, $self->option('protocol'),
+ user => $r{admin_user},
+ password => $r{admin_password},
+ host => $r{admin_address},
+ Timeout => $self->option('Timeout'),
+ Prompt => $self->option('Prompt'),
+ command => eval(qq("$command")),
+ );
+ } else {
+ return '';
+ }
+}
+
+#a good idea to queue anything that could fail or take any time
+sub router_queue {
+ #warn join ':', @_;
+ my( $self, $svcnum, $protocol ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ };
+ $queue->job ("FS::part_export::router::".$protocol."_cmd");
+ $queue->insert( @_ );
+}
+
+sub ssh_cmd { #subroutine, not method
+ use Net::SSH '0.08';
+ &Net::SSH::ssh_cmd( { @_ } );
+}
+
+sub telnet_cmd {
+ eval 'use Net::Telnet;';
+ die $@ if $@;
+
+ warn join(', ', @_);
+
+ my %arg = @_;
+
+ my $t = new Net::Telnet (Timeout => $arg{Timeout},
+ Prompt => $arg{Prompt});
+ $t->open($arg{host});
+ $t->login($arg{user}, $arg{password});
+ my @error = $t->cmd($arg{command});
+ die @error if (grep /^ERROR/, @error);
+}
+
+#sub router_insert { #subroutine, not method
+#}
+#sub router_replace { #subroutine, not method
+#}
+#sub router_delete { #subroutine, not method
+#}
+
+1;
+
diff --git a/FS/FS/part_export/shellcommands.pm b/FS/FS/part_export/shellcommands.pm
new file mode 100644
index 0000000..4f201cf
--- /dev/null
+++ b/FS/FS/part_export/shellcommands.pm
@@ -0,0 +1,338 @@
+package FS::part_export::shellcommands;
+
+use vars qw(@ISA %info @saltset);
+use Tie::IxHash;
+use String::ShellQuote;
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'user' => { label=>'Remote username', default=>'root' },
+ 'useradd' => { label=>'Insert command',
+ default=>'useradd -c $finger -d $dir -m -s $shell -u $uid -p $crypt_password $username'
+ #default=>'cp -pr /etc/skel $dir; chown -R $uid.$gid $dir'
+ },
+ 'useradd_stdin' => { label=>'Insert command STDIN',
+ type =>'textarea',
+ default=>'',
+ },
+ 'userdel' => { label=>'Delete command',
+ default=>'userdel -r $username',
+ #default=>'rm -rf $dir',
+ },
+ 'userdel_stdin' => { label=>'Delete command STDIN',
+ type =>'textarea',
+ default=>'',
+ },
+ 'usermod' => { label=>'Modify command',
+ default=>'usermod -c $new_finger -d $new_dir -m -l $new_username -s $new_shell -u $new_uid -p $new_crypt_password $old_username',
+ #default=>'[ -d $old_dir ] && mv $old_dir $new_dir || ( '.
+ # 'chmod u+t $old_dir; mkdir $new_dir; cd $old_dir; '.
+ # 'find . -depth -print | cpio -pdm $new_dir; '.
+ # 'chmod u-t $new_dir; chown -R $uid.$gid $new_dir; '.
+ # 'rm -rf $old_dir'.
+ #')'
+ },
+ 'usermod_stdin' => { label=>'Modify command STDIN',
+ type =>'textarea',
+ default=>'',
+ },
+ 'usermod_pwonly' => { label=>'Disallow username changes',
+ type =>'checkbox',
+ },
+ 'suspend' => { label=>'Suspension command',
+ default=>'usermod -L $username',
+ },
+ 'suspend_stdin' => { label=>'Suspension command STDIN',
+ default=>'',
+ },
+ 'unsuspend' => { label=>'Unsuspension command',
+ default=>'usermod -U $username',
+ },
+ 'unsuspend_stdin' => { label=>'Unsuspension command STDIN',
+ default=>'',
+ },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' =>
+ 'Real-time export via remote SSH (i.e. useradd, userdel, etc.)',
+ 'options' => \%options,
+ 'nodomain' => 'Y',
+ 'notes' => <<'END'
+Run remote commands via SSH. Usernames are considered unique (also see
+shellcommands_withdomain). You probably want this if the commands you are
+running will not accept a domain as a parameter. You will need to
+<a href="../docs/ssh.html">setup SSH for unattended operation</a>.
+
+<BR><BR>Use these buttons for some useful presets:
+<UL>
+ <LI>
+ <INPUT TYPE="button" VALUE="Linux" onClick='
+ this.form.useradd.value = "useradd -c $finger -d $dir -m -s $shell -u $uid -p $crypt_password $username";
+ this.form.useradd_stdin.value = "";
+ this.form.userdel.value = "userdel -r $username";
+ this.form.userdel_stdin.value="";
+ this.form.usermod.value = "usermod -c $new_finger -d $new_dir -m -l $new_username -s $new_shell -u $new_uid -p $new_crypt_password $old_username";
+ this.form.usermod_stdin.value = "";
+ this.form.suspend.value = "usermod -L $username";
+ this.form.suspend_stdin.value="";
+ this.form.unsuspend.value = "usermod -U $username";
+ this.form.unsuspend_stdin.value="";
+ '>
+ <LI>
+ <INPUT TYPE="button" VALUE="FreeBSD before 4.10 / 5.3" onClick='
+ this.form.useradd.value = "lockf /etc/passwd.lock pw useradd $username -d $dir -m -s $shell -u $uid -g $gid -c $finger -h 0";
+ this.form.useradd_stdin.value = "$_password\n";
+ this.form.userdel.value = "lockf /etc/passwd.lock pw userdel $username -r"; this.form.userdel_stdin.value="";
+ this.form.usermod.value = "lockf /etc/passwd.lock pw usermod $old_username -d $new_dir -m -l $new_username -s $new_shell -u $new_uid -c $new_finger -h 0";
+ this.form.usermod_stdin.value = "$new__password\n"; this.form.suspend.value = "lockf /etc/passwd.lock pw lock $username";
+ this.form.suspend_stdin.value="";
+ this.form.unsuspend.value = "lockf /etc/passwd.lock pw unlock $username"; this.form.unsuspend_stdin.value="";
+ '>
+ Note: On FreeBSD versions before 5.3 and 4.10 (4.10 is after 4.9, not
+ 4.1!), due to deficient locking in pw(1), you must disable the chpass(1),
+ chsh(1), chfn(1), passwd(1), and vipw(1) commands, or replace them with
+ wrappers that prepend "lockf /etc/passwd.lock". Alternatively, apply the
+ patch in
+ <A HREF="http://www.freebsd.org/cgi/query-pr.cgi?pr=23501">FreeBSD PR#23501</A>
+ and use the "FreeBSD 4.10 / 5.3 or later" button below.
+ <LI>
+ <INPUT TYPE="button" VALUE="FreeBSD 4.10 / 5.3 or later" onClick='
+ this.form.useradd.value = "pw useradd $username -d $dir -m -s $shell -u $uid -g $gid -c $finger -h 0";
+ this.form.useradd_stdin.value = "$_password\n";
+ this.form.userdel.value = "pw userdel $username -r";
+ this.form.userdel_stdin.value="";
+ this.form.usermod.value = "pw usermod $old_username -d $new_dir -m -l $new_username -s $new_shell -u $new_uid -c $new_finger -h 0";
+ this.form.usermod_stdin.value = "$new__password\n";
+ this.form.suspend.value = "pw lock $username";
+ this.form.suspend_stdin.value="";
+ this.form.unsuspend.value = "pw unlock $username";
+ this.form.unsuspend_stdin.value="";
+ '>
+ <LI>
+ <INPUT TYPE="button" VALUE="NetBSD/OpenBSD" onClick='
+ this.form.useradd.value = "useradd -c $finger -d $dir -m -s $shell -u $uid -p $crypt_password $username";
+ this.form.useradd_stdin.value = "";
+ this.form.userdel.value = "userdel -r $username";
+ this.form.userdel_stdin.value="";
+ this.form.usermod.value = "usermod -c $new_finger -d $new_dir -m -l $new_username -s $new_shell -u $new_uid -p $new_crypt_password $old_username";
+ this.form.usermod_stdin.value = "";
+ this.form.suspend.value = "";
+ this.form.suspend_stdin.value="";
+ this.form.unsuspend.value = "";
+ this.form.unsuspend_stdin.value="";
+ '>
+ <LI>
+ <INPUT TYPE="button" VALUE="Just maintain directories (use with sysvshell or bsdshell)" onClick='
+ this.form.useradd.value = "cp -pr /etc/skel $dir; chown -R $uid.$gid $dir"; this.form.useradd_stdin.value = "";
+ this.form.usermod.value = "[ -d $old_dir ] && mv $old_dir $new_dir || ( chmod u+t $old_dir; mkdir $new_dir; cd $old_dir; find . -depth -print | cpio -pdm $new_dir; chmod u-t $new_dir; chown -R $new_uid.$new_gid $new_dir; rm -rf $old_dir )";
+ this.form.usermod_stdin.value = "";
+ this.form.userdel.value = "rm -rf $dir";
+ this.form.userdel_stdin.value="";
+ this.form.suspend.value = "";
+ this.form.suspend_stdin.value="";
+ this.form.unsuspend.value = "";
+ this.form.unsuspend_stdin.value="";
+ '>
+</UL>
+
+The following variables are available for interpolation (prefixed with new_ or
+old_ for replace operations):
+<UL>
+ <LI><code>$username</code>
+ <LI><code>$_password</code>
+ <LI><code>$quoted_password</code> - unencrypted password quoted for the shell
+ <LI><code>$crypt_password</code> - encrypted password
+ <LI><code>$uid</code>
+ <LI><code>$gid</code>
+ <LI><code>$finger</code> - GECOS, already quoted for the shell (do not add additional quotes)
+ <LI><code>$first</code> - First name of GECOS, already quoted for the shell (do not add additional quotes)
+ <LI><code>$last</code> - Last name of GECOS, already quoted for the shell (do not add additional quotes)
+ <LI><code>$dir</code> - home directory
+ <LI><code>$shell</code>
+ <LI><code>$quota</code>
+ <LI><code>@radius_groups</code>
+ <LI>All other fields in <a href="../docs/schema.html#svc_acct">svc_acct</a> are also available.
+</UL>
+END
+);
+
+@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self) = shift;
+ $self->_export_command('useradd', @_);
+}
+
+sub _export_delete {
+ my($self) = shift;
+ $self->_export_command('userdel', @_);
+}
+
+sub _export_suspend {
+ my($self) = shift;
+ $self->_export_command_or_super('suspend', @_);
+}
+
+sub _export_unsuspend {
+ my($self) = shift;
+ $self->_export_command_or_super('unsuspend', @_);
+}
+
+sub _export_command_or_super {
+ my($self, $action) = (shift, shift);
+ if ( $self->option($action) =~ /^\s*$/ ) {
+ my $method = "SUPER::_export_$action";
+ $self->$method(@_);
+ } else {
+ $self->_export_command($action, @_);
+ }
+};
+
+
+sub _export_command {
+ my ( $self, $action, $svc_acct) = (shift, shift, shift);
+ my $command = $self->option($action);
+ return '' if $command =~ /^\s*$/;
+ my $stdin = $self->option($action."_stdin");
+
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${$_} = $svc_acct->getfield($_) foreach $svc_acct->fields;
+
+ my $count = 1;
+ foreach my $acct_snarf ( $svc_acct->acct_snarf ) {
+ ${"snarf_$_$count"} = shell_quote( $acct_snarf->get($_) )
+ foreach qw( machine username _password );
+ $count++;
+ }
+ }
+
+ my $cust_pkg = $svc_acct->cust_svc->cust_pkg;
+ if ( $cust_pkg ) {
+ $email = ( grep { $_ ne 'POST' } $cust_pkg->cust_main->invoicing_list )[0];
+ } else {
+ $email = '';
+ }
+
+ $finger =~ /^(.*)\s+(\S+)$/ or $finger =~ /^((.*))$/;
+ ($first, $last ) = ( $1, $2 );
+ $first = shell_quote $first;
+ $last = shell_quote $last;
+ $finger = shell_quote $finger;
+ $quoted_password = shell_quote $_password;
+ $domain = $svc_acct->domain;
+
+ #eventually should check a "password-encoding" field
+ if ( length($svc_acct->_password) == 13
+ || $svc_acct->_password =~ /^\$(1|2a?)\$/ ) {
+ $crypt_password = shell_quote $svc_acct->_password;
+ } else {
+ $crypt_password = crypt(
+ $svc_acct->_password,
+ $saltset[int(rand(64))].$saltset[int(rand(64))]
+ );
+ }
+
+ @radius_groups = $svc_acct->radius_groups;
+
+ $self->shellcommands_queue( $svc_acct->svcnum,
+ user => $self->option('user')||'root',
+ host => $self->machine,
+ command => eval(qq("$command")),
+ stdin_string => eval(qq("$stdin")),
+ );
+}
+
+sub _export_replace {
+ my($self, $new, $old ) = (shift, shift, shift);
+ my $command = $self->option('usermod');
+ my $stdin = $self->option('usermod_stdin');
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${"old_$_"} = $old->getfield($_) foreach $old->fields;
+ ${"new_$_"} = $new->getfield($_) foreach $new->fields;
+ }
+ $new_finger =~ /^(.*)\s+(\S+)$/ or $finger =~ /^((.*))$/;
+ ($new_first, $new_last ) = ( $1, $2 );
+ $new_first = shell_quote $new_first;
+ $new_last = shell_quote $new_last;
+ $new_finger = shell_quote $new_finger;
+ $quoted_new__password = shell_quote $new__password; #old, wrong?
+ $new_quoted_password = shell_quote $new__password; #new, better?
+ $old_domain = $old->domain;
+ $new_domain = $new->domain;
+
+ #eventuall should check a "password-encoding" field
+ if ( length($new->_password) == 13
+ || $new->_password =~ /^\$(1|2a?)\$/ ) {
+ $new_crypt_password = shell_quote $new->_password;
+ } else {
+ $new_crypt_password =
+ crypt( $new->_password, $saltset[int(rand(64))].$saltset[int(rand(64))]
+ );
+ }
+
+ @old_radius_groups = $old->radius_groups;
+ @new_radius_groups = $new->radius_groups;
+
+ if ( $self->option('usermod_pwonly') ) {
+ my $error = '';
+ if ( $old_username ne $new_username ) {
+ $error ||= "can't change username";
+ }
+ if ( $old_domain ne $new_domain ) {
+ $error ||= "can't change domain";
+ }
+ if ( $old_uid != $new_uid ) {
+ $error ||= "can't change uid";
+ }
+ if ( $old_dir ne $new_dir ) {
+ $error ||= "can't change dir";
+ }
+ if ( join("\n", sort @old_radius_groups) ne
+ join("\n", sort @new_radius_groups) ) {
+ $error ||= "can't change RADIUS groups";
+ }
+ return $error. ' ('. $self->exporttype. ' to '. $self->machine. ')'
+ if $error;
+ }
+ $self->shellcommands_queue( $new->svcnum,
+ user => $self->option('user')||'root',
+ host => $self->machine,
+ command => eval(qq("$command")),
+ stdin_string => eval(qq("$stdin")),
+ );
+}
+
+#a good idea to queue anything that could fail or take any time
+sub shellcommands_queue {
+ my( $self, $svcnum ) = (shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::shellcommands::ssh_cmd",
+ };
+ $queue->insert( @_ );
+}
+
+sub ssh_cmd { #subroutine, not method
+ use Net::SSH '0.08';
+ &Net::SSH::ssh_cmd( { @_ } );
+}
+
+#sub shellcommands_insert { #subroutine, not method
+#}
+#sub shellcommands_replace { #subroutine, not method
+#}
+#sub shellcommands_delete { #subroutine, not method
+#}
+
+1;
+
diff --git a/FS/FS/part_export/shellcommands_withdomain.pm b/FS/FS/part_export/shellcommands_withdomain.pm
new file mode 100644
index 0000000..89ee95f
--- /dev/null
+++ b/FS/FS/part_export/shellcommands_withdomain.pm
@@ -0,0 +1,105 @@
+package FS::part_export::shellcommands_withdomain;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export::shellcommands;
+
+@ISA = qw(FS::part_export::shellcommands);
+
+tie my %options, 'Tie::IxHash',
+ 'user' => { label=>'Remote username', default=>'root' },
+ 'useradd' => { label=>'Insert command',
+ #default=>''
+ },
+ 'useradd_stdin' => { label=>'Insert command STDIN',
+ type =>'textarea',
+ #default=>"$_password\n$_password\n",
+ },
+ 'userdel' => { label=>'Delete command',
+ #default=>'',
+ },
+ 'userdel_stdin' => { label=>'Delete command STDIN',
+ type =>'textarea',
+ #default=>'',
+ },
+ 'usermod' => { label=>'Modify command',
+ default=>'',
+ },
+ 'usermod_stdin' => { label=>'Modify command STDIN',
+ type =>'textarea',
+ #default=>"$_password\n$_password\n",
+ },
+ 'usermod_pwonly' => { label=>'Disallow username changes',
+ type =>'checkbox',
+ },
+ 'suspend' => { label=>'Suspension command',
+ default=>'',
+ },
+ 'suspend_stdin' => { label=>'Suspension command STDIN',
+ default=>'',
+ },
+ 'unsuspend' => { label=>'Unsuspension command',
+ default=>'',
+ },
+ 'unsuspend_stdin' => { label=>'Unsuspension command STDIN',
+ default=>'',
+ },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export via remote SSH (vpopmail, ISPMan)',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Run remote commands via SSH. username@domain (rather than just usernames) are
+considered unique (also see shellcommands). You probably want this if the
+commands you are running will accept a domain as a parameter, and will allow
+the same username with different domains. You will need to
+<a href="../docs/ssh.html">setup SSH for unattended operation</a>.
+
+<BR><BR>Use these buttons for some useful presets:
+<UL>
+ <LI><INPUT TYPE="button" VALUE="vpopmail" onClick='
+ this.form.useradd.value = "/home/vpopmail/bin/vadduser $username\\\@$domain $quoted_password";
+ this.form.useradd_stdin.value = "";
+ this.form.userdel.value = "/home/vpopmail/bin/vdeluser $username\\\@$domain";
+ this.form.userdel_stdin.value="";
+ this.form.usermod.value = "/home/vpopmail/bin/vpasswd $new_username\\\@$new_domain $new_quoted_password";
+ this.form.usermod_stdin.value = "";
+ this.form.usermod_pwonly.checked = true;
+ '>
+ <LI><INPUT TYPE="button" VALUE="ISPMan CLI" onClick='
+ this.form.useradd.value = "/usr/local/ispman/bin/ispman.addUser -d $domain -f $first -l $last -q $quota -p $quoted_password $username";
+ this.form.useradd_stdin.value = "";
+ this.form.userdel.value = "/usr/local/ispman/bin/ispman.delUser -d $domain $username";
+ this.form.userdel_stdin.value="";
+ this.form.usermod.value = "/usr/local/ispman/bin/ispman.passwd.user $new_username\\\@$new_domain $new_quoted_password";
+ this.form.usermod_stdin.value = "";
+ this.form.usermod_pwonly.checked = true;
+ '>
+</UL>
+
+The following variables are available for interpolation (prefixed with
+<code>new_</code> or <code>old_</code> for replace operations):
+<UL>
+ <LI><code>$username</code>
+ <LI><code>$domain</code>
+ <LI><code>$_password</code>
+ <LI><code>$quoted_password</code> - unencrypted password quoted for the shell
+ <LI><code>$crypt_password</code> - encrypted password
+ <LI><code>$uid</code>
+ <LI><code>$gid</code>
+ <LI><code>$finger</code> - GECOS, already quoted for the shell (do not add additional quotes)
+ <LI><code>$first</code> - First name of GECOS, already quoted for the shell (do not add additional quotes)
+ <LI><code>$last</code> - Last name of GECOS, already quoted for the shell (do not add additional quotes)
+ <LI><code>$dir</code> - home directory
+ <LI><code>$shell</code>
+ <LI><code>$quota</code>
+ <LI><code>@radius_groups</code>
+ <LI>All other fields in <a href="../docs/schema.html#svc_acct">svc_acct</a> are also available.
+</UL>
+END
+);
+
+1;
+
diff --git a/FS/FS/part_export/sqlmail.pm b/FS/FS/part_export/sqlmail.pm
new file mode 100644
index 0000000..6d61e0e
--- /dev/null
+++ b/FS/FS/part_export/sqlmail.pm
@@ -0,0 +1,220 @@
+package FS::part_export::sqlmail;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use Digest::MD5 qw(md5_hex);
+use FS::Record qw(qsearchs);
+use FS::part_export;
+use FS::svc_domain;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'datasrc' => { label => 'DBI data source' },
+ 'username' => { label => 'Database username' },
+ 'password' => { label => 'Database password' },
+ 'server_type' => {
+ label => 'Server type',
+ type => 'select',
+ options => [qw(dovecot_plain dovecot_crypt dovecot_digest_md5 courier_plain
+ courier_crypt)],
+ default => ['dovecot_plain'], },
+ 'svc_acct_table' => { label => 'User Table', default => 'user_acct' },
+ 'svc_forward_table' => { label => 'Forward Table', default => 'forward' },
+ 'svc_domain_table' => { label => 'Domain Table', default => 'domain' },
+ 'svc_acct_fields' => { label => 'svc_acct Export Fields',
+ default => 'username _password domsvc svcnum' },
+ 'svc_forward_fields' => { label => 'svc_forward Export Fields',
+ default => 'domain svcnum catchall' },
+ 'svc_domain_fields' => { label => 'svc_domain Export Fields',
+ default => 'srcsvc dstsvc dst' },
+ 'resolve_dstsvc' => { label => q{Resolve svc_forward.dstsvc to an email address and store it in dst. (Doesn't require that you also export dstsvc.)},
+ type => 'checkbox' },
+;
+
+%info = (
+ 'svc' => [qw( svc_acct svc_domain svc_forward )],
+ 'desc' => 'Real-time export to SQL-backed mail server',
+ 'options' => \%options,
+ 'nodomain' => '',
+ 'notes' => <<'END'
+Database schema can be made to work with Courier IMAP, Exim and Dovecot.
+Others could work but are untested. (more detailed description from
+Kristian / fire2wire? )
+END
+);
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self, $svc) = (shift, shift);
+ # this is a svc_something.
+
+ my $svcdb = $svc->cust_svc->part_svc->svcdb;
+ my $export_table = $self->option($svcdb . '_table')
+ or die('Export table not defined for svcdb: ' . $svcdb);
+ my @export_fields = split(/\s+/, $self->option($svcdb . '_fields'));
+ my $svchash = update_values($self, $svc, $svcdb);
+
+ foreach my $key (keys(%$svchash)) {
+ unless (grep { $key eq $_ } @export_fields) {
+ delete $svchash->{$key};
+ }
+ }
+
+ my $error = $self->sqlmail_queue( $svc->svcnum, 'insert',
+ $self->option('server_type'), $export_table,
+ (map { ($_, $svchash->{$_}); } keys(%$svchash)));
+ return $error if $error;
+ '';
+
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+
+ my $svcdb = $new->cust_svc->part_svc->svcdb;
+ my $export_table = $self->option($svcdb . '_table')
+ or die('Export table not defined for svcdb: ' . $svcdb);
+ my @export_fields = split(/\s+/, $self->option($svcdb . '_fields'));
+ my $svchash = update_values($self, $new, $svcdb);
+
+ foreach my $key (keys(%$svchash)) {
+ unless (grep { $key eq $_ } @export_fields) {
+ delete $svchash->{$key};
+ }
+ }
+
+ my $error = $self->sqlmail_queue( $new->svcnum, 'replace',
+ $old->svcnum, $self->option('server_type'), $export_table,
+ (map { ($_, $svchash->{$_}); } keys(%$svchash)));
+ return $error if $error;
+ '';
+
+}
+
+sub _export_delete {
+ my( $self, $svc ) = (shift, shift);
+
+ my $svcdb = $svc->cust_svc->part_svc->svcdb;
+ my $table = $self->option($svcdb . '_table')
+ or die('Export table not defined for svcdb: ' . $svcdb);
+
+ $self->sqlmail_queue( $svc->svcnum, 'delete', $table,
+ $svc->svcnum );
+}
+
+sub sqlmail_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::sqlmail::sqlmail_$method",
+ };
+ $queue->insert(
+ $self->option('datasrc'),
+ $self->option('username'),
+ $self->option('password'),
+ @_,
+ );
+}
+
+sub sqlmail_insert { #subroutine, not method
+ my $dbh = sqlmail_connect(shift, shift, shift);
+ my( $server_type, $table ) = (shift, shift);
+
+ my %attrs = @_;
+
+ map { $attrs{$_} = $attrs{$_} ? qq!'$attrs{$_}'! : 'NULL'; } keys(%attrs);
+ my $query = sprintf("INSERT INTO %s (%s) values (%s)",
+ $table, join(",", keys(%attrs)),
+ join(',', values(%attrs)));
+
+ $dbh->do($query) or die $dbh->errstr;
+ $dbh->disconnect;
+
+ '';
+}
+
+sub sqlmail_delete { #subroutine, not method
+ my $dbh = sqlmail_connect(shift, shift, shift);
+ my( $table, $svcnum ) = @_;
+
+ $dbh->do("DELETE FROM $table WHERE svcnum = $svcnum") or die $dbh->errstr;
+ $dbh->disconnect;
+
+ '';
+}
+
+sub sqlmail_replace {
+ my $dbh = sqlmail_connect(shift, shift, shift);
+ my($oldsvcnum, $server_type, $table) = (shift, shift, shift);
+
+ my %attrs = @_;
+ map { $attrs{$_} = $attrs{$_} ? qq!'$attrs{$_}'! : 'NULL'; } keys(%attrs);
+
+ my $query = "SELECT COUNT(*) FROM $table WHERE svcnum = $oldsvcnum";
+ my $result = $dbh->selectrow_arrayref($query) or die $dbh->errstr;
+
+ if (@$result[0] == 0) {
+ $query = sprintf("INSERT INTO %s (%s) values (%s)",
+ $table, join(",", keys(%attrs)),
+ join(',', values(%attrs)));
+ $dbh->do($query) or die $dbh->errstr;
+ } else {
+ $query = sprintf('UPDATE %s SET %s WHERE svcnum = %s',
+ $table, join(', ', map {"$_ = $attrs{$_}"} keys(%attrs)),
+ $oldsvcnum);
+ $dbh->do($query) or die $dbh->errstr;
+ }
+
+ $dbh->disconnect;
+
+ '';
+}
+
+sub sqlmail_connect {
+ DBI->connect(@_) or die $DBI::errstr;
+}
+
+sub update_values {
+
+ # Update records to conform to a particular server_type.
+
+ my ($self, $svc, $svcdb) = (shift,shift,shift);
+ my $svchash = { %{$svc->hashref} } or return ''; # We need a copy.
+
+ if ($svcdb eq 'svc_acct') {
+ if ($self->option('server_type') eq 'courier_crypt') {
+ my $salt = join '', ('.', '/', 0..9,'A'..'Z', 'a'..'z')[rand 64, rand 64];
+ $svchash->{_password} = crypt($svchash->{_password}, $salt);
+
+ } elsif ($self->option('server_type') eq 'dovecot_plain') {
+ $svchash->{_password} = '{PLAIN}' . $svchash->{_password};
+
+ } elsif ($self->option('server_type') eq 'dovecot_crypt') {
+ my $salt = join '', ('.', '/', 0..9,'A'..'Z', 'a'..'z')[rand 64, rand 64];
+ $svchash->{_password} = '{CRYPT}' . crypt($svchash->{_password}, $salt);
+
+ } elsif ($self->option('server_type') eq 'dovecot_digest_md5') {
+ my $svc_domain = qsearchs('svc_domain', { svcnum => $svc->domsvc });
+ die('Unable to lookup svc_domain with domsvc: ' . $svc->domsvc)
+ unless ($svc_domain);
+
+ my $domain = $svc_domain->domain;
+ my $md5hash = '{DIGEST-MD5}' . md5_hex(join(':', $svchash->{username},
+ $domain, $svchash->{_password}));
+ $svchash->{_password} = $md5hash;
+ }
+ } elsif ($svcdb eq 'svc_forward') {
+ if ($self->option('resolve_dstsvc') && $svc->dstsvc_acct) {
+ $svchash->{dst} = $svc->dstsvc_acct->username . '@' .
+ $svc->dstsvc_acct->svc_domain->domain;
+ }
+ }
+
+ return($svchash);
+
+}
+
+1;
+
diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm
new file mode 100644
index 0000000..fd5bb89
--- /dev/null
+++ b/FS/FS/part_export/sqlradius.pm
@@ -0,0 +1,337 @@
+package FS::part_export::sqlradius;
+
+use vars qw(@ISA %info %options $notes1 $notes2);
+use Tie::IxHash;
+use FS::Record qw( dbh );
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie %options, 'Tie::IxHash',
+ 'datasrc' => { label=>'DBI data source ' },
+ 'username' => { label=>'Database username' },
+ 'password' => { label=>'Database password' },
+ 'ignore_accounting' => {
+ type => 'checkbox',
+ label=>'Ignore accounting records from this database'
+ },
+;
+
+$notes1 = <<'END';
+Real-time export of radcheck, radreply and usergroup tables to any SQL database
+for <a href="http://www.freeradius.org/">FreeRADIUS</a>,
+<a href="http://radius.innercite.com/">ICRADIUS</a>
+or <a href="http://www.open.com.au/radiator/">Radiator</a>.
+END
+
+$notes2 = <<'END';
+An existing RADIUS database will be updated in realtime, but you can use
+<a href="../docs/man/bin/freeside-sqlradius-reset">freeside-sqlradius-reset</a>
+to delete the entire RADIUS database and repopulate the tables from the
+Freeside database. See the
+<a href="http://search.cpan.org/dist/DBI/DBI.pm#connect">DBI documentation</a>
+and the
+<a href="http://search.cpan.org/search?mode=module&query=DBD%3A%3A">documentation for your DBD</a>
+for the exact syntax of a DBI data source.
+<ul>
+ <li>Using FreeRADIUS 0.9.0 with the PostgreSQL backend, the db_postgresql.sql schema and postgresql.conf queries contain incompatible changes. This is fixed in 0.9.1. Only new installs with 0.9.0 and PostgreSQL are affected - upgrades and other database backends and versions are unaffected.
+ <li>Using ICRADIUS, add a dummy "op" column to your database:
+ <blockquote><code>
+ ALTER&nbsp;TABLE&nbsp;radcheck&nbsp;ADD&nbsp;COLUMN&nbsp;op&nbsp;VARCHAR(2)&nbsp;NOT&nbsp;NULL&nbsp;DEFAULT&nbsp;'=='<br>
+ ALTER&nbsp;TABLE&nbsp;radreply&nbsp;ADD&nbsp;COLUMN&nbsp;op&nbsp;VARCHAR(2)&nbsp;NOT&nbsp;NULL&nbsp;DEFAULT&nbsp;'=='<br>
+ ALTER&nbsp;TABLE&nbsp;radgroupcheck&nbsp;ADD&nbsp;COLUMN&nbsp;op&nbsp;VARCHAR(2)&nbsp;NOT&nbsp;NULL&nbsp;DEFAULT&nbsp;'=='<br>
+ ALTER&nbsp;TABLE&nbsp;radgroupreply&nbsp;ADD&nbsp;COLUMN&nbsp;op&nbsp;VARCHAR(2)&nbsp;NOT&nbsp;NULL&nbsp;DEFAULT&nbsp;'=='
+ </code></blockquote>
+ <li>Using Radiator, see the
+ <a href="http://www.open.com.au/radiator/faq.html#38">Radiator FAQ</a>
+ for configuration information.
+</ul>
+END
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export to SQL-backed RADIUS (FreeRADIUS, ICRADIUS, Radiator)',
+ 'options' => \%options,
+ 'nodomain' => 'Y',
+ 'notes' => $notes1.
+ 'This export does not export RADIUS realms (see also '.
+ 'sqlradius_withdomain). '.
+ $notes2
+);
+
+sub rebless { shift; }
+
+sub export_username {
+ my($self, $svc_acct) = (shift, shift);
+ $svc_acct->username;
+}
+
+sub _export_insert {
+ my($self, $svc_acct) = (shift, shift);
+
+ foreach my $table (qw(reply check)) {
+ my $method = "radius_$table";
+ my %attrib = $svc_acct->$method();
+ next unless keys %attrib;
+ my $err_or_queue = $self->sqlradius_queue( $svc_acct->svcnum, 'insert',
+ $table, $self->export_username($svc_acct), %attrib );
+ return $err_or_queue unless ref($err_or_queue);
+ }
+ my @groups = $svc_acct->radius_groups;
+ if ( @groups ) {
+ my $err_or_queue = $self->sqlradius_queue(
+ $svc_acct->svcnum, 'usergroup_insert',
+ $self->export_username($svc_acct), @groups );
+ return $err_or_queue unless ref($err_or_queue);
+ }
+ '';
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $jobnum = '';
+ if ( $self->export_username($old) ne $self->export_username($new) ) {
+ my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'rename',
+ $self->export_username($new), $self->export_username($old) );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ $jobnum = $err_or_queue->jobnum;
+ }
+
+ foreach my $table (qw(reply check)) {
+ my $method = "radius_$table";
+ my %new = $new->$method();
+ my %old = $old->$method();
+ if ( grep { !exists $old{$_} #new attributes
+ || $new{$_} ne $old{$_} #changed
+ } keys %new
+ ) {
+ my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'insert',
+ $table, $self->export_username($new), %new );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ my @del = grep { !exists $new{$_} } keys %old;
+ if ( @del ) {
+ my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'attrib_delete',
+ $table, $self->export_username($new), @del );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+ }
+
+ # (sorta) false laziness with FS::svc_acct::replace
+ my @oldgroups = @{$old->usergroup}; #uuuh
+ my @newgroups = $new->radius_groups;
+ my @delgroups = ();
+ foreach my $oldgroup ( @oldgroups ) {
+ if ( grep { $oldgroup eq $_ } @newgroups ) {
+ @newgroups = grep { $oldgroup ne $_ } @newgroups;
+ next;
+ }
+ push @delgroups, $oldgroup;
+ }
+
+ if ( @delgroups ) {
+ my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'usergroup_delete',
+ $self->export_username($new), @delgroups );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ if ( @newgroups ) {
+ my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'usergroup_insert',
+ $self->export_username($new), @newgroups );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+}
+
+sub _export_delete {
+ my( $self, $svc_acct ) = (shift, shift);
+ my $err_or_queue = $self->sqlradius_queue( $svc_acct->svcnum, 'delete',
+ $self->export_username($svc_acct) );
+ ref($err_or_queue) ? '' : $err_or_queue;
+}
+
+sub sqlradius_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::sqlradius::sqlradius_$method",
+ };
+ $queue->insert(
+ $self->option('datasrc'),
+ $self->option('username'),
+ $self->option('password'),
+ @_,
+ ) or $queue;
+}
+
+sub sqlradius_insert { #subroutine, not method
+ my $dbh = sqlradius_connect(shift, shift, shift);
+ my( $table, $username, %attributes ) = @_;
+
+ foreach my $attribute ( keys %attributes ) {
+
+ my $s_sth = $dbh->prepare(
+ "SELECT COUNT(*) FROM rad$table WHERE UserName = ? AND Attribute = ?"
+ ) or die $dbh->errstr;
+ $s_sth->execute( $username, $attribute ) or die $s_sth->errstr;
+
+ if ( $s_sth->fetchrow_arrayref->[0] ) {
+
+ my $u_sth = $dbh->prepare(
+ "UPDATE rad$table SET Value = ? WHERE UserName = ? AND Attribute = ?"
+ ) or die $dbh->errstr;
+ $u_sth->execute($attributes{$attribute}, $username, $attribute)
+ or die $u_sth->errstr;
+
+ } else {
+
+ my $i_sth = $dbh->prepare(
+ "INSERT INTO rad$table ( UserName, Attribute, op, Value ) ".
+ "VALUES ( ?, ?, ?, ? )"
+ ) or die $dbh->errstr;
+ $i_sth->execute(
+ $username,
+ $attribute,
+ ( $attribute =~ /Password/i ? '==' : ':=' ),
+ $attributes{$attribute},
+ ) or die $i_sth->errstr;
+
+ }
+
+ }
+ $dbh->disconnect;
+}
+
+sub sqlradius_usergroup_insert { #subroutine, not method
+ my $dbh = sqlradius_connect(shift, shift, shift);
+ my( $username, @groups ) = @_;
+
+ my $sth = $dbh->prepare(
+ "INSERT INTO usergroup ( UserName, GroupName ) VALUES ( ?, ? )"
+ ) or die $dbh->errstr;
+ foreach my $group ( @groups ) {
+ $sth->execute( $username, $group )
+ or die "can't insert into groupname table: ". $sth->errstr;
+ }
+ $dbh->disconnect;
+}
+
+sub sqlradius_usergroup_delete { #subroutine, not method
+ my $dbh = sqlradius_connect(shift, shift, shift);
+ my( $username, @groups ) = @_;
+
+ my $sth = $dbh->prepare(
+ "DELETE FROM usergroup WHERE UserName = ? AND GroupName = ?"
+ ) or die $dbh->errstr;
+ foreach my $group ( @groups ) {
+ $sth->execute( $username, $group )
+ or die "can't delete from groupname table: ". $sth->errstr;
+ }
+ $dbh->disconnect;
+}
+
+sub sqlradius_rename { #subroutine, not method
+ my $dbh = sqlradius_connect(shift, shift, shift);
+ my($new_username, $old_username) = @_;
+ foreach my $table (qw(radreply radcheck usergroup )) {
+ my $sth = $dbh->prepare("UPDATE $table SET Username = ? WHERE UserName = ?")
+ or die $dbh->errstr;
+ $sth->execute($new_username, $old_username)
+ or die "can't update $table: ". $sth->errstr;
+ }
+ $dbh->disconnect;
+}
+
+sub sqlradius_attrib_delete { #subroutine, not method
+ my $dbh = sqlradius_connect(shift, shift, shift);
+ my( $table, $username, @attrib ) = @_;
+
+ foreach my $attribute ( @attrib ) {
+ my $sth = $dbh->prepare(
+ "DELETE FROM rad$table WHERE UserName = ? AND Attribute = ?" )
+ or die $dbh->errstr;
+ $sth->execute($username,$attribute)
+ or die "can't delete from rad$table table: ". $sth->errstr;
+ }
+ $dbh->disconnect;
+}
+
+sub sqlradius_delete { #subroutine, not method
+ my $dbh = sqlradius_connect(shift, shift, shift);
+ my $username = shift;
+
+ foreach my $table (qw( radcheck radreply usergroup )) {
+ my $sth = $dbh->prepare( "DELETE FROM $table WHERE UserName = ?" );
+ $sth->execute($username)
+ or die "can't delete from $table table: ". $sth->errstr;
+ }
+ $dbh->disconnect;
+}
+
+sub sqlradius_connect {
+ #my($datasrc, $username, $password) = @_;
+ #DBI->connect($datasrc, $username, $password) or die $DBI::errstr;
+ DBI->connect(@_) or die $DBI::errstr;
+}
+
+1;
+
diff --git a/FS/FS/part_export/sqlradius_withdomain.pm b/FS/FS/part_export/sqlradius_withdomain.pm
new file mode 100644
index 0000000..6130e5e
--- /dev/null
+++ b/FS/FS/part_export/sqlradius_withdomain.pm
@@ -0,0 +1,28 @@
+package FS::part_export::sqlradius_withdomain;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export::sqlradius;
+
+tie my %options, 'Tie::IxHash', %FS::part_export::sqlradius::options;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export to SQL-backed RADIUS (FreeRADIUS, ICRADIUS, Radiator) with realms',
+ 'options' => \%options,
+ 'nodomain' => '',
+ 'notes' => $FS::part_export::sqlradius::notes1.
+ 'This export exports domains to RADIUS realms (see also '.
+ 'sqlradius). '.
+ $FS::part_export::sqlradius::notes2
+);
+
+@ISA = qw(FS::part_export::sqlradius);
+
+sub export_username {
+ my($self, $svc_acct) = (shift, shift);
+ $svc_acct->email;
+}
+
+1;
+
diff --git a/FS/FS/part_export/sysvshell.pm b/FS/FS/part_export/sysvshell.pm
new file mode 100644
index 0000000..244c3bf
--- /dev/null
+++ b/FS/FS/part_export/sysvshell.pm
@@ -0,0 +1,25 @@
+package FS::part_export::sysvshell;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export::passwdfile;
+
+@ISA = qw(FS::part_export::passwdfile);
+
+tie my %options, 'Tie::IxHash', %FS::part_export::passwdfile::options;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' =>
+ 'Batch export of /etc/passwd and /etc/shadow files (Linux, Solaris)',
+ 'options' => \%options,
+ 'nodomain' => 'Y',
+ 'notes' => <<'END'
+MD5 crypt requires installation of
+<a href="http://search.cpan.org/dist/Crypt-PasswdMD5">Crypt::PasswdMD5</a>
+from CPAN. Run bin/sysvshell.export to export the files.
+END
+);
+
+1;
+
diff --git a/FS/FS/part_export/textradius.pm b/FS/FS/part_export/textradius.pm
new file mode 100644
index 0000000..65936ea
--- /dev/null
+++ b/FS/FS/part_export/textradius.pm
@@ -0,0 +1,191 @@
+package FS::part_export::textradius;
+
+use vars qw(@ISA %info $prefix);
+use Fcntl qw(:flock);
+use Tie::IxHash;
+use FS::UID qw(datasrc);
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'user' => { label=>'Remote username', default=>'root' },
+ 'users' => { label=>'users file location', default=>'/etc/raddb/users' },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' =>
+ 'Real-time export to a text /etc/raddb/users file (Livingston, Cistron)',
+ 'options' => \%options,
+ 'notes' => <<'END'
+This will edit a text RADIUS users file in place on a remote server.
+Requires installation of
+<a href="http://search.cpan.org/dist/RADIUS-UserFile">RADIUS::UserFile</a>
+from CPAN. If using RADIUS::UserFile 1.01, make sure to apply
+<a href="http://rt.cpan.org/NoAuth/Bug.html?id=1210">this patch</a>. Also
+make sure <a href="http://rsync.samba.org/">rsync</a> is installed on the
+remote machine, and <a href="../docs/ssh.html">SSH is setup for unattended
+operation</a>.
+END
+);
+
+$prefix = "/usr/local/etc/freeside/export.";
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self, $svc_acct) = (shift, shift);
+ $err_or_queue = $self->textradius_queue( $svc_acct->svcnum, 'insert',
+ $svc_acct->username, $svc_acct->radius_check, '-', $svc_acct->radius_reply);
+ ref($err_or_queue) ? '' : $err_or_queue;
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+ return "can't (yet?) change username with textradius"
+ if $old->username ne $new->username;
+ #return '' unless $old->_password ne $new->_password;
+ $err_or_queue = $self->textradius_queue( $new->svcnum, 'insert',
+ $new->username, $new->radius_check, '-', $new->radius_reply);
+ ref($err_or_queue) ? '' : $err_or_queue;
+}
+
+sub _export_delete {
+ my( $self, $svc_acct ) = (shift, shift);
+ $err_or_queue = $self->textradius_queue( $svc_acct->svcnum, 'delete',
+ $svc_acct->username );
+ ref($err_or_queue) ? '' : $err_or_queue;
+}
+
+#a good idea to queue anything that could fail or take any time
+sub textradius_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::textradius::textradius_$method",
+ };
+ $queue->insert(
+ $self->option('user')||'root',
+ $self->machine,
+ $self->option('users'),
+ @_,
+ ) or $queue;
+}
+
+sub textradius_insert { #subroutine, not method
+ my( $user, $host, $users, $username, @attributes ) = @_;
+
+ #silly arg processing
+ my($att, @check);
+ push @check, $att while @attributes && ($att=shift @attributes) ne '-';
+ my %check = @check;
+ my %reply = @attributes;
+
+ my $file = textradius_download($user, $host, $users);
+
+ eval "use RADIUS::UserFile;";
+ die $@ if $@;
+
+ my $userfile = new RADIUS::UserFile(
+ File => $file,
+ Who => [ $username ],
+ Check_Items => [ keys %check ],
+ ) or die "error parsing $file";
+
+ $userfile->remove($username);
+ $userfile->add(
+ Who => $username,
+ Attributes => { %check, %reply },
+ Comment => 'user added by Freeside',
+ ) or die "error adding to $file";
+
+ $userfile->update( Who => [ $username ] )
+ or die "error updating $file";
+
+ textradius_upload($user, $host, $users);
+
+}
+
+sub textradius_delete { #subroutine, not method
+ my( $user, $host, $users, $username ) = @_;
+
+ my $file = textradius_download($user, $host, $users);
+
+ eval "use RADIUS::UserFile;";
+ die $@ if $@;
+
+ my $userfile = new RADIUS::UserFile(
+ File => $file,
+ Who => [ $username ],
+ ) or die "error parsing $file";
+
+ $userfile->remove($username);
+
+ $userfile->update( Who => [ $username ] )
+ or die "error updating $file";
+
+ textradius_upload($user, $host, $users);
+}
+
+sub textradius_download {
+ my( $user, $host, $users ) = @_;
+
+ my $dir = $prefix. datasrc;
+ mkdir $dir, 0700 or die $! unless -d $dir;
+ $dir .= "/$host";
+ mkdir $dir, 0700 or die $! unless -d $dir;
+
+ my $dest = "$dir/users";
+
+ eval "use File::Rsync;";
+ die $@ if $@;
+ my $rsync = File::Rsync->new({ rsh => 'ssh' });
+
+ open(LOCK, "+>>$dest.lock")
+ and flock(LOCK,LOCK_EX)
+ or die "can't open $dest.lock: $!";
+
+ $rsync->exec( {
+ src => "$user\@$host:$users",
+ dest => $dest,
+ } ); # true/false return value from exec is not working, alas
+ if ( $rsync->err ) {
+ die "error downloading $user\@$host:$users : ".
+ 'exit status: '. $rsync->status. ', '.
+ 'STDERR: '. join(" / ", $rsync->err). ', '.
+ 'STDOUT: '. join(" / ", $rsync->out);
+ }
+
+ $dest;
+}
+
+sub textradius_upload {
+ my( $user, $host, $users ) = @_;
+
+ my $dir = $prefix. datasrc. "/$host";
+
+ eval "use File::Rsync;";
+ die $@ if $@;
+ my $rsync = File::Rsync->new({
+ rsh => 'ssh',
+ #dry_run => 1,
+ });
+ $rsync->exec( {
+ src => "$dir/users",
+ dest => "$user\@$host:$users",
+ } ); # true/false return value from exec is not working, alas
+ if ( $rsync->err ) {
+ die "error uploading to $user\@$host:$users : ".
+ 'exit status: '. $rsync->status. ', '.
+ 'STDERR: '. join(" / ", $rsync->err). ', '.
+ 'STDOUT: '. join(" / ", $rsync->out);
+ }
+
+ flock(LOCK,LOCK_UN);
+ close LOCK;
+
+}
+
+1;
+
diff --git a/FS/FS/part_export/vpopmail.pm b/FS/FS/part_export/vpopmail.pm
new file mode 100644
index 0000000..62fa8ba
--- /dev/null
+++ b/FS/FS/part_export/vpopmail.pm
@@ -0,0 +1,252 @@
+package FS::part_export::vpopmail;
+
+use vars qw(@ISA %info @saltset $exportdir);
+use Fcntl qw(:flock);
+use Tie::IxHash;
+use File::Path;
+use FS::UID qw( datasrc );
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ #'machine' => { label=>'vpopmail machine', },
+ 'dir' => { label=>'directory', }, # ?more info? default?
+ 'uid' => { label=>'vpopmail uid' },
+ 'gid' => { label=>'vpopmail gid' },
+ 'restart' => { label=> 'vpopmail restart command',
+ default=> 'cd /home/vpopmail/domains; for domain in *; do /home/vpopmail/bin/vmkpasswd $domain; done; /var/qmail/bin/qmail-newu; killall -HUP qmail-send',
+ },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export to vpopmail text files',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Real time export to <a href="http://inter7.com/vpopmail/">vpopmail</a> text
+files. <a href="http://search.cpan.org/dist/File-Rsync">File::Rsync</a>
+must be installed, and you will need to
+<a href="../docs/ssh.html">setup SSH for unattended operation</a>
+to <b>vpopmail</b>@<i>export.host</i>. See shellcommands_withdomain for an
+export that uses vpopmail commands instead.
+END
+);
+
+@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self, $svc_acct) = (shift, shift);
+ $self->vpopmail_queue( $svc_acct->svcnum, 'insert',
+ $svc_acct->username,
+ crypt($svc_acct->_password,$saltset[int(rand(64))].$saltset[int(rand(64))]),
+ $svc_acct->domain,
+ $svc_acct->quota,
+ $svc_acct->finger,
+ );
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+
+ my $cpassword = crypt(
+ $new->_password, $saltset[int(rand(64))].$saltset[int(rand(64))]
+ );
+
+ return "can't change username with vpopmail"
+ if $old->username ne $new->username;
+
+ #no.... if mail can't be preserved, better to disallow username changes
+ #if ($old->username ne $new->username || $old->domain ne $new->domain ) {
+ # vpopmail_queue( $svc_acct->svcnum, 'delete',
+ # $old->username, $old->domain
+ # );
+ # vpopmail_queue( $svc_acct->svcnum, 'insert',
+ # $new->username,
+ # $cpassword,
+ # $new->domain,
+ # );
+
+ return '' unless $old->_password ne $new->_password;
+
+ $self->vpopmail_queue( $new->svcnum, 'replace',
+ $new->username, $cpassword, $new->domain, $new->quota, $new->finger );
+}
+
+sub _export_delete {
+ my( $self, $svc_acct ) = (shift, shift);
+ $self->vpopmail_queue( $svc_acct->svcnum, 'delete',
+ $svc_acct->username, $svc_acct->domain );
+}
+
+#a good idea to queue anything that could fail or take any time
+sub vpopmail_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+
+ my $exportdir = "/usr/local/etc/freeside/export." . datasrc;
+ mkdir $exportdir, 0700 or die $! unless -d $exportdir;
+ $exportdir .= "/vpopmail";
+ mkdir $exportdir, 0700 or die $! unless -d $exportdir;
+ $exportdir .= '/'. $self->machine;
+ mkdir $exportdir, 0700 or die $! unless -d $exportdir;
+ mkdir "$exportdir/domains", 0700 or die $! unless -d "$exportdir/domains";
+
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::vpopmail::vpopmail_$method",
+ };
+ $queue->insert(
+ $exportdir,
+ $self->machine,
+ $self->option('dir'),
+ $self->option('uid'),
+ $self->option('gid'),
+ $self->option('restart'),
+ @_
+ );
+}
+
+sub vpopmail_insert { #subroutine, not method
+ my( $exportdir, $machine, $dir, $uid, $gid, $restart ) = splice @_,0,6;
+ my( $username, $password, $domain, $quota, $finger ) = @_;
+
+ mkdir "$exportdir/domains/$domain", 0700 or die $!
+ unless -d "$exportdir/domains/$domain";
+
+ (open(VPASSWD, ">>$exportdir/domains/$domain/vpasswd")
+ and flock(VPASSWD,LOCK_EX)
+ ) or die "can't open vpasswd file for $username\@$domain: ".
+ "$exportdir/domains/$domain/vpasswd: $!";
+ print VPASSWD join(":",
+ $username,
+ $password,
+ '1',
+ '0',
+ $finger,
+ "$dir/domains/$domain/$username",
+ $quota ? $quota.'S' : 'NOQUOTA',
+ ), "\n";
+
+ flock(VPASSWD,LOCK_UN);
+ close(VPASSWD);
+
+ for my $mkdir (
+ grep { ! -d $_ } map { "$exportdir/domains/$domain/$username$_" }
+ ( '', qw( /Maildir /Maildir/cur /Maildir/new /Maildir/tmp ) )
+ ) {
+ mkdir $mkdir, 0700 or die "can't mkdir $mkdir: $!";
+ }
+
+ vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid, $restart );
+
+}
+
+sub vpopmail_replace { #subroutine, not method
+ my( $exportdir, $machine, $dir, $uid, $gid, $restart ) = splice @_,0,6;
+ my( $username, $password, $domain, $quota, $finger ) = @_;
+
+ (open(VPASSWD, "$exportdir/domains/$domain/vpasswd")
+ and flock(VPASSWD,LOCK_EX)
+ ) or die "can't open $exportdir/domains/$domain/vpasswd: $!";
+
+ open(VPASSWDTMP, ">$exportdir/domains/$domain/vpasswd.tmp")
+ or die "Can't open $exportdir/domains/$domain/vpasswd.tmp: $!";
+
+ while (<VPASSWD>) {
+ my ($mailbox, $pw, $vuid, $vgid, $vfinger, $vdir, $vquota, @rest) =
+ split(':', $_);
+ if ( $username ne $mailbox ) {
+ print VPASSWDTMP $_;
+ next
+ }
+ print VPASSWDTMP join (':',
+ $mailbox,
+ $password,
+ '1',
+ '0',
+ $finger,
+ "$dir/domains/$domain/$username", #$vdir
+ $quota ? $quota.'S' : 'NOQUOTA',
+ ), "\n";
+ }
+
+ close(VPASSWDTMP);
+
+ rename "$exportdir/domains/$domain/vpasswd.tmp", "$exportdir/domains/$domain/vpasswd"
+ or die "Can't rename $exportdir/domains/$domain/vpasswd.tmp: $!";
+
+ flock(VPASSWD,LOCK_UN);
+ close(VPASSWD);
+
+ vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid, $restart );
+
+}
+
+sub vpopmail_delete { #subroutine, not method
+ my( $exportdir, $machine, $dir, $uid, $gid, $restart ) = splice @_,0,6;
+ my( $username, $domain ) = @_;
+
+ (open(VPASSWD, "$exportdir/domains/$domain/vpasswd")
+ and flock(VPASSWD,LOCK_EX)
+ ) or die "can't open $exportdir/domains/$domain/vpasswd: $!";
+
+ open(VPASSWDTMP, ">$exportdir/domains/$domain/vpasswd.tmp")
+ or die "Can't open $exportdir/domains/$domain/vpasswd.tmp: $!";
+
+ while (<VPASSWD>) {
+ my ($mailbox, $rest) = split(':', $_);
+ print VPASSWDTMP $_ unless $username eq $mailbox;
+ }
+
+ close(VPASSWDTMP);
+
+ rename "$exportdir/domains/$domain/vpasswd.tmp",
+ "$exportdir/domains/$domain/vpasswd"
+ or die "Can't rename $exportdir/domains/$domain/vpasswd.tmp: $!";
+
+ flock(VPASSWD,LOCK_UN);
+ close(VPASSWD);
+
+ rmtree "$exportdir/domains/$domain/$username"
+ or die "can't rmtree $exportdir/domains/$domain/$username: $!";
+
+ vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid, $restart );
+}
+
+sub vpopmail_sync {
+ my( $exportdir, $machine, $dir, $uid, $gid, $restart ) = splice @_,0,6;
+
+ chdir $exportdir;
+# my @args = ( $rsync, "-rlpt", "-e", $ssh, "domains/",
+# "vpopmail\@$machine:$dir/domains/" );
+# system {$args[0]} @args;
+
+ eval "use File::Rsync;";
+ die $@ if $@;
+
+ my $rsync = File::Rsync->new({ rsh => 'ssh' });
+
+ $rsync->exec( {
+ recursive => 1,
+ perms => 1,
+ times => 1,
+ src => "$exportdir/domains/",
+ dest => "vpopmail\@$machine:$dir/domains/",
+ } ); # true/false return value from exec is not working, alas
+ if ( $rsync->err ) {
+ die "error uploading to vpopmail\@$machine:$dir/domains/ : ".
+ 'exit status: '. $rsync->status. ', '.
+ 'STDERR: '. join(" / ", $rsync->err). ', '.
+ 'STDOUT: '. join(" / ", $rsync->out);
+ }
+
+ eval "use Net::SSH qw(ssh);";
+ die $@ if $@;
+
+ ssh("vpopmail\@$machine", $restart) if $restart;
+}
+
+1;
+
diff --git a/FS/FS/part_export/www_shellcommands.pm b/FS/FS/part_export/www_shellcommands.pm
new file mode 100644
index 0000000..0e50d60
--- /dev/null
+++ b/FS/FS/part_export/www_shellcommands.pm
@@ -0,0 +1,166 @@
+package FS::part_export::www_shellcommands;
+
+use strict;
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'user' => { label=>'Remote username', default=>'root' },
+ 'useradd' => { label=>'Insert command',
+ default=>'mkdir $homedir/$zone; chown $username $homedir/$zone; ln -s $homedir/$zone /var/www/$zone',
+ },
+ 'userdel' => { label=>'Delete command',
+ default=>'[ -n "$zone" ] && rm -rf /var/www/$zone; rm -rf $homedir/$zone',
+ },
+ 'usermod' => { label=>'Modify command',
+ default=>'[ -n "$old_zone" ] && rm /var/www/$old_zone; [ "$old_zone" != "$new_zone" -a -n "$new_zone" ] && ( mv $old_homedir/$old_zone $new_homedir/$new_zone; ln -sf $new_homedir/$new_zone /var/www/$new_zone ); [ "$old_username" != "$new_username" ] && chown -R $new_username $new_homedir/$new_zone; ln -sf $new_homedir/$new_zone /var/www/$new_zone',
+ },
+;
+
+%info = (
+ 'svc' => 'svc_www',
+ 'desc' => 'Run remote commands via SSH, for virtual web sites (directory maintenance, FrontPage, ISPMan)',
+ 'options' => \%options,
+ 'notes' => <<'END'
+Run remote commands via SSH, for virtual web sites. You will need to
+<a href="../docs/ssh.html">setup SSH for unattended operation</a>.
+<BR><BR>Use these buttons for some useful presets:
+<UL>
+ <LI>
+ <INPUT TYPE="button" VALUE="Maintain directories" onClick='
+ this.form.user.value = "root";
+ this.form.useradd.value = "mkdir $homedir/$zone; chown $username $homedir/$zone; ln -s $homedir/$zone /var/www/$zone";
+ this.form.userdel.value = "[ -n \"$zone\" ] && rm -rf /var/www/$zone; rm -rf $homedir/$zone";
+ this.form.usermod.value = "[ -n \"$old_zone\" ] && rm /var/www/$old_zone; [ \"$old_zone\" != \"$new_zone\" -a -n \"$new_zone\" ] && ( mv $old_homedir/$old_zone $new_homedir/$new_zone; ln -sf $new_homedir/$new_zone /var/www/$new_zone ); [ \"$old_username\" != \"$new_username\" ] && chown -R $new_username $new_homedir/$new_zone; ln -sf $new_homedir/$new_zone /var/www/$new_zone";
+ '>
+ <LI>
+ <INPUT TYPE="button" VALUE="FrontPage extensions" onClick='
+ this.form.user.value = "root";
+ this.form.useradd.value = "/usr/local/frontpage/version5.0/bin/owsadm.exe -o install -p 80 -m $zone -xu $username -xg www-data -s /etc/apache/httpd.conf -u $username -pw $_password";
+ this.form.userdel.value = "/usr/local/frontpage/version5.0/bin/owsadm.exe -o uninstall -p 80 -m $zone -s /etc/apache/httpd.conf";
+ this.form.usermod.value = "";
+ '>
+ <LI>
+ <INPUT TYPE="button" VALUE="ISPMan CLI" onClick='
+ this.form.user.value = "root";
+ this.form.useradd.value = "/usr/local/ispman/bin/ispman.addvhost -d $domain $bare_zone";
+ this.form.userdel.value = "/usr/local/ispman/bin/ispman.deletevhost -d $domain $bare_zone";
+ this.form.usermod.value = "";
+ '></UL>
+The following variables are available for interpolation (prefixed with
+<code>new_</code> or <code>old_</code> for replace operations):
+<UL>
+ <LI><code>$zone</code> - fully-qualified zone of this virtual host
+ <LI><code>$bare_zone</code> - just the zone of this virtual host, without the domain portion
+ <LI><code>$domain</code> - base domain
+ <LI><code>$username</code>
+ <LI><code>$homedir</code>
+ <LI>All other fields in <a href="../docs/schema.html#svc_www">svc_www</a>
+ are also available.
+</UL>
+END
+);
+
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self) = shift;
+ $self->_export_command('useradd', @_);
+}
+
+sub _export_delete {
+ my($self) = shift;
+ $self->_export_command('userdel', @_);
+}
+
+sub _export_command {
+ my ( $self, $action, $svc_www) = (shift, shift, shift);
+ my $command = $self->option($action);
+
+ #set variable for the command
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${$_} = $svc_www->getfield($_) foreach $svc_www->fields;
+ }
+ my $domain_record = $svc_www->domain_record; # or die ?
+ my $zone = $domain_record->zone; # or die ?
+ my $domain = $domain_record->svc_domain->domain;
+ ( my $bare_zone = $zone ) =~ s/\.$domain$//;
+ my $svc_acct = $svc_www->svc_acct; # or die ?
+ my $username = $svc_acct->username;
+ my $_password = $svc_acct->_password;
+ my $homedir = $svc_acct->dir; # or die ?
+
+ #done setting variables for the command
+
+ $self->shellcommands_queue( $svc_www->svcnum,
+ user => $self->option('user')||'root',
+ host => $self->machine,
+ command => eval(qq("$command")),
+ );
+}
+
+sub _export_replace {
+ my($self, $new, $old ) = (shift, shift, shift);
+ my $command = $self->option('usermod');
+
+ #set variable for the command
+ no strict 'vars';
+ {
+ no strict 'refs';
+ ${"old_$_"} = $old->getfield($_) foreach $old->fields;
+ ${"new_$_"} = $new->getfield($_) foreach $new->fields;
+ }
+ my $old_domain_record = $old->domain_record; # or die ?
+ my $old_zone = $old_domain_record->zone; # or die ?
+ my $old_domain = $old_domain_record->svc_domain->domain;
+ ( my $old_bare_zone = $old_zone ) =~ s/\.$old_domain$//;
+ my $old_svc_acct = $old->svc_acct; # or die ?
+ my $old_username = $old_svc_acct->username;
+ my $old_homedir = $old_svc_acct->dir; # or die ?
+
+ my $new_domain_record = $new->domain_record; # or die ?
+ my $new_zone = $new_domain_record->zone; # or die ?
+ my $new_domain = $new_domain_record->svc_domain->domain;
+ ( my $new_bare_zone = $new_zone ) =~ s/\.$new_domain$//;
+ my $new_svc_acct = $new->svc_acct; # or die ?
+ my $new_username = $new_svc_acct->username;
+ #my $new__password = $new_svc_acct->_password;
+ my $new_homedir = $new_svc_acct->dir; # or die ?
+
+ #done setting variables for the command
+
+ $self->shellcommands_queue( $new->svcnum,
+ user => $self->option('user')||'root',
+ host => $self->machine,
+ command => eval(qq("$command")),
+ );
+}
+
+#a good idea to queue anything that could fail or take any time
+sub shellcommands_queue {
+ my( $self, $svcnum ) = (shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::www_shellcommands::ssh_cmd",
+ };
+ $queue->insert( @_ );
+}
+
+sub ssh_cmd { #subroutine, not method
+ use Net::SSH '0.08';
+ &Net::SSH::ssh_cmd( { @_ } );
+}
+
+#sub shellcommands_insert { #subroutine, not method
+#}
+#sub shellcommands_replace { #subroutine, not method
+#}
+#sub shellcommands_delete { #subroutine, not method
+#}
+
diff --git a/FS/FS/part_export_option.pm b/FS/FS/part_export_option.pm
new file mode 100644
index 0000000..33b5e5a
--- /dev/null
+++ b/FS/FS/part_export_option.pm
@@ -0,0 +1,134 @@
+package FS::part_export_option;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+use FS::part_export;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::part_export_option - Object methods for part_export_option records
+
+=head1 SYNOPSIS
+
+ use FS::part_export_option;
+
+ $record = new FS::part_export_option \%hash;
+ $record = new FS::part_export_option { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_export_option object represents an export option.
+FS::part_export_option inherits from FS::Record. The following fields are
+currently supported:
+
+=over 4
+
+=item optionnum - primary key
+
+=item exportnum - export (see L<FS::part_export>)
+
+=item optionname - option name
+
+=item optionvalue - option value
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new export option. To add the export option to the database, see
+L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'part_export_option'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid export option. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('optionnum')
+ || $self->ut_number('exportnum')
+ || $self->ut_alpha('optionname')
+ || $self->ut_anything('optionvalue')
+ ;
+ return $error if $error;
+
+ return "Unknown exportnum: ". $self->exportnum
+ unless qsearchs('part_export', { 'exportnum' => $self->exportnum } );
+
+ #check options & values?
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+Possibly.
+
+=head1 SEE ALSO
+
+L<FS::part_export>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm
new file mode 100644
index 0000000..dcce66b
--- /dev/null
+++ b/FS/FS/part_pkg.pm
@@ -0,0 +1,333 @@
+package FS::part_pkg;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch dbh dbdef );
+use FS::pkg_svc;
+use FS::agent_type;
+use FS::type_pkgs;
+use FS::Conf;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::part_pkg - Object methods for part_pkg objects
+
+=head1 SYNOPSIS
+
+ use FS::part_pkg;
+
+ $record = new FS::part_pkg \%hash
+ $record = new FS::part_pkg { 'column' => 'value' };
+
+ $custom_record = $template_record->clone;
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ @pkg_svc = $record->pkg_svc;
+
+ $svcnum = $record->svcpart;
+ $svcnum = $record->svcpart( 'svc_acct' );
+
+=head1 DESCRIPTION
+
+An FS::part_pkg object represents a billing item definition. FS::part_pkg
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item pkgpart - primary key (assigned automatically for new billing item definitions)
+
+=item pkg - Text name of this billing item definition (customer-viewable)
+
+=item comment - Text name of this billing item definition (non-customer-viewable)
+
+=item setup - Setup fee expression
+
+=item freq - Frequency of recurring fee
+
+=item recur - Recurring fee expression
+
+=item setuptax - Setup fee tax exempt flag, empty or `Y'
+
+=item recurtax - Recurring fee tax exempt flag, empty or `Y'
+
+=item taxclass - Tax class flag
+
+=item plan - Price plan
+
+=item plandata - Price plan data
+
+=item disabled - Disabled flag, empty or `Y'
+
+=back
+
+setup and recur are evaluated as Safe perl expressions. You can use numbers
+just as you would normally. More advanced semantics are not yet defined.
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new billing item definition. To add the billing item definition to
+the database, see L<"insert">.
+
+=cut
+
+sub table { 'part_pkg'; }
+
+=item clone
+
+An alternate constructor. Creates a new billing item definition by duplicating
+an existing definition. A new pkgpart is assigned and `(CUSTOM) ' is prepended
+to the comment field. To add the billing item definition to the database, see
+L<"insert">.
+
+=cut
+
+sub clone {
+ my $self = shift;
+ my $class = ref($self);
+ my %hash = $self->hash;
+ $hash{'pkgpart'} = '';
+ $hash{'comment'} = "(CUSTOM) ". $hash{'comment'}
+ unless $hash{'comment'} =~ /^\(CUSTOM\) /;
+ #new FS::part_pkg ( \%hash ); # ?
+ new $class ( \%hash ); # ?
+}
+
+=item insert
+
+Adds this billing item definition to the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ my $conf = new FS::Conf;
+
+ if ( $conf->exists('agent_defaultpkg') ) {
+ foreach my $agent_type ( qsearch('agent_type', {} ) ) {
+ my $type_pkgs = new FS::type_pkgs({
+ 'typenum' => $agent_type->typenum,
+ 'pkgpart' => $self->pkgpart,
+ });
+ my $error = $type_pkgs->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+}
+
+=item delete
+
+Currently unimplemented.
+
+=cut
+
+sub delete {
+ return "Can't (yet?) delete package definitions.";
+# check & make sure the pkgpart isn't in cust_pkg or type_pkgs?
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid billing item definition. If
+there is an error, returns the error, otherwise returns false. Called by the
+insert and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ for (qw(setup recur)) { $self->set($_=>0) if $self->get($_) =~ /^\s*$/; }
+
+ my $conf = new FS::Conf;
+ if ( $conf->exists('safe-part_pkg') ) {
+
+ my $error = $self->ut_anything('setup')
+ || $self->ut_anything('recur');
+ return $error if $error;
+
+ my $s = $self->setup;
+
+ $s =~ /^\s*\d*\.?\d*\s*$/
+
+ or $s =~ /^my \$d = \$cust_pkg->bill || \$time; \$d += 86400 \* \s*\d+\s*; \$cust_pkg->bill\(\$d\); \$cust_pkg_mod_flag=1; \s*\d*\.?\d*\s*$/
+
+ or do {
+ #log!
+ return "illegal setup: $s";
+ };
+
+ my $r = $self->recur;
+
+ $r =~ /^\s*\d*\.?\d*\s*$/
+
+ #or $r =~ /^\$sdate += 86400 \* \s*\d+\s*; \s*\d*\.?\d*\s*$/
+
+ or $r =~ /^my \$mnow = \$sdate; my \(\$sec,\$min,\$hour,\$mday,\$mon,\$year\) = \(localtime\(\$sdate\) \)\[0,1,2,3,4,5\]; my \$mstart = timelocal\(0,0,0,1,\$mon,\$year\); my \$mend = timelocal\(0,0,0,1, \$mon == 11 \? 0 : \$mon\+1, \$year\+\(\$mon==11\)\); \$sdate = \$mstart; \( \$part_pkg->freq \- 1 \) \* \d*\.?\d* \/ \$part_pkg\-\>freq \+ \d*\.?\d* \/ \$part_pkg\-\>freq \* \(\$mend\-\$mnow\) \/ \(\$mend\-\$mstart\) ;\s*$/
+
+ or $r =~ /^my \$mnow = \$sdate; my \(\$sec,\$min,\$hour,\$mday,\$mon,\$year\) = \(localtime\(\$sdate\) \)\[0,1,2,3,4,5\]; \$sdate = timelocal\(0,0,0,1,\$mon,\$year\); \s*\d*\.?\d*\s*;\s*$/
+
+ or $r =~ /^my \$error = \$cust_pkg\->cust_main\->credit\( \s*\d*\.?\d*\s* \* scalar\(\$cust_pkg\->cust_main\->referral_cust_main_ncancelled\(\s*\d+\s*\)\), "commission" \); die \$error if \$error; \s*\d*\.?\d*\s*;\s*$/
+
+ or $r =~ /^my \$error = \$cust_pkg\->cust_main\->credit\( \s*\d*\.?\d*\s* \* scalar\(\$cust_pkg\->cust_main->referral_cust_pkg\(\s*\d+\s*\)\), "commission" \); die \$error if \$error; \s*\d*\.?\d*\s*;\s*$/
+
+ or $r =~ /^my \$error = \$cust_pkg\->cust_main\->credit\( \s*\d*\.?\d*\s* \* scalar\( grep \{ my \$pkgpart = \$_\->pkgpart; grep \{ \$_ == \$pkgpart \} \(\s*(\s*\d+,\s*)*\s*\) \} \$cust_pkg\->cust_main->referral_cust_pkg\(\s*\d+\s*\)\), "commission" \); die \$error if \$error; \s*\d*\.?\d*\s*;\s*$/
+
+ or $r =~ /^my \$hours = \$cust_pkg\->seconds_since\(\$cust_pkg\->bill \|\| 0\) \/ 3600 \- \s*\d*\.?\d*\s*; \$hours = 0 if \$hours < 0; \s*\d*\.?\d*\s* \+ \s*\d*\.?\d*\s* \* \$hours;\s*$/
+
+ or $r =~ /^my \$min = \$cust_pkg\->seconds_since\(\$cust_pkg\->bill \|\| 0\) \/ 60 \- \s*\d*\.?\d*\s*; \$min = 0 if \$min < 0; \s*\d*\.?\d*\s* \+ \s*\d*\.?\d*\s* \* \$min;\s*$/
+
+ or $r =~ /^my \$last_bill = \$cust_pkg\->last_bill; my \$hours = \$cust_pkg\->seconds_since_sqlradacct\(\$last_bill, \$sdate \) \/ 3600 - \s*\d\.?\d*\s*; \$hours = 0 if \$hours < 0; my \$input = \$cust_pkg\->attribute_since_sqlradacct\(\$last_bill, \$sdate, "AcctInputOctets" \) \/ 1048576; my \$output = \$cust_pkg\->attribute_since_sqlradacct\(\$last_bill, \$sdate, "AcctOutputOctets" \) \/ 1048576; my \$total = \$input \+ \$output \- \s*\d\.?\d*\s*; \$total = 0 if \$total < 0; my \$input = \$input - \s*\d\.?\d*\s*; \$input = 0 if \$input < 0; my \$output = \$output - \s*\d\.?\d*\s*; \$output = 0 if \$output < 0; \s*\d\.?\d*\s* \+ \s*\d\.?\d*\s* \* \$hours \+ \s*\d\.?\d*\s* \* \$input \+ \s*\d\.?\d*\s* \* \$output \+ \s*\d\.?\d*\s* \* \$total *;\s*$/
+
+ or do {
+ #log!
+ return "illegal recur: $r";
+ };
+
+ }
+
+ if ( $self->dbdef_table->column('freq')->type =~ /(int)/i ) {
+ my $error = $self->ut_number('freq');
+ return $error if $error;
+ } else {
+ $self->freq =~ /^(\d+[dw]?)$/
+ or return "Illegal or empty freq: ". $self->freq;
+ $self->freq($1);
+ }
+
+ $self->ut_numbern('pkgpart')
+ || $self->ut_text('pkg')
+ || $self->ut_text('comment')
+ || $self->ut_anything('setup')
+ || $self->ut_anything('recur')
+ || $self->ut_alphan('plan')
+ || $self->ut_anything('plandata')
+ || $self->ut_enum('setuptax', [ '', 'Y' ] )
+ || $self->ut_enum('recurtax', [ '', 'Y' ] )
+ || $self->ut_textn('taxclass')
+ || $self->ut_enum('disabled', [ '', 'Y' ] )
+ || $self->SUPER::check
+ ;
+}
+
+=item pkg_svc
+
+Returns all FS::pkg_svc objects (see L<FS::pkg_svc>) for this package
+definition (with non-zero quantity).
+
+=cut
+
+sub pkg_svc {
+ my $self = shift;
+ grep { $_->quantity } qsearch( 'pkg_svc', { 'pkgpart' => $self->pkgpart } );
+}
+
+=item svcpart [ SVCDB ]
+
+Returns the svcpart of the primary service definition (see L<FS::part_svc>)
+associated with this billing item definition (see L<FS::pkg_svc>). Returns
+false if there not a primary service definition or exactly one service
+definition with quantity 1, or if SVCDB is specified and does not match the
+svcdb of the service definition,
+
+=cut
+
+sub svcpart {
+ my $self = shift;
+ my $svcdb = scalar(@_) ? shift : '';
+ my @svcdb_pkg_svc =
+ grep { ( $svcdb eq $_->part_svc->svcdb || !$svcdb ) } $self->pkg_svc;
+ my @pkg_svc = ();
+ @pkg_svc = grep { $_->primary_svc =~ /^Y/i } @svcdb_pkg_svc
+ if dbdef->table('pkg_svc')->column('primary_svc');
+ @pkg_svc = grep {$_->quantity == 1 } @svcdb_pkg_svc
+ unless @pkg_svc;
+ return '' if scalar(@pkg_svc) != 1;
+ $pkg_svc[0]->svcpart;
+}
+
+=item payby
+
+Returns a list of the acceptable payment types for this package. Eventually
+this should come out of a database table and be editable, but currently has the
+following logic instead;
+
+If the package has B<0> setup and B<0> recur, the single item B<BILL> is
+returned, otherwise, the single item B<CARD> is returned.
+
+(CHEK? LEC? Probably shouldn't accept those by default, prone to abuse)
+
+=cut
+
+sub payby {
+ my $self = shift;
+ #if ( $self->setup == 0 && $self->recur == 0 ) {
+ if ( $self->setup =~ /^\s*0+(\.0*)?\s*$/
+ && $self->recur =~ /^\s*0+(\.0*)?\s*$/ ) {
+ ( 'BILL' );
+ } else {
+ ( 'CARD' );
+ }
+}
+
+=back
+
+=head1 BUGS
+
+The delete method is unimplemented.
+
+setup and recur semantics are not yet defined (and are implemented in
+FS::cust_bill. hmm.).
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_pkg>, L<FS::type_pkgs>, L<FS::pkg_svc>, L<Safe>.
+schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_pop_local.pm b/FS/FS/part_pop_local.pm
new file mode 100644
index 0000000..f7d5eac
--- /dev/null
+++ b/FS/FS/part_pop_local.pm
@@ -0,0 +1,117 @@
+package FS::part_pop_local;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record; # qw( qsearchs );
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::part_pop_local - Object methods for part_pop_local records
+
+=head1 SYNOPSIS
+
+ use FS::part_pop_local;
+
+ $record = new FS::part_pop_local \%hash;
+ $record = new FS::part_pop_local { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_pop_local object represents a local call area. Each
+FS::part_pop_local record maps a NPA/NXX (area code and exchange) to the POP
+(see L<FS::svc_acct_pop>) which is a local call. FS::part_pop_local inherits
+from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item localnum - primary key (assigned automatically for new accounts)
+
+=item popnum - see L<FS::svc_acct_pop>
+
+=item city
+
+=item state
+
+=item npa - area code
+
+=item nxx - exchange
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new point of presence (if only it were that easy!). To add the
+point of presence to the database, see L<"insert">.
+
+=cut
+
+sub table { 'part_pop_local'; }
+
+=item insert
+
+Adds this point of presence to the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item delete
+
+Removes this point of presence from the database.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid point of presence. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('localnum')
+ or $self->ut_numbern('popnum')
+ or $self->ut_text('city')
+ or $self->ut_text('state')
+ or $self->ut_number('npa')
+ or $self->ut_number('nxx')
+ or $self->SUPER::check
+ ;
+
+}
+
+=back
+
+=head1 VERSION
+
+$Id: part_pop_local.pm,v 1.2 2003-08-05 00:20:44 khoff Exp $
+
+=head1 BUGS
+
+US/CA-centric.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::svc_acct_pop>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_referral.pm b/FS/FS/part_referral.pm
new file mode 100644
index 0000000..c0858c0
--- /dev/null
+++ b/FS/FS/part_referral.pm
@@ -0,0 +1,126 @@
+package FS::part_referral;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::part_referral - Object methods for part_referral objects
+
+=head1 SYNOPSIS
+
+ use FS::part_referral;
+
+ $record = new FS::part_referral \%hash
+ $record = new FS::part_referral { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_referral represents a advertising source - where a customer heard
+of your services. This can be used to track the effectiveness of a particular
+piece of advertising, for example. FS::part_referral inherits from FS::Record.
+The following fields are currently supported:
+
+=over 4
+
+=item refnum - primary key (assigned automatically for new referrals)
+
+=item referral - Text name of this advertising source
+
+=item disabled - Disabled flag, empty or 'Y'
+
+=back
+
+=head1 NOTE
+
+These were called B<referrals> before version 1.4.0 - the name was changed
+so as not to be confused with the new customer-to-customer referrals.
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new advertising source. To add the referral to the database, see
+L<"insert">.
+
+=cut
+
+sub table { 'part_referral'; }
+
+=item insert
+
+Adds this advertising source to the database. If there is an error, returns
+the error, otherwise returns false.
+
+=item delete
+
+Currently unimplemented.
+
+=cut
+
+sub delete {
+ my $self = shift;
+ return "Can't (yet?) delete part_referral records";
+ #need to make sure no customers have this referral!
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid advertising source. If there is
+an error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error = $self->ut_numbern('refnum')
+ || $self->ut_text('referral')
+ ;
+ return $error if $error;
+
+ if ( $self->dbdef_table->column('disabled') ) {
+ $error = $self->ut_enum('disabled', [ '', 'Y' ] );
+ return $error if $error;
+ }
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+The delete method is unimplemented.
+
+`Advertising source'. Yes, it's a sucky name. The only other ones I could
+come up with were "Marketing channel" and "Heard Abouts" and those are
+definately both worse.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_main>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_svc.pm b/FS/FS/part_svc.pm
new file mode 100644
index 0000000..aacc3ab
--- /dev/null
+++ b/FS/FS/part_svc.pm
@@ -0,0 +1,324 @@
+package FS::part_svc;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs fields dbh );
+use FS::part_svc_column;
+use FS::part_export;
+use FS::export_svc;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::part_svc - Object methods for part_svc objects
+
+=head1 SYNOPSIS
+
+ use FS::part_svc;
+
+ $record = new FS::part_svc \%hash
+ $record = new FS::part_svc { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_svc represents a service definition. FS::part_svc inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item svcpart - primary key (assigned automatically for new service definitions)
+
+=item svc - text name of this service definition
+
+=item svcdb - table used for this service. See L<FS::svc_acct>,
+L<FS::svc_domain>, and L<FS::svc_forward>, among others.
+
+=item disabled - Disabled flag, empty or `Y'
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new service definition. To add the service definition to the
+database, see L<"insert">.
+
+=cut
+
+sub table { 'part_svc'; }
+
+=item insert EXTRA_FIELDS_ARRAYREF
+
+Adds this service definition to the database. If there is an error, returns
+the error, otherwise returns false.
+
+TODOC:
+
+=item I<svcdb>__I<field> - Default or fixed value for I<field> in I<svcdb>.
+
+=item I<svcdb>__I<field>_flag - defines I<svcdb>__I<field> action: null, `D' for default, or `F' for fixed. For virtual fields, can also be 'X' for excluded.
+
+TODOC: EXTRA_FIELDS_ARRAYREF
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my @fields = ();
+ @fields = @{shift(@_)} if @_;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ my $svcdb = $self->svcdb;
+# my @rows = map { /^${svcdb}__(.*)$/; $1 }
+# grep ! /_flag$/,
+# grep /^${svcdb}__/,
+# fields('part_svc');
+ foreach my $field (
+ grep { $_ ne 'svcnum'
+ && defined( $self->getfield($svcdb.'__'.$_.'_flag') )
+ } (fields($svcdb), @fields)
+ ) {
+ my $part_svc_column = $self->part_svc_column($field);
+ my $previous = qsearchs('part_svc_column', {
+ 'svcpart' => $self->svcpart,
+ 'columnname' => $field,
+ } );
+
+ my $flag = $self->getfield($svcdb.'__'.$field.'_flag');
+ if ( uc($flag) =~ /^([DFX])$/ ) {
+ $part_svc_column->setfield('columnflag', $1);
+ $part_svc_column->setfield('columnvalue',
+ $self->getfield($svcdb.'__'.$field)
+ );
+ if ( $previous ) {
+ $error = $part_svc_column->replace($previous);
+ } else {
+ $error = $part_svc_column->insert;
+ }
+ } else {
+ $error = $previous ? $previous->delete : '';
+ }
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+}
+
+=item delete
+
+Currently unimplemented.
+
+=cut
+
+sub delete {
+ return "Can't (yet?) delete service definitions.";
+# check & make sure the svcpart isn't in cust_svc or pkg_svc (in any packages)?
+}
+
+=item replace OLD_RECORD [ '1.3-COMPAT' [ , EXTRA_FIELDS_ARRAYREF ] ]
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+TODOC: 1.3-COMPAT
+
+TODOC: EXTRA_FIELDS_ARRAYREF
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+
+ return "Can't change svcdb for an existing service definition!"
+ unless $old->svcdb eq $new->svcdb;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $new->SUPER::replace( $old );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ if ( @_ && $_[0] eq '1.3-COMPAT' ) {
+ shift;
+ my @fields = ();
+ @fields = @{shift(@_)} if @_;
+
+ my $svcdb = $new->svcdb;
+ foreach my $field (
+ grep { $_ ne 'svcnum'
+ && defined( $new->getfield($svcdb.'__'.$_.'_flag') )
+ } (fields($svcdb),@fields)
+ ) {
+ my $part_svc_column = $new->part_svc_column($field);
+ my $previous = qsearchs('part_svc_column', {
+ 'svcpart' => $new->svcpart,
+ 'columnname' => $field,
+ } );
+
+ my $flag = $new->getfield($svcdb.'__'.$field.'_flag');
+ if ( uc($flag) =~ /^([DFX])$/ ) {
+ $part_svc_column->setfield('columnflag', $1);
+ $part_svc_column->setfield('columnvalue',
+ $new->getfield($svcdb.'__'.$field)
+ );
+ if ( $previous ) {
+ $error = $part_svc_column->replace($previous);
+ } else {
+ $error = $part_svc_column->insert;
+ }
+ } else {
+ $error = $previous ? $previous->delete : '';
+ }
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ } else {
+ $dbh->rollback if $oldAutoCommit;
+ return 'non-1.3-COMPAT interface not yet written';
+ #not yet implemented
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+}
+
+=item check
+
+Checks all fields to make sure this is a valid service definition. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+ my $recref = $self->hashref;
+
+ my $error;
+ $error=
+ $self->ut_numbern('svcpart')
+ || $self->ut_text('svc')
+ || $self->ut_alpha('svcdb')
+ || $self->ut_enum('disabled', [ '', 'Y' ] )
+ ;
+ return $error if $error;
+
+ my @fields = eval { fields( $recref->{svcdb} ) }; #might die
+ return "Unknown svcdb!" unless @fields;
+
+ $self->SUPER::check;
+}
+
+=item part_svc_column COLUMNNAME
+
+Returns the part_svc_column object (see L<FS::part_svc_column>) for the given
+COLUMNNAME, or a new part_svc_column object if none exists.
+
+=cut
+
+sub part_svc_column {
+ my( $self, $columnname) = @_;
+ $self->svcpart &&
+ qsearchs('part_svc_column', {
+ 'svcpart' => $self->svcpart,
+ 'columnname' => $columnname,
+ }
+ ) or new FS::part_svc_column {
+ 'svcpart' => $self->svcpart,
+ 'columnname' => $columnname,
+ };
+}
+
+=item all_part_svc_column
+
+=cut
+
+sub all_part_svc_column {
+ my $self = shift;
+ qsearch('part_svc_column', { 'svcpart' => $self->svcpart } );
+}
+
+=item part_export [ EXPORTTYPE ]
+
+Returns all exports (see L<FS::part_export>) for this service, or, if an
+export type is specified, only returns exports of the given type.
+
+=cut
+
+sub part_export {
+ my $self = shift;
+ my %search;
+ $search{'exporttype'} = shift if @_;
+ map { qsearchs('part_export', { 'exportnum' => $_->exportnum, %search } ) }
+ qsearch('export_svc', { 'svcpart' => $self->svcpart } );
+}
+
+=back
+
+=head1 BUGS
+
+Delete is unimplemented.
+
+The list of svc_* tables is hardcoded. When svc_acct_pop is renamed, this
+should be fixed.
+
+all_part_svc_column method should be documented
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::part_svc_column>, L<FS::part_pkg>, L<FS::pkg_svc>,
+L<FS::cust_svc>, L<FS::svc_acct>, L<FS::svc_forward>, L<FS::svc_domain>,
+schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_svc_column.pm b/FS/FS/part_svc_column.pm
new file mode 100644
index 0000000..885155b
--- /dev/null
+++ b/FS/FS/part_svc_column.pm
@@ -0,0 +1,118 @@
+package FS::part_svc_column;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( fields );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::part_svc_column - Object methods for part_svc_column objects
+
+=head1 SYNOPSIS
+
+ use FS::part_svc_column;
+
+ $record = new FS::part_svc_column \%hash
+ $record = new FS::part_svc_column { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_svc_column record represents a service definition column
+constraint. FS::part_svc_column inherits from FS::Record. The following
+fields are currently supported:
+
+=over 4
+
+=item columnnum - primary key (assigned automatcially for new records)
+
+=item svcpart - service definition (see L<FS::part_svc>)
+
+=item columnname - column name in part_svc.svcdb table
+
+=item columnvalue - default or fixed value for the column
+
+=item columnflag - null, D, F, X (virtual fields)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new column constraint. To add the column constraint to the database, see L<"insert">.
+
+=cut
+
+sub table { 'part_svc_column'; }
+
+=item insert
+
+Adds this service definition to the database. If there is an error, returns
+the error, otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('columnnum')
+ || $self->ut_number('svcpart')
+ || $self->ut_alpha('columnname')
+ || $self->ut_anything('columnvalue')
+ ;
+ return $error if $error;
+
+ $self->columnflag =~ /^([DFX])$/
+ or return "illegal columnflag ". $self->columnflag;
+ $self->columnflag(uc($1));
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 VERSION
+
+$Id: part_svc_column.pm,v 1.2 2003-08-05 00:20:44 khoff Exp $
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::part_svc>, L<FS::part_pkg>, L<FS::pkg_svc>,
+L<FS::cust_svc>, L<FS::svc_acct>, L<FS::svc_forward>, L<FS::svc_domain>,
+schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_svc_router.pm b/FS/FS/part_svc_router.pm
new file mode 100755
index 0000000..0b23ab5
--- /dev/null
+++ b/FS/FS/part_svc_router.pm
@@ -0,0 +1,32 @@
+package FS::part_svc_router;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw(qsearchs);
+use FS::router;
+use FS::part_svc;
+
+@ISA = qw(FS::Record);
+
+sub table { 'part_svc_router'; }
+
+sub check {
+ my $self = shift;
+ my $error =
+ $self->ut_foreign_key('svcpart', 'part_svc', 'svcpart')
+ || $self->ut_foreign_key('routernum', 'router', 'routernum');
+ return $error if $error;
+ ''; #no error
+}
+
+sub router {
+ my $self = shift;
+ return qsearchs('router', { routernum => $self->routernum });
+}
+
+sub part_svc {
+ my $self = shift;
+ return qsearchs('part_svc', { svcpart => $self->svcpart });
+}
+
+1;
diff --git a/FS/FS/part_virtual_field.pm b/FS/FS/part_virtual_field.pm
new file mode 100755
index 0000000..03c34cc
--- /dev/null
+++ b/FS/FS/part_virtual_field.pm
@@ -0,0 +1,303 @@
+package FS::part_virtual_field;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs qsearch dbdef );
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::part_virtual_field - Object methods for part_virtual_field records
+
+=head1 SYNOPSIS
+
+ use FS::part_virtual_field;
+
+ $record = new FS::part_virtual_field \%hash;
+ $record = new FS::part_virtual_field { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_virtual_field object represents the definition of a virtual field
+(see the BACKGROUND section). FS::part_virtual_field contains the name and
+base table of the field, as well as validation rules and UI hints about the
+display of the field. The actual data is stored in FS::virtual_field; see
+its manpage for details.
+
+FS::part_virtual_field inherits from FS::Record. The following fields are
+currently supported:
+
+=over 2
+
+=item vfieldpart - primary key (assigned automatically)
+
+=item name - name of the field
+
+=item dbtable - table for which this virtual field is defined
+
+=item check_block - Perl code to validate/normalize data
+
+=item list_source - Perl code to generate a list of values (UI hint)
+
+=item length - expected length of the value (UI hint)
+
+=item label - descriptive label for the field (UI hint)
+
+=item sequence - sort key (UI hint; unimplemented)
+
+=back
+
+=head1 BACKGROUND
+
+"Form is none other than emptiness,
+ and emptiness is none other than form."
+-- Heart Sutra
+
+The virtual field mechanism allows site admins to make trivial changes to
+the Freeside database schema without modifying the code. Specifically, the
+user can add custom-defined 'fields' to the set of data tracked by Freeside
+about objects such as customers and services. These fields are not associated
+with any logic in the core Freeside system, but may be referenced in peripheral
+code such as exports, price calculations, or alternate interfaces, or may just
+be stored in the database for future reference.
+
+This system was originally devised for svc_broadband, which (by necessity)
+comprises such a wide range of access technologies that no static set of fields
+could contain all the information needed by the exports. In an appalling
+display of False Laziness, a parallel mechanism was implemented for the
+router table, to store properties such as passwords to configure routers.
+
+The original system treated svc_broadband custom fields (sb_fields) as records
+in a completely separate table. Any code that accessed or manipulated these
+fields had to be aware that they were I<not> fields in svc_broadband, but
+records in sb_field. For example, code that inserted a svc_broadband with
+several custom fields had to create an FS::svc_broadband object, call its
+insert() method, and then create several FS::sb_field objects and call I<their>
+insert() methods.
+
+This created a problem for exports. The insert method on any FS::svc_Common
+object (including svc_broadband) automatically triggers exports after the
+record has been inserted. However, at this point, the sb_fields had not yet
+been inserted, so the export could not rely on their presence, which was the
+original purpose of sb_fields.
+
+Hence the new system. Virtual fields are appended to the field list of every
+record at the FS::Record level, whether the object is created ex nihilo with
+new() or fetched with qsearch(). The fields() method now returns a list of
+both real and virtual fields. The insert(), replace(), and delete() methods
+now update both the base table and the virtual fields, in a single transaction.
+
+A new method is provided, virtual_fields(), which gives only the virtual
+fields. UI code that dynamically generates form widgets to edit virtual field
+data should use this to figure out what fields are defined. (See below.)
+
+Subclasses may override virtual_fields() to restrict the set of virtual
+fields available. Some discipline and sanity on the part of the programmer
+are required; in particular, this function should probably not depend on any
+fields in the record other than the primary key, since the others may change
+after the object is instantiated. (Making it depend on I<virtual> fields is
+just asking for pain.) One use of this is seen in FS::svc_Common; another
+possibility is field-level access control based on FS::UID::getotaker().
+
+As a trivial case, a subclass may opt out of supporting virtual fields with
+the following code:
+
+sub virtual_fields { () }
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see "insert".
+
+=cut
+
+sub table { 'part_virtual_field'; }
+sub virtual_fields { () }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+If there is an error, returns the error, otherwise returns false.
+Called by the insert and replace methods.
+
+=back
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error = $self->ut_text('name') ||
+ $self->ut_text('dbtable') ||
+ $self->ut_number('length')
+ ;
+ return $error if $error;
+
+ # Make sure it's a real table with a numeric primary key
+ my ($table, $pkey);
+ if($table = $FS::Record::dbdef->table($self->dbtable)) {
+ if($pkey = $table->primary_key) {
+ if($table->column($pkey)->type =~ /int/i) {
+ # this is what it should be
+ } else {
+ $error = "$table.$pkey is not an integer";
+ }
+ } else {
+ $error = "$table does not have a single-field primary key";
+ }
+ } else {
+ $error = "$table does not exist in the schema";
+ }
+ return $error if $error;
+
+ # Possibly some sanity checks for check_block and list_source?
+
+ $self->SUPER::check;
+}
+
+=item list
+
+Evaluates list_source.
+
+=cut
+
+sub list {
+ my $self = shift;
+ return () unless $self->list_source;
+
+ my @opts = eval($self->list_source);
+ if($@) {
+ warn $@;
+ return ();
+ } else {
+ return @opts;
+ }
+}
+
+=item widget UI_TYPE MODE [ VALUE ]
+
+Generates UI code for a widget suitable for editing/viewing the field, based on
+list_source and length.
+
+The only UI_TYPE currently supported is 'HTML', and the only MODE is 'view'.
+Others will be added later.
+
+In HTML, all widgets are assumed to be table rows. View widgets look like
+<TR><TD ALIGN="right">Label</TD><TD BGCOLOR="#ffffff">Value</TD></TR>
+
+(Most of the display style stuff, such as the colors, should probably go into
+a separate module specific to the UI. That can wait, though. The API for
+this function won't change.)
+
+VALUE (optional) is the current value of the field.
+
+=cut
+
+sub widget {
+ my $self = shift;
+ my ($ui_type, $mode, $value) = @_;
+ my $text;
+ my $label = $self->label || $self->name;
+
+ if ($ui_type eq 'HTML') {
+ if ($mode eq 'view') {
+ $text = q!<TR><TD ALIGN="right">! . $label .
+ q!</TD><TD BGCOLOR="#ffffff">! . $value .
+ q!</TD></TR>! . "\n";
+ } elsif ($mode eq 'edit') {
+ $text = q!<TR><TD ALIGN="right">! . $label .
+ q!</TD><TD>!;
+ if ($self->list_source) {
+ $text .= q!<SELECT NAME="! . $self->name .
+ q!" SIZE=1>! . "\n";
+ foreach ($self->list) {
+ $text .= q!<OPTION VALUE="! . $_ . q!"!;
+ $text .= ' SELECTED' if ($_ eq $value);
+ $text .= '>' . $_ . '</OPTION>' . "\n";
+ }
+ } else {
+ $text .= q!<INPUT NAME="! . $self->name .
+ q!" VALUE="! . $value . q!"!;
+ if ($self->length) {
+ $text .= q! SIZE="! . $self->length . q!"!;
+ }
+ $text .= '>';
+ }
+ $text .= q!</TD></TR>! . "\n";
+ } else {
+ return '';
+ }
+ } else {
+ return '';
+ }
+ return $text;
+}
+
+=head1 VERSION
+
+$Id: part_virtual_field.pm,v 1.2 2003-08-05 00:20:45 khoff Exp $
+
+=head1 NOTES
+
+=head2 Semantics of check_block:
+
+This has been changed from the sb_field implementation to make check_blocks
+simpler and more natural to Perl programmers who work on things other than
+Freeside.
+
+The check_block is eval'd with the (proposed) new value of the field in $_,
+and the object to be updated in $self. Its return value is ignored. The
+check_block may change the value of $_ to override the proposed value, or
+call die() (with an appropriate error message) to reject the update entirely;
+the error string will be returned as the output of the check() method.
+
+This makes check_blocks like
+
+C<s/foo/bar/>
+
+do what you expect.
+
+The check_block is expected NOT to do anything freaky to $self, like modifying
+other fields or calling $self->check(). You have been warned.
+
+(FIXME: Rewrite some of the warnings from part_sb_field and insert here.)
+
+=head1 BUGS
+
+None. It's absolutely falwless.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::virtual_field>
+
+=cut
+
+1;
+
+
diff --git a/FS/FS/pkg_svc.pm b/FS/FS/pkg_svc.pm
new file mode 100644
index 0000000..ea52176
--- /dev/null
+++ b/FS/FS/pkg_svc.pm
@@ -0,0 +1,155 @@
+package FS::pkg_svc;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs );
+use FS::part_pkg;
+use FS::part_svc;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::pkg_svc - Object methods for pkg_svc records
+
+=head1 SYNOPSIS
+
+ use FS::pkg_svc;
+
+ $record = new FS::pkg_svc \%hash;
+ $record = new FS::pkg_svc { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $part_pkg = $record->part_pkg;
+
+ $part_svc = $record->part_svc;
+
+=head1 DESCRIPTION
+
+An FS::pkg_svc record links a billing item definition (see L<FS::part_pkg>) to
+a service definition (see L<FS::part_svc>). FS::pkg_svc inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item pkgpart - Billing item definition (see L<FS::part_pkg>)
+
+=item svcpart - Service definition (see L<FS::part_svc>)
+
+=item quantity - Quantity of this service definition that this billing item
+definition includes
+
+=item primary_svc - primary flag, empty or 'Y'
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'pkg_svc'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+
+ return "Can't change pkgpart!" if $old->pkgpart != $new->pkgpart;
+ return "Can't change svcpart!" if $old->svcpart != $new->svcpart;
+
+ $new->SUPER::replace($old);
+}
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error;
+ $error =
+ $self->ut_number('pkgpart')
+ || $self->ut_number('svcpart')
+ || $self->ut_number('quantity')
+ ;
+ return $error if $error;
+
+ return "Unknown pkgpart!" unless $self->part_pkg;
+ return "Unknown svcpart!" unless $self->part_svc;
+
+ if ( $self->dbdef_table->column('primary_svc') ) {
+ $error = $self->ut_enum('primary_svc', [ '', 'Y' ] );
+ return $error if $error;
+ }
+
+ $self->SUPER::check;
+}
+
+=item part_pkg
+
+Returns the FS::part_pkg object (see L<FS::part_pkg>).
+
+=cut
+
+sub part_pkg {
+ my $self = shift;
+ qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
+}
+
+=item part_svc
+
+Returns the FS::part_svc object (see L<FS::part_svc>).
+
+=cut
+
+sub part_svc {
+ my $self = shift;
+ qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::part_pkg>, L<FS::part_svc>, schema.html from the base
+documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/port.pm b/FS/FS/port.pm
new file mode 100644
index 0000000..620030a
--- /dev/null
+++ b/FS/FS/port.pm
@@ -0,0 +1,160 @@
+package FS::port;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs );
+use FS::nas;
+use FS::session;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::port - Object methods for port records
+
+=head1 SYNOPSIS
+
+ use FS::port;
+
+ $record = new FS::port \%hash;
+ $record = new FS::port { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $session = $port->session;
+
+=head1 DESCRIPTION
+
+An FS::port object represents an individual port on a NAS. FS::port inherits
+from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item portnum - primary key
+
+=item ip - IP address of this port
+
+=item nasport - port number on the NAS
+
+=item nasnum - NAS this port is on - see L<FS::nas>
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new port. To add the example to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'port'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid example. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+ my $error =
+ $self->ut_numbern('portnum')
+ || $self->ut_ipn('ip')
+ || $self->ut_numbern('nasport')
+ || $self->ut_number('nasnum');
+ ;
+ return $error if $error;
+ return "Either ip or nasport must be specified"
+ unless $self->ip || $self->nasport;
+ return "Unknown nasnum"
+ unless qsearchs('nas', { 'nasnum' => $self->nasnum } );
+ $self->SUPER::check;
+}
+
+=item session
+
+Returns the currently open session on this port, or if no session is currently
+open, the most recent session. See L<FS::session>.
+
+=cut
+
+sub session {
+ my $self = shift;
+ qsearchs('session', { 'portnum' => $self->portnum }, '*',
+ 'ORDER BY login DESC LIMIT 1' );
+}
+
+=back
+
+=head1 VERSION
+
+$Id: port.pm,v 1.6 2003-08-05 00:20:45 khoff Exp $
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+The session method won't deal well if you have multiple open sessions on a
+port, for example if your RADIUS server drops B<stop> records. Suggestions for
+how to deal with this sort of lossage welcome; should we close the session
+when we get a new session on that port? Tag it as invalid somehow? Close it
+one second after it was opened? *sigh* Maybe FS::session shouldn't let you
+create overlapping sessions, at least folks will find out their logging is
+dropping records.
+
+If you think the above refers multiple user logins you need to read the
+manpages again.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/prepay_credit.pm b/FS/FS/prepay_credit.pm
new file mode 100644
index 0000000..a9d26d1
--- /dev/null
+++ b/FS/FS/prepay_credit.pm
@@ -0,0 +1,127 @@
+package FS::prepay_credit;
+
+use strict;
+use vars qw( @ISA );
+#use FS::Record qw( qsearch qsearchs );
+use FS::Record qw();
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::prepay_credit - Object methods for prepay_credit records
+
+=head1 SYNOPSIS
+
+ use FS::prepay_credit;
+
+ $record = new FS::prepay_credit \%hash;
+ $record = new FS::prepay_credit {
+ 'identifier' => '4198123455512121'
+ 'amount' => '19.95',
+ };
+
+ $record = new FS::prepay_credit {
+ 'identifier' => '4198123455512121'
+ 'seconds' => '7200',
+ };
+
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::table_name object represents an pre--paid credit, such as a pre-paid
+"calling card". FS::prepay_credit inherits from FS::Record. The following
+fields are currently supported:
+
+=over 4
+
+=item field - description
+
+=item identifier - identifier entered by the user to receive the credit
+
+=item amount - amount of the credit
+
+=item seconds - time amount of credit (see L<FS::svc_acct/seconds>)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new pre-paid credit. To add the example to the database, see
+L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'prepay_credit'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+=item check
+
+Checks all fields to make sure this is a valid pre-paid credit. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $identifier = $self->identifier;
+ $identifier =~ s/\W//g; #anything else would just confuse things
+ $self->identifier($identifier);
+
+ $self->ut_numbern('prepaynum')
+ || $self->ut_alpha('identifier')
+ || $self->ut_money('amount')
+ || $self->utnumbern('seconds')
+ || $self->SUPER::check
+ ;
+
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::svc_acct>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/queue.pm b/FS/FS/queue.pm
new file mode 100644
index 0000000..8396fc9
--- /dev/null
+++ b/FS/FS/queue.pm
@@ -0,0 +1,438 @@
+package FS::queue;
+
+use strict;
+use vars qw( @ISA @EXPORT_OK $DEBUG $conf $jobnums);
+use Exporter;
+use FS::UID;
+use FS::Conf;
+use FS::Record qw( qsearch qsearchs dbh );
+#use FS::queue;
+use FS::queue_arg;
+use FS::queue_depend;
+use FS::cust_svc;
+
+@ISA = qw(FS::Record);
+@EXPORT_OK = qw( joblisting );
+
+$DEBUG = 0;
+#$DEBUG = 1;
+
+$FS::UID::callback{'FS::queue'} = sub {
+ $conf = new FS::Conf;
+};
+
+$jobnums = '';
+
+=head1 NAME
+
+FS::queue - Object methods for queue records
+
+=head1 SYNOPSIS
+
+ use FS::queue;
+
+ $record = new FS::queue \%hash;
+ $record = new FS::queue { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::queue object represents an queued job. FS::queue inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item jobnum - primary key
+
+=item job - fully-qualified subroutine name
+
+=item status - job status
+
+=item statustext - freeform text status message
+
+=item _date - UNIX timestamp
+
+=item svcnum - optional link to service (see L<FS::cust_svc>)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new job. To add the example to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'queue'; }
+
+=item insert [ ARGUMENT, ARGUMENT... ]
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+If any arguments are supplied, a queue_arg record for each argument is also
+created (see L<FS::queue_arg>).
+
+=cut
+
+#false laziness w/part_export.pm
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ foreach my $arg ( @_ ) {
+ my $queue_arg = new FS::queue_arg ( {
+ 'jobnum' => $self->jobnum,
+ 'arg' => $arg,
+ } );
+ $error = $queue_arg->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ if ( $jobnums ) {
+ warn "jobnums global is active: $jobnums\n" if $DEBUG;
+ push @$jobnums, $self->jobnum;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item delete
+
+Delete this record from the database. Any corresponding queue_arg records are
+deleted as well
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my @del = qsearch( 'queue_arg', { 'jobnum' => $self->jobnum } );
+ push @del, qsearch( 'queue_depend', { 'depend_jobnum' => $self->jobnum } );
+
+ my $error = $self->SUPER::delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ foreach my $del ( @del ) {
+ $error = $del->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+
+}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid job. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+ my $error =
+ $self->ut_numbern('jobnum')
+ || $self->ut_anything('job')
+ || $self->ut_numbern('_date')
+ || $self->ut_enum('status',['', qw( new locked failed )])
+ || $self->ut_anything('statustext')
+ || $self->ut_numbern('svcnum')
+ ;
+ return $error if $error;
+
+ $error = $self->ut_foreign_keyn('svcnum', 'cust_svc', 'svcnum');
+ $self->svcnum('') if $error;
+
+ $self->status('new') unless $self->status;
+ $self->_date(time) unless $self->_date;
+
+ $self->SUPER::check;
+}
+
+=item args
+
+Returns a list of the arguments associated with this job.
+
+=cut
+
+sub args {
+ my $self = shift;
+ map $_->arg, qsearch( 'queue_arg',
+ { 'jobnum' => $self->jobnum },
+ '',
+ 'ORDER BY argnum'
+ );
+}
+
+=item cust_svc
+
+Returns the FS::cust_svc object associated with this job, if any.
+
+=cut
+
+sub cust_svc {
+ my $self = shift;
+ qsearchs('cust_svc', { 'svcnum' => $self->svcnum } );
+}
+
+=item queue_depend
+
+Returns the FS::queue_depend objects associated with this job, if any.
+(Dependancies that must complete before this job can be run).
+
+=cut
+
+sub queue_depend {
+ my $self = shift;
+ qsearch('queue_depend', { 'jobnum' => $self->jobnum } );
+}
+
+=item depend_insert OTHER_JOBNUM
+
+Inserts a dependancy for this job - it will not be run until the other job
+specified completes. If there is an error, returns the error, otherwise
+returns false.
+
+When using job dependancies, you should wrap the insertion of all relevant jobs
+in a database transaction.
+
+=cut
+
+sub depend_insert {
+ my($self, $other_jobnum) = @_;
+ my $queue_depend = new FS::queue_depend ( {
+ 'jobnum' => $self->jobnum,
+ 'depend_jobnum' => $other_jobnum,
+ } );
+ $queue_depend->insert;
+}
+
+=item queue_depended
+
+Returns the FS::queue_depend objects that associate other jobs with this job,
+if any. (The jobs that are waiting for this job to complete before they can
+run).
+
+=cut
+
+sub queue_depended {
+ my $self = shift;
+ qsearch('queue_depend', { 'depend_jobnum' => $self->jobnum } );
+}
+
+=item depended_delete
+
+Deletes the other queued jobs (FS::queue objects) that are waiting for this
+job, if any. If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub depended_delete {
+ my $self = shift;
+ my $error;
+ foreach my $job (
+ map { qsearchs('queue', { 'jobnum' => $_->jobnum } ) } $self->queue_depended
+ ) {
+ $error = $job->depended_delete;
+ return $error if $error;
+ $error = $job->delete;
+ return $error if $error
+ }
+}
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item joblisting HASHREF NOACTIONS
+
+=cut
+
+sub joblisting {
+ my($hashref, $noactions) = @_;
+
+ use Date::Format;
+ use HTML::Entities;
+ use FS::CGI;
+
+ my @queue = qsearch( 'queue', $hashref );
+ return '' unless scalar(@queue);
+
+ my $p = FS::CGI::popurl(2);
+
+ my $html = qq!<FORM ACTION="$p/misc/queue.cgi" METHOD="POST">!.
+ FS::CGI::table(). <<END;
+ <TR>
+ <TH COLSPAN=2>Job</TH>
+ <TH>Args</TH>
+ <TH>Date</TH>
+ <TH>Status</TH>
+END
+ $html .= '<TH>Account</TH>' unless $hashref->{svcnum};
+ $html .= '</TR>';
+
+ my $dangerous = $conf->exists('queue_dangerous_controls');
+
+ my $areboxes = 0;
+
+ foreach my $queue ( sort {
+ $a->getfield('jobnum') <=> $b->getfield('jobnum')
+ } @queue ) {
+ my $queue_hashref = $queue->hashref;
+ my $jobnum = $queue->jobnum;
+
+ my $args;
+ if ( $dangerous || $queue->job !~ /^FS::part_export::/ || !$noactions ) {
+ $args = encode_entities( join(' ', $queue->args) );
+ } else {
+ $args = '';
+ }
+
+ my $date = time2str( "%a %b %e %T %Y", $queue->_date );
+ my $status = $queue->status;
+ $status .= ': '. $queue->statustext if $queue->statustext;
+ my @queue_depend = $queue->queue_depend;
+ $status .= ' (waiting for '.
+ join(', ', map { $_->depend_jobnum } @queue_depend ).
+ ')'
+ if @queue_depend;
+ my $changable = $dangerous
+ || ( ! $noactions && $status =~ /^failed/ || $status =~ /^locked/ );
+ if ( $changable ) {
+ $status .=
+ qq! (&nbsp;<A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=new">retry</A>&nbsp;|!.
+ qq!&nbsp;<A HREF="$p/misc/queue.cgi?jobnum=$jobnum&action=del">remove</A>&nbsp;)!;
+ }
+ my $cust_svc = $queue->cust_svc;
+
+ $html .= <<END;
+ <TR>
+ <TD>$jobnum</TD>
+ <TD>$queue_hashref->{job}</TD>
+ <TD>$args</TD>
+ <TD>$date</TD>
+ <TD>$status</TD>
+END
+
+ unless ( $hashref->{svcnum} ) {
+ my $account;
+ if ( $cust_svc ) {
+ my $table = $cust_svc->part_svc->svcdb;
+ my $label = ( $cust_svc->label )[1];
+ $account = qq!<A HREF="../view/$table.cgi?!. $queue->svcnum.
+ qq!">$label</A>!;
+ } else {
+ $account = '';
+ }
+ $html .= "<TD>$account</TD>";
+ }
+
+ if ( $changable ) {
+ $areboxes=1;
+ $html .=
+ qq!<TD><INPUT NAME="jobnum$jobnum" TYPE="checkbox" VALUE="1"></TD>!;
+
+ }
+
+ $html .= '</TR>';
+
+}
+
+ $html .= '</TABLE>';
+
+ if ( $areboxes ) {
+ $html .= '<BR><INPUT TYPE="submit" NAME="action" VALUE="retry selected">'.
+ '<INPUT TYPE="submit" NAME="action" VALUE="remove selected"><BR>';
+ }
+
+ $html;
+
+}
+
+=back
+
+=head1 VERSION
+
+$Id: queue.pm,v 1.18 2004-05-04 18:44:48 ivan Exp $
+
+=head1 BUGS
+
+$jobnums global
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/queue_arg.pm b/FS/FS/queue_arg.pm
new file mode 100644
index 0000000..d23ee2a
--- /dev/null
+++ b/FS/FS/queue_arg.pm
@@ -0,0 +1,121 @@
+package FS::queue_arg;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::queue_arg - Object methods for queue_arg records
+
+=head1 SYNOPSIS
+
+ use FS::queue_arg;
+
+ $record = new FS::queue_arg \%hash;
+ $record = new FS::queue_arg { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::queue_arg object represents job argument. FS::queue_arg inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item argnum - primary key
+
+=item jobnum - see L<FS::queue>
+
+=item arg - argument
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new argument. To add the example to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'queue_arg'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid argument. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+ my $error =
+ $self->ut_numbern('argnum')
+ || $self->ut_numbern('jobnum')
+ || $self->ut_anything('arg')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 VERSION
+
+$Id: queue_arg.pm,v 1.2 2003-08-05 00:20:46 khoff Exp $
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::queue>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/queue_depend.pm b/FS/FS/queue_depend.pm
new file mode 100644
index 0000000..bc910d8
--- /dev/null
+++ b/FS/FS/queue_depend.pm
@@ -0,0 +1,121 @@
+package FS::queue_depend;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+use FS::queue;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::queue_depend - Object methods for queue_depend records
+
+=head1 SYNOPSIS
+
+ use FS::queue_depend;
+
+ $record = new FS::queue_depend \%hash;
+ $record = new FS::queue_depend { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::queue_depend object represents an job dependancy. FS::queue_depend
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item dependnum - primary key
+
+=item jobnum - source jobnum (see L<FS::queue>).
+
+=item depend_jobnum - dependancy jobnum (see L<FS::queue>)
+
+=back
+
+The job specified by B<jobnum> depends on the job specified B<depend_jobnum> -
+the B<jobnum> job will not be run until the B<depend_jobnum> job has completed
+sucessfully (or manually removed).
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new dependancy. To add the dependancy to the database, see
+L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'queue_depend'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid dependancy. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('dependnum')
+ || $self->ut_foreign_key('jobnum', 'queue', 'jobnum')
+ || $self->ut_foreign_key('depend_jobnum', 'queue', 'jobnum')
+ || $self->SUPER::check
+ ;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::queue>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/raddb.pm b/FS/FS/raddb.pm
new file mode 100644
index 0000000..efeb739
--- /dev/null
+++ b/FS/FS/raddb.pm
@@ -0,0 +1,1599 @@
+package FS::raddb;
+use vars qw(%attrib);
+
+%attrib = (
+ 'usr_at_zip_output_filter' => 'USR-AT-Zip-Output-Filter',
+ 'ms_filter' => 'MS-Filter',
+ 'annex_compression_protoc' => 'Annex-Compression-Protocol',
+ 'xedia_ssh_privileges' => 'Xedia-SSH-Privileges',
+ 'usr_blocks_received' => 'USR-Blocks-Received',
+ 'shiva_called_number' => 'Shiva-Called-Number',
+ 'annex_filter' => 'Annex-Filter',
+ 'usr_channel_expansion' => 'USR-Channel-Expansion',
+ 'erx_tunnel_tos' => 'ERX-Tunnel-Tos',
+ 'session_timeout' => 'Session-Timeout',
+ 'ascend_route_ipx' => 'Ascend-Route-IPX',
+ 'annex_error_correction_p' => 'Annex-Error-Correction-Prot',
+ 'acc_callback_mode' => 'Acc-Callback-Mode',
+ 'usr_filter_zones' => 'USR-Filter-Zones',
+ 'erx_input_gigapkts' => 'ERX-Input-Gigapkts',
+ 'ascend_session_svr_key' => 'Ascend-Session-Svr-Key',
+ 'bind_l2tp_tunnel_namf' => 'Bind_L2TP_Tunnel_Name',
+ 'ascend_dsl_cir_recv_limi' => 'Ascend-Dsl-CIR-Recv-Limit',
+ 'altiga_secondary_wins_g' => 'Altiga-Secondary-WINS-G',
+ 'ascend_ts_idle_limit' => 'Ascend-TS-Idle-Limit',
+ 'usr_port_tap_priority' => 'USR-Port-Tap-Priority',
+ 'cvpn3000_ipsec_client_fw' => 'CVPN3000-IPSec-Client-Fw-Filter-Name',
+ 'ascend_private_route_req' => 'Ascend-Private-Route-Required',
+ 'ascend_private_route' => 'Ascend-Private-Route',
+ 'prompt' => 'Prompt',
+ 'acct_link_count' => 'Acct-Link-Count',
+ 'bind_auth_service_grq' => 'Bind_Auth_Service_Grp',
+ 'itk_tunnel_ip' => 'ITK-Tunnel-IP',
+ 'login_lat_node' => 'Login-LAT-Node',
+ 'usr_mbi_ct_pri_card_slot' => 'USR-Mbi_Ct_PRI_Card_Slot',
+ 'lac_real_poru' => 'LAC_Real_Port',
+ 'erx_ingress_statistics' => 'ERX-Ingress-Statistics',
+ 'digest_nonce' => 'Digest-Nonce',
+ 'annex_system_disc_reason' => 'Annex-System-Disc-Reason',
+ 'pool_name' => 'Pool-Name',
+ 'altiga_use_client_addres' => 'Altiga-Use-Client-Address-G/U',
+ 'police_bursu' => 'Police_Burst',
+ 'usr_call_arrival_time' => 'USR-Call-Arrival-Time',
+ 'ascend_disconnect_cause' => 'Ascend-Disconnect-Cause',
+ 'ascend_user_acct_time' => 'Ascend-User-Acct-Time',
+ 'chap_challenge' => 'CHAP-Challenge',
+ 'ascend_mpp_idle_percent' => 'Ascend-MPP-Idle-Percent',
+ 'ascend_user_acct_port' => 'Ascend-User-Acct-Port',
+ 'ldap_group' => 'Ldap-Group',
+ 'ascend_numbering_plan_id' => 'Ascend-Numbering-Plan-ID',
+ 'usr_last_number_dialed_o' => 'USR-Last-Number-Dialed-Out',
+ 'pvc_encapsulation_type' => 'PVC-Encapsulation-Type',
+ 'ascend_bir_bridge_group' => 'Ascend-BIR-Bridge-Group',
+ 'ascend_atm_group' => 'Ascend-ATM-Group',
+ 'ascend_fr_svc_addr' => 'Ascend-FR-SVC-Addr',
+ 'x_ascend_send_auth' => 'X-Ascend-Send-Auth',
+ 'le_ip_pool' => 'LE-IP-Pool',
+ 'post_proxy_type' => 'Post-Proxy-Type',
+ 'wispr_session_terminate_' => 'WISPr-Session-Terminate-Time',
+ 'bintec_pppextiftable' => 'BinTec-pppExtIfTable',
+ 'nomadix_subnet' => 'Nomadix-Subnet',
+ 'login_port' => 'Login-Port',
+ 'ms_chap2_response' => 'MS-CHAP2-Response',
+ 'ascend_ipsec_profile' => 'Ascend-IPSEC-Profile',
+ 'usr_compression_algorith' => 'USR-Compression-Algorithm',
+ 'usr_accm_type' => 'USR-ACCM-Type',
+ 'simultaneous_use' => 'Simultaneous-Use',
+ 'cisco_account_info' => 'Cisco-Account-Info',
+ 'framed_protocol' => 'Framed-Protocol',
+ 'erx_tunnel_maximum_sessi' => 'ERX-Tunnel-Maximum-Sessions',
+ 'redcreek_tunneled_wins_t' => 'RedCreek-Tunneled-WINS-Server2',
+ 'ascend_recv_name' => 'Ascend-Recv-Name',
+ 'usr_call_connecting_time' => 'USR-Call-Connecting-Time',
+ 'quintum_h323_gw_id' => 'Quintum-h323-gw-id',
+ 'acct_dyn_ac_ent' => 'Acct-Dyn-Ac-Ent',
+ 'tunnel_remote_name' => 'Tunnel-Remote-Name',
+ 'annex_ppp_trace_level' => 'Annex-PPP-Trace-Level',
+ 'cisco_call_type' => 'Cisco-Call-Type',
+ 'cisco_fax_recipient_coun' => 'Cisco-Fax-Recipient-Count',
+ 'altiga_ipsec_authenticat' => 'Altiga-IPSec-Authentication-G',
+ 'wispr_location_id' => 'WISPr-Location-ID',
+ 'itk_start_delay' => 'ITK-Start-Delay',
+ 'ascend_pre_output_packet' => 'Ascend-Pre-Output-Packets',
+ 'usr_rmmie_firmware_versi' => 'USR-RMMIE-Firmware-Version',
+ 'usr_vts_session_key' => 'USR-VTS-Session-Key',
+ 'ascend_fr_dce_n393' => 'Ascend-FR-DCE-N393',
+ 'login_host' => 'Login-Host',
+ 'usr_reply_script3' => 'USR-Reply-Script3',
+ 'cvpn3000_ipsec_split_tuo' => 'CVPN3000-IPSec-Split-Tunneling-Policy',
+ 'ascend_pppoe_enable' => 'Ascend-PPPoE-Enable',
+ 'annex_primary_dns_server' => 'Annex-Primary-DNS-Server',
+ 'x_ascend_bridge_address' => 'X-Ascend-Bridge-Address',
+ 'usr_number_of_link_naks' => 'USR-Number-of-Link-NAKs',
+ 'altiga_priority_on_sep_g' => 'Altiga-Priority-on-SEP-G/U',
+ 'annex_cli_command' => 'Annex-CLI-Command',
+ 'usr_pw_framed_routing_v2' => 'USR-PW_Framed_Routing_V2',
+ 'session_error_codf' => 'Session_Error_Code',
+ 'annex_user_server_locati' => 'Annex-User-Server-Location',
+ 'cisco_fax_mdn_address' => 'Cisco-Fax-Mdn-Address',
+ 'ascend_calling_subaddres' => 'Ascend-Calling-Subaddress',
+ 'ascend_call_by_call' => 'Ascend-Call-By-Call',
+ 'ascend_first_dest' => 'Ascend-First-Dest',
+ 'annex_tunnel_authen_type' => 'Annex-Tunnel-Authen-Type',
+ 'acct_type' => 'Acct-Type',
+ 'sql_user_name' => 'SQL-User-Name',
+ 'erx_secondary_dns' => 'ERX-Secondary-Dns',
+ 'bridge_grouq' => 'Bridge_Group',
+ 'h323_return_code' => 'h323-return-code',
+ 'annex_host_allow' => 'Annex-Host-Allow',
+ 'cvx_modem_end_recv_line_' => 'CVX-Modem-End-Recv-Line-Lvl',
+ 'sip_method' => 'Sip-Method',
+ 'x_ascend_require_auth' => 'X-Ascend-Require-Auth',
+ 'cvpn3000_sep_card_assign' => 'CVPN3000-SEP-Card-Assignment',
+ 'le_ipsec_deny_action' => 'LE-IPSec-Deny-Action',
+ 'annex_edo' => 'Annex-EDO',
+ 'acct_delay_time' => 'Acct-Delay-Time',
+ 'login_tcp_port' => 'Login-TCP-Port',
+ 'ascend_temporary_rtes' => 'Ascend-Temporary-Rtes',
+ 'versanet_termination_cau' => 'Versanet-Termination-Cause',
+ 'ascend_dialed_number' => 'Ascend-Dialed-Number',
+ 'cvpn3000_ipsec_authentic' => 'CVPN3000-IPSec-Authentication',
+ 'ascend_fr_dlci' => 'Ascend-FR-DLCI',
+ 'annex_modem_disc_reason' => 'Annex-Modem-Disc-Reason',
+ 'x_ascend_receive_secret' => 'X-Ascend-Receive-Secret',
+ 'usr_ospf_addressless_ind' => 'USR-OSPF-Addressless-Index',
+ 'usr_ip_default_route_opt' => 'USR-IP-Default-Route-Option',
+ 'char_noecho' => 'Char-Noecho',
+ 'redcreek_tunneled_search' => 'RedCreek-Tunneled-Search-List',
+ 'ascend_pri_number_type' => 'Ascend-PRI-Number-Type',
+ 'aat_ip_tos_apply_to' => 'AAT-IP-TOS-Apply-To',
+ 'x_ascend_modem_shelfno' => 'X-Ascend-Modem-ShelfNo',
+ 'prefix' => 'Prefix',
+ 'usr_rad_dvmrp_metric' => 'USR-Rad-Dvmrp-Metric',
+ 'x_ascend_call_attempt_li' => 'X-Ascend-Call-Attempt-Limit',
+ 'usr_ip_saa_filter' => 'USR-IP-SAA-Filter',
+ 'itk_prompt' => 'ITK-Prompt',
+ 'ascend_port_redir_protoc' => 'Ascend-Port-Redir-Protocol',
+ 'cvx_modem_tx_packets' => 'CVX-Modem-Tx-Packets',
+ 'usr_tunnel_switch_endpoi' => 'USR-Tunnel-Switch-Endpoint',
+ 'ascend_home_network_name' => 'Ascend-Home-Network-Name',
+ 'acc_customer_id' => 'Acc-Customer-Id',
+ 'message_authenticator' => 'Message-Authenticator',
+ 'cisco_fax_coverpage_flag' => 'Cisco-Fax-Coverpage-Flag',
+ 'usr_multicast_forwarding' => 'USR-Multicast-Forwarding',
+ 'cvpn3000_allow_network_e' => 'CVPN3000-Allow-Network-Extension-Mode',
+ 'ascend_call_direction' => 'Ascend-Call-Direction',
+ 'acc_connect_rx_speed' => 'Acc-Connect-Rx-Speed',
+ 'ascend_force_56' => 'Ascend-Force-56',
+ 'st_service_domain' => 'ST-Service-Domain',
+ 'usr_harc_disconnect_code' => 'USR-HARC-Disconnect-Code',
+ 'shasta_service_profile' => 'Shasta-Service-Profile',
+ 'cisco_maximum_time' => 'Cisco-Maximum-Time',
+ 'usr_tunnel_auth_hostname' => 'USR-Tunnel-Auth-Hostname',
+ 'acc_ip_gateway_pri' => 'Acc-Ip-Gateway-Pri',
+ 'ascend_bridge_address' => 'Ascend-Bridge-Address',
+ 'altiga_pptp_min_authenti' => 'Altiga-PPTP-Min-Authentication-G/U',
+ 'ns_secondary_wins' => 'NS-Secondary-WINS',
+ 'cbbsm_bandwidth' => 'CBBSM-Bandwidth',
+ 'x_ascend_fr_link_mgt' => 'X-Ascend-FR-Link-Mgt',
+ 'altiga_ipsec_banner_g' => 'Altiga-IPSec-Banner-G',
+ 'ascend_handle_ipx' => 'Ascend-Handle-IPX',
+ 'ascend_x25_pad_alias_2' => 'Ascend-X25-Pad-Alias-2',
+ 'st_policy_name' => 'ST-Policy-Name',
+ 'ascend_group' => 'Ascend-Group',
+ 'ascend_dsl_rate_type' => 'Ascend-Dsl-Rate-Type',
+ 'tunnel_contexu' => 'Tunnel_Context',
+ 'ascend_require_auth' => 'Ascend-Require-Auth',
+ 'cvx_modem_local_retrains' => 'CVX-Modem-Local-Retrains',
+ 'cvpn5000_echo' => 'CVPN5000-Echo',
+ 'cvx_secondary_dns' => 'CVX-Secondary-DNS',
+ 'x_ascend_billing_number' => 'X-Ascend-Billing-Number',
+ 'usr_orig_nas_type' => 'USR-Orig-NAS-Type',
+ 'ascend_remote_fw' => 'Ascend-Remote-FW',
+ 'acct_output_packets' => 'Acct-Output-Packets',
+ 'lm_password' => 'LM-Password',
+ 'tunnel_window' => 'Tunnel-Window',
+ 'cisco_avpair' => 'Cisco-AVPair',
+ 'st_service_name' => 'ST-Service-Name',
+ 'shiva_event_flags' => 'Shiva-Event-Flags',
+ 'annex_retrain_requests_s' => 'Annex-Retrain-Requests-Sent',
+ 'ascend_ts_idle_mode' => 'Ascend-TS-Idle-Mode',
+ 'usr_ip_rip_simple_auth_p' => 'USR-IP-RIP-Simple-Auth-Password',
+ 'tunnel_deadtimf' => 'Tunnel_Deadtime',
+ 'state' => 'State',
+ 'usr_keypress_timeout' => 'USR-Keypress-Timeout',
+ 'usr_pw_vpn_neighbor' => 'USR-PW_VPN_Neighbor',
+ 'erx_pppoe_description' => 'ERX-Pppoe-Description',
+ 'ldap_userdn' => 'Ldap-UserDn',
+ 'x_ascend_fr_n391' => 'X-Ascend-FR-N391',
+ 'ascend_calling_id_presen' => 'Ascend-Calling-Id-Presentatn',
+ 'erx_local_loopback_inter' => 'ERX-Local-Loopback-Interface',
+ 'x_ascend_fr_direct' => 'X-Ascend-FR-Direct',
+ 'nas_ip_address' => 'NAS-IP-Address',
+ 'usr_call_end_time' => 'USR-Call-End-Time',
+ 'acct_mcast_out_packett' => 'Acct_Mcast_Out_Packets',
+ 'tunnel_algorithm' => 'Tunnel-Algorithm',
+ 'usr_vpn_encrypter' => 'USR-VPN-Encrypter',
+ 'tunnel_grouq' => 'Tunnel_Group',
+ 'ascend_atm_connect_group' => 'Ascend-ATM-Connect-Group',
+ 'x_ascend_ft1_caller' => 'X-Ascend-FT1-Caller',
+ 'usr_dnis_reauthenticatio' => 'USR-DNIS-ReAuthentication',
+ 'login_callback_number' => 'Login-Callback-Number',
+ 'usr_ip_rip_input_filter' => 'USR-IP-RIP-Input-Filter',
+ 'usr_rmmie_rcv_pwrlvl_330' => 'USR-RMMIE-Rcv-PwrLvl-3300Hz',
+ 'h323_disconnect_cause' => 'h323-disconnect-cause',
+ 'x_ascend_handle_ipx' => 'X-Ascend-Handle-IPX',
+ 'usr_igmp_version' => 'USR-IGMP-Version',
+ 'usr_imsi' => 'USR-IMSI',
+ 'group_name' => 'Group-Name',
+ 'usr_nas_type' => 'USR-NAS-Type',
+ 'context_namf' => 'Context-Name',
+ 'ascend_ip_tos' => 'Ascend-IP-TOS',
+ 'x_ascend_token_immediate' => 'X-Ascend-Token-Immediate',
+ 'tunnel_session_auth_serw' => 'Tunnel_Session_Auth_Service_Grp',
+ 'ms_chap2_cpw' => 'MS-CHAP2-CPW',
+ 'tunnel_session_auth_ctx' => 'Tunnel-Session-Auth-Ctx',
+ 'usr_mobile_numbytes_rxed' => 'USR-Mobile-NumBytes-Rxed',
+ 'usr_mbi_ct_tdm_time_slot' => 'USR-Mbi_Ct_TDM_Time_Slot',
+ 'ascend_x25_nui' => 'Ascend-X25-Nui',
+ 'x_ascend_first_dest' => 'X-Ascend-First-Dest',
+ 'usr_send_password' => 'USR-Send-Password',
+ 'x_ascend_fr_direct_profi' => 'X-Ascend-FR-Direct-Profile',
+ 'x_ascend_fr_t391' => 'X-Ascend-FR-T391',
+ 'altiga_ipsec_sec_associa' => 'Altiga-IPSec-Sec-Association-G/U',
+ 'ip_address_pool_namf' => 'Ip_Address_Pool_Name',
+ 'acct_input_octets' => 'Acct-Input-Octets',
+ 'cvx_modem_begin_modulati' => 'CVX-Modem-Begin-Modulation',
+ 'wispr_session_terminatea' => 'WISPr-Session-Terminate-End-Of-Day',
+ 'cvpn3000_use_client_addr' => 'CVPN3000-Use-Client-Address',
+ 'bridge_group' => 'Bridge-Group',
+ 'annex_sec_profile_index' => 'Annex-Sec-Profile-Index',
+ 'acc_dns_server_pri' => 'Acc-Dns-Server-Pri',
+ 'ms_acct_auth_type' => 'MS-Acct-Auth-Type',
+ 'x_ascend_maximum_call_du' => 'X-Ascend-Maximum-Call-Duration',
+ 'tunnel_password' => 'Tunnel-Password',
+ 'framed_ipv6_prefix' => 'Framed-IPv6-Prefix',
+ 'usr_reply_script5' => 'USR-Reply-Script5',
+ 'shiva_links_in_bundle' => 'Shiva-Links-In-Bundle',
+ 'ascend_fr_profile_name' => 'Ascend-FR-Profile-Name',
+ 'ascend_mtu' => 'Ascend-MTU',
+ 'nokia_charging_id' => 'Nokia-Charging-Id',
+ 'cvpn3000_ms_client_subne' => 'CVPN3000-MS-Client-Subnet-Mask',
+ 'cvpn3000_ipsec_sec_assoc' => 'CVPN3000-IPSec-Sec-Association',
+ 'cisco_ppp_async_map' => 'Cisco-PPP-Async-Map',
+ 'cvpn3000_user_auth_servf' => 'CVPN3000-User-Auth-Server-Port',
+ 'cisco_num_in_multilink' => 'Cisco-Num-In-Multilink',
+ 'wispr_logoff_url' => 'WISPr-Logoff-URL',
+ 'usr_mobile_ip_address' => 'USR-Mobile-IP-Address',
+ 'usr_final_tx_link_data_r' => 'USR-Final-Tx-Link-Data-Rate',
+ 'itk_ppp_compression_prot' => 'ITK-PPP-Compression-Prot',
+ 'ascend_bridge' => 'Ascend-Bridge',
+ 'x_ascend_presession_time' => 'X-Ascend-PreSession-Time',
+ 'aat_client_primary_dns' => 'AAT-Client-Primary-DNS',
+ 'cvpn3000_strip_realm' => 'CVPN3000-Strip-Realm',
+ 'tunnel_cmd_timeout' => 'Tunnel-Cmd-Timeout',
+ 'ascend_multicast_client' => 'Ascend-Multicast-Client',
+ 'cvx_modem_remote_rate_ne' => 'CVX-Modem-Remote-Rate-Negs',
+ 'tunnel_private_group_id' => 'Tunnel-Private-Group-Id',
+ 'usr_rmmie_rcv_tot_pwrlvl' => 'USR-RMMIE-Rcv-Tot-PwrLvl',
+ 'calling_station_id' => 'Calling-Station-Id',
+ 'tunnel_rate_limit_burst' => 'Tunnel-Rate-Limit-Burst',
+ 'usr_device_connected_to' => 'USR-Device-Connected-To',
+ 'aat_source_ip_check' => 'AAT-Source-IP-Check',
+ 'login_lat_service' => 'Login-LAT-Service',
+ 'ascend_h323_fegw_address' => 'Ascend-H323-Fegw-Address',
+ 'usr_called_party_number' => 'USR-Called-Party-Number',
+ 'bintec_ipnatpresettable' => 'BinTec-ipNatPresetTable',
+ 'ascend_remove_seconds' => 'Ascend-Remove-Seconds',
+ 'shiva_user_attributes' => 'Shiva-User-Attributes',
+ 'cisco_fax_dsn_flag' => 'Cisco-Fax-Dsn-Flag',
+ 'x_ascend_route_ipx' => 'X-Ascend-Route-IPX',
+ 'acc_route_policy' => 'Acc-Route-Policy',
+ 'bind_l2tp_flow_controm' => 'Bind_L2TP_Flow_Control',
+ 'erx_qos_profile_name' => 'ERX-Qos-Profile-Name',
+ 'x_ascend_client_gateway' => 'X-Ascend-Client-Gateway',
+ 'pre_proxy_type' => 'Pre-Proxy-Type',
+ 'smb_account_ctrl_text' => 'SMB-Account-CTRL-TEXT',
+ 'x_ascend_data_filter' => 'X-Ascend-Data-Filter',
+ 'usr_rmmie_last_update_ti' => 'USR-RMMIE-Last-Update-Time',
+ 'ascend_atm_direct' => 'Ascend-ATM-Direct',
+ 'ascend_session_type' => 'Ascend-Session-Type',
+ 'x_ascend_fr_linkup' => 'X-Ascend-FR-LinkUp',
+ 'ascend_metric' => 'Ascend-Metric',
+ 'x_ascend_assign_ip_clien' => 'X-Ascend-Assign-IP-Client',
+ 'usr_speed_of_connection' => 'USR-Speed-Of-Connection',
+ 'cvpn3000_require_hw_clie' => 'CVPN3000-Require-HW-Client-Auth',
+ 'session_type' => 'Session-Type',
+ 'acct_input_octets_65' => 'Acct_Input_Octets_64',
+ 'le_nat_outsource_outmap' => 'LE-NAT-Outsource-Outmap',
+ 'cvx_modem_local_rate_neg' => 'CVX-Modem-Local-Rate-Negs',
+ 'mcast_sene' => 'Mcast_Send',
+ 'pppoe_url' => 'PPPOE-URL',
+ 'erx_service_bundle' => 'ERX-Service-Bundle',
+ 'altiga_secondary_dns_g' => 'Altiga-Secondary-DNS-G',
+ 'bg_trans_bpdv' => 'BG_Trans_BPDU',
+ 'cvx_data_filter' => 'CVX-Data-Filter',
+ 'acct_mcast_out_octets' => 'Acct-Mcast-Out-Octets',
+ 'ascend_callback' => 'Ascend-Callback',
+ 'tunnel_client_auth_id' => 'Tunnel-Client-Auth-Id',
+ 'acct_unique_session_id' => 'Acct-Unique-Session-Id',
+ 'usr_port_tap_format' => 'USR-Port-Tap-Format',
+ 'ascend_ckt_type' => 'Ascend-Ckt-Type',
+ 'ascend_ppp_async_map' => 'Ascend-PPP-Async-Map',
+ 'usr_rmmie_rcv_pwrlvl_375' => 'USR-RMMIE-Rcv-PwrLvl-3750Hz',
+ 'usr_acct_reason_code' => 'USR-Acct-Reason-Code',
+ 'ascend_filter' => 'Ascend-Filter',
+ 'h323_redirect_number' => 'h323-redirect-number',
+ 'port_limit' => 'Port-Limit',
+ 'rewrite_rule' => 'Rewrite-Rule',
+ 'tunnel_police_rate' => 'Tunnel-Police-Rate',
+ 'usr_multicast_proxy' => 'USR-Multicast-Proxy',
+ 'ascend_max_shared_users' => 'Ascend-Max-Shared-Users',
+ 'usr_bridging' => 'USR-Bridging',
+ 'cvx_presession_time' => 'CVX-PreSession-Time',
+ 'cvpn5000_vpn_groupinfo' => 'CVPN5000-VPN-GroupInfo',
+ 'autz_type' => 'Autz-Type',
+ 'x_ascend_fr_dlci' => 'X-Ascend-FR-DLCI',
+ 'usr_request_type' => 'USR-Request-Type',
+ 'acc_igmp_admin_state' => 'Acc-Igmp-Admin-State',
+ 'ascend_host_info' => 'Ascend-Host-Info',
+ 'ascend_dhcp_maximum_leas' => 'Ascend-DHCP-Maximum-Leases',
+ 'usr_rmmie_num_of_updates' => 'USR-RMMIE-Num-Of-Updates',
+ 'x_ascend_fr_profile_name' => 'X-Ascend-FR-Profile-Name',
+ 'ascend_fr_direct_profile' => 'Ascend-FR-Direct-Profile',
+ 'x_ascend_bridge' => 'X-Ascend-Bridge',
+ 'tunnel_deadtime' => 'Tunnel-Deadtime',
+ 'ms_chap_error' => 'MS-CHAP-Error',
+ 'framed_route' => 'Framed-Route',
+ 'sip_from' => 'Sip-From',
+ 'expiration' => 'Expiration',
+ 'ascend_backup' => 'Ascend-Backup',
+ 'ascend_pre_output_octets' => 'Ascend-Pre-Output-Octets',
+ 'ascend_calling_id_number' => 'Ascend-Calling-Id-Number-Plan',
+ 'framed_appletalk_zone' => 'Framed-AppleTalk-Zone',
+ 'annex_audit_level' => 'Annex-Audit-Level',
+ 'digest_algorithm' => 'Digest-Algorithm',
+ 'bind_auth_context' => 'Bind-Auth-Context',
+ 'ascend_user_acct_base' => 'Ascend-User-Acct-Base',
+ 'st_secondary_dns_server' => 'ST-Secondary-DNS-Server',
+ 'mcast_receive' => 'Mcast-Receive',
+ 'usr_ds0' => 'USR-DS0',
+ 'aat_atm_traffic_profile' => 'AAT-ATM-Traffic-Profile',
+ 'ms_ras_vendor' => 'MS-RAS-Vendor',
+ 'tunnel_domain' => 'Tunnel-Domain',
+ 'tunnel_max_sessions' => 'Tunnel-Max-Sessions',
+ 'ascend_ip_direct' => 'Ascend-IP-Direct',
+ 'xedia_address_pool' => 'Xedia-Address-Pool',
+ 'idle_timeout' => 'Idle-Timeout',
+ 'tunnel_rate_limit_ratf' => 'Tunnel_Rate_Limit_Rate',
+ 'annex_rate_reneg_req_sen' => 'Annex-Rate-Reneg-Req-Sent',
+ 'usr_initial_tx_link_data' => 'USR-Initial-Tx-Link-Data-Rate',
+ 'tunnel_server_auth_id' => 'Tunnel-Server-Auth-Id',
+ 'cvpn3000_ipsec_banner1' => 'CVPN3000-IPSec-Banner1',
+ 'usr_start_time' => 'USR-Start-Time',
+ 'usr_ip' => 'USR-IP',
+ 'cvpn3000_reqrd_client_fw' => 'CVPN3000-Reqrd-Client-Fw-Vendor-Code',
+ 'altiga_ipsec_secondary_d' => 'Altiga-IPSec-Secondary-Domains-G',
+ 'usr_gateway_ip_address' => 'USR-Gateway-IP-Address',
+ 'ascend_dba_monitor' => 'Ascend-DBA-Monitor',
+ 'ms_link_utilization_thre' => 'MS-Link-Utilization-Threshold',
+ 'st_primary_dns_server' => 'ST-Primary-DNS-Server',
+ 'acc_ace_token_ttl' => 'Acc-Ace-Token-Ttl',
+ 'ms_chap_domain' => 'MS-CHAP-Domain',
+ 'cisco_pre_input_octets' => 'Cisco-Pre-Input-Octets',
+ 'ascend_primary_home_agen' => 'Ascend-Primary-Home-Agent',
+ 'acct_session_time' => 'Acct-Session-Time',
+ 'framed_ip_address' => 'Framed-IP-Address',
+ 'ns_admin_privilege' => 'NS-Admin-Privilege',
+ 'medium_type' => 'Medium-Type',
+ 'acct_output_octets_64' => 'Acct-Output-Octets-64',
+ 'ascend_cir_timer' => 'Ascend-CIR-Timer',
+ 'police_rate' => 'Police-Rate',
+ 'tunnel_functioo' => 'Tunnel_Function',
+ 'quintum_h323_time_and_da' => 'Quintum-h323-time-and-day',
+ 'ip_tos_fiele' => 'IP_TOS_Field',
+ 'erx_framed_ip_route_tag' => 'ERX-Framed-Ip-Route-Tag',
+ 'ms_mppe_send_key' => 'MS-MPPE-Send-Key',
+ 'ascend_maximum_call_dura' => 'Ascend-Maximum-Call-Duration',
+ 'pppoe_motn' => 'PPPOE_MOTM',
+ 'lac_poru' => 'LAC_Port',
+ 'bind_dot1q_slou' => 'Bind_Dot1q_Slot',
+ 'ascend_secondary_home_ag' => 'Ascend-Secondary-Home-Agent',
+ 'usr_ip_call_output_filte' => 'USR-IP-Call-Output-Filter',
+ 'x_ascend_host_info' => 'X-Ascend-Host-Info',
+ 'erx_egress_policy_name' => 'ERX-Egress-Policy-Name',
+ 'erx_ppp_password' => 'ERX-PPP-Password',
+ 'user_name' => 'User-Name',
+ 'usr_number_of_characters' => 'USR-Number-Of-Characters-Lost',
+ 'bind_bypass_bypass' => 'Bind-Bypass-Bypass',
+ 'usr_rad_multicast_routip' => 'USR-Rad-Multicast-Routing-Proto',
+ 'annex_acct_servers' => 'Annex-Acct-Servers',
+ 'cvpn5000_tunnel_throughp' => 'CVPN5000-Tunnel-Throughput',
+ 'usr_chassis_call_channel' => 'USR-Chassis-Call-Channel',
+ 'annex_input_filter' => 'Annex-Input-Filter',
+ 'wispr_billing_class_of_s' => 'WISPr-Billing-Class-Of-Service',
+ 'nas_port_type' => 'NAS-Port-Type',
+ 'cvx_client_assign_dns' => 'CVX-Client-Assign-DNS',
+ 'nomadix_maxbytesdown' => 'Nomadix-MaxBytesDown',
+ 'ascend_endpoint_disc' => 'Ascend-Endpoint-Disc',
+ 'tunnel_police_burst' => 'Tunnel-Police-Burst',
+ 'bind_auth_max_sessions' => 'Bind-Auth-Max-Sessions',
+ 'cvx_identification' => 'CVX-Identification',
+ 'cvpn3000_ipsec_allow_pas' => 'CVPN3000-IPSec-Allow-Passwd-Store',
+ 'ascend_calling_id_type_o' => 'Ascend-Calling-Id-Type-Of-Num',
+ 'x_ascend_fr_dce_n392' => 'X-Ascend-FR-DCE-N392',
+ 'usr_connect_term_reason' => 'USR-Connect-Term-Reason',
+ 'erx_egress_statistics' => 'ERX-Egress-Statistics',
+ 'ascend_fr_dte_n392' => 'Ascend-FR-DTE-N392',
+ 'usr_esn' => 'USR-ESN',
+ 'x_ascend_fr_dte_n392' => 'X-Ascend-FR-DTE-N392',
+ 'itk_modem_init_string' => 'ITK-Modem-Init-String',
+ 'x_ascend_fr_nailed_grp' => 'X-Ascend-FR-Nailed-Grp',
+ 'ascend_bridge_non_pppoe' => 'Ascend-Bridge-Non-PPPoE',
+ 'cvpn3000_ipsec_reqrd_cli' => 'CVPN3000-IPSec-Reqrd-Client-Fw-Cap',
+ 'ascend_ipx_alias' => 'Ascend-IPX-Alias',
+ 'acc_tunnel_port' => 'Acc-Tunnel-Port',
+ 'quintum_h323_return_code' => 'Quintum-h323-return-code',
+ 'cvpn3000_l2tp_encryption' => 'CVPN3000-L2TP-Encryption',
+ 'acct_input_gigawords' => 'Acct-Input-Gigawords',
+ 'bind_dot1q_poru' => 'Bind_Dot1q_Port',
+ 'altiga_primary_wins_g' => 'Altiga-Primary-WINS-G',
+ 'ascend_maximum_channels' => 'Ascend-Maximum-Channels',
+ 'x_ascend_home_agent_pass' => 'X-Ascend-Home-Agent-Password',
+ 'x_ascend_ppp_async_map' => 'X-Ascend-PPP-Async-Map',
+ 'usr_rmmie_manufacturer_i' => 'USR-RMMIE-Manufacturer-ID',
+ 'usr_retrains_requested' => 'USR-Retrains-Requested',
+ 'x_ascend_metric' => 'X-Ascend-Metric',
+ 'acc_apsm_oversubscribed' => 'Acc-Apsm-Oversubscribed',
+ 'usr_originate_answer_mod' => 'USR-Originate-Answer-Mode',
+ 'erx_atm_pcr' => 'ERX-Atm-PCR',
+ 'itk_nas_name' => 'ITK-NAS-Name',
+ 'usr_ipx_routing' => 'USR-IPX-Routing',
+ 'usr_tunneled_mlpp' => 'USR-Tunneled-MLPP',
+ 'usr_send_script5' => 'USR-Send-Script5',
+ 'ascend_traffic_shaper' => 'Ascend-Traffic-Shaper',
+ 'ascend_client_secondarya' => 'Ascend-Client-Secondary-DNS',
+ 'ascend_bacp_enable' => 'Ascend-BACP-Enable',
+ 'usr_call_terminate_in_gm' => 'USR-Call-Terminate-in-GMT',
+ 'login_time' => 'Login-Time',
+ 'bg_path_cosu' => 'BG_Path_Cost',
+ 'aat_require_auth' => 'AAT-Require-Auth',
+ 'cvpn3000_reqrd_client_fy' => 'CVPN3000-Reqrd-Client-Fw-Description',
+ 'ascend_call_type' => 'Ascend-Call-Type',
+ 'erx_address_pool_name' => 'ERX-Address-Pool-Name',
+ 'cvpn3000_ipsec_backup_sf' => 'CVPN3000-IPSec-Backup-Server-List',
+ 'h323_incoming_conf_id' => 'h323-incoming-conf-id',
+ 'user_profile' => 'User-Profile',
+ 'ip_host_adds' => 'Ip_Host_Addr',
+ 'ns_primary_wins' => 'NS-Primary-WINS',
+ 'packet_type' => 'Packet-Type',
+ 'bind_auth_max_sessiont' => 'Bind_Auth_Max_Sessions',
+ 'altiga_allow_alpha_only_' => 'Altiga-Allow-Alpha-Only-Passwords-G',
+ 'usr_security_resp_limit' => 'USR-Security-Resp-Limit',
+ 'ip_address_pool_name' => 'Ip-Address-Pool-Name',
+ 'ascend_ipx_node_addr' => 'Ascend-IPX-Node-Addr',
+ 'ascend_cbcp_trunk_group' => 'Ascend-CBCP-Trunk-Group',
+ 'ascend_menu_selector' => 'Ascend-Menu-Selector',
+ 'ascend_assign_ip_global_' => 'Ascend-Assign-IP-Global-Pool',
+ 'usr_ds0s' => 'USR-DS0s',
+ 'usr_actual_voltage' => 'USR-Actual-Voltage',
+ 'quintum_h323_call_type' => 'Quintum-h323-call-type',
+ 'annex_sw_version' => 'Annex-SW-Version',
+ 'ascend_receive_secret' => 'Ascend-Receive-Secret',
+ 'bintec_qospolicytable' => 'BinTec-qosPolicyTable',
+ 'usr_ip_rip_policies' => 'USR-IP-RIP-Policies',
+ 'redcreek_tunneled_ip_add' => 'RedCreek-Tunneled-IP-Addr',
+ 'ascend_pw_warntime' => 'Ascend-PW-Warntime',
+ 'x_ascend_inc_channel_cou' => 'X-Ascend-Inc-Channel-Count',
+ 'usr_blocks_resent' => 'USR-Blocks-Resent',
+ 'usr_fallback_enabled' => 'USR-Fallback-Enabled',
+ 'arap_challenge_response' => 'ARAP-Challenge-Response',
+ 'tunnel_session_auth' => 'Tunnel-Session-Auth',
+ 'usr_sync_async_mode' => 'USR-Sync-Async-Mode',
+ 'itk_dialout_type' => 'ITK-Dialout-Type',
+ 'extreme_netlogin_url' => 'Extreme-Netlogin-Url',
+ 'client_port_dnis' => 'Client-Port-DNIS',
+ 'digest_realm' => 'Digest-Realm',
+ 'ascend_ppp_vj_1172' => 'Ascend-PPP-VJ-1172',
+ 'ascend_fr_n391' => 'Ascend-FR-N391',
+ 'ascend_remote_addr' => 'Ascend-Remote-Addr',
+ 'client_port_id' => 'Client-Port-Id',
+ 'digest_body_digest' => 'Digest-Body-Digest',
+ 'le_ipsec_active_profile' => 'LE-IPSec-Active-Profile',
+ 'digest_cnonce' => 'Digest-CNonce',
+ 'usr_port_tap_facility' => 'USR-Port-Tap-Facility',
+ 'usr_callback_type' => 'USR-Callback-Type',
+ 'client_dns_prj' => 'Client_DNS_Pri',
+ 'digest_response' => 'Digest-Response',
+ 'login_lat_group' => 'Login-LAT-Group',
+ 'x_ascend_call_type' => 'X-Ascend-Call-Type',
+ 'ascend_route_ip' => 'Ascend-Route-IP',
+ 'usr_rad_multicast_routio' => 'USR-Rad-Multicast-Routing-RtLim',
+ 'usr_pw_vpn_id' => 'USR-PW_VPN_ID',
+ 'cvx_modem_end_modulation' => 'CVX-Modem-End-Modulation',
+ 'cvpn3000_pptp_mppc_compr' => 'CVPN3000-PPTP-MPPC-Compression',
+ 'cisco_pre_output_octets' => 'Cisco-Pre-Output-Octets',
+ 'h323_billing_model' => 'h323-billing-model',
+ 'usr_equalization_type' => 'USR-Equalization-Type',
+ 'acc_clearing_cause' => 'Acc-Clearing-Cause',
+ 'altiga_access_hours_g_u' => 'Altiga-Access-Hours-G/U',
+ 'cvpn3000_ipsec_user_grou' => 'CVPN3000-IPSec-User-Group-Lock',
+ 'x_ascend_menu_selector' => 'X-Ascend-Menu-Selector',
+ 'x_ascend_netware_timeout' => 'X-Ascend-Netware-timeout',
+ 'ascend_fr_linkup' => 'Ascend-FR-LinkUp',
+ 'annex_num_in_multilink' => 'Annex-Num-In-Multilink',
+ 'police_burst' => 'Police-Burst',
+ 'altiga_l2tp_min_authenti' => 'Altiga-L2TP-Min-Authentication-G/U',
+ 'ascend_filter_required' => 'Ascend-Filter-Required',
+ 'x_ascend_idle_limit' => 'X-Ascend-Idle-Limit',
+ 'nomadix_logoff_url' => 'Nomadix-Logoff-URL',
+ 'cvpn3000_ms_client_icpt_' => 'CVPN3000-MS-Client-Icpt-DHCP-Conf-Msg',
+ 'ip_tos_field' => 'IP-TOS-Field',
+ 'ascend_ip_tos_apply_to' => 'Ascend-IP-TOS-Apply-To',
+ 'usr_call_event_code' => 'USR-Call-Event-Code',
+ 'usr_et_bridge_output_fil' => 'USR-ET-Bridge-Output-Filter',
+ 'le_nat_sess_dir_fail_act' => 'LE-NAT-Sess-Dir-Fail-Action',
+ 'usr_rmmie_product_code' => 'USR-RMMIE-Product-Code',
+ 'usr_host_type' => 'USR-Host-Type',
+ 'erx_tunnel_interface_id' => 'ERX-Tunnel-Interface-Id',
+ 'ascend_send_auth' => 'Ascend-Send-Auth',
+ 'shiva_compression_type' => 'Shiva-Compression-Type',
+ 'itk_banner' => 'ITK-Banner',
+ 'ascend_ft1_caller' => 'Ascend-FT1-Caller',
+ 'filter_id' => 'Filter-Id',
+ 'annex_pre_output_octets' => 'Annex-Pre-Output-Octets',
+ 'acct_mcast_in_octett' => 'Acct_Mcast_In_Octets',
+ 'usr_log_filter_packets' => 'USR-Log-Filter-Packets',
+ 'ascend_fr_nailed_grp' => 'Ascend-FR-Nailed-Grp',
+ 'ascend_atm_loopback_cell' => 'Ascend-ATM-Loopback-Cell-Loss',
+ 'usr_at_rtmp_output_filte' => 'USR-AT-RTMP-Output-Filter',
+ 'acc_input_errors' => 'Acc-Input-Errors',
+ 'x_ascend_user_acct_port' => 'X-Ascend-User-Acct-Port',
+ 'erx_secondary_wins' => 'ERX-Secondary-Wins',
+ 'usr_rmmie_serial_number' => 'USR-RMMIE-Serial-Number',
+ 'usr_et_bridge_input_filt' => 'USR-ET-Bridge-Input-Filter',
+ 'ns_primary_dns' => 'NS-Primary-DNS',
+ 'usr_slot_connected_to' => 'USR-Slot-Connected-To',
+ 'shiva_disconnect_reason' => 'Shiva-Disconnect-Reason',
+ 'cvpn5000_client_assignee' => 'CVPN5000-Client-Assigned-IPX',
+ 'cvx_radius_redirect' => 'CVX-Radius-Redirect',
+ 'usr_receive_acc_map' => 'USR-Receive-Acc-Map',
+ 'x_ascend_tunneling_proto' => 'X-Ascend-Tunneling-Protocol',
+ 'itk_acct_serv_ip' => 'ITK-Acct-Serv-IP',
+ 'ascend_fr_type' => 'Ascend-FR-Type',
+ 'ascend_client_assign_dns' => 'Ascend-Client-Assign-DNS',
+ 'annex_retrain_requests_r' => 'Annex-Retrain-Requests-Rcvd',
+ 'x_ascend_assign_ip_globa' => 'X-Ascend-Assign-IP-Global-Pool',
+ 'tunnel_client_endpoint' => 'Tunnel-Client-Endpoint',
+ 'alteon_service_type' => 'Alteon-Service-Type',
+ 'x_ascend_send_secret' => 'X-Ascend-Send-Secret',
+ 'x_ascend_call_filter' => 'X-Ascend-Call-Filter',
+ 'usr_ipx_rip_input_filter' => 'USR-IPX-RIP-Input-Filter',
+ 'x_ascend_maximum_time' => 'X-Ascend-Maximum-Time',
+ 'pvc_profile_name' => 'PVC-Profile-Name',
+ 'usr_framed_ip_address_po' => 'USR-Framed_IP_Address_Pool_Name',
+ 'cvpn3000_ipsec_split_dns' => 'CVPN3000-IPSec-Split-DNS-Names',
+ 'ascend_global_call_id' => 'Ascend-Global-Call-Id',
+ 'usr_initial_rx_link_data' => 'USR-Initial-Rx-Link-Data-Rate',
+ 'st_primary_nbns_server' => 'ST-Primary-NBNS-Server',
+ 'usr_number_of_rings_limi' => 'USR-Number-of-Rings-Limit',
+ 'tunnel_local_name' => 'Tunnel-Local-Name',
+ 'ascend_fr_t392' => 'Ascend-FR-T392',
+ 'annex_pool_id' => 'Annex-Pool-Id',
+ 'ascend_token_immediate' => 'Ascend-Token-Immediate',
+ 'usr_rmmie_firmware_build' => 'USR-RMMIE-Firmware-Build-Date',
+ 'wispr_bandwidth_min_down' => 'WISPr-Bandwidth-Min-Down',
+ 'usr_chassis_call_slot' => 'USR-Chassis-Call-Slot',
+ 'rate_limit_burst' => 'Rate-Limit-Burst',
+ 'cisco_route_ip' => 'Cisco-Route-IP',
+ 'xedia_netbios_server' => 'Xedia-NetBios-Server',
+ 'session_error_msg' => 'Session-Error-Msg',
+ 'dhcp_max_leases' => 'DHCP-Max-Leases',
+ 'acc_vpsm_reject_cause' => 'Acc-Vpsm-Reject-Cause',
+ 'user_category' => 'User-Category',
+ 'x_ascend_multicast_rate_' => 'X-Ascend-Multicast-Rate-Limit',
+ 'cvpn3000_ipsec_auth_on_r' => 'CVPN3000-IPSec-Auth-On-Rekey',
+ 'altiga_min_password_leng' => 'Altiga-Min-Password-Length-G',
+ 'bind_type' => 'Bind-Type',
+ 'ascend_tunneling_protoco' => 'Ascend-Tunneling-Protocol',
+ 'cvx_modem_retx_packets' => 'CVX-Modem-ReTx-Packets',
+ 'usr_framed_ipx_route' => 'USR-Framed-IPX-Route',
+ 'rate_limit_rate' => 'Rate-Limit-Rate',
+ 'ascend_atm_connect_vpi' => 'Ascend-ATM-Connect-Vpi',
+ 'connect_info' => 'Connect-Info',
+ 'usr_port_tap_address' => 'USR-Port-Tap-Address',
+ 'usr_simplified_mnp_level' => 'USR-Simplified-MNP-Levels',
+ 'mcast_receivf' => 'Mcast_Receive',
+ 'annex_begin_modulation' => 'Annex-Begin-Modulation',
+ 'usr_pw_usr_ifilter_ip' => 'USR-PW_USR_IFilter_IP',
+ 'ascend_route_appletalk' => 'Ascend-Route-Appletalk',
+ 'ms_chap_lm_enc_pw' => 'MS-CHAP-LM-Enc-PW',
+ 'altiga_ipsec_over_nat_po' => 'Altiga-IPSec-Over-NAT-Port-Num-G',
+ 'itk_isdn_prot' => 'ITK-ISDN-Prot',
+ 'ascend_callback_delay' => 'Ascend-Callback-Delay',
+ 'session_error_code' => 'Session-Error-Code',
+ 'nomadix_endofsession' => 'Nomadix-EndofSession',
+ 'x_ascend_bacp_enable' => 'X-Ascend-BACP-Enable',
+ 'bg_trans_bpdu' => 'BG-Trans-BPDU',
+ 'bind_int_interface_namf' => 'Bind_Int_Interface_Name',
+ 'foundry_privilege_level' => 'Foundry-Privilege-Level',
+ 'huntgroup_name' => 'Huntgroup-Name',
+ 'x_ascend_ipx_alias' => 'X-Ascend-IPX-Alias',
+ 'tunnel_l2f_second_passwp' => 'Tunnel_L2F_Second_Password',
+ 'xedia_dns_server' => 'Xedia-DNS-Server',
+ 'usr_ipx_wan' => 'USR-IPX-WAN',
+ 'annex_addr_resolution_se' => 'Annex-Addr-Resolution-Servers',
+ 'acct_output_octets_65' => 'Acct_Output_Octets_64',
+ 'menu' => 'Menu',
+ 'erx_tunnel_nas_port_meth' => 'ERX-Tunnel-Nas-Port-Method',
+ 'aat_output_octets_diff' => 'AAT-Output-Octets-Diff',
+ 'x_ascend_fr_direct_dlci' => 'X-Ascend-FR-Direct-DLCI',
+ 'acct_status_type' => 'Acct-Status-Type',
+ 'ascend_port_redir_server' => 'Ascend-Port-Redir-Server',
+ 'telebit_port_name' => 'Telebit-Port-Name',
+ 'acc_dns_server_sec' => 'Acc-Dns-Server-Sec',
+ 'cvx_modem_remote_retrain' => 'CVX-Modem-Remote-Retrains',
+ 'ascend_minimum_channels' => 'Ascend-Minimum-Channels',
+ 'ascend_ipx_route' => 'Ascend-IPX-Route',
+ 'ascend_telnet_profile' => 'Ascend-Telnet-Profile',
+ 'usr_call_connect_in_gmt' => 'USR-Call-Connect-in-GMT',
+ 'usr_cusr_hat_script_rule' => 'USR-CUSR-hat-Script-Rules',
+ 'x_ascend_dba_monitor' => 'X-Ascend-DBA-Monitor',
+ 'response_packet_type' => 'Response-Packet-Type',
+ 'usr_event_id' => 'USR-Event-Id',
+ 'cvpn3000_ipsec_over_udp_' => 'CVPN3000-IPSec-Over-UDP-Port',
+ 'ascend_inc_channel_count' => 'Ascend-Inc-Channel-Count',
+ 'usr_send_script3' => 'USR-Send-Script3',
+ 'annex_pre_input_packets' => 'Annex-Pre-Input-Packets',
+ 'framed_callback_id' => 'Framed-Callback-Id',
+ 'xedia_client_access_netw' => 'Xedia-Client-Access-Network',
+ 'arap_zone_access' => 'ARAP-Zone-Access',
+ 'ascend_port_redir_portnu' => 'Ascend-Port-Redir-Portnum',
+ 'service_type' => 'Service-Type',
+ 'usr_nfas_id' => 'USR-NFAS-ID',
+ 'shiva_calling_number' => 'Shiva-Calling-Number',
+ 'ascend_user_acct_host' => 'Ascend-User-Acct-Host',
+ 'tunnel_session_auth_serv' => 'Tunnel-Session-Auth-Service-Grp',
+ 'juniper_deny_commands' => 'Juniper-Deny-Commands',
+ 'ascend_fr_link_mgt' => 'Ascend-FR-Link-Mgt',
+ 'nokia_imsi' => 'Nokia-IMSI',
+ 'quintum_h323_prompt_id' => 'Quintum-h323-prompt-id',
+ 'cvpn3000_require_individ' => 'CVPN3000-Require-Individual-User-Auth',
+ 'tunnel_retransmiu' => 'Tunnel_Retransmit',
+ 'source_validatioo' => 'Source_Validation',
+ 'sip_to' => 'Sip-To',
+ 'ms_primary_nbns_server' => 'MS-Primary-NBNS-Server',
+ 'quintum_avpair' => 'Quintum-AVPair',
+ 'ascend_transit_number' => 'Ascend-Transit-Number',
+ 'ascend_cache_refresh' => 'Ascend-Cache-Refresh',
+ 'ascend_user_acct_type' => 'Ascend-User-Acct-Type',
+ 'usr_num_fax_pages_proces' => 'USR-Num-Fax-Pages-Processed',
+ 'usr_mic' => 'USR-MIC',
+ 'usr_failure_to_connect_r' => 'USR-Failure-to-Connect-Reason',
+ 'cisco_fax_auth_status' => 'Cisco-Fax-Auth-Status',
+ 'bind_dot1q_vlan_tag_ie' => 'Bind_Dot1q_Vlan_Tag_Id',
+ 'ms_chap2_success' => 'MS-CHAP2-Success',
+ 'erx_tunnel_virtual_route' => 'ERX-Tunnel-Virtual-Router',
+ 'cisco_idle_limit' => 'Cisco-Idle-Limit',
+ 'ascend_pw_lifetime' => 'Ascend-PW-Lifetime',
+ 'cvpn3000_access_hours' => 'CVPN3000-Access-Hours',
+ 'bintec_sapcirctable' => 'BinTec-sapCircTable',
+ 'usr_packet_bus_session' => 'USR-Packet-Bus-Session',
+ 'acct_input_packets_64' => 'Acct-Input-Packets-64',
+ 'ascend_x25_pad_x3_parame' => 'Ascend-X25-Pad-X3-Parameters',
+ 'usr_secondary_nbns_serve' => 'USR-Secondary_NBNS_Server',
+ 'ascend_modem_slotno' => 'Ascend-Modem-SlotNo',
+ 'digest_qop' => 'Digest-QOP',
+ 'usr_characters_received' => 'USR-Characters-Received',
+ 'rate_limit_ratf' => 'Rate_Limit_Rate',
+ 'ms_bap_usage' => 'MS-BAP-Usage',
+ 'cisco_data_filter' => 'Cisco-Data-Filter',
+ 'usr_simplified_v42bis_us' => 'USR-Simplified-V42bis-Usage',
+ 'h323_setup_time' => 'h323-setup-time',
+ 'annex_wan_number' => 'Annex-Wan-Number',
+ 'cvx_vpop_id' => 'CVX-VPOP-ID',
+ 'usr_pw_tunnel_authentica' => 'USR-PW_Tunnel_Authentication',
+ 'le_nat_outsource_inmap' => 'LE-NAT-Outsource-Inmap',
+ 'cvx_modem_begin_recv_lin' => 'CVX-Modem-Begin-Recv-Line-Lvl',
+ 'telebit_login_command' => 'Telebit-Login-Command',
+ 'cisco_command_code' => 'Cisco-Command-Code',
+ 'itk_ppp_auth_type' => 'ITK-PPP-Auth-Type',
+ 'bintec_qosiftable' => 'BinTec-qosIfTable',
+ 'x_ascend_mpp_idle_percen' => 'X-Ascend-MPP-Idle-Percent',
+ 'usr_sap_filter_in' => 'USR-SAP-Filter-In',
+ 'framed_appletalk_link' => 'Framed-AppleTalk-Link',
+ 'tunnel_domaio' => 'Tunnel_Domain',
+ 'usr_ipx' => 'USR-IPX',
+ 'nas_real_poru' => 'NAS_Real_Port',
+ 'shiva_connect_reason' => 'Shiva-Connect-Reason',
+ 'x_ascend_pre_output_octe' => 'X-Ascend-Pre-Output-Octets',
+ 'cisco_ppp_vj_slot_comp' => 'Cisco-PPP-VJ-Slot-Comp',
+ 'freeradius_proxied_to' => 'Freeradius-Proxied-To',
+ 'ascend_atm_vpi' => 'Ascend-ATM-Vpi',
+ 'acc_ml_mlx_admin_state' => 'Acc-ML-MLX-Admin-State',
+ 'cvx_modem_snr' => 'CVX-Modem-SNR',
+ 'usr_igmp_robustness' => 'USR-IGMP-Robustness',
+ 'annex_rate_reneg_req_rcv' => 'Annex-Rate-Reneg-Req-Rcvd',
+ 'add_prefix' => 'Add-Prefix',
+ 'x_ascend_call_by_call' => 'X-Ascend-Call-By-Call',
+ 'usr_last_callers_number_' => 'USR-Last-Callers-Number-ANI',
+ 'postauth_type' => 'PostAuth-Type',
+ 'pvc_circuit_paddinh' => 'PVC_Circuit_Padding',
+ 'usr_at_rtmp_input_filter' => 'USR-AT-RTMP-Input-Filter',
+ 'erx_igmp_enable' => 'ERX-Igmp-Enable',
+ 'bind_bypass_contexu' => 'Bind_Bypass_Context',
+ 'x_ascend_num_in_multilin' => 'X-Ascend-Num-In-Multilink',
+ 'usr_pw_packet' => 'USR-PW_Packet',
+ 'dialback_no' => 'Dialback-No',
+ 'ascend_ip_tos_precedence' => 'Ascend-IP-TOS-Precedence',
+ 'cvpn5000_vpn_password' => 'CVPN5000-VPN-Password',
+ 'annex_cli_filter' => 'Annex-CLI-Filter',
+ 'x_ascend_dial_number' => 'X-Ascend-Dial-Number',
+ 'usr_iwf_call_identifier' => 'USR-IWF-Call-Identifier',
+ 'ms_secondary_dns_server' => 'MS-Secondary-DNS-Server',
+ 'shiva_type_of_service' => 'Shiva-Type-Of-Service',
+ 'bind_ses_context' => 'Bind-Ses-Context',
+ 'acc_reason_code' => 'Acc-Reason-Code',
+ 'ms_chap_cpw_1' => 'MS-CHAP-CPW-1',
+ 'wispr_bandwidth_max_down' => 'WISPr-Bandwidth-Max-Down',
+ 'h323_call_type' => 'h323-call-type',
+ 'bind_bypass_bypast' => 'Bind_Bypass_Bypass',
+ 'usr_number_of_link_timeo' => 'USR-Number-of-Link-Timeouts',
+ 'ascend_fr_08_mode' => 'Ascend-FR-08-Mode',
+ 'usr_calling_party_number' => 'USR-Calling-Party-Number',
+ 'usr_reply_script2' => 'USR-Reply-Script2',
+ 'usr_security_login_limit' => 'USR-Security-Login-Limit',
+ 'cisco_link_compression' => 'Cisco-Link-Compression',
+ 'ascend_vrouter_name' => 'Ascend-VRouter-Name',
+ 'erx_ppp_auth_protocol' => 'ERX-PPP-Auth-Protocol',
+ 'x_ascend_call_block_dura' => 'X-Ascend-Call-Block-Duration',
+ 'usr_modem_setup_time' => 'USR-Modem-Setup-Time',
+ 'pppoe_urm' => 'PPPOE_URL',
+ 'cisco_ip_direct' => 'Cisco-IP-Direct',
+ 'x_ascend_temporary_rtes' => 'X-Ascend-Temporary-Rtes',
+ 'ascend_x25_pad_alias_3' => 'Ascend-X25-Pad-Alias-3',
+ 'annex_multilink_id' => 'Annex-Multilink-Id',
+ 'mcast_maxgroupt' => 'Mcast_MaxGroups',
+ 'configuration_token' => 'Configuration-Token',
+ 'ascend_h323_conference_i' => 'Ascend-H323-Conference-Id',
+ 'ascend_ipx_header_compre' => 'Ascend-IPX-Header-Compression',
+ 'stripped_user_name' => 'Stripped-User-Name',
+ 'usr_ipx_rip_output_filte' => 'USR-IPX-RIP-Output-Filter',
+ 'cisco_call_filter' => 'Cisco-Call-Filter',
+ 'nas_ipv6_address' => 'NAS-IPv6-Address',
+ 'termination_menu' => 'Termination-Menu',
+ 'ascend_shared_profile_en' => 'Ascend-Shared-Profile-Enable',
+ 'port_message' => 'Port-Message',
+ 'erx_ingress_policy_name' => 'ERX-Ingress-Policy-Name',
+ 'acc_service_profile' => 'Acc-Service-Profile',
+ 'ascend_bir_proxy' => 'Ascend-BIR-Proxy',
+ 'aat_ppp_address' => 'AAT-PPP-Address',
+ 'usr_mbi_ct_pri_card_span' => 'USR-Mbi_Ct_PRI_Card_Span_Line',
+ 'ascend_x25_nui_prompt' => 'Ascend-X25-Nui-Prompt',
+ 'itk_modem_pool_id' => 'ITK-Modem-Pool-Id',
+ 'usr_compression_reset_mo' => 'USR-Compression-Reset-Mode',
+ 'usr_unauthenticated_time' => 'USR-Unauthenticated-Time',
+ 'ascend_multicast_gleave_' => 'Ascend-Multicast-GLeave-Delay',
+ 'acc_callback_cbcp_type' => 'Acc-Callback-CBCP-Type',
+ 'medium_typf' => 'Medium_Type',
+ 'login_service' => 'Login-Service',
+ 'itk_username_prompt' => 'ITK-Username-Prompt',
+ 'ascend_dial_number' => 'Ascend-Dial-Number',
+ 'framed_ipv6_route' => 'Framed-IPv6-Route',
+ 'x_ascend_remote_addr' => 'X-Ascend-Remote-Addr',
+ 'usr_call_end_date_time' => 'USR-Call-End-Date-Time',
+ 'bind_dot1q_slot' => 'Bind-Dot1q-Slot',
+ 'le_connect_detail' => 'LE-Connect-Detail',
+ 'annex_user_level' => 'Annex-User-Level',
+ 'tunnel_dnis' => 'Tunnel-DNIS',
+ 'assigned_ip_address' => 'Assigned-IP-Address',
+ 'acc_bridging_support' => 'Acc-Bridging-Support',
+ 'usr_channel' => 'USR-Channel',
+ 'arap_security_data' => 'ARAP-Security-Data',
+ 'bind_auth_service_grp' => 'Bind-Auth-Service-Grp',
+ 'cisco_abort_cause' => 'Cisco-Abort-Cause',
+ 'bg_span_dit' => 'BG_Span_Dis',
+ 'h323_voice_quality' => 'h323-voice-quality',
+ 'lac_real_port_typf' => 'LAC_Real_Port_Type',
+ 'usr_channel_connected_to' => 'USR-Channel-Connected-To',
+ 'ascend_client_assign_win' => 'Ascend-Client-Assign-WINS',
+ 'redcreek_tunneled_gatewa' => 'RedCreek-Tunneled-Gateway',
+ 'usr_number_of_fallbacks' => 'USR-Number-of-Fallbacks',
+ 'nokia_prepaid_ind' => 'Nokia-Prepaid-Ind',
+ 'nomadix_maxbytesup' => 'Nomadix-MaxBytesUp',
+ 'login_hosu' => 'Login-Host',
+ 'ascend_bir_enable' => 'Ascend-BIR-Enable',
+ 'usr_connect_time_limit' => 'USR-Connect-Time-Limit',
+ 'ascend_presession_time' => 'Ascend-PreSession-Time',
+ 'altiga_simultaneous_logi' => 'Altiga-Simultaneous-Logins-G/U',
+ 'cvpn3000_ipsec_default_d' => 'CVPN3000-IPSec-Default-Domain',
+ 'aat_atm_vci' => 'AAT-ATM-VCI',
+ 'extreme_netlogin_url_des' => 'Extreme-Netlogin-Url-Desc',
+ 'itk_auth_serv_ip' => 'ITK-Auth-Serv-IP',
+ 'erx_alternate_cli_vroute' => 'ERX-Alternate-Cli-Vrouter-Name',
+ 'framed_compression' => 'Framed-Compression',
+ 'ascend_svc_enabled' => 'Ascend-SVC-Enabled',
+ 'proxy_state' => 'Proxy-State',
+ 'aat_vrouter_name' => 'AAT-Vrouter-Name',
+ 'usr_rmmie_pwrlvl_farecho' => 'USR-RMMIE-PwrLvl-FarEcho-Canc',
+ 'nas_poru' => 'NAS-Port',
+ 'wispr_location_name' => 'WISPr-Location-Name',
+ 'digest_user_name' => 'Digest-User-Name',
+ 'ascend_modem_shelfno' => 'Ascend-Modem-ShelfNo',
+ 'shasta_user_privilege' => 'Shasta-User-Privilege',
+ 'bind_auth_protocol' => 'Bind-Auth-Protocol',
+ 'ascend_home_agent_passwo' => 'Ascend-Home-Agent-Password',
+ 'acct_interim_interval' => 'Acct-Interim-Interval',
+ 'ascend_history_weigh_typ' => 'Ascend-History-Weigh-Type',
+ 'ms_link_drop_time_limit' => 'MS-Link-Drop-Time-Limit',
+ 'hint' => 'Hint',
+ 'x_ascend_target_util' => 'X-Ascend-Target-Util',
+ 'acc_access_partition' => 'Acc-Access-Partition',
+ 'usr_power_supply_number' => 'USR-Power-Supply-Number',
+ 'x_ascend_multilink_id' => 'X-Ascend-Multilink-ID',
+ 'redcreek_tunneled_domain' => 'RedCreek-Tunneled-DomainName',
+ 'nomadix_bw_down' => 'Nomadix-Bw-Down',
+ 'acc_ipx_compression' => 'Acc-Ipx-Compression',
+ 'quintum_h323_setup_time' => 'Quintum-h323-setup-time',
+ 'cisco_target_util' => 'Cisco-Target-Util',
+ 'acc_ip_gateway_sec' => 'Acc-Ip-Gateway-Sec',
+ 'ascend_dsl_cir_xmit_limi' => 'Ascend-Dsl-CIR-Xmit-Limit',
+ 'ascend_ip_pool_definitio' => 'Ascend-IP-Pool-Definition',
+ 'bind_sub_user_at_contexu' => 'Bind_Sub_User_At_Context',
+ 'itk_dest_no' => 'ITK-Dest-No',
+ 'usr_connect_time' => 'USR-Connect-Time',
+ 'usr_call_start_date_time' => 'USR-Call-Start-Date-Time',
+ 'altiga_l2tp_encryption_g' => 'Altiga-L2TP-Encryption-G',
+ 'ascend_auth_delay' => 'Ascend-Auth-Delay',
+ 'ascend_x25_pad_x3_profil' => 'Ascend-X25-Pad-X3-Profile',
+ 'ascend_access_intercepta' => 'Ascend-Access-Intercept-Log',
+ 'ascend_home_agent_udp_po' => 'Ascend-Home-Agent-UDP-Port',
+ 'bind_tun_context' => 'Bind-Tun-Context',
+ 'dialback_name' => 'Dialback-Name',
+ 'h323_redirect_ip_address' => 'h323-redirect-ip-address',
+ 'annex_keypress_timeout' => 'Annex-Keypress-Timeout',
+ 'x_ascend_home_network_na' => 'X-Ascend-Home-Network-Name',
+ 'ascend_x25_pad_alias_1' => 'Ascend-X25-Pad-Alias-1',
+ 'ascend_call_attempt_limi' => 'Ascend-Call-Attempt-Limit',
+ 'quintum_h323_currency_ty' => 'Quintum-h323-currency-type',
+ 'ms_chap_response' => 'MS-CHAP-Response',
+ 'st_secondary_nbns_server' => 'ST-Secondary-NBNS-Server',
+ 'x_ascend_history_weigh_t' => 'X-Ascend-History-Weigh-Type',
+ 'usr_max_channels' => 'USR-Max-Channels',
+ 'ascend_fr_dte_n393' => 'Ascend-FR-DTE-N393',
+ 'ascend_pre_input_octets' => 'Ascend-Pre-Input-Octets',
+ 'erx_atm_mbs' => 'ERX-Atm-MBS',
+ 'cvpn3000_simultaneous_lo' => 'CVPN3000-Simultaneous-Logins',
+ 'juniper_allow_commands' => 'Juniper-Allow-Commands',
+ 'usr_line_reversals' => 'USR-Line-Reversals',
+ 'itk_users_default_pw' => 'ITK-Users-Default-Pw',
+ 'x_ascend_third_prompt' => 'X-Ascend-Third-Prompt',
+ 'cisco_fax_msg_id' => 'Cisco-Fax-Msg-Id',
+ 'x_ascend_pw_warntime' => 'X-Ascend-PW-Warntime',
+ 'ascend_data_filter' => 'Ascend-Data-Filter',
+ 'framed_address' => 'Framed-Address',
+ 'context_name' => 'Context-Name',
+ 'usr_send_script2' => 'USR-Send-Script2',
+ 'ms_arap_pw_change_reason' => 'MS-ARAP-PW-Change-Reason',
+ 'tunnel_session_auth_cty' => 'Tunnel_Session_Auth_Ctx',
+ 'acct_session_id' => 'Acct-Session-Id',
+ 'annex_port' => 'Annex-Port',
+ 'quintum_h323_call_origin' => 'Quintum-h323-call-origin',
+ 'erx_cli_initial_access_l' => 'ERX-Cli-Initial-Access-Level',
+ 'x_ascend_shared_profile_' => 'X-Ascend-Shared-Profile-Enable',
+ 'tunnel_cmd_timeouu' => 'Tunnel_Cmd_Timeout',
+ 'initial_modulation_type' => 'Initial-Modulation-Type',
+ 'ascend_h323_gatekeeper' => 'Ascend-H323-Gatekeeper',
+ 'x_ascend_fcp_parameter' => 'X-Ascend-FCP-Parameter',
+ 'multi_link_flag' => 'Multi-Link-Flag',
+ 'tunnel_type' => 'Tunnel-Type',
+ 'erx_output_gigapkts' => 'ERX-Output-Gigapkts',
+ 'ascend_idle_limit' => 'Ascend-Idle-Limit',
+ 'ns_user_group' => 'NS-User-Group',
+ 'password_retry' => 'Password-Retry',
+ 'h323_remote_address' => 'h323-remote-address',
+ 'erx_atm_service_category' => 'ERX-Atm-Service-Category',
+ 'acct_input_packets' => 'Acct-Input-Packets',
+ 'h323_disconnect_time' => 'h323-disconnect-time',
+ 'usr_syslog_tap' => 'USR-Syslog-Tap',
+ 'telebit_accounting_info' => 'Telebit-Accounting-Info',
+ 'ascend_billing_number' => 'Ascend-Billing-Number',
+ 'ascend_tunnel_vrouter_na' => 'Ascend-Tunnel-VRouter-Name',
+ 'ms_mppe_encryption_type' => 'MS-MPPE-Encryption-Type',
+ 'quintum_h323_credit_amou' => 'Quintum-h323-credit-amount',
+ 'acc_ace_token' => 'Acc-Ace-Token',
+ 'ascend_assign_ip_pool' => 'Ascend-Assign-IP-Pool',
+ 'annex_end_modulation' => 'Annex-End-Modulation',
+ 'usr_routing_protocol' => 'USR-Routing-Protocol',
+ 'cvx_assign_ip_pool' => 'CVX-Assign-IP-Pool',
+ 'usr_rad_location_type' => 'USR-Rad-Location-Type',
+ 'usr_rmmie_pwrlvl_noise_l' => 'USR-RMMIE-PwrLvl-Noise-Lvl',
+ 'usr_characters_sent' => 'USR-Characters-Sent',
+ 'usr_mp_edo_hiper' => 'USR-MP-EDO-HIPER',
+ 'ascend_x25_nui_password_' => 'Ascend-X25-Nui-Password-Prompt',
+ 'annex_host_restrict' => 'Annex-Host-Restrict',
+ 'user_service_type' => 'User-Service-Type',
+ 'acct_multi_session_id' => 'Acct-Multi-Session-Id',
+ 'ms_chap_cpw_2' => 'MS-CHAP-CPW-2',
+ 'x_ascend_secondary_home_' => 'X-Ascend-Secondary-Home-Agent',
+ 'x_ascend_dialout_allowed' => 'X-Ascend-Dialout-Allowed',
+ 'ascend_connect_progress' => 'Ascend-Connect-Progress',
+ 'x_ascend_ara_pw' => 'X-Ascend-Ara-PW',
+ 'cisco_fax_modem_time' => 'Cisco-Fax-Modem-Time',
+ 'sql_group' => 'Sql-Group',
+ 'annex_multicast_rate_lim' => 'Annex-Multicast-Rate-Limit',
+ 'cvpn3000_user_auth_servg' => 'CVPN3000-User-Auth-Server-Secret',
+ 'ns_mta_md5_password' => 'NS-MTA-MD5-Password',
+ 'annex_addr_resolution_pr' => 'Annex-Addr-Resolution-Protocol',
+ 'callback_number' => 'Callback-Number',
+ 'cvx_multilink_match_info' => 'CVX-Multilink-Match-Info',
+ 'tunnel_max_tunnelt' => 'Tunnel_Max_Tunnels',
+ 'tunnel_local_namf' => 'Tunnel_Local_Name',
+ 'quintum_h323_conf_id' => 'Quintum-h323-conf-id',
+ 'acct_output_packets_64' => 'Acct-Output-Packets-64',
+ 'annex_signal_to_noise_ra' => 'Annex-Signal-to-Noise-Ratio',
+ 'acct_output_packets_65' => 'Acct_Output_Packets_64',
+ 'x_ascend_user_acct_key' => 'X-Ascend-User-Acct-Key',
+ 'erx_dial_out_number' => 'ERX-Dial-Out-Number',
+ 'ascend_modem_portno' => 'Ascend-Modem-PortNo',
+ 'ascend_assign_ip_server' => 'Ascend-Assign-IP-Server',
+ 'ascend_fcp_parameter' => 'Ascend-FCP-Parameter',
+ 'usr_chassis_temp_thresho' => 'USR-Chassis-Temp-Threshold',
+ 'usr_mpip_tunnel_originat' => 'USR-MPIP-Tunnel-Originator',
+ 'tunnel_rate_limit_bursu' => 'Tunnel_Rate_Limit_Burst',
+ 'client_ip_address' => 'Client-IP-Address',
+ 'le_nat_tcp_session_timeo' => 'LE-NAT-TCP-Session-Timeout',
+ 'quintum_h323_redirect_ip' => 'Quintum-h323-redirect-ip-address',
+ 'ms_acct_eap_type' => 'MS-Acct-EAP-Type',
+ 'usr_rmmie_x2_status' => 'USR-RMMIE-x2-Status',
+ 'x_ascend_user_acct_type' => 'X-Ascend-User-Acct-Type',
+ 'shiva_customer_id' => 'Shiva-Customer-Id',
+ 'pvc_encapsulation_typf' => 'PVC_Encapsulation_Type',
+ 'st_acct_vc_connection_id' => 'ST-Acct-VC-Connection-Id',
+ 'lac_real_port' => 'LAC-Real-Port',
+ 'h323_connect_time' => 'h323-connect-time',
+ 'usr_vpn_gw_location_id' => 'USR-VPN-GW-Location-Id',
+ 'old_password' => 'Old-Password',
+ 'x_ascend_if_netmask' => 'X-Ascend-IF-Netmask',
+ 'add_suffix' => 'Add-Suffix',
+ 'lac_port_typf' => 'LAC_Port_Type',
+ 'acc_ip_pool_name' => 'Acc-Ip-Pool-Name',
+ 'usr_terminal_type' => 'USR-Terminal-Type',
+ 'usr_spoofing' => 'USR-Spoofing',
+ 'erx_tunnel_password' => 'ERX-Tunnel-Password',
+ 'ascend_inter_arrival_jit' => 'Ascend-Inter-Arrival-Jitter',
+ 'ascend_call_block_durati' => 'Ascend-Call-Block-Duration',
+ 'itk_channel_binding' => 'ITK-Channel-Binding',
+ 'usr_server_time' => 'USR-Server-Time',
+ 'ascend_assign_ip_client' => 'Ascend-Assign-IP-Client',
+ 'erx_pppoe_max_sessions' => 'ERX-Pppoe-Max-Sessions',
+ 'cvx_multilink_group_numb' => 'CVX-Multilink-Group-Number',
+ 'x_ascend_client_assign_d' => 'X-Ascend-Client-Assign-DNS',
+ 'erx_pppoe_url' => 'ERX-Pppoe-Url',
+ 'police_ratf' => 'Police_Rate',
+ 'ascend_data_svc' => 'Ascend-Data-Svc',
+ 'annex_authen_servers' => 'Annex-Authen-Servers',
+ 'nomadix_bw_up' => 'Nomadix-Bw-Up',
+ 'cvx_modem_data_compressi' => 'CVX-Modem-Data-Compression',
+ 'shiva_link_speed' => 'Shiva-Link-Speed',
+ 'usr_reply_script6' => 'USR-Reply-Script6',
+ 'usr_expansion_algorithm' => 'USR-Expansion-Algorithm',
+ 'cabletron_protocol_calla' => 'Cabletron-Protocol-Callable',
+ 'cisco_data_rate' => 'Cisco-Data-Rate',
+ 'usr_primary_dns_server' => 'USR-Primary_DNS_Server',
+ 'juniper_deny_configurati' => 'Juniper-Deny-Configuration',
+ 'ascend_target_util' => 'Ascend-Target-Util',
+ 'digest_method' => 'Digest-Method',
+ 'altiga_ipsec_split_tunne' => 'Altiga-IPSec-Split-Tunnel-List-G',
+ 'erx_alternate_cli_access' => 'ERX-Alternate-Cli-Access-Level',
+ 'x_ascend_event_type' => 'X-Ascend-Event-Type',
+ 'usr_q931_call_reference_' => 'USR-Q931-Call-Reference-Value',
+ 'usr_mp_mrru' => 'USR-MP-MRRU',
+ 'cvx_ipsvc_mask' => 'CVX-IPSVC-Mask',
+ 'bind_bypass_context' => 'Bind-Bypass-Context',
+ 'usr_rmmie_last_update_ev' => 'USR-RMMIE-Last-Update-Event',
+ 'no_such_attribute' => 'No-Such-Attribute',
+ 'acct_mcast_out_packets' => 'Acct-Mcast-Out-Packets',
+ 'tunnel_medium_type' => 'Tunnel-Medium-Type',
+ 'quintum_h323_remote_addr' => 'Quintum-h323-remote-address',
+ 'acc_callback_delay' => 'Acc-Callback-Delay',
+ 'acct_input_octets_64' => 'Acct-Input-Octets-64',
+ 'ascend_base_channel_coun' => 'Ascend-Base-Channel-Count',
+ 'ascend_atm_connect_vci' => 'Ascend-ATM-Connect-Vci',
+ 'erx_primary_dns' => 'ERX-Primary-Dns',
+ 'altiga_ipsec_over_nat_g' => 'Altiga-IPSec-Over-NAT-G',
+ 'cvx_multicast_rate_limit' => 'CVX-Multicast-Rate-Limit',
+ 'ascend_xmit_rate' => 'Ascend-Xmit-Rate',
+ 'ms_new_arap_password' => 'MS-New-ARAP-Password',
+ 'usr_call_error_code' => 'USR-Call-Error-Code',
+ 'acct_output_octets' => 'Acct-Output-Octets',
+ 'ascend_client_primary_wi' => 'Ascend-Client-Primary-WINS',
+ 'cvpn3000_primary_wins' => 'CVPN3000-Primary-WINS',
+ 'bintec_ipextrttable' => 'BinTec-ipExtRtTable',
+ 'cisco_fax_mdn_flag' => 'Cisco-Fax-Mdn-Flag',
+ 'ascend_destination_nas_p' => 'Ascend-Destination-Nas-Port',
+ 'ascend_num_in_multilink' => 'Ascend-Num-In-Multilink',
+ 'digest_attributes' => 'Digest-Attributes',
+ 'cvpn3000_ipsec_tunnel_ty' => 'CVPN3000-IPSec-Tunnel-Type',
+ 'x_ascend_number_sessions' => 'X-Ascend-Number-Sessions',
+ 'usr_ip_rip_output_filter' => 'USR-IP-RIP-Output-Filter',
+ 'tunnel_police_bursu' => 'Tunnel_Police_Burst',
+ 'redcreek_tunneled_wins_s' => 'RedCreek-Tunneled-WINS-Server1',
+ 'usr_blocks_sent' => 'USR-Blocks-Sent',
+ 'erx_cli_allow_all_vr_acc' => 'ERX-Cli-Allow-All-VR-Access',
+ 'tunnel_police_ratf' => 'Tunnel_Police_Rate',
+ 'usr_ids0_call_type' => 'USR-IDS0-Call-Type',
+ 'acc_ccp_option' => 'Acc-Ccp-Option',
+ 'ascend_client_gateway' => 'Ascend-Client-Gateway',
+ 'cvx_maximum_channels' => 'CVX-Maximum-Channels',
+ 'bg_aging_timf' => 'BG_Aging_Time',
+ 'annex_secondary_dns_serv' => 'Annex-Secondary-DNS-Server',
+ 'le_ipsec_passive_profile' => 'LE-IPSec-Passive-Profile',
+ 'usr_chassis_call_span' => 'USR-Chassis-Call-Span',
+ 'aat_client_primary_wins_' => 'AAT-Client-Primary-WINS-NBNS',
+ 'h323_currency' => 'h323-currency',
+ 'password' => 'Password',
+ 'le_nat_log_options' => 'LE-NAT-Log-Options',
+ 'usr_fallback_limit' => 'USR-Fallback-Limit',
+ 'x_ascend_ppp_address' => 'X-Ascend-PPP-Address',
+ 'suffix' => 'Suffix',
+ 'usr_multicast_receive' => 'USR-Multicast-Receive',
+ 'client_dns_sec' => 'Client-DNS-Sec',
+ 'annex_product_name' => 'Annex-Product-Name',
+ 'cisco_pw_lifetime' => 'Cisco-PW-Lifetime',
+ 'x_ascend_fr_dce_n393' => 'X-Ascend-FR-DCE-N393',
+ 'x_ascend_ts_idle_limit' => 'X-Ascend-TS-Idle-Limit',
+ 'mcast_send' => 'Mcast-Send',
+ 'x_ascend_primary_home_ag' => 'X-Ascend-Primary-Home-Agent',
+ 'tunnel_max_sessiont' => 'Tunnel_Max_Sessions',
+ 'pppoe_motm' => 'PPPOE-MOTM',
+ 'usr_pw_usr_ifilter_ipx' => 'USR-PW_USR_IFilter_IPX',
+ 'ms_ras_version' => 'MS-RAS-Version',
+ 'ascend_source_ip_check' => 'Ascend-Source-IP-Check',
+ 'bintec_ospfiftable' => 'BinTec-ospfIfTable',
+ 'acc_ml_call_threshold' => 'Acc-ML-Call-Threshold',
+ 'x_ascend_modem_slotno' => 'X-Ascend-Modem-SlotNo',
+ 'ascend_menu_item' => 'Ascend-Menu-Item',
+ 'callback_id' => 'Callback-Id',
+ 'framed_ipx_network' => 'Framed-IPX-Network',
+ 'altiga_pptp_encryption_g' => 'Altiga-PPTP-Encryption-G',
+ 'ascend_x25_reverse_charg' => 'Ascend-X25-Reverse-Charging',
+ 'ascend_user_acct_key' => 'Ascend-User-Acct-Key',
+ 'x_ascend_pw_lifetime' => 'X-Ascend-PW-Lifetime',
+ 'user_name_is_star' => 'User-Name-Is-Star',
+ 'nomadix_url_redirection' => 'Nomadix-URL-Redirection',
+ 'framed_pool' => 'Framed-Pool',
+ 'x_ascend_authen_alias' => 'X-Ascend-Authen-Alias',
+ 'cisco_fax_dsn_address' => 'Cisco-Fax-Dsn-Address',
+ 'ms_primary_dns_server' => 'MS-Primary-DNS-Server',
+ 'acc_dialout_auth_usernam' => 'Acc-Dialout-Auth-Username',
+ 'realm' => 'Realm',
+ 'arap_features' => 'ARAP-Features',
+ 'bind_auth_protocom' => 'Bind_Auth_Protocol',
+ 'acc_connect_tx_speed' => 'Acc-Connect-Tx-Speed',
+ 'usr_chassis_temperature' => 'USR-Chassis-Temperature',
+ 'altiga_ipsec_mode_config' => 'Altiga-IPSec-Mode-Config-G',
+ 'ascend_home_agent_ip_add' => 'Ascend-Home-Agent-IP-Addr',
+ 'x_ascend_xmit_rate' => 'X-Ascend-Xmit-Rate',
+ 'cvpn3000_secondary_dns' => 'CVPN3000-Secondary-DNS',
+ 'x_ascend_send_passwd' => 'X-Ascend-Send-Passwd',
+ 'bind_int_contexu' => 'Bind_Int_Context',
+ 'cisco_fax_account_id_ori' => 'Cisco-Fax-Account-Id-Origin',
+ 'le_modem_info' => 'LE-Modem-Info',
+ 'ascend_ipx_peer_mode' => 'Ascend-IPX-Peer-Mode',
+ 'juniper_local_user_name' => 'Juniper-Local-User-Name',
+ 'tunnel_rate_limit_rate' => 'Tunnel-Rate-Limit-Rate',
+ 'quintum_h323_credit_time' => 'Quintum-h323-credit-time',
+ 'acc_modem_modulation_typ' => 'Acc-Modem-Modulation-Type',
+ 'x_ascend_seconds_of_hist' => 'X-Ascend-Seconds-Of-History',
+ 'ascend_dhcp_pool_number' => 'Ascend-DHCP-Pool-Number',
+ 'redcreek_tunneled_ip_net' => 'RedCreek-Tunneled-IP-Netmask',
+ 'x_ascend_callback' => 'X-Ascend-Callback',
+ 'usr_iwf_ip_address' => 'USR-IWF-IP-Address',
+ 'aat_input_octets_diff' => 'AAT-Input-Octets-Diff',
+ 'nas_port_id' => 'NAS-Port-Id',
+ 'le_advice_of_charge' => 'LE-Advice-of-Charge',
+ 'x_ascend_dhcp_pool_numbe' => 'X-Ascend-DHCP-Pool-Number',
+ 'ascend_add_seconds' => 'Ascend-Add-Seconds',
+ 'annex_transmit_speed' => 'Annex-Transmit-Speed',
+ 'usr_port_tap' => 'USR-Port-Tap',
+ 'usr_at_call_input_filter' => 'USR-AT-Call-Input-Filter',
+ 'framed_ipv6_pool' => 'Framed-IPv6-Pool',
+ 'ascend_qos_downstream' => 'Ascend-QOS-Downstream',
+ 'lac_port' => 'LAC-Port',
+ 'tunnel_assignment_id' => 'Tunnel-Assignment-Id',
+ 'acct_mcast_out_octett' => 'Acct_Mcast_Out_Octets',
+ 'ascend_bi_directional_au' => 'Ascend-Bi-Directional-Auth',
+ 'fall_through' => 'Fall-Through',
+ 'cvpn3000_ipsec_ip_compre' => 'CVPN3000-IPSec-IP-Compression',
+ 'cisco_disconnect_cause' => 'Cisco-Disconnect-Cause',
+ 'usr_rad_multicast_routiq' => 'USR-Rad-Multicast-Routing-Bound',
+ 'altiga_tunneling_protoco' => 'Altiga-Tunneling-Protocols-G/U',
+ 'itk_tunnel_prot' => 'ITK-Tunnel-Prot',
+ 'client_dns_sed' => 'Client_DNS_Sec',
+ 'framed_ip_netmask' => 'Framed-IP-Netmask',
+ 'usr_call_reference_numbe' => 'USR-Call-Reference-Number',
+ 'ascend_egress_enabled' => 'Ascend-Egress-Enabled',
+ 'ascend_dsl_rate_mode' => 'Ascend-Dsl-Rate-Mode',
+ 'usr_pw_usr_ofilter_sap' => 'USR-PW_USR_OFilter_SAP',
+ 'bintec_iproutetable' => 'BinTec-ipRouteTable',
+ 'acct_terminate_cause' => 'Acct-Terminate-Cause',
+ 'x_ascend_fr_dte_n393' => 'X-Ascend-FR-DTE-N393',
+ 'ascend_ppp_address' => 'Ascend-PPP-Address',
+ 'erx_maximum_bps' => 'ERX-Maximum-BPS',
+ 'caller_id' => 'Caller-ID',
+ 'bintec_ipfiltertable' => 'BinTec-ipFilterTable',
+ 'x_ascend_base_channel_co' => 'X-Ascend-Base-Channel-Count',
+ 'bind_int_interface_name' => 'Bind-Int-Interface-Name',
+ 'usr_modem_group' => 'USR-Modem-Group',
+ 'cisco_maximum_channels' => 'Cisco-Maximum-Channels',
+ 'erx_ppp_username' => 'ERX-PPP-Username',
+ 'ascend_link_compression' => 'Ascend-Link-Compression',
+ 'annex_retransmitted_pack' => 'Annex-Retransmitted-Packets',
+ 'usr_retrains_granted' => 'USR-Retrains-Granted',
+ 'ascend_dropped_packets' => 'Ascend-Dropped-Packets',
+ 'erx_bearer_type' => 'ERX-Bearer-Type',
+ 'usr_pw_usr_ofilter_ip' => 'USR-PW_USR_OFilter_IP',
+ 'quintum_nas_port' => 'Quintum-NAS-Port',
+ 'x_ascend_pre_output_pack' => 'X-Ascend-Pre-Output-Packets',
+ 'usr_cdma_call_reference_' => 'USR-CDMA-Call-Reference-Number',
+ 'tunnel_function' => 'Tunnel-Function',
+ 'annex_tunnel_authen_mode' => 'Annex-Tunnel-Authen-Mode',
+ 'usr_mp_edo' => 'USR-MP-EDO',
+ 'le_nat_outmap' => 'LE-NAT-Outmap',
+ 'cvpn3000_primary_dns' => 'CVPN3000-Primary-DNS',
+ 'usr_modulation_type' => 'USR-Modulation-Type',
+ 'ascend_calling_id_screen' => 'Ascend-Calling-Id-Screening',
+ 'ascend_maximum_time' => 'Ascend-Maximum-Time',
+ 'user_password' => 'User-Password',
+ 'annex_callback_portlist' => 'Annex-Callback-Portlist',
+ 'cvpn3000_ipsec_split_tun' => 'CVPN3000-IPSec-Split-Tunnel-List',
+ 'annex_pre_output_packets' => 'Annex-Pre-Output-Packets',
+ 'usr_at_call_output_filte' => 'USR-AT-Call-Output-Filter',
+ 'x_ascend_client_primary_' => 'X-Ascend-Client-Primary-DNS',
+ 'tunnel_server_endpoint' => 'Tunnel-Server-Endpoint',
+ 'x_ascend_remove_seconds' => 'X-Ascend-Remove-Seconds',
+ 'cvpn3000_user_auth_serve' => 'CVPN3000-User-Auth-Server-Name',
+ 'arap_password' => 'ARAP-Password',
+ 'x_ascend_assign_ip_serve' => 'X-Ascend-Assign-IP-Server',
+ 'cisco_fax_pages' => 'Cisco-Fax-Pages',
+ 'ms_chap_mppe_keys' => 'MS-CHAP-MPPE-Keys',
+ 'ascend_source_auth' => 'Ascend-Source-Auth',
+ 'group' => 'Group',
+ 'usr_send_script6' => 'USR-Send-Script6',
+ 'le_nat_inmap' => 'LE-NAT-Inmap',
+ 'chap_password' => 'CHAP-Password',
+ 'annex_receive_speed' => 'Annex-Receive-Speed',
+ 'usr_mobileip_home_agent_' => 'USR-MobileIP-Home-Agent-Address',
+ 'bind_l2tp_flow_control' => 'Bind-L2TP-Flow-Control',
+ 'smb_account_ctrl' => 'SMB-Account-CTRL',
+ 'ascend_ip_pool_chaining' => 'Ascend-IP-Pool-Chaining',
+ 'le_admin_group' => 'LE-Admin-Group',
+ 'tunnel_connection_id' => 'Tunnel-Connection-Id',
+ 'tunnel_windox' => 'Tunnel_Window',
+ 'nas_identifier' => 'NAS-Identifier',
+ 'dhcp_max_leaset' => 'DHCP_Max_Leases',
+ 'digest_nonce_count' => 'Digest-Nonce-Count',
+ 'nas_real_port' => 'NAS-Real-Port',
+ 'ms_old_arap_password' => 'MS-Old-ARAP-Password',
+ 'usr_pw_index' => 'USR-PW_Index',
+ 'erx_primary_wins' => 'ERX-Primary-Wins',
+ 'ascend_appletalk_peer_mo' => 'Ascend-Appletalk-Peer-Mode',
+ 'le_ipsec_log_options' => 'LE-IPSec-Log-Options',
+ 'x_ascend_maximum_channel' => 'X-Ascend-Maximum-Channels',
+ 'cvx_ipsvc_aznlvl' => 'CVX-IPSVC-AZNLVL',
+ 'x_ascend_client_secondar' => 'X-Ascend-Client-Secondary-DNS',
+ 'annex_re_chap_timeout' => 'Annex-Re-CHAP-Timeout',
+ 'aat_ip_pool_definition' => 'AAT-IP-Pool-Definition',
+ 'client_dns_pri' => 'Client-DNS-Pri',
+ 'cisco_service_info' => 'Cisco-Service-Info',
+ 'usr_primary_nbns_server' => 'USR-Primary_NBNS_Server',
+ 'aat_atm_direct' => 'AAT-ATM-Direct',
+ 'bind_ses_contexu' => 'Bind_Ses_Context',
+ 'sip_translated_request_u' => 'Sip-Translated-Request-URI',
+ 'acc_acct_on_off_reason' => 'Acc-Acct-On-Off-Reason',
+ 'le_multicast_client' => 'LE-Multicast-Client',
+ 'bind_sub_passwore' => 'Bind_Sub_Password',
+ 'cvpn3000_cisco_ip_phone_' => 'CVPN3000-Cisco-IP-Phone-Bypass',
+ 'ascend_send_passwd' => 'Ascend-Send-Passwd',
+ 'tunnel_remote_namf' => 'Tunnel_Remote_Name',
+ 'cvx_disconnect_cause' => 'CVX-Disconnect-Cause',
+ 'itk_auth_serv_prot' => 'ITK-Auth-Serv-Prot',
+ 'tunnel_context' => 'Tunnel-Context',
+ 'digest_uri' => 'Digest-URI',
+ 'usr_channel_decrement' => 'USR-Channel-Decrement',
+ 'acc_nbns_server_sec' => 'Acc-Nbns-Server-Sec',
+ 'ms_chap_challenge' => 'MS-CHAP-Challenge',
+ 'cisco_assign_ip_pool' => 'Cisco-Assign-IP-Pool',
+ 'ascend_cbcp_mode' => 'Ascend-CBCP-Mode',
+ 'ascend_x25_rpoa' => 'Ascend-X25-Rpoa',
+ 'usr_dtr_false_timeout' => 'USR-DTR-False-Timeout',
+ 'acct_dyn_ac_enu' => 'Acct_Dyn_Ac_Ent',
+ 'usr_physical_state' => 'USR-Physical-State',
+ 'x_ascend_ppp_vj_slot_com' => 'X-Ascend-PPP-VJ-Slot-Comp',
+ 'x_ascend_link_compressio' => 'X-Ascend-Link-Compression',
+ 'ascend_fr_t391' => 'Ascend-FR-T391',
+ 'bind_dot1q_port' => 'Bind-Dot1q-Port',
+ 'ns_secondary_dns' => 'NS-Secondary-DNS',
+ 'altiga_ipsec_tunnel_type' => 'Altiga-IPSec-Tunnel-Type-G',
+ 'lac_port_type' => 'LAC-Port-Type',
+ 'bg_aging_time' => 'BG-Aging-Time',
+ 'erx_atm_scr' => 'ERX-Atm-SCR',
+ 'x_ascend_pre_input_octet' => 'X-Ascend-Pre-Input-Octets',
+ 'cisco_fax_connect_speed' => 'Cisco-Fax-Connect-Speed',
+ 'x_ascend_menu_item' => 'X-Ascend-Menu-Item',
+ 'quintum_h323_voice_quali' => 'Quintum-h323-voice-quality',
+ 'ascend_x25_pad_banner' => 'Ascend-X25-Pad-Banner',
+ 'module_failure_message' => 'Module-Failure-Message',
+ 'h323_gw_id' => 'h323-gw-id',
+ 'h323_preferred_lang' => 'h323-preferred-lang',
+ 'usr_min_compression_size' => 'USR-Min-Compression-Size',
+ 'usr_compression_type' => 'USR-Compression-Type',
+ 'bintec_ipxstaticroutetab' => 'BinTec-ipxStaticRouteTable',
+ 'ascend_dialout_allowed' => 'Ascend-Dialout-Allowed',
+ 'annex_local_username' => 'Annex-Local-Username',
+ 'cisco_pre_input_packets' => 'Cisco-Pre-Input-Packets',
+ 'shiva_function' => 'Shiva-Function',
+ 'ascend_send_secret' => 'Ascend-Send-Secret',
+ 'usr_number_of_blers' => 'USR-Number-of-Blers',
+ 'usr_dte_data_idle_timout' => 'USR-DTE-Data-Idle-Timout',
+ 'usr_card_type' => 'USR-Card-Type',
+ 'x_ascend_connect_progres' => 'X-Ascend-Connect-Progress',
+ 'x_ascend_group' => 'X-Ascend-Group',
+ 'ascend_token_idle' => 'Ascend-Token-Idle',
+ 'erx_qos_profile_interfac' => 'ERX-Qos-Profile-Interface-Type',
+ 'ascend_private_route_tab' => 'Ascend-Private-Route-Table-ID',
+ 'nt_password' => 'NT-Password',
+ 'acct_mcast_in_packets' => 'Acct-Mcast-In-Packets',
+ 'x_ascend_multicast_clien' => 'X-Ascend-Multicast-Client',
+ 'usr_supports_tags' => 'USR-Supports-Tags',
+ 'cvpn3000_authd_user_idle' => 'CVPN3000-Authd-User-Idle-Timeout',
+ 'ascend_number_sessions' => 'Ascend-Number-Sessions',
+ 'x_ascend_add_seconds' => 'X-Ascend-Add-Seconds',
+ 'usr_number_of_upshifts' => 'USR-Number-of-Upshifts',
+ 'proxy_to_realm' => 'Proxy-To-Realm',
+ 'aat_client_secondary_win' => 'AAT-Client-Secondary-WINS-NBNS',
+ 'aat_ip_tos_precedence' => 'AAT-IP-TOS-Precedence',
+ 'acc_callback_num_valid' => 'Acc-Callback-Num-Valid',
+ 'nokia_ggsn_ip_address' => 'Nokia-GGSN-IP-Address',
+ 'acc_access_community' => 'Acc-Access-Community',
+ 'ascend_multicast_rate_li' => 'Ascend-Multicast-Rate-Limit',
+ 'usr_default_dte_data_rat' => 'USR-Default-DTE-Data-Rate',
+ 'usr_rmmie_pwrlvl_nearech' => 'USR-RMMIE-PwrLvl-NearEcho-Canc',
+ 'usr_send_name' => 'USR-Send-Name',
+ 'usr_chassis_slot' => 'USR-Chassis-Slot',
+ 'login_ip_host' => 'Login-IP-Host',
+ 'ascend_netware_timeout' => 'Ascend-Netware-timeout',
+ 'bind_sub_user_at_context' => 'Bind-Sub-User-At-Context',
+ 'vendor_specific' => 'Vendor-Specific',
+ 'ascend_fr_direct_dlci' => 'Ascend-FR-Direct-DLCI',
+ 'ascend_qos_upstream' => 'Ascend-QOS-Upstream',
+ 'aat_user_mac_address' => 'AAT-User-MAC-Address',
+ 'source_validation' => 'Source-Validation',
+ 'x_ascend_token_expiry' => 'X-Ascend-Token-Expiry',
+ 'altiga_ipsec_user_group_' => 'Altiga-IPSec-User-Group-Lock-G',
+ 'ascend_dec_channel_count' => 'Ascend-Dec-Channel-Count',
+ 'assigned_ip_addrest' => 'Assigned_IP_Address',
+ 'usr_local_framed_ip_addr' => 'USR-Local-Framed-IP-Addr',
+ 'usr_service_option' => 'USR-Service-Option',
+ 'usr_transmit_acc_map' => 'USR-Transmit-Acc-Map',
+ 'ascend_fr_direct' => 'Ascend-FR-Direct',
+ 'usr_final_rx_link_data_r' => 'USR-Final-Rx-Link-Data-Rate',
+ 'x_ascend_expect_callback' => 'X-Ascend-Expect-Callback',
+ 'x_ascend_disconnect_caus' => 'X-Ascend-Disconnect-Cause',
+ 'acc_ml_damping_factor' => 'Acc-ML-Damping-Factor',
+ 'framed_netmask' => 'Framed-Netmask',
+ 'usr_connect_speed' => 'USR-Connect-Speed',
+ 'x_ascend_home_agent_ip_a' => 'X-Ascend-Home-Agent-IP-Addr',
+ 'usr_disconnect_cause_ind' => 'USR-Disconnect-Cause-Indicator',
+ 'bg_span_dis' => 'BG-Span-Dis',
+ 'cisco_multilink_id' => 'Cisco-Multilink-ID',
+ 'tunnel_max_tunnels' => 'Tunnel-Max-Tunnels',
+ 'ascend_dsl_downstream_li' => 'Ascend-Dsl-Downstream-Limit',
+ 'ascend_multilink_id' => 'Ascend-Multilink-ID',
+ 'altiga_ipsec_default_dom' => 'Altiga-IPSec-Default-Domain-G',
+ 'ascend_dhcp_reply' => 'Ascend-DHCP-Reply',
+ 'login_ipv6_host' => 'Login-IPv6-Host',
+ 'ascend_x25_cug' => 'Ascend-X25-Cug',
+ 'shiva_network_protocols' => 'Shiva-Network-Protocols',
+ 'cvpn3000_ipsec_mode_conf' => 'CVPN3000-IPSec-Mode-Config',
+ 'extreme_netlogin_vlan' => 'Extreme-Netlogin-Vlan',
+ 'ascend_ara_pw' => 'Ascend-Ara-PW',
+ 'tunnel_l2f_second_passwo' => 'Tunnel-L2F-Second-Password',
+ 'altiga_sep_card_assignme' => 'Altiga-SEP-Card-Assignment-G/U',
+ 'ip_host_addr' => 'Ip-Host-Addr',
+ 'le_ip_gateway' => 'LE-IP-Gateway',
+ 'usr_mobile_numbytes_txed' => 'USR-Mobile-NumBytes-Txed',
+ 'altiga_ipsec_allow_passw' => 'Altiga-IPSec-Allow-Passwd-Store-G/U',
+ 'itk_users_default_entry' => 'ITK-Users-Default-Entry',
+ 'quintum_h323_redirect_nu' => 'Quintum-h323-redirect-number',
+ 'x_ascend_fr_t392' => 'X-Ascend-FR-T392',
+ 'acc_igmp_version' => 'Acc-Igmp-Version',
+ 'cisco_pre_output_packets' => 'Cisco-Pre-Output-Packets',
+ 'tunnel_group' => 'Tunnel-Group',
+ 'x_ascend_home_agent_udp_' => 'X-Ascend-Home-Agent-UDP-Port',
+ 'cvpn3000_tunneling_proto' => 'CVPN3000-Tunneling-Protocols',
+ 'usr_igmp_maximum_respons' => 'USR-IGMP-Maximum-Response-Time',
+ 'bind_sub_password' => 'Bind-Sub-Password',
+ 'eap_message' => 'EAP-Message',
+ 'exec_program' => 'Exec-Program',
+ 'cvpn3000_reqrd_client_fx' => 'CVPN3000-Reqrd-Client-Fw-Product-Code',
+ 'bg_path_cost' => 'BG-Path-Cost',
+ 'usr_modem_training_time' => 'USR-Modem-Training-Time',
+ 'auth_type' => 'Auth-Type',
+ 'itk_acct_serv_prot' => 'ITK-Acct-Serv-Prot',
+ 'x_ascend_ipx_route' => 'X-Ascend-IPX-Route',
+ 'altiga_primary_dns_g' => 'Altiga-Primary-DNS-G',
+ 'ascend_cbcp_enable' => 'Ascend-CBCP-Enable',
+ 'ms_mppe_encryption_polic' => 'MS-MPPE-Encryption-Policy',
+ 'annex_unauthenticated_ti' => 'Annex-Unauthenticated-Time',
+ 'annex_begin_receive_line' => 'Annex-Begin-Receive-Line-Level',
+ 'ascend_atm_direct_profil' => 'Ascend-ATM-Direct-Profile',
+ 'redcreek_tunneled_dns_se' => 'RedCreek-Tunneled-DNS-Server',
+ 'ascend_redirect_number' => 'Ascend-Redirect-Number',
+ 'h323_credit_time' => 'h323-credit-time',
+ 'cvx_idle_limit' => 'CVX-Idle-Limit',
+ 'ascend_appletalk_route' => 'Ascend-Appletalk-Route',
+ 'aat_ip_tos' => 'AAT-IP-TOS',
+ 'cvx_ppp_address' => 'CVX-PPP-Address',
+ 'aat_data_filter' => 'AAT-Data-Filter',
+ 'cvx_primary_dns' => 'CVX-Primary-DNS',
+ 'shiva_link_protocol' => 'Shiva-Link-Protocol',
+ 'x_ascend_fr_circuit_name' => 'X-Ascend-FR-Circuit-Name',
+ 'usr_appletalk' => 'USR-Appletalk',
+ 'client_id' => 'Client-Id',
+ 'tunnel_algorithn' => 'Tunnel_Algorithm',
+ 'aat_assign_ip_pool' => 'AAT-Assign-IP-Pool',
+ 'quintum_h323_incoming_co' => 'Quintum-h323-incoming-conf-id',
+ 'aat_atm_vpi' => 'AAT-ATM-VPI',
+ 'annex_output_filter' => 'Annex-Output-Filter',
+ 'pvc_circuit_padding' => 'PVC-Circuit-Padding',
+ 'usr_ipx_call_output_filt' => 'USR-IPX-Call-Output-Filter',
+ 'usr_rmmie_planned_discon' => 'USR-RMMIE-Planned-Disconnect',
+ 'session_error_msh' => 'Session_Error_Msg',
+ 'usr_rad_multicast_routin' => 'USR-Rad-Multicast-Routing-Ttl',
+ 'h323_time_and_day' => 'h323-time-and-day',
+ 'cvpn3000_ipsec_backup_se' => 'CVPN3000-IPSec-Backup-Servers',
+ 'termination_action' => 'Termination-Action',
+ 'cvpn3000_ipsec_client_fx' => 'CVPN3000-IPSec-Client-Fw-Filter-Opt',
+ 'aat_client_primary_dnt' => 'AAT-Client-Primary-DNS',
+ 'acct_tunnel_packets_lost' => 'Acct-Tunnel-Packets-Lost',
+ 'x_ascend_modem_portno' => 'X-Ascend-Modem-PortNo',
+ 'framed_filter_id' => 'Framed-Filter-Id',
+ 'usr_ccp_algorithm' => 'USR-CCP-Algorithm',
+ 'quintum_h323_preferred_l' => 'Quintum-h323-preferred-lang',
+ 'ascend_fr_link_status_dl' => 'Ascend-FR-Link-Status-DLCI',
+ 'ascend_token_expiry' => 'Ascend-Token-Expiry',
+ 'itk_auth_req_type' => 'ITK-Auth-Req-Type',
+ 'acc_modem_error_protocol' => 'Acc-Modem-Error-Protocol',
+ 'acc_request_type' => 'Acc-Request-Type',
+ 'usr_last_number_dialed_i' => 'USR-Last-Number-Dialed-In-DNIS',
+ 'x_ascend_ipx_peer_mode' => 'X-Ascend-IPX-Peer-Mode',
+ 'ascend_ppp_vj_slot_comp' => 'Ascend-PPP-VJ-Slot-Comp',
+ 'cisco_presession_time' => 'Cisco-PreSession-Time',
+ 'usr_chat_script_name' => 'USR-Chat-Script-Name',
+ 'tunnel_session_auti' => 'Tunnel_Session_Auth',
+ 'ascend_fr_circuit_name' => 'Ascend-FR-Circuit-Name',
+ 'ascend_expect_callback' => 'Ascend-Expect-Callback',
+ 'framed_mtu' => 'Framed-MTU',
+ 'usr_pw_vpn_name' => 'USR-PW_VPN_Name',
+ 'nomadix_ip_upsell' => 'Nomadix-IP-Upsell',
+ 'ascend_nas_port_format' => 'Ascend-NAS-Port-Format',
+ 'usr_dtr_true_timeout' => 'USR-DTR-True-Timeout',
+ 'shasta_vpn_name' => 'Shasta-VPN-Name',
+ 'connect_rate' => 'Connect-Rate',
+ 'ascend_third_prompt' => 'Ascend-Third-Prompt',
+ 'cabletron_protocol_enabl' => 'Cabletron-Protocol-Enable',
+ 'annex_pre_input_octets' => 'Annex-Pre-Input-Octets',
+ 'cvx_modem_error_correcti' => 'CVX-Modem-Error-Correction',
+ 'cvx_ss7_session_id_type' => 'CVX-SS7-Session-ID-Type',
+ 'called_station_id' => 'Called-Station-Id',
+ 'itk_ddi' => 'ITK-DDI',
+ 'usr_pw_cutoff' => 'USR-PW_Cutoff',
+ 'ascend_data_rate' => 'Ascend-Data-Rate',
+ 'acct_input_packets_65' => 'Acct_Input_Packets_64',
+ 'x_ascend_ts_idle_mode' => 'X-Ascend-TS-Idle-Mode',
+ 'ascend_x25_pad_prompt' => 'Ascend-X25-Pad-Prompt',
+ 'x_ascend_dhcp_reply' => 'X-Ascend-DHCP-Reply',
+ 'acc_nbns_server_pri' => 'Acc-Nbns-Server-Pri',
+ 'post_auth_type' => 'Post-Auth-Type',
+ 'ascend_call_filter' => 'Ascend-Call-Filter',
+ 'acc_tunnel_secret' => 'Acc-Tunnel-Secret',
+ 'colubris_avpair' => 'Colubris-AVPair',
+ 'bind_int_context' => 'Bind-Int-Context',
+ 'annex_logical_channel_nu' => 'Annex-Logical-Channel-Number',
+ 'erx_virtual_router_name' => 'ERX-Virtual-Router-Name',
+ 'wispr_redirection_url' => 'WISPr-Redirection-URL',
+ 'bintec_ipextiftable' => 'BinTec-ipExtIfTable',
+ 'crypt_password' => 'Crypt-Password',
+ 'challenge_state' => 'Challenge-State',
+ 'x_ascend_pre_input_packe' => 'X-Ascend-Pre-Input-Packets',
+ 'altiga_ipsec_l2l_keepali' => 'Altiga-IPSec-L2L-Keepalives-G',
+ 'x_ascend_dhcp_maximum_le' => 'X-Ascend-DHCP-Maximum-Leases',
+ 'acc_dialout_auth_passwor' => 'Acc-Dialout-Auth-Password',
+ 'itk_ip_pool' => 'ITK-IP-Pool',
+ 'pvc_profile_namf' => 'PVC_Profile_Name',
+ 'x_ascend_user_acct_host' => 'X-Ascend-User-Acct-Host',
+ 'strip_user_name' => 'Strip-User-Name',
+ 'itk_ppp_client_server_mo' => 'ITK-PPP-Client-Server-Mode',
+ 'usr_mbi_ct_bchannel_used' => 'USR-Mbi_Ct_BChannel_Used',
+ 'x_ascend_route_ip' => 'X-Ascend-Route-IP',
+ 'ascend_seconds_of_histor' => 'Ascend-Seconds-Of-History',
+ 'cvx_data_rate' => 'CVX-Data-Rate',
+ 'ascend_x25_profile_name' => 'Ascend-X25-Profile-Name',
+ 'itk_ftp_auth_ip' => 'ITK-Ftp-Auth-IP',
+ 'cisco_control_info' => 'Cisco-Control-Info',
+ 'cvpn3000_secondary_wins' => 'CVPN3000-Secondary-WINS',
+ 'usr_call_type' => 'USR-Call-Type',
+ 'x_ascend_user_acct_base' => 'X-Ascend-User-Acct-Base',
+ 'acct_mcast_in_packett' => 'Acct_Mcast_In_Packets',
+ 'ns_vsys_name' => 'NS-VSYS-Name',
+ 'acct_output_gigawords' => 'Acct-Output-Gigawords',
+ 'bind_typf' => 'Bind_Type',
+ 'bintec_ipqostable' => 'BinTec-ipQoSTable',
+ 'bintec_ipxstaticservtabl' => 'BinTec-ipxStaticServTable',
+ 'cvpn3000_l2tp_mppc_compr' => 'CVPN3000-L2TP-MPPC-Compression',
+ 'login_lat_port' => 'Login-LAT-Port',
+ 'usr_call_arrival_in_gmt' => 'USR-Call-Arrival-in-GMT',
+ 'acct_mcast_in_octets' => 'Acct-Mcast-In-Octets',
+ 'erx_sa_validate' => 'ERX-Sa-Validate',
+ 'ascend_service_type' => 'Ascend-Service-Type',
+ 'usr_pw_vpn_gateway' => 'USR-PW_VPN_Gateway',
+ 'acc_ip_compression' => 'Acc-Ip-Compression',
+ 'ascend_fr_dce_n392' => 'Ascend-FR-DCE-N392',
+ 'bintec_ipxcirctable' => 'BinTec-ipxCircTable',
+ 'lac_real_port_type' => 'LAC-Real-Port-Type',
+ 'ascend_client_primary_dn' => 'Ascend-Client-Primary-DNS',
+ 'acct_session_start_time' => 'Acct-Session-Start-Time',
+ 'ascend_if_netmask' => 'Ascend-IF-Netmask',
+ 'ms_chap_nt_enc_pw' => 'MS-CHAP-NT-Enc-PW',
+ 'ms_mppe_encryption_types' => 'MS-MPPE-Encryption-Types',
+ 'cisco_fax_process_abort_' => 'Cisco-Fax-Process-Abort-Flag',
+ 'mcast_maxgroups' => 'Mcast-MaxGroups',
+ 'annex_end_receive_line_l' => 'Annex-End-Receive-Line-Level',
+ 'usr_ipx_call_input_filte' => 'USR-IPX-Call-Input-Filter',
+ 'usr_back_channel_data_ra' => 'USR-Back-Channel-Data-Rate',
+ 'ascend_cache_time' => 'Ascend-Cache-Time',
+ 'x_ascend_data_svc' => 'X-Ascend-Data-Svc',
+ 'usr_re_chap_timeout' => 'USR-Re-Chap-Timeout',
+ 'bintec_bibodialtable' => 'BinTec-biboDialTable',
+ 'annex_connect_progress' => 'Annex-Connect-Progress',
+ 'x_ascend_ppp_vj_1172' => 'X-Ascend-PPP-VJ-1172',
+ 'usr_igmp_routing' => 'USR-IGMP-Routing',
+ 'x_ascend_ip_pool_definit' => 'X-Ascend-IP-Pool-Definition',
+ 'h323_prompt_id' => 'h323-prompt-id',
+ 'foundry_command_string' => 'Foundry-Command-String',
+ 'le_terminate_detail' => 'LE-Terminate-Detail',
+ 'cvpn3000_pptp_encryption' => 'CVPN3000-PPTP-Encryption',
+ 'quintum_h323_disconnect_' => 'Quintum-h323-disconnect-time',
+ 'acc_ml_clear_threshold' => 'Acc-ML-Clear-Threshold',
+ 'x_ascend_ip_direct' => 'X-Ascend-IP-Direct',
+ 'usr_ip_call_input_filter' => 'USR-IP-Call-Input-Filter',
+ 'x_ascend_data_rate' => 'X-Ascend-Data-Rate',
+ 'nas_port' => 'NAS-Port',
+ 'ascend_client_secondary_' => 'Ascend-Client-Secondary-WINS',
+ 'ascend_auth_type' => 'Ascend-Auth-Type',
+ 'x_ascend_preempt_limit' => 'X-Ascend-Preempt-Limit',
+ 'cvx_xmit_rate' => 'CVX-Xmit-Rate',
+ 'annex_transmitted_packet' => 'Annex-Transmitted-Packets',
+ 'h323_credit_amount' => 'h323-credit-amount',
+ 'usr_reply_script1' => 'USR-Reply-Script1',
+ 'current_time' => 'Current-Time',
+ 'cisco_xmit_rate' => 'Cisco-Xmit-Rate',
+ 'x_ascend_session_svr_key' => 'X-Ascend-Session-Svr-Key',
+ 'ascend_authen_alias' => 'Ascend-Authen-Alias',
+ 'erx_redirect_vr_name' => 'ERX-Redirect-VR-Name',
+ 'module_success_message' => 'Module-Success-Message',
+ 'acc_dialout_auth_mode' => 'Acc-Dialout-Auth-Mode',
+ 'bind_auth_contexu' => 'Bind_Auth_Context',
+ 'x_ascend_minimum_channel' => 'X-Ascend-Minimum-Channels',
+ 'usr_event_date_time' => 'USR-Event-Date-Time',
+ 'x_ascend_ipx_node_addr' => 'X-Ascend-IPX-Node-Addr',
+ 'cvpn3000_ipsec_over_udp' => 'CVPN3000-IPSec-Over-UDP',
+ 'x_ascend_user_acct_time' => 'X-Ascend-User-Acct-Time',
+ 'cisco_email_server_ack_f' => 'Cisco-Email-Server-Ack-Flag',
+ 'telebit_activate_command' => 'Telebit-Activate-Command',
+ 'acc_output_errors' => 'Acc-Output-Errors',
+ 'juniper_allow_configurat' => 'Juniper-Allow-Configuration',
+ 'bind_l2tp_tunnel_name' => 'Bind-L2TP-Tunnel-Name',
+ 'x_ascend_pri_number_type' => 'X-Ascend-PRI-Number-Type',
+ 'bintec_biboppptable' => 'BinTec-biboPPPTable',
+ 'le_ipsec_outsource_profi' => 'LE-IPSec-Outsource-Profile',
+ 'usr_at_zip_input_filter' => 'USR-AT-Zip-Input-Filter',
+ 'replicate_to_realm' => 'Replicate-To-Realm',
+ 'annex_mrru' => 'Annex-MRRU',
+ 'event_timestamp' => 'Event-Timestamp',
+ 'nokia_sgsn_ip_address' => 'Nokia-SGSN-IP-Address',
+ 'ascend_pre_input_packets' => 'Ascend-Pre-Input-Packets',
+ 'cvpn5000_client_assigned' => 'CVPN5000-Client-Assigned-IP',
+ 'tunnel_dnit' => 'Tunnel_DNIS',
+ 'h323_call_origin' => 'h323-call-origin',
+ 'x_ascend_fr_type' => 'X-Ascend-FR-Type',
+ 'itk_provider_id' => 'ITK-Provider-Id',
+ 'cvx_ppp_log_mask' => 'CVX-PPP-Log-Mask',
+ 'x_ascend_token_idle' => 'X-Ascend-Token-Idle',
+ 'usr_rmmie_pwrlvl_xmit_lv' => 'USR-RMMIE-PwrLvl-Xmit-Lvl',
+ 'usr_igmp_query_interval' => 'USR-IGMP-Query-Interval',
+ 'quintum_h323_billing_mod' => 'Quintum-h323-billing-model',
+ 'ascend_atm_vci' => 'Ascend-ATM-Vci',
+ 'usr_port_tap_output' => 'USR-Port-Tap-Output',
+ 'session' => 'Session',
+ 'itk_welcome_message' => 'ITK-Welcome-Message',
+ 'cvpn3000_ike_keep_alives' => 'CVPN3000-IKE-Keep-Alives',
+ 'ascend_uu_info' => 'Ascend-UU-Info',
+ 'usr_et_bridge_call_outpu' => 'USR-ET-Bridge-Call-Output-Filte',
+ 'usr_secondary_dns_server' => 'USR-Secondary_DNS_Server',
+ 'ms_mppe_recv_key' => 'MS-MPPE-Recv-Key',
+ 'bintec_ripcirctable' => 'BinTec-ripCircTable',
+ 'acc_dial_port_index' => 'Acc-Dial-Port-Index',
+ 'cisco_nas_port' => 'Cisco-NAS-Port',
+ 'itk_username' => 'ITK-Username',
+ 'usr_send_script1' => 'USR-Send-Script1',
+ 'cvpn3000_ipsec_ike_peer_' => 'CVPN3000-IPSec-IKE-Peer-ID-Check',
+ 'ascend_dsl_upstream_limi' => 'Ascend-Dsl-Upstream-Limit',
+ 'x_ascend_dec_channel_cou' => 'X-Ascend-Dec-Channel-Count',
+ 'usr_tunnel_security' => 'USR-Tunnel-Security',
+ 'arap_security' => 'ARAP-Security',
+ 'tunnel_preference' => 'Tunnel-Preference',
+ 'cisco_port_used' => 'Cisco-Port-Used',
+ 'usr_reply_script4' => 'USR-Reply-Script4',
+ 'cvpn5000_client_real_ip' => 'CVPN5000-Client-Real-IP',
+ 'usr_rmmie_status' => 'USR-RMMIE-Status',
+ 'usr_send_script4' => 'USR-Send-Script4',
+ 'quintum_h323_connect_tim' => 'Quintum-h323-connect-time',
+ 'annex_syslog_tap' => 'Annex-Syslog-Tap',
+ 'redcreek_tunneled_hostna' => 'RedCreek-Tunneled-HostName',
+ 'acc_clearing_location' => 'Acc-Clearing-Location',
+ 'ascend_access_intercept_' => 'Ascend-Access-Intercept-LEA',
+ 'annex_disconnect_reason' => 'Annex-Disconnect-Reason',
+ 'usr_at_input_filter' => 'USR-AT-Input-Filter',
+ 'usr_auth_mode' => 'USR-Auth-Mode',
+ 'usr_expected_voltage' => 'USR-Expected-Voltage',
+ 'shiva_session_id' => 'Shiva-Session-Id',
+ 'annex_maximum_call_durat' => 'Annex-Maximum-Call-Duration',
+ 'usr_block_error_count_li' => 'USR-Block-Error-Count-Limit',
+ 'ascend_owner_ip_addr' => 'Ascend-Owner-IP-Addr',
+ 'bind_tun_contexu' => 'Bind_Tun_Context',
+ 'usr_pw_usr_ofilter_ipx' => 'USR-PW_USR_OFilter_IPX',
+ 'framed_routing' => 'Framed-Routing',
+ 'annex_primary_nbns_serve' => 'Annex-Primary-NBNS-Server',
+ 'usr_interface_index' => 'USR-Interface-Index',
+ 'pam_auth' => 'Pam-Auth',
+ 'usr_end_time' => 'USR-End-Time',
+ 'rate_limit_bursu' => 'Rate_Limit_Burst',
+ 'nomadix_expiration' => 'Nomadix-Expiration',
+ 'x_ascend_transit_number' => 'X-Ascend-Transit-Number',
+ 'itk_usergroup' => 'ITK-Usergroup',
+ 'x_ascend_assign_ip_pool' => 'X-Ascend-Assign-IP-Pool',
+ 'annex_secondary_nbns_ser' => 'Annex-Secondary-NBNS-Server',
+ 'bind_dot1q_vlan_tag_id' => 'Bind-Dot1q-Vlan-Tag-Id',
+ 'ms_secondary_nbns_server' => 'MS-Secondary-NBNS-Server',
+ 'tunnel_retransmit' => 'Tunnel-Retransmit',
+ 'acct_tunnel_connection' => 'Acct-Tunnel-Connection',
+ 'x_ascend_backup' => 'X-Ascend-Backup',
+ 'xedia_ppp_echo_interval' => 'Xedia-PPP-Echo-Interval',
+ 'usr_bearer_capabilities' => 'USR-Bearer-Capabilities',
+ 'shiva_acct_serv_switch' => 'Shiva-Acct-Serv-Switch',
+ 'acct_authentic' => 'Acct-Authentic',
+ 'le_nat_other_session_tim' => 'LE-NAT-Other-Session-Timeout',
+ 'cvpn3000_ipsec_banner2' => 'CVPN3000-IPSec-Banner2',
+ 'x_ascend_force_56' => 'X-Ascend-Force-56',
+ 'framed_appletalk_network' => 'Framed-AppleTalk-Network',
+ 'reply_message' => 'Reply-Message',
+ 'class' => 'Class',
+ 'h323_conf_id' => 'h323-conf-id',
+ 'quintum_h323_disconnecta' => 'Quintum-h323-disconnect-cause',
+ 'itk_filter_rule' => 'ITK-Filter-Rule',
+ 'wispr_bandwidth_max_up' => 'WISPr-Bandwidth-Max-Up',
+ 'usr_appletalk_network_ra' => 'USR-Appletalk-Network-Range',
+ 'ascend_cbcp_delay' => 'Ascend-CBCP-Delay',
+ 'usr_dte_ring_no_answer_l' => 'USR-DTE-Ring-No-Answer-Limit',
+ 'pre_acct_type' => 'Pre-Acct-Type',
+ 'usr_local_ip_address' => 'USR-Local-IP-Address',
+ 'ascend_dropped_octets' => 'Ascend-Dropped-Octets',
+ 'ascend_h323_dialed_time' => 'Ascend-H323-Dialed-Time',
+ 'cisco_email_server_addre' => 'Cisco-Email-Server-Address',
+ 'ascend_x25_x121_address' => 'Ascend-X25-X121-Address',
+ 'cvx_multicast_client' => 'CVX-Multicast-Client',
+ 'wispr_bandwidth_min_up' => 'WISPr-Bandwidth-Min-Up',
+ 'usr_at_output_filter' => 'USR-AT-Output-Filter',
+ 'annex_local_ip_address' => 'Annex-Local-IP-Address',
+ 'cisco_ip_pool_definition' => 'Cisco-IP-Pool-Definition',
+ 'cisco_gateway_id' => 'Cisco-Gateway-Id',
+ 'itk_password_prompt' => 'ITK-Password-Prompt',
+ 'annex_domain_name' => 'Annex-Domain-Name',
+ 'foundry_command_exceptio' => 'Foundry-Command-Exception-Flag',
+ 'ascend_preempt_limit' => 'Ascend-Preempt-Limit',
+ 'erx_minimum_bps' => 'ERX-Minimum-BPS',
+ 'aat_mcast_client' => 'AAT-MCast-Client',
+ 'ascend_atm_fault_managem' => 'Ascend-ATM-Fault-Management',
+ 'ascend_event_type' => 'Ascend-Event-Type',
+ 'exec_program_wait' => 'Exec-Program-Wait',
+ 'framed_interface_id' => 'Framed-Interface-Id',
+
+ #NETC.NET.AU (RADIATOR?)
+ 'authentication_type' => 'Authentication-Type',
+
+);
+
+1;
diff --git a/FS/FS/radius_usergroup.pm b/FS/FS/radius_usergroup.pm
new file mode 100644
index 0000000..9bba057
--- /dev/null
+++ b/FS/FS/radius_usergroup.pm
@@ -0,0 +1,131 @@
+package FS::radius_usergroup;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+use FS::svc_acct;
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::radius_usergroup - Object methods for radius_usergroup records
+
+=head1 SYNOPSIS
+
+ use FS::radius_usergroup;
+
+ $record = new FS::radius_usergroup \%hash;
+ $record = new FS::radius_usergroup { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::radius_usergroup object links an account (see L<FS::svc_acct>) with a
+RADIUS group. FS::radius_usergroup inherits from FS::Record. The following
+fields are currently supported:
+
+=over 4
+
+=item usergroupnum - primary key
+
+=item svcnum - Account (see L<FS::svc_acct>).
+
+=item groupname - group name
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record. To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'radius_usergroup'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+#inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+#inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+#inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('usergroupnum')
+ || $self->ut_number('svcnum')
+ || $self->ut_foreign_key('svcnum','svc_acct','svcnum')
+ || $self->ut_text('groupname')
+ || $self->SUPER::check
+ ;
+}
+
+=item svc_acct
+
+Returns the account associated with this record (see L<FS::svc_acct>).
+
+=cut
+
+sub svc_acct {
+ my $self = shift;
+ qsearchs('svc_acct', { svcnum => $self->svcnum } );
+}
+
+=back
+
+=head1 BUGS
+
+Don't let 'em get you down.
+
+=head1 SEE ALSO
+
+L<svc_acct>, L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/router.pm b/FS/FS/router.pm
new file mode 100755
index 0000000..2554ce8
--- /dev/null
+++ b/FS/FS/router.pm
@@ -0,0 +1,144 @@
+package FS::router;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs qsearch );
+use FS::addr_block;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::router - Object methods for router records
+
+=head1 SYNOPSIS
+
+ use FS::router;
+
+ $record = new FS::router \%hash;
+ $record = new FS::router { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::router record describes a broadband router, such as a DSLAM or a wireless
+ access point. FS::router inherits from FS::Record. The following
+fields are currently supported:
+
+=over 4
+
+=item routernum - primary key
+
+=item routername - descriptive name for the router
+
+=item svcnum - svcnum of the owning FS::svc_broadband, if appropriate
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see "insert".
+
+=cut
+
+sub table { 'router'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('routernum')
+ || $self->ut_text('routername');
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=item addr_block
+
+Returns a list of FS::addr_block objects (address blocks) associated
+with this object.
+
+=cut
+
+sub addr_block {
+ my $self = shift;
+ return qsearch('addr_block', { routernum => $self->routernum });
+}
+
+=item part_svc_router
+
+Returns a list of FS::part_svc_router objects associated with this
+object. This is unlikely to be useful for any purpose other than retrieving
+the associated FS::part_svc objects. See below.
+
+=cut
+
+sub part_svc_router {
+ my $self = shift;
+ return qsearch('part_svc_router', { routernum => $self->routernum });
+}
+
+=item part_svc
+
+Returns a list of FS::part_svc objects associated with this object.
+
+=cut
+
+sub part_svc {
+ my $self = shift;
+ return map { qsearchs('part_svc', { svcpart => $_->svcpart }) }
+ $self->part_svc_router;
+}
+
+=back
+
+=head1 VERSION
+
+$Id:
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+FS::svc_broadband, FS::router, FS::addr_block, FS::part_svc,
+schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/session.pm b/FS/FS/session.pm
new file mode 100644
index 0000000..2ad594c
--- /dev/null
+++ b/FS/FS/session.pm
@@ -0,0 +1,269 @@
+package FS::session;
+
+use strict;
+use vars qw( @ISA $conf $start $stop );
+use FS::UID qw( dbh );
+use FS::Record qw( qsearchs );
+use FS::svc_acct;
+use FS::port;
+use FS::nas;
+
+@ISA = qw(FS::Record);
+
+$FS::UID::callback{'FS::session'} = sub {
+ $conf = new FS::Conf;
+ $start = $conf->exists('session-start') ? $conf->config('session-start') : '';
+ $stop = $conf->exists('session-stop') ? $conf->config('session-stop') : '';
+};
+
+=head1 NAME
+
+FS::session - Object methods for session records
+
+=head1 SYNOPSIS
+
+ use FS::session;
+
+ $record = new FS::session \%hash;
+ $record = new FS::session {
+ 'portnum' => 1,
+ 'svcnum' => 2,
+ 'login' => $timestamp,
+ 'logout' => $timestamp,
+ };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->nas_heartbeat($timestamp);
+
+=head1 DESCRIPTION
+
+An FS::session object represents an user login session. FS::session inherits
+from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item sessionnum - primary key
+
+=item portnum - NAS port for this session - see L<FS::port>
+
+=item svcnum - User for this session - see L<FS::svc_acct>
+
+=item login - timestamp indicating the beginning of this user session.
+
+=item logout - timestamp indicating the end of this user session. May be null,
+ which indicates a currently open session.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new session. To add the session to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'session'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false. If the `login' field is empty, it is replaced with
+the current time.
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ $error = $self->check;
+ return $error if $error;
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ if ( qsearchs('session', { 'portnum' => $self->portnum, 'logout' => '' } ) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "a session on that port is already open!";
+ }
+
+ $self->setfield('login', time()) unless $self->getfield('login');
+
+ $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $self->nas_heartbeat($self->getfield('login'));
+
+ #session-starting callback
+ #redundant with heartbeat, yuck
+ my $port = qsearchs('port',{'portnum'=>$self->portnum});
+ my $nas = qsearchs('nas',{'nasnum'=>$port->nasnum});
+ #kcuy
+ my( $ip, $nasip, $nasfqdn ) = ( $port->ip, $nas->nasip, $nas->nasfqdn );
+ system( eval qq("$start") ) if $start;
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false. If the `logout' field is empty,
+it is replaced with the current time.
+
+=cut
+
+sub replace {
+ my($self, $old) = @_;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ $error = $self->check;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $self->setfield('logout', time()) unless $self->getfield('logout');
+
+ $error = $self->SUPER::replace($old);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $self->nas_heartbeat($self->getfield('logout'));
+
+ #session-ending callback
+ #redundant with heartbeat, yuck
+ my $port = qsearchs('port',{'portnum'=>$self->portnum});
+ my $nas = qsearchs('nas',{'nasnum'=>$port->nasnum});
+ #kcuy
+ my( $ip, $nasip, $nasfqdn ) = ( $port->ip, $nas->nasip, $nas->nasfqdn );
+ system( eval qq("$stop") ) if $stop;
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+}
+
+=item check
+
+Checks all fields to make sure this is a valid session. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+ my $error =
+ $self->ut_numbern('sessionnum')
+ || $self->ut_number('portnum')
+ || $self->ut_number('svcnum')
+ || $self->ut_numbern('login')
+ || $self->ut_numbern('logout')
+ ;
+ return $error if $error;
+ return "Unknown svcnum"
+ unless qsearchs('svc_acct', { 'svcnum' => $self->svcnum } );
+ $self->SUPER::check;
+}
+
+=item nas_heartbeat
+
+Heartbeats the nas associated with this session (see L<FS::nas>).
+
+=cut
+
+sub nas_heartbeat {
+ my $self = shift;
+ my $port = qsearchs('port',{'portnum'=>$self->portnum});
+ my $nas = qsearchs('nas',{'nasnum'=>$port->nasnum});
+ $nas->heartbeat(shift);
+}
+
+=item svc_acct
+
+Returns the svc_acct record associated with this session (see L<FS::svc_acct>).
+
+=cut
+
+sub svc_acct {
+ my $self = shift;
+ qsearchs('svc_acct', { 'svcnum' => $self->svcnum } );
+}
+
+=back
+
+=head1 VERSION
+
+$Id: session.pm,v 1.8 2003-08-05 00:20:46 khoff Exp $
+
+=head1 BUGS
+
+Maybe you shouldn't be able to insert a session if there's currently an open
+session on that port. Or maybe the open session on that port should be flagged
+as problematic? autoclosed? *sigh*
+
+Hmm, sessions refer to current svc_acct records... probably need to constrain
+deletions to svc_acct records such that no svc_acct records are deleted which
+have a session (even if long-closed).
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm
new file mode 100644
index 0000000..a223266
--- /dev/null
+++ b/FS/FS/svc_Common.pm
@@ -0,0 +1,515 @@
+package FS::svc_Common;
+
+use strict;
+use vars qw( @ISA $noexport_hack $DEBUG );
+use FS::Record qw( qsearch qsearchs fields dbh );
+use FS::cust_svc;
+use FS::part_svc;
+use FS::queue;
+
+@ISA = qw( FS::Record );
+
+$DEBUG = 0;
+#$DEBUG = 1;
+
+=head1 NAME
+
+FS::svc_Common - Object method for all svc_ records
+
+=head1 SYNOPSIS
+
+use FS::svc_Common;
+
+@ISA = qw( FS::svc_Common );
+
+=head1 DESCRIPTION
+
+FS::svc_Common is intended as a base class for table-specific classes to
+inherit from, i.e. FS::svc_acct. FS::svc_Common inherits from FS::Record.
+
+=head1 METHODS
+
+=over 4
+
+=cut
+
+sub virtual_fields {
+
+ # This restricts the fields based on part_svc_column and the svcpart of
+ # the service. There are four possible cases:
+ # 1. svcpart passed as part of the svc_x hash.
+ # 2. svcpart fetched via cust_svc based on svcnum.
+ # 3. No svcnum or svcpart. In this case, return ALL the fields with
+ # dbtable eq $self->table.
+ # 4. Called via "fields('svc_acct')" or something similar. In this case
+ # there is no $self object.
+
+ my $self = shift;
+ my $svcpart;
+ my @vfields = $self->SUPER::virtual_fields;
+
+ return @vfields unless (ref $self); # Case 4
+
+ if ($self->svcpart) { # Case 1
+ $svcpart = $self->svcpart;
+ } elsif ( $self->svcnum
+ && qsearchs('cust_svc',{'svcnum'=>$self->svcnum} )
+ ) { #Case 2
+ $svcpart = $self->cust_svc->svcpart;
+ } else { # Case 3
+ $svcpart = '';
+ }
+
+ if ($svcpart) { #Cases 1 and 2
+ my %flags = map { $_->columnname, $_->columnflag } (
+ qsearch ('part_svc_column', { svcpart => $svcpart } )
+ );
+ return grep { not ($flags{$_} eq 'X') } @vfields;
+ } else { # Case 3
+ return @vfields;
+ }
+ return ();
+}
+
+=item check
+
+Checks the validity of fields in this record.
+
+At present, this does nothing but call FS::Record::check (which, in turn,
+does nothing but run virtual field checks).
+
+=cut
+
+sub check {
+ my $self = shift;
+ $self->SUPER::check;
+}
+
+=item insert [ , OPTION => VALUE ... ]
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+Currently available options are: I<jobnums>, I<child_objects> and
+I<depend_jobnum>.
+
+If I<jobnum> is set to an array reference, the jobnums of any export jobs will
+be added to the referenced array.
+
+If I<child_objects> is set to an array reference of FS::tablename objects (for
+example, FS::acct_snarf objects), they will have their svcnum fieldsset and
+will be inserted after this record, but before any exports are run.
+
+If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
+jobnums), all provisioning jobs will have a dependancy on the supplied
+jobnum(s) (they will not run until the specific job(s) complete(s)).
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my %options = @_;
+ warn "FS::svc_Common::insert called with options ".
+ join(', ', map { "$_: $options{$_}" } keys %options ). "\n"
+ if $DEBUG;
+
+ my @jobnums = ();
+ local $FS::queue::jobnums = \@jobnums;
+ warn "FS::svc_Common::insert: set \$FS::queue::jobnums to $FS::queue::jobnums"
+ if $DEBUG;
+ my $objects = $options{'child_objects'} || [];
+ my $depend_jobnums = $options{'depend_jobnum'} || [];
+ $depend_jobnums = [ $depend_jobnums ] unless ref($depend_jobnums);
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ $error = $self->check;
+ return $error if $error;
+
+ my $svcnum = $self->svcnum;
+ my $cust_svc = $svcnum ? qsearchs('cust_svc',{'svcnum'=>$self->svcnum}) : '';
+ #unless ( $svcnum ) {
+ if ( !$svcnum or !$cust_svc ) {
+ $cust_svc = new FS::cust_svc ( {
+ #hua?# 'svcnum' => $svcnum,
+ 'svcnum' => $self->svcnum,
+ 'pkgnum' => $self->pkgnum,
+ 'svcpart' => $self->svcpart,
+ } );
+ $error = $cust_svc->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ $svcnum = $self->svcnum($cust_svc->svcnum);
+ } else {
+ #$cust_svc = qsearchs('cust_svc',{'svcnum'=>$self->svcnum});
+ unless ( $cust_svc ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "no cust_svc record found for svcnum ". $self->svcnum;
+ }
+ $self->pkgnum($cust_svc->pkgnum);
+ $self->svcpart($cust_svc->svcpart);
+ }
+
+ $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ foreach my $object ( @$objects ) {
+ $object->svcnum($self->svcnum);
+ $error = $object->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ #new-style exports!
+ unless ( $noexport_hack ) {
+
+ warn "FS::svc_Common::insert: \$FS::queue::jobnums is $FS::queue::jobnums"
+ if $DEBUG;
+
+ foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
+ my $error = $part_export->export_insert($self);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "exporting to ". $part_export->exporttype.
+ " (transaction rolled back): $error";
+ }
+ }
+
+ foreach my $depend_jobnum ( @$depend_jobnums ) {
+ warn "inserting dependancies on supplied job $depend_jobnum\n"
+ if $DEBUG;
+ foreach my $jobnum ( @jobnums ) {
+ my $queue = qsearchs('queue', { 'jobnum' => $jobnum } );
+ warn "inserting dependancy for job $jobnum on $depend_jobnum\n"
+ if $DEBUG;
+ my $error = $queue->depend_insert($depend_jobnum);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error queuing job dependancy: $error";
+ }
+ }
+ }
+
+ }
+
+ if ( exists $options{'jobnums'} ) {
+ push @{ $options{'jobnums'} }, @jobnums;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+}
+
+=item delete
+
+Deletes this account from the database. If there is an error, returns the
+error, otherwise returns false.
+
+The corresponding FS::cust_svc record will be deleted as well.
+
+=cut
+
+sub delete {
+ my $self = shift;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $svcnum = $self->svcnum;
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ $error = $self->SUPER::delete;
+ return $error if $error;
+
+ #new-style exports!
+ unless ( $noexport_hack ) {
+ foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
+ my $error = $part_export->export_delete($self);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "exporting to ". $part_export->exporttype.
+ " (transaction rolled back): $error";
+ }
+ }
+ }
+
+ return $error if $error;
+
+ my $cust_svc = $self->cust_svc;
+ $error = $cust_svc->delete;
+ return $error if $error;
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ '';
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub replace {
+ my ($new, $old) = (shift, shift);
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $new->SUPER::replace($old);
+ if ($error) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ #new-style exports!
+ unless ( $noexport_hack ) {
+ foreach my $part_export ( $new->cust_svc->part_svc->part_export ) {
+ my $error = $part_export->export_replace($new,$old);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error exporting to ". $part_export->exporttype.
+ " (transaction rolled back): $error";
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+}
+
+
+=item setfixed
+
+Sets any fixed fields for this service (see L<FS::part_svc>). If there is an
+error, returns the error, otherwise returns the FS::part_svc object (use ref()
+to test the return). Usually called by the check method.
+
+=cut
+
+sub setfixed {
+ my $self = shift;
+ $self->setx('F');
+}
+
+=item setdefault
+
+Sets all fields to their defaults (see L<FS::part_svc>), overriding their
+current values. If there is an error, returns the error, otherwise returns
+the FS::part_svc object (use ref() to test the return).
+
+=cut
+
+sub setdefault {
+ my $self = shift;
+ $self->setx('D');
+}
+
+sub setx {
+ my $self = shift;
+ my $x = shift;
+
+ my $error;
+
+ $error =
+ $self->ut_numbern('svcnum')
+ ;
+ return $error if $error;
+
+ #get part_svc
+ my $svcpart;
+ if ( $self->svcnum && qsearchs('cust_svc', {'svcnum'=>$self->svcnum}) ) {
+ my $cust_svc = $self->cust_svc;
+ return "Unknown svcnum" unless $cust_svc;
+ $svcpart = $cust_svc->svcpart;
+ } else {
+ $svcpart = $self->getfield('svcpart');
+ }
+ my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } );
+ return "Unkonwn svcpart" unless $part_svc;
+
+ #set default/fixed/whatever fields from part_svc
+ my $table = $self->table;
+ foreach my $field ( grep { $_ ne 'svcnum' } $self->fields ) {
+ my $part_svc_column = $part_svc->part_svc_column($field);
+ if ( $part_svc_column->columnflag eq $x ) {
+ $self->setfield( $field, $part_svc_column->columnvalue );
+ }
+ }
+
+ $part_svc;
+
+}
+
+=item cust_svc
+
+Returns the cust_svc record associated with this svc_ record, as a FS::cust_svc
+object (see L<FS::cust_svc>).
+
+=cut
+
+sub cust_svc {
+ my $self = shift;
+ qsearchs('cust_svc', { 'svcnum' => $self->svcnum } );
+}
+
+=item suspend
+
+Runs export_suspend callbacks.
+
+=cut
+
+sub suspend {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ #new-style exports!
+ unless ( $noexport_hack ) {
+ foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
+ my $error = $part_export->export_suspend($self);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error exporting to ". $part_export->exporttype.
+ " (transaction rolled back): $error";
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item unsuspend
+
+Runs export_unsuspend callbacks.
+
+=cut
+
+sub unsuspend {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ #new-style exports!
+ unless ( $noexport_hack ) {
+ foreach my $part_export ( $self->cust_svc->part_svc->part_export ) {
+ my $error = $part_export->export_unsuspend($self);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error exporting to ". $part_export->exporttype.
+ " (transaction rolled back): $error";
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item cancel
+
+Stub - returns false (no error) so derived classes don't need to define these
+methods. Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=cut
+
+sub cancel { ''; }
+
+=item clone_suspended
+
+Constructor used by FS::part_export::_export_suspend fallback. Stub returning
+same object for svc_ classes which don't implement a suspension fallback
+(everything except svc_acct at the moment). Document better.
+
+=cut
+
+sub clone_suspended {
+ shift;
+}
+
+=item clone_kludge_unsuspend
+
+Constructor used by FS::part_export::_export_unsuspend fallback. Stub returning
+same object for svc_ classes which don't implement a suspension fallback
+(everything except svc_acct at the moment). Document better.
+
+=cut
+
+sub clone_kludge_unsuspend {
+ shift;
+}
+
+=back
+
+=head1 BUGS
+
+The setfixed method return value.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>, schema.html
+from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm
new file mode 100644
index 0000000..f66c715
--- /dev/null
+++ b/FS/FS/svc_acct.pm
@@ -0,0 +1,1415 @@
+package FS::svc_acct;
+
+use strict;
+use vars qw( @ISA $DEBUG $me $conf
+ $dir_prefix @shells $usernamemin
+ $usernamemax $passwordmin $passwordmax
+ $username_ampersand $username_letter $username_letterfirst
+ $username_noperiod $username_nounderscore $username_nodash
+ $username_uppercase
+ $welcome_template $welcome_from $welcome_subject $welcome_mimetype
+ $smtpmachine
+ $radius_password $radius_ip
+ $dirhash
+ @saltset @pw_set );
+use Carp;
+use Fcntl qw(:flock);
+use Crypt::PasswdMD5;
+use FS::UID qw( datasrc );
+use FS::Conf;
+use FS::Record qw( qsearch qsearchs fields dbh dbdef );
+use FS::svc_Common;
+use FS::cust_svc;
+use FS::part_svc;
+use FS::svc_acct_pop;
+use FS::cust_main_invoice;
+use FS::svc_domain;
+use FS::raddb;
+use FS::queue;
+use FS::radius_usergroup;
+use FS::export_svc;
+use FS::part_export;
+use FS::Msgcat qw(gettext);
+use FS::svc_forward;
+use FS::svc_www;
+
+@ISA = qw( FS::svc_Common );
+
+$DEBUG = 0;
+#$DEBUG = 1;
+$me = '[FS::svc_acct]';
+
+#ask FS::UID to run this stuff for us later
+$FS::UID::callback{'FS::svc_acct'} = sub {
+ $conf = new FS::Conf;
+ $dir_prefix = $conf->config('home');
+ @shells = $conf->config('shells');
+ $usernamemin = $conf->config('usernamemin') || 2;
+ $usernamemax = $conf->config('usernamemax');
+ $passwordmin = $conf->config('passwordmin') || 6;
+ $passwordmax = $conf->config('passwordmax') || 8;
+ $username_letter = $conf->exists('username-letter');
+ $username_letterfirst = $conf->exists('username-letterfirst');
+ $username_noperiod = $conf->exists('username-noperiod');
+ $username_nounderscore = $conf->exists('username-nounderscore');
+ $username_nodash = $conf->exists('username-nodash');
+ $username_uppercase = $conf->exists('username-uppercase');
+ $username_ampersand = $conf->exists('username-ampersand');
+ $dirhash = $conf->config('dirhash') || 0;
+ if ( $conf->exists('welcome_email') ) {
+ $welcome_template = new Text::Template (
+ TYPE => 'ARRAY',
+ SOURCE => [ map "$_\n", $conf->config('welcome_email') ]
+ ) or warn "can't create welcome email template: $Text::Template::ERROR";
+ $welcome_from = $conf->config('welcome_email-from'); # || 'your-isp-is-dum'
+ $welcome_subject = $conf->config('welcome_email-subject') || 'Welcome';
+ $welcome_mimetype = $conf->config('welcome_email-mimetype') || 'text/plain';
+ } else {
+ $welcome_template = '';
+ $welcome_from = '';
+ $welcome_subject = '';
+ $welcome_mimetype = '';
+ }
+ $smtpmachine = $conf->config('smtpmachine');
+ $radius_password = $conf->config('radius-password') || 'Password';
+ $radius_ip = $conf->config('radius-ip') || 'Framed-IP-Address';
+};
+
+@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+@pw_set = ( 'a'..'z', 'A'..'Z', '0'..'9', '(', ')', '#', '!', '.', ',' );
+
+sub _cache {
+ my $self = shift;
+ my ( $hashref, $cache ) = @_;
+ if ( $hashref->{'svc_acct_svcnum'} ) {
+ $self->{'_domsvc'} = FS::svc_domain->new( {
+ 'svcnum' => $hashref->{'domsvc'},
+ 'domain' => $hashref->{'svc_acct_domain'},
+ 'catchall' => $hashref->{'svc_acct_catchall'},
+ } );
+ }
+}
+
+=head1 NAME
+
+FS::svc_acct - Object methods for svc_acct records
+
+=head1 SYNOPSIS
+
+ use FS::svc_acct;
+
+ $record = new FS::svc_acct \%hash;
+ $record = new FS::svc_acct { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $error = $record->cancel;
+
+ %hash = $record->radius;
+
+ %hash = $record->radius_reply;
+
+ %hash = $record->radius_check;
+
+ $domain = $record->domain;
+
+ $svc_domain = $record->svc_domain;
+
+ $email = $record->email;
+
+ $seconds_since = $record->seconds_since($timestamp);
+
+=head1 DESCRIPTION
+
+An FS::svc_acct object represents an account. FS::svc_acct inherits from
+FS::svc_Common. The following fields are currently supported:
+
+=over 4
+
+=item svcnum - primary key (assigned automatcially for new accounts)
+
+=item username
+
+=item _password - generated if blank
+
+=item sec_phrase - security phrase
+
+=item popnum - Point of presence (see L<FS::svc_acct_pop>)
+
+=item uid
+
+=item gid
+
+=item finger - GECOS
+
+=item dir - set automatically if blank (and uid is not)
+
+=item shell
+
+=item quota - (unimplementd)
+
+=item slipip - IP address
+
+=item seconds -
+
+=item domsvc - svcnum from svc_domain
+
+=item radius_I<Radius_Attribute> - I<Radius-Attribute>
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new account. To add the account to the database, see L<"insert">.
+
+=cut
+
+sub table { 'svc_acct'; }
+
+=item insert [ , OPTION => VALUE ... ]
+
+Adds this account to the database. If there is an error, returns the error,
+otherwise returns false.
+
+The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+The additional field I<usergroup> can optionally be defined; if so it should
+contain an arrayref of group names. See L<FS::radius_usergroup>.
+
+The additional field I<child_objects> can optionally be defined; if so it
+should contain an arrayref of FS::tablename objects. They will have their
+svcnum fields set and will be inserted after this record, but before any
+exports are run.
+
+Currently available options are: I<depend_jobnum>
+
+If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
+jobnums), all provisioning jobs will have a dependancy on the supplied
+jobnum(s) (they will not run until the specific job(s) complete(s)).
+
+(TODOC: L<FS::queue> and L<freeside-queued>)
+
+(TODOC: new exports!)
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my %options = @_;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ $error = $self->check;
+ return $error if $error;
+
+ #no, duplicate checking just got a whole lot more complicated
+ #(perhaps keep this check with a config option to turn on?)
+
+ #return gettext('username_in_use'). ": ". $self->username
+ # if qsearchs( 'svc_acct', { 'username' => $self->username,
+ # 'domsvc' => $self->domsvc,
+ # } );
+
+ if ( $self->svcnum && qsearchs('cust_svc',{'svcnum'=>$self->svcnum}) ) {
+ my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$self->svcnum});
+ unless ( $cust_svc ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "no cust_svc record found for svcnum ". $self->svcnum;
+ }
+ $self->pkgnum($cust_svc->pkgnum);
+ $self->svcpart($cust_svc->svcpart);
+ }
+
+ #new duplicate username checking
+
+ my $part_svc = qsearchs('part_svc', { 'svcpart' => $self->svcpart } );
+ unless ( $part_svc ) {
+ $dbh->rollback if $oldAutoCommit;
+ return 'unknown svcpart '. $self->svcpart;
+ }
+
+ my @dup_user = qsearch( 'svc_acct', { 'username' => $self->username } );
+ my @dup_userdomain = qsearch( 'svc_acct', { 'username' => $self->username,
+ 'domsvc' => $self->domsvc } );
+ my @dup_uid;
+ if ( $part_svc->part_svc_column('uid')->columnflag ne 'F'
+ && $self->username !~ /^(toor|(hyla)?fax)$/ ) {
+ @dup_uid = qsearch( 'svc_acct', { 'uid' => $self->uid } );
+ } else {
+ @dup_uid = ();
+ }
+
+ if ( @dup_user || @dup_userdomain || @dup_uid ) {
+ my $exports = FS::part_export::export_info('svc_acct');
+ my %conflict_user_svcpart;
+ my %conflict_userdomain_svcpart = ( $self->svcpart => 'SELF', );
+
+ foreach my $part_export ( $part_svc->part_export ) {
+
+ #this will catch to the same exact export
+ my @svcparts = map { $_->svcpart }
+ qsearch('export_svc', { 'exportnum' => $part_export->exportnum });
+
+ #this will catch to exports w/same exporthost+type ???
+ #my @other_part_export = qsearch('part_export', {
+ # 'machine' => $part_export->machine,
+ # 'exporttype' => $part_export->exporttype,
+ #} );
+ #foreach my $other_part_export ( @other_part_export ) {
+ # push @svcparts, map { $_->svcpart }
+ # qsearch('export_svc', { 'exportnum' => $part_export->exportnum });
+ #}
+
+ #my $nodomain = $exports->{$part_export->exporttype}{'nodomain'};
+ #silly kludge to avoid uninitialized value errors
+ my $nodomain = exists( $exports->{$part_export->exporttype}{'nodomain'} )
+ ? $exports->{$part_export->exporttype}{'nodomain'}
+ : '';
+ if ( $nodomain =~ /^Y/i ) {
+ $conflict_user_svcpart{$_} = $part_export->exportnum
+ foreach @svcparts;
+ } else {
+ $conflict_userdomain_svcpart{$_} = $part_export->exportnum
+ foreach @svcparts;
+ }
+ }
+
+ foreach my $dup_user ( @dup_user ) {
+ my $dup_svcpart = $dup_user->cust_svc->svcpart;
+ if ( exists($conflict_user_svcpart{$dup_svcpart}) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "duplicate username: conflicts with svcnum ". $dup_user->svcnum.
+ " via exportnum ". $conflict_user_svcpart{$dup_svcpart};
+ }
+ }
+
+ foreach my $dup_userdomain ( @dup_userdomain ) {
+ my $dup_svcpart = $dup_userdomain->cust_svc->svcpart;
+ if ( exists($conflict_userdomain_svcpart{$dup_svcpart}) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "duplicate username\@domain: conflicts with svcnum ".
+ $dup_userdomain->svcnum. " via exportnum ".
+ $conflict_userdomain_svcpart{$dup_svcpart};
+ }
+ }
+
+ foreach my $dup_uid ( @dup_uid ) {
+ my $dup_svcpart = $dup_uid->cust_svc->svcpart;
+ if ( exists($conflict_user_svcpart{$dup_svcpart})
+ || exists($conflict_userdomain_svcpart{$dup_svcpart}) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "duplicate uid: conflicts with svcnum". $dup_uid->svcnum.
+ "via exportnum ". $conflict_user_svcpart{$dup_svcpart}
+ || $conflict_userdomain_svcpart{$dup_svcpart};
+ }
+ }
+
+ }
+
+ #see? i told you it was more complicated
+
+ my @jobnums;
+ $error = $self->SUPER::insert(
+ 'jobnums' => \@jobnums,
+ 'child_objects' => $self->child_objects,
+ %options,
+ );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ if ( $self->usergroup ) {
+ foreach my $groupname ( @{$self->usergroup} ) {
+ my $radius_usergroup = new FS::radius_usergroup ( {
+ svcnum => $self->svcnum,
+ groupname => $groupname,
+ } );
+ my $error = $radius_usergroup->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+ }
+
+ #false laziness with sub replace (and cust_main)
+ my $queue = new FS::queue {
+ 'svcnum' => $self->svcnum,
+ 'job' => 'FS::svc_acct::append_fuzzyfiles'
+ };
+ $error = $queue->insert($self->username);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "queueing job (transaction rolled back): $error";
+ }
+
+ my $cust_pkg = $self->cust_svc->cust_pkg;
+
+ if ( $cust_pkg ) {
+ my $cust_main = $cust_pkg->cust_main;
+
+ if ( $conf->exists('emailinvoiceauto') ) {
+ my @invoicing_list = $cust_main->invoicing_list;
+ push @invoicing_list, $self->email;
+ $cust_main->invoicing_list(\@invoicing_list);
+ }
+
+ #welcome email
+ my $to = '';
+ if ( $welcome_template && $cust_pkg ) {
+ my $to = join(', ', grep { $_ ne 'POST' } $cust_main->invoicing_list );
+ if ( $to ) {
+ my $wqueue = new FS::queue {
+ 'svcnum' => $self->svcnum,
+ 'job' => 'FS::svc_acct::send_email'
+ };
+ my $error = $wqueue->insert(
+ 'to' => $to,
+ 'from' => $welcome_from,
+ 'subject' => $welcome_subject,
+ 'mimetype' => $welcome_mimetype,
+ 'body' => $welcome_template->fill_in( HASH => {
+ 'custnum' => $self->custnum,
+ 'username' => $self->username,
+ 'password' => $self->_password,
+ 'first' => $cust_main->first,
+ 'last' => $cust_main->getfield('last'),
+ 'pkg' => $cust_pkg->part_pkg->pkg,
+ } ),
+ );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error queuing welcome email: $error";
+ }
+
+ if ( $options{'depend_jobnum'} ) {
+ warn "$me depend_jobnum found; adding to welcome email dependancies"
+ if $DEBUG;
+ if ( ref($options{'depend_jobnum'}) ) {
+ warn "$me adding jobs ". join(', ', @{$options{'depend_jobnum'}} ).
+ "to welcome email dependancies"
+ if $DEBUG;
+ push @jobnums, @{ $options{'depend_jobnum'} };
+ } else {
+ warn "$me adding job $options{'depend_jobnum'} ".
+ "to welcome email dependancies"
+ if $DEBUG;
+ push @jobnums, $options{'depend_jobnum'};
+ }
+ }
+
+ foreach my $jobnum ( @jobnums ) {
+ my $error = $wqueue->depend_insert($jobnum);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error queuing welcome email job dependancy: $error";
+ }
+ }
+
+ }
+
+ }
+
+ } # if ( $cust_pkg )
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ ''; #no error
+}
+
+=item delete
+
+Deletes this account from the database. If there is an error, returns the
+error, otherwise returns false.
+
+The corresponding FS::cust_svc record will be deleted as well.
+
+(TODOC: new exports!)
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ return "can't delete system account" if $self->_check_system;
+
+ return "Can't delete an account which is a (svc_forward) source!"
+ if qsearch( 'svc_forward', { 'srcsvc' => $self->svcnum } );
+
+ return "Can't delete an account which is a (svc_forward) destination!"
+ if qsearch( 'svc_forward', { 'dstsvc' => $self->svcnum } );
+
+ return "Can't delete an account with (svc_www) web service!"
+ if qsearch( 'svc_www', { 'usersvc' => $self->svcnum } );
+
+ # what about records in session ? (they should refer to history table)
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $cust_main_invoice (
+ qsearch( 'cust_main_invoice', { 'dest' => $self->svcnum } )
+ ) {
+ unless ( defined($cust_main_invoice) ) {
+ warn "WARNING: something's wrong with qsearch";
+ next;
+ }
+ my %hash = $cust_main_invoice->hash;
+ $hash{'dest'} = $self->email;
+ my $new = new FS::cust_main_invoice \%hash;
+ my $error = $new->replace($cust_main_invoice);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ foreach my $svc_domain (
+ qsearch( 'svc_domain', { 'catchall' => $self->svcnum } )
+ ) {
+ my %hash = new FS::svc_domain->hash;
+ $hash{'catchall'} = '';
+ my $new = new FS::svc_domain \%hash;
+ my $error = $new->replace($svc_domain);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ foreach my $radius_usergroup (
+ qsearch('radius_usergroup', { 'svcnum' => $self->svcnum } )
+ ) {
+ my $error = $radius_usergroup->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ my $error = $self->SUPER::delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+The additional field I<usergroup> can optionally be defined; if so it should
+contain an arrayref of group names. See L<FS::radius_usergroup>.
+
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+ my $error;
+ warn "$me replacing $old with $new\n" if $DEBUG;
+
+ return "can't modify system account" if $old->_check_system;
+
+ return "Username in use"
+ if $old->username ne $new->username &&
+ qsearchs( 'svc_acct', { 'username' => $new->username,
+ 'domsvc' => $new->domsvc,
+ } );
+ {
+ #no warnings 'numeric'; #alas, a 5.006-ism
+ local($^W) = 0;
+ return "Can't change uid!" if $old->uid != $new->uid;
+ }
+
+ #change homdir when we change username
+ $new->setfield('dir', '') if $old->username ne $new->username;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ # redundant, but so $new->usergroup gets set
+ $error = $new->check;
+ return $error if $error;
+
+ $old->usergroup( [ $old->radius_groups ] );
+ warn "old groups: ". join(' ',@{$old->usergroup}). "\n" if $DEBUG;
+ warn "new groups: ". join(' ',@{$new->usergroup}). "\n" if $DEBUG;
+ if ( $new->usergroup ) {
+ #(sorta) false laziness with FS::part_export::sqlradius::_export_replace
+ my @newgroups = @{$new->usergroup};
+ foreach my $oldgroup ( @{$old->usergroup} ) {
+ if ( grep { $oldgroup eq $_ } @newgroups ) {
+ @newgroups = grep { $oldgroup ne $_ } @newgroups;
+ next;
+ }
+ my $radius_usergroup = qsearchs('radius_usergroup', {
+ svcnum => $old->svcnum,
+ groupname => $oldgroup,
+ } );
+ my $error = $radius_usergroup->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error deleting radius_usergroup $oldgroup: $error";
+ }
+ }
+
+ foreach my $newgroup ( @newgroups ) {
+ my $radius_usergroup = new FS::radius_usergroup ( {
+ svcnum => $new->svcnum,
+ groupname => $newgroup,
+ } );
+ my $error = $radius_usergroup->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error adding radius_usergroup $newgroup: $error";
+ }
+ }
+
+ }
+
+ $error = $new->SUPER::replace($old);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error if $error;
+ }
+
+ if ( $new->username ne $old->username ) {
+ #false laziness with sub insert (and cust_main)
+ my $queue = new FS::queue {
+ 'svcnum' => $new->svcnum,
+ 'job' => 'FS::svc_acct::append_fuzzyfiles'
+ };
+ $error = $queue->insert($new->username);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "queueing job (transaction rolled back): $error";
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ ''; #no error
+}
+
+=item suspend
+
+Suspends this account by calling export-specific suspend hooks. If there is
+an error, returns the error, otherwise returns false.
+
+Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=cut
+
+sub suspend {
+ my $self = shift;
+ return "can't suspend system account" if $self->_check_system;
+ $self->SUPER::suspend;
+}
+
+=item unsuspend
+
+Unsuspends this account by by calling export-specific suspend hooks. If there
+is an error, returns the error, otherwise returns false.
+
+Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=cut
+
+sub unsuspend {
+ my $self = shift;
+ my %hash = $self->hash;
+ if ( $hash{_password} =~ /^\*SUSPENDED\* (.*)$/ ) {
+ $hash{_password} = $1;
+ my $new = new FS::svc_acct ( \%hash );
+ my $error = $new->replace($self);
+ return $error if $error;
+ }
+
+ $self->SUPER::unsuspend;
+}
+
+=item cancel
+
+Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+If the B<auto_unset_catchall> configuration option is set, this method will
+automatically remove any references to the canceled service in the catchall
+field of svc_domain. This allows packages that contain both a svc_domain and
+its catchall svc_acct to be canceled in one step.
+
+=cut
+
+sub cancel {
+ # Only one thing to do at this level
+ my $self = shift;
+ foreach my $svc_domain (
+ qsearch( 'svc_domain', { catchall => $self->svcnum } ) ) {
+ if($conf->exists('auto_unset_catchall')) {
+ my %hash = $svc_domain->hash;
+ $hash{catchall} = '';
+ my $new = new FS::svc_domain ( \%hash );
+ my $error = $new->replace($svc_domain);
+ return $error if $error;
+ } else {
+ return "cannot unprovision svc_acct #".$self->svcnum.
+ " while assigned as catchall for svc_domain #".$svc_domain->svcnum;
+ }
+ }
+
+ $self->SUPER::cancel;
+}
+
+
+=item check
+
+Checks all fields to make sure this is a valid service. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+Sets any fixed values; see L<FS::part_svc>.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my($recref) = $self->hashref;
+
+ my $x = $self->setfixed;
+ return $x unless ref($x);
+ my $part_svc = $x;
+
+ if ( $part_svc->part_svc_column('usergroup')->columnflag eq "F" ) {
+ $self->usergroup(
+ [ split(',', $part_svc->part_svc_column('usergroup')->columnvalue) ] );
+ }
+
+ my $error = $self->ut_numbern('svcnum')
+ #|| $self->ut_number('domsvc')
+ || $self->ut_foreign_key('domsvc', 'svc_domain', 'svcnum' )
+ || $self->ut_textn('sec_phrase')
+ ;
+ return $error if $error;
+
+ my $ulen = $usernamemax || $self->dbdef_table->column('username')->length;
+ if ( $username_uppercase ) {
+ $recref->{username} =~ /^([a-z0-9_\-\.\&]{$usernamemin,$ulen})$/i
+ or return gettext('illegal_username'). " ($usernamemin-$ulen): ". $recref->{username};
+ $recref->{username} = $1;
+ } else {
+ $recref->{username} =~ /^([a-z0-9_\-\.\&]{$usernamemin,$ulen})$/
+ or return gettext('illegal_username'). " ($usernamemin-$ulen): ". $recref->{username};
+ $recref->{username} = $1;
+ }
+
+ if ( $username_letterfirst ) {
+ $recref->{username} =~ /^[a-z]/ or return gettext('illegal_username');
+ } elsif ( $username_letter ) {
+ $recref->{username} =~ /[a-z]/ or return gettext('illegal_username');
+ }
+ if ( $username_noperiod ) {
+ $recref->{username} =~ /\./ and return gettext('illegal_username');
+ }
+ if ( $username_nounderscore ) {
+ $recref->{username} =~ /_/ and return gettext('illegal_username');
+ }
+ if ( $username_nodash ) {
+ $recref->{username} =~ /\-/ and return gettext('illegal_username');
+ }
+ unless ( $username_ampersand ) {
+ $recref->{username} =~ /\&/ and return gettext('illegal_username');
+ }
+
+ $recref->{popnum} =~ /^(\d*)$/ or return "Illegal popnum: ".$recref->{popnum};
+ $recref->{popnum} = $1;
+ return "Unknown popnum" unless
+ ! $recref->{popnum} ||
+ qsearchs('svc_acct_pop',{'popnum'=> $recref->{popnum} } );
+
+ unless ( $part_svc->part_svc_column('uid')->columnflag eq 'F' ) {
+
+ $recref->{uid} =~ /^(\d*)$/ or return "Illegal uid";
+ $recref->{uid} = $1 eq '' ? $self->unique('uid') : $1;
+
+ $recref->{gid} =~ /^(\d*)$/ or return "Illegal gid";
+ $recref->{gid} = $1 eq '' ? $recref->{uid} : $1;
+ #not all systems use gid=uid
+ #you can set a fixed gid in part_svc
+
+ return "Only root can have uid 0"
+ if $recref->{uid} == 0
+ && $recref->{username} ne 'root'
+ && $recref->{username} ne 'toor';
+
+
+ $recref->{dir} =~ /^([\/\w\-\.\&]*)$/
+ or return "Illegal directory: ". $recref->{dir};
+ $recref->{dir} = $1;
+ return "Illegal directory"
+ if $recref->{dir} =~ /(^|\/)\.+(\/|$)/; #no .. component
+ return "Illegal directory"
+ if $recref->{dir} =~ /\&/ && ! $username_ampersand;
+ unless ( $recref->{dir} ) {
+ $recref->{dir} = $dir_prefix . '/';
+ if ( $dirhash > 0 ) {
+ for my $h ( 1 .. $dirhash ) {
+ $recref->{dir} .= substr($recref->{username}, $h-1, 1). '/';
+ }
+ } elsif ( $dirhash < 0 ) {
+ for my $h ( reverse $dirhash .. -1 ) {
+ $recref->{dir} .= substr($recref->{username}, $h, 1). '/';
+ }
+ }
+ $recref->{dir} .= $recref->{username};
+ ;
+ }
+
+ unless ( $recref->{username} eq 'sync' ) {
+ if ( grep $_ eq $recref->{shell}, @shells ) {
+ $recref->{shell} = (grep $_ eq $recref->{shell}, @shells)[0];
+ } else {
+ return "Illegal shell \`". $self->shell. "\'; ".
+ $conf->dir. "/shells contains: @shells";
+ }
+ } else {
+ $recref->{shell} = '/bin/sync';
+ }
+
+ } else {
+ $recref->{gid} ne '' ?
+ return "Can't have gid without uid" : ( $recref->{gid}='' );
+ $recref->{dir} ne '' ?
+ return "Can't have directory without uid" : ( $recref->{dir}='' );
+ $recref->{shell} ne '' ?
+ return "Can't have shell without uid" : ( $recref->{shell}='' );
+ }
+
+ # $error = $self->ut_textn('finger');
+ # return $error if $error;
+ if ( $self->getfield('finger') eq '' ) {
+ my $cust_pkg = $self->svcnum
+ ? $self->cust_svc->cust_pkg
+ : qsearchs('cust_pkg', { 'pkgnum' => $self->getfield('pkgnum') } );
+ if ( $cust_pkg ) {
+ my $cust_main = $cust_pkg->cust_main;
+ $self->setfield('finger', $cust_main->first.' '.$cust_main->get('last') );
+ }
+ }
+ $self->getfield('finger') =~
+ /^([\w \t\!\@\#\$\%\&\(\)\-\+\;\'\"\,\.\?\/\*\<\>]*)$/
+ or return "Illegal finger: ". $self->getfield('finger');
+ $self->setfield('finger', $1);
+
+ $recref->{quota} =~ /^(\w*)$/ or return "Illegal quota";
+ $recref->{quota} = $1;
+
+ unless ( $part_svc->part_svc_column('slipip')->columnflag eq 'F' ) {
+ if ( $recref->{slipip} eq '' ) {
+ $recref->{slipip} = '';
+ } elsif ( $recref->{slipip} eq '0e0' ) {
+ $recref->{slipip} = '0e0';
+ } else {
+ $recref->{slipip} =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/
+ or return "Illegal slipip: ". $self->slipip;
+ $recref->{slipip} = $1;
+ }
+
+ }
+
+ #arbitrary RADIUS stuff; allow ut_textn for now
+ foreach ( grep /^radius_/, fields('svc_acct') ) {
+ $self->ut_textn($_);
+ }
+
+ #generate a password if it is blank
+ $recref->{_password} = join('',map($pw_set[ int(rand $#pw_set) ], (0..7) ) )
+ unless ( $recref->{_password} );
+
+ #if ( $recref->{_password} =~ /^((\*SUSPENDED\* )?)([^\t\n]{4,16})$/ ) {
+ if ( $recref->{_password} =~ /^((\*SUSPENDED\* )?)([^\t\n]{$passwordmin,$passwordmax})$/ ) {
+ $recref->{_password} = $1.$3;
+ #uncomment this to encrypt password immediately upon entry, or run
+ #bin/crypt_pw in cron to give new users a window during which their
+ #password is available to techs, for faxing, etc. (also be aware of
+ #radius issues!)
+ #$recref->{password} = $1.
+ # crypt($3,$saltset[int(rand(64))].$saltset[int(rand(64))]
+ #;
+ } elsif ( $recref->{_password} =~ /^((\*SUSPENDED\* )?)([\w\.\/\$\;\+]{13,60})$/ ) {
+ $recref->{_password} = $1.$3;
+ } elsif ( $recref->{_password} eq '*' ) {
+ $recref->{_password} = '*';
+ } elsif ( $recref->{_password} eq '!' ) {
+ $recref->{_password} = '!';
+ } elsif ( $recref->{_password} eq '!!' ) {
+ $recref->{_password} = '!!';
+ } else {
+ #return "Illegal password";
+ return gettext('illegal_password'). " $passwordmin-$passwordmax ".
+ FS::Msgcat::_gettext('illegal_password_characters').
+ ": ". $recref->{_password};
+ }
+
+ $self->SUPER::check;
+}
+
+=item _check_system
+
+=cut
+
+sub _check_system {
+ my $self = shift;
+ scalar( grep { $self->username eq $_ || $self->email eq $_ }
+ $conf->config('system_usernames')
+ );
+}
+
+=item radius
+
+Depriciated, use radius_reply instead.
+
+=cut
+
+sub radius {
+ carp "FS::svc_acct::radius depriciated, use radius_reply";
+ $_[0]->radius_reply;
+}
+
+=item radius_reply
+
+Returns key/value pairs, suitable for assigning to a hash, for any RADIUS
+reply attributes of this record.
+
+Note that this is now the preferred method for reading RADIUS attributes -
+accessing the columns directly is discouraged, as the column names are
+expected to change in the future.
+
+=cut
+
+sub radius_reply {
+ my $self = shift;
+ my %reply =
+ map {
+ /^(radius_(.*))$/;
+ my($column, $attrib) = ($1, $2);
+ #$attrib =~ s/_/\-/g;
+ ( $FS::raddb::attrib{lc($attrib)}, $self->getfield($column) );
+ } grep { /^radius_/ && $self->getfield($_) } fields( $self->table );
+ if ( $self->slipip && $self->slipip ne '0e0' ) {
+ $reply{$radius_ip} = $self->slipip;
+ }
+ %reply;
+}
+
+=item radius_check
+
+Returns key/value pairs, suitable for assigning to a hash, for any RADIUS
+check attributes of this record.
+
+Note that this is now the preferred method for reading RADIUS attributes -
+accessing the columns directly is discouraged, as the column names are
+expected to change in the future.
+
+=cut
+
+sub radius_check {
+ my $self = shift;
+ my $password = $self->_password;
+ my $pw_attrib = length($password) <= 12 ? $radius_password : 'Crypt-Password';
+ ( $pw_attrib => $password,
+ map {
+ /^(rc_(.*))$/;
+ my($column, $attrib) = ($1, $2);
+ #$attrib =~ s/_/\-/g;
+ ( $FS::raddb::attrib{lc($attrib)}, $self->getfield($column) );
+ } grep { /^rc_/ && $self->getfield($_) } fields( $self->table )
+ );
+}
+
+=item domain
+
+Returns the domain associated with this account.
+
+=cut
+
+sub domain {
+ my $self = shift;
+ die "svc_acct.domsvc is null for svcnum ". $self->svcnum unless $self->domsvc;
+ my $svc_domain = $self->svc_domain
+ or die "no svc_domain.svcnum for svc_acct.domsvc ". $self->domsvc;
+ $svc_domain->domain;
+}
+
+=item svc_domain
+
+Returns the FS::svc_domain record for this account's domain (see
+L<FS::svc_domain>).
+
+=cut
+
+sub svc_domain {
+ my $self = shift;
+ $self->{'_domsvc'}
+ ? $self->{'_domsvc'}
+ : qsearchs( 'svc_domain', { 'svcnum' => $self->domsvc } );
+}
+
+=item cust_svc
+
+Returns the FS::cust_svc record for this account (see L<FS::cust_svc>).
+
+=cut
+
+sub cust_svc {
+ my $self = shift;
+ qsearchs( 'cust_svc', { 'svcnum' => $self->svcnum } );
+}
+
+=item email
+
+Returns an email address associated with the account.
+
+=cut
+
+sub email {
+ my $self = shift;
+ $self->username. '@'. $self->domain;
+}
+
+=item acct_snarf
+
+Returns an array of FS::acct_snarf records associated with the account.
+If the acct_snarf table does not exist or there are no associated records,
+an empty list is returned
+
+=cut
+
+sub acct_snarf {
+ my $self = shift;
+ return () unless dbdef->table('acct_snarf');
+ eval "use FS::acct_snarf;";
+ die $@ if $@;
+ qsearch('acct_snarf', { 'svcnum' => $self->svcnum } );
+}
+
+=item seconds_since TIMESTAMP
+
+Returns the number of seconds this account has been online since TIMESTAMP,
+according to the session monitor (see L<FS::Session>).
+
+TIMESTAMP is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=cut
+
+#note: POD here, implementation in FS::cust_svc
+sub seconds_since {
+ my $self = shift;
+ $self->cust_svc->seconds_since(@_);
+}
+
+=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END
+
+Returns the numbers of seconds this account has been online between
+TIMESTAMP_START (inclusive) and TIMESTAMP_END (exclusive), according to an
+external SQL radacct table, specified via sqlradius export. Sessions which
+started in the specified range but are still open are counted from session
+start to the end of the range (unless they are over 1 day old, in which case
+they are presumed missing their stop record and not counted). Also, sessions
+which end in the range but started earlier are counted from the start of the
+range to session end. Finally, sessions which start before the range but end
+after are counted for the entire range.
+
+TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see
+L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for conversion
+functions.
+
+=cut
+
+#note: POD here, implementation in FS::cust_svc
+sub seconds_since_sqlradacct {
+ my $self = shift;
+ $self->cust_svc->seconds_since_sqlradacct(@_);
+}
+
+=item attribute_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ATTRIBUTE
+
+Returns the sum of the given attribute for all accounts (see L<FS::svc_acct>)
+in this package for sessions ending between TIMESTAMP_START (inclusive) and
+TIMESTAMP_END (exclusive).
+
+TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see
+L<perlfunc/"time">. Also see L<Time::Local> and L<Date::Parse> for conversion
+functions.
+
+=cut
+
+#note: POD here, implementation in FS::cust_svc
+sub attribute_since_sqlradacct {
+ my $self = shift;
+ $self->cust_svc->attribute_since_sqlradacct(@_);
+}
+
+=item get_session_history_sqlradacct TIMESTAMP_START TIMESTAMP_END
+
+Returns an array of hash references of this customers login history for the
+given time range. (document this better)
+
+=cut
+
+sub get_session_history_sqlradacct {
+ my $self = shift;
+ $self->cust_svc->get_session_history_sqlradacct(@_);
+}
+
+=item radius_groups
+
+Returns all RADIUS groups for this account (see L<FS::radius_usergroup>).
+
+=cut
+
+sub radius_groups {
+ my $self = shift;
+ if ( $self->usergroup ) {
+ #when provisioning records, export callback runs in svc_Common.pm before
+ #radius_usergroup records can be inserted...
+ @{$self->usergroup};
+ } else {
+ map { $_->groupname }
+ qsearch('radius_usergroup', { 'svcnum' => $self->svcnum } );
+ }
+}
+
+=item clone_suspended
+
+Constructor used by FS::part_export::_export_suspend fallback. Document
+better.
+
+=cut
+
+sub clone_suspended {
+ my $self = shift;
+ my %hash = $self->hash;
+ $hash{_password} = join('',map($pw_set[ int(rand $#pw_set) ], (0..7) ) );
+ new FS::svc_acct \%hash;
+}
+
+=item clone_kludge_unsuspend
+
+Constructor used by FS::part_export::_export_unsuspend fallback. Document
+better.
+
+=cut
+
+sub clone_kludge_unsuspend {
+ my $self = shift;
+ my %hash = $self->hash;
+ $hash{_password} = '';
+ new FS::svc_acct \%hash;
+}
+
+=item check_password
+
+Checks the supplied password against the (possibly encrypted) password in the
+database. Returns true for a sucessful authentication, false for no match.
+
+Currently supported encryptions are: classic DES crypt() and MD5
+
+=cut
+
+sub check_password {
+ my($self, $check_password) = @_;
+
+ #remove old-style SUSPENDED kludge, they should be allowed to login to
+ #self-service and pay up
+ ( my $password = $self->_password ) =~ s/^\*SUSPENDED\* //;
+
+ #eventually should check a "password-encoding" field
+ if ( $password =~ /^(\*|!!?)$/ ) { #no self-service login
+ return 0;
+ } elsif ( length($password) < 13 ) { #plaintext
+ $check_password eq $password;
+ } elsif ( length($password) == 13 ) { #traditional DES crypt
+ crypt($check_password, $password) eq $password;
+ } elsif ( $password =~ /^\$1\$/ ) { #MD5 crypt
+ unix_md5_crypt($check_password, $password) eq $password;
+ } elsif ( $password =~ /^\$2a?\$/ ) { #Blowfish
+ warn "Can't check password: Blowfish encryption not yet supported, svcnum".
+ $self->svcnum. "\n";
+ 0;
+ } else {
+ warn "Can't check password: Unrecognized encryption for svcnum ".
+ $self->svcnum. "\n";
+ 0;
+ }
+
+}
+
+=item crypt_password
+
+Returns an encrypted password, either by passing through an encrypted password
+in the database or by encrypting a plaintext password from the database.
+
+=cut
+
+sub crypt_password {
+ my $self = shift;
+ #false laziness w/shellcommands.pm
+ #eventually should check a "password-encoding" field
+ if ( length($self->_password) == 13
+ || $self->_password =~ /^\$(1|2a?)\$/ ) {
+ $self->_password;
+ } else {
+ crypt(
+ $self->_password,
+ $saltset[int(rand(64))].$saltset[int(rand(64))]
+ );
+ }
+}
+
+=item virtual_maildir
+
+Returns $domain/maildirs/$username/
+
+=cut
+
+sub virtual_maildir {
+ my $self = shift;
+ $self->domain. '/maildirs/'. $self->username. '/';
+}
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item send_email
+
+This is the FS::svc_acct job-queue-able version. It still uses
+FS::Misc::send_email under-the-hood.
+
+=cut
+
+sub send_email {
+ my %opt = @_;
+
+ eval "use FS::Misc qw(send_email)";
+ die $@ if $@;
+
+ $opt{mimetype} ||= 'text/plain';
+ $opt{mimetype} .= '; charset="iso-8859-1"' unless $opt{mimetype} =~ /charset/;
+
+ my $error = send_email(
+ 'from' => $opt{from},
+ 'to' => $opt{to},
+ 'subject' => $opt{subject},
+ 'content-type' => $opt{mimetype},
+ 'body' => [ map "$_\n", split("\n", $opt{body}) ],
+ );
+ die $error if $error;
+}
+
+=item check_and_rebuild_fuzzyfiles
+
+=cut
+
+sub check_and_rebuild_fuzzyfiles {
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ -e "$dir/svc_acct.username"
+ or &rebuild_fuzzyfiles;
+}
+
+=item rebuild_fuzzyfiles
+
+=cut
+
+sub rebuild_fuzzyfiles {
+
+ use Fcntl qw(:flock);
+
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+
+ #username
+
+ open(USERNAMELOCK,">>$dir/svc_acct.username")
+ or die "can't open $dir/svc_acct.username: $!";
+ flock(USERNAMELOCK,LOCK_EX)
+ or die "can't lock $dir/svc_acct.username: $!";
+
+ my @all_username = map $_->getfield('username'), qsearch('svc_acct', {});
+
+ open (USERNAMECACHE,">$dir/svc_acct.username.tmp")
+ or die "can't open $dir/svc_acct.username.tmp: $!";
+ print USERNAMECACHE join("\n", @all_username), "\n";
+ close USERNAMECACHE or die "can't close $dir/svc_acct.username.tmp: $!";
+
+ rename "$dir/svc_acct.username.tmp", "$dir/svc_acct.username";
+ close USERNAMELOCK;
+
+}
+
+=item all_username
+
+=cut
+
+sub all_username {
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ open(USERNAMECACHE,"<$dir/svc_acct.username")
+ or die "can't open $dir/svc_acct.username: $!";
+ my @array = map { chomp; $_; } <USERNAMECACHE>;
+ close USERNAMECACHE;
+ \@array;
+}
+
+=item append_fuzzyfiles USERNAME
+
+=cut
+
+sub append_fuzzyfiles {
+ my $username = shift;
+
+ &check_and_rebuild_fuzzyfiles;
+
+ use Fcntl qw(:flock);
+
+ my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+
+ open(USERNAME,">>$dir/svc_acct.username")
+ or die "can't open $dir/svc_acct.username: $!";
+ flock(USERNAME,LOCK_EX)
+ or die "can't lock $dir/svc_acct.username: $!";
+
+ print USERNAME "$username\n";
+
+ flock(USERNAME,LOCK_UN)
+ or die "can't unlock $dir/svc_acct.username: $!";
+ close USERNAME;
+
+ 1;
+}
+
+
+
+=item radius_usergroup_selector GROUPS_ARRAYREF [ SELECTNAME ]
+
+=cut
+
+sub radius_usergroup_selector {
+ my $sel_groups = shift;
+ my %sel_groups = map { $_=>1 } @$sel_groups;
+
+ my $selectname = shift || 'radius_usergroup';
+
+ my $dbh = dbh;
+ my $sth = $dbh->prepare(
+ 'SELECT DISTINCT(groupname) FROM radius_usergroup ORDER BY groupname'
+ ) or die $dbh->errstr;
+ $sth->execute() or die $sth->errstr;
+ my @all_groups = map { $_->[0] } @{$sth->fetchall_arrayref};
+
+ my $html = <<END;
+ <SCRIPT>
+ function ${selectname}_doadd(object) {
+ var myvalue = object.${selectname}_add.value;
+ var optionName = new Option(myvalue,myvalue,false,true);
+ var length = object.$selectname.length;
+ object.$selectname.options[length] = optionName;
+ object.${selectname}_add.value = "";
+ }
+ </SCRIPT>
+ <SELECT MULTIPLE NAME="$selectname">
+END
+
+ foreach my $group ( @all_groups ) {
+ $html .= '<OPTION';
+ if ( $sel_groups{$group} ) {
+ $html .= ' SELECTED';
+ $sel_groups{$group} = 0;
+ }
+ $html .= ">$group</OPTION>\n";
+ }
+ foreach my $group ( grep { $sel_groups{$_} } keys %sel_groups ) {
+ $html .= "<OPTION SELECTED>$group</OPTION>\n";
+ };
+ $html .= '</SELECT>';
+
+ $html .= qq!<BR><INPUT TYPE="text" NAME="${selectname}_add">!.
+ qq!<INPUT TYPE="button" VALUE="Add new group" onClick="${selectname}_doadd(this.form)">!;
+
+ $html;
+}
+
+=back
+
+=head1 BUGS
+
+The $recref stuff in sub check should be cleaned up.
+
+The suspend, unsuspend and cancel methods update the database, but not the
+current object. This is probably a bug as it's unexpected and
+counterintuitive.
+
+radius_usergroup_selector? putting web ui components in here? they should
+probably live somewhere else...
+
+insertion of RADIUS group stuff in insert could be done with child_objects now
+(would probably clean up export of them too)
+
+=head1 SEE ALSO
+
+L<FS::svc_Common>, edit/part_svc.cgi from an installed web interface,
+export.html from the base documentation, L<FS::Record>, L<FS::Conf>,
+L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>, L<FS::queue>,
+L<freeside-queued>), L<FS::svc_acct_pop>,
+schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/svc_acct_pop.pm b/FS/FS/svc_acct_pop.pm
new file mode 100644
index 0000000..f98f91a
--- /dev/null
+++ b/FS/FS/svc_acct_pop.pm
@@ -0,0 +1,210 @@
+package FS::svc_acct_pop;
+
+use strict;
+use vars qw( @ISA @EXPORT_OK @svc_acct_pop %svc_acct_pop );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw( FS::Record Exporter );
+@EXPORT_OK = qw( popselector );
+
+=head1 NAME
+
+FS::svc_acct_pop - Object methods for svc_acct_pop records
+
+=head1 SYNOPSIS
+
+ use FS::svc_acct_pop;
+
+ $record = new FS::svc_acct_pop \%hash;
+ $record = new FS::svc_acct_pop { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $html = FS::svc_acct_pop::popselector( $popnum, $state );
+
+=head1 DESCRIPTION
+
+An FS::svc_acct object represents an point of presence. FS::svc_acct_pop
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item popnum - primary key (assigned automatically for new accounts)
+
+=item city
+
+=item state
+
+=item ac - area code
+
+=item exch - exchange
+
+=item loc - rest of number
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new point of presence (if only it were that easy!). To add the
+point of presence to the database, see L<"insert">.
+
+=cut
+
+sub table { 'svc_acct_pop'; }
+
+=item insert
+
+Adds this point of presence to the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item delete
+
+Removes this point of presence from the database.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid point of presence. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ $self->ut_numbern('popnum')
+ or $self->ut_text('city')
+ or $self->ut_text('state')
+ or $self->ut_number('ac')
+ or $self->ut_number('exch')
+ or $self->ut_numbern('loc')
+ or $self->SUPER::check
+ ;
+
+}
+
+=item text
+
+Returns:
+
+"$city, $state ($ac)/$exch"
+
+=cut
+
+sub text {
+ my $self = shift;
+ $self->city. ', '. $self->state.
+ ' ('. $self->ac. ')/'. $self->exch. '-'. $self->loc;
+}
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item popselector [ POPNUM [ STATE ] ]
+
+=cut
+
+#horrible false laziness with signup.cgi (pull special-case for 0 & 1
+# pop code out from signup.cgi??)
+sub popselector {
+ my( $popnum, $state ) = @_;
+
+ unless ( @svc_acct_pop ) { #cache pop list
+ @svc_acct_pop = qsearch('svc_acct_pop', {} );
+ %svc_acct_pop = ();
+ push @{$svc_acct_pop{$_->state}}, $_ foreach @svc_acct_pop;
+ }
+
+ my $text = <<END;
+ <SCRIPT>
+ function opt(what,href,text) {
+ var optionName = new Option(text, href, false, false)
+ var length = what.length;
+ what.options[length] = optionName;
+ }
+
+ function popstate_changed(what) {
+ state = what.options[what.selectedIndex].text;
+ what.form.popnum.options.length = 0
+ what.form.popnum.options[0] = new Option("", "", false, true);
+END
+
+ foreach my $popstate ( sort { $a cmp $b } keys %svc_acct_pop ) {
+ $text .= "\nif ( state == \"$popstate\" ) {\n";
+
+ foreach my $pop ( @{$svc_acct_pop{$popstate}}) {
+ my $o_popnum = $pop->popnum;
+ my $poptext = $pop->text;
+ $text .= "opt(what.form.popnum, \"$o_popnum\", \"$poptext\");\n"
+ }
+ $text .= "}\n";
+ }
+
+ $text .= "}\n</SCRIPT>\n";
+
+ $text .=
+ qq!<SELECT NAME="popstate" SIZE=1 onChange="popstate_changed(this)">!.
+ qq!<OPTION> !;
+ $text .= "<OPTION>$_" foreach sort { $a cmp $b } keys %svc_acct_pop;
+ $text .= '</SELECT>'; #callback? return 3 html pieces? #'</TD><TD>';
+
+ $text .= qq!<SELECT NAME="popnum" SIZE=1><OPTION> !;
+ my @initial_select;
+ if ( scalar(@svc_acct_pop) > 100 ) {
+ @initial_select = qsearchs( 'svc_acct_pop', { 'popnum' => $popnum } );
+ } else {
+ @initial_select = @svc_acct_pop;
+ }
+ foreach my $pop ( @initial_select ) {
+ $text .= qq!<OPTION VALUE="!. $pop->popnum. '"'.
+ ( ( $popnum && $pop->popnum == $popnum ) ? ' SELECTED' : '' ). ">".
+ $pop->text;
+ }
+ $text .= '</SELECT>';
+
+ $text;
+
+}
+
+=back
+
+=head1 VERSION
+
+$Id: svc_acct_pop.pm,v 1.10 2003-08-05 00:20:47 khoff Exp $
+
+=head1 BUGS
+
+It should be renamed to part_pop.
+
+popselector? putting web ui components in here? they should probably live
+somewhere else...
+
+popselector: pull special-case for 0 & 1 pop code out from signup.cgi
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::svc_acct>, L<FS::part_pop_local>, schema.html from the
+base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm
new file mode 100755
index 0000000..aaac891
--- /dev/null
+++ b/FS/FS/svc_broadband.pm
@@ -0,0 +1,243 @@
+package FS::svc_broadband;
+
+use strict;
+use vars qw(@ISA $conf);
+use FS::Record qw( qsearchs qsearch dbh );
+use FS::svc_Common;
+use FS::cust_svc;
+use FS::addr_block;
+use NetAddr::IP;
+
+@ISA = qw( FS::svc_Common );
+
+$FS::UID::callback{'FS::svc_broadband'} = sub {
+ $conf = new FS::Conf;
+};
+
+=head1 NAME
+
+FS::svc_broadband - Object methods for svc_broadband records
+
+=head1 SYNOPSIS
+
+ use FS::svc_broadband;
+
+ $record = new FS::svc_broadband \%hash;
+ $record = new FS::svc_broadband { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $error = $record->cancel;
+
+=head1 DESCRIPTION
+
+An FS::svc_broadband object represents a 'broadband' Internet connection, such
+as a DSL, cable modem, or fixed wireless link. These services are assumed to
+have the following properties:
+
+FS::svc_broadband inherits from FS::svc_Common. The following fields are
+currently supported:
+
+=over 4
+
+=item svcnum - primary key
+
+=item blocknum - see FS::addr_block
+
+=item
+speed_up - maximum upload speed, in bits per second. If set to zero, upload
+speed will be unlimited. Exports that do traffic shaping should handle this
+correctly, and not blindly set the upload speed to zero and kill the customer's
+connection.
+
+=item
+speed_down - maximum download speed, as above
+
+=item ip_addr - the customer's IP address. If the customer needs more than one
+IP address, set this to the address of the customer's router. As a result, the
+customer's router will have the same address for both its internal and external
+interfaces thus saving address space. This has been found to work on most NAT
+routers available.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new svc_broadband. To add the record to the database, see
+"insert".
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'svc_broadband'; }
+
+=item insert [ , OPTION => VALUE ... ]
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+The additional fields pkgnum and svcpart (see FS::cust_svc) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+Currently available options are: I<depend_jobnum>
+
+If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
+jobnums), all provisioning jobs will have a dependancy on the supplied
+jobnum(s) (they will not run until the specific job(s) complete(s)).
+
+=cut
+
+# Standard FS::svc_Common::insert
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# Standard FS::svc_Common::delete
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# Standard FS::svc_Common::replace
+
+=item suspend
+
+Called by the suspend method of FS::cust_pkg (see FS::cust_pkg).
+
+=item unsuspend
+
+Called by the unsuspend method of FS::cust_pkg (see FS::cust_pkg).
+
+=item cancel
+
+Called by the cancel method of FS::cust_pkg (see FS::cust_pkg).
+
+=item check
+
+Checks all fields to make sure this is a valid broadband service. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+ my $x = $self->setfixed;
+
+ return $x unless ref($x);
+
+ my $error =
+ $self->ut_numbern('svcnum')
+ || $self->ut_foreign_key('blocknum', 'addr_block', 'blocknum')
+ || $self->ut_number('speed_up')
+ || $self->ut_number('speed_down')
+ || $self->ut_ipn('ip_addr')
+ ;
+ return $error if $error;
+
+ if($self->speed_up < 0) { return 'speed_up must be positive'; }
+ if($self->speed_down < 0) { return 'speed_down must be positive'; }
+
+ if (not($self->ip_addr) or $self->ip_addr eq '0.0.0.0') {
+ my $next_addr = $self->addr_block->next_free_addr;
+ if ($next_addr) {
+ $self->ip_addr($next_addr->addr);
+ } else {
+ return "No free addresses in addr_block (blocknum: ".$self->blocknum.")";
+ }
+ }
+
+ # This should catch errors in the ip_addr. If it doesn't,
+ # they'll almost certainly not map into the block anyway.
+ my $self_addr = $self->NetAddr; #netmask is /32
+ return ('Cannot parse address: ' . $self->ip_addr) unless $self_addr;
+
+ my $block_addr = $self->addr_block->NetAddr;
+ unless ($block_addr->contains($self_addr)) {
+ return 'blocknum '.$self->blocknum.' does not contain address '.$self->ip_addr;
+ }
+
+ my $router = $self->addr_block->router
+ or return 'Cannot assign address from unallocated block:'.$self->addr_block->blocknum;
+ if(grep { $_->routernum == $router->routernum} $self->allowed_routers) {
+ } # do nothing
+ else {
+ return 'Router '.$router->routernum.' cannot provide svcpart '.$self->svcpart;
+ }
+
+ $self->SUPER::check;
+}
+
+=item NetAddr
+
+Returns a NetAddr::IP object containing the IP address of this service. The netmask
+is /32.
+
+=cut
+
+sub NetAddr {
+ my $self = shift;
+ return new NetAddr::IP ($self->ip_addr);
+}
+
+=item addr_block
+
+Returns the FS::addr_block record (i.e. the address block) for this broadband service.
+
+=cut
+
+sub addr_block {
+ my $self = shift;
+
+ return qsearchs('addr_block', { blocknum => $self->blocknum });
+}
+
+=back
+
+=item allowed_routers
+
+Returns a list of allowed FS::router objects.
+
+=cut
+
+sub allowed_routers {
+ my $self = shift;
+
+ return map { $_->router } qsearch('part_svc_router', { svcpart => $self->svcpart });
+}
+
+=head1 BUGS
+
+The business with sb_field has been 'fixed', in a manner of speaking.
+
+=head1 SEE ALSO
+
+FS::svc_Common, FS::Record, FS::addr_block,
+FS::part_svc, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/svc_domain.pm b/FS/FS/svc_domain.pm
new file mode 100644
index 0000000..2642146
--- /dev/null
+++ b/FS/FS/svc_domain.pm
@@ -0,0 +1,445 @@
+package FS::svc_domain;
+
+use strict;
+use vars qw( @ISA $whois_hack $conf
+ @defaultrecords $soadefaultttl $soaemail $soaexpire $soamachine
+ $soarefresh $soaretry
+);
+use Carp;
+use Date::Format;
+#use Net::Whois::Raw;
+use FS::Record qw(fields qsearch qsearchs dbh);
+use FS::Conf;
+use FS::svc_Common;
+use FS::cust_svc;
+use FS::svc_acct;
+use FS::cust_pkg;
+use FS::cust_main;
+use FS::domain_record;
+use FS::queue;
+
+@ISA = qw( FS::svc_Common );
+
+#ask FS::UID to run this stuff for us later
+$FS::UID::callback{'FS::domain'} = sub {
+ $conf = new FS::Conf;
+
+ @defaultrecords = $conf->config('defaultrecords');
+ $soadefaultttl = $conf->config('soadefaultttl');
+ $soaemail = $conf->config('soaemail');
+ $soaexpire = $conf->config('soaexpire');
+ $soamachine = $conf->config('soamachine');
+ $soarefresh = $conf->config('soarefresh');
+ $soaretry = $conf->config('soaretry');
+
+};
+
+=head1 NAME
+
+FS::svc_domain - Object methods for svc_domain records
+
+=head1 SYNOPSIS
+
+ use FS::svc_domain;
+
+ $record = new FS::svc_domain \%hash;
+ $record = new FS::svc_domain { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $error = $record->cancel;
+
+=head1 DESCRIPTION
+
+An FS::svc_domain object represents a domain. FS::svc_domain inherits from
+FS::svc_Common. The following fields are currently supported:
+
+=over 4
+
+=item svcnum - primary key (assigned automatically for new accounts)
+
+=item domain
+
+=item catchall - optional svcnum of an svc_acct record, designating an email catchall account.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new domain. To add the domain to the database, see L<"insert">.
+
+=cut
+
+sub table { 'svc_domain'; }
+
+=item insert [ , OPTION => VALUE ... ]
+
+Adds this domain to the database. If there is an error, returns the error,
+otherwise returns false.
+
+The additional fields I<pkgnum> and I<svcpart> (see L<FS::cust_svc>) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+The additional field I<action> should be set to I<N> for new domains or I<M>
+for transfers.
+
+A registration or transfer email will be submitted unless
+$FS::svc_domain::whois_hack is true.
+
+The additional field I<email> can be used to manually set the admin contact
+email address on this email. Otherwise, the svc_acct records for this package
+(see L<FS::cust_pkg>) are searched. If there is exactly one svc_acct record
+in the same package, it is automatically used. Otherwise an error is returned.
+
+If any I<soamachine> configuration file exists, an SOA record is added to
+the domain_record table (see <FS::domain_record>).
+
+If any records are defined in the I<defaultrecords> configuration file,
+appropriate records are added to the domain_record table (see
+L<FS::domain_record>).
+
+Currently available options are: I<depend_jobnum>
+
+If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
+jobnums), all provisioning jobs will have a dependancy on the supplied
+jobnum(s) (they will not run until the specific job(s) complete(s)).
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ $error = $self->check;
+ return $error if $error;
+
+ return "Domain in use (here)"
+ if qsearchs( 'svc_domain', { 'domain' => $self->domain } );
+
+ my $whois = $self->whois;
+ if ( $self->action eq "N" && ! $whois_hack && $whois ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Domain in use (see whois)";
+ }
+ if ( $self->action eq "M" && ! $whois ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Domain not found (see whois)";
+ }
+
+ $error = $self->SUPER::insert(@_);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $self->submit_internic unless $whois_hack;
+
+ if ( $soamachine ) {
+ my $soa = new FS::domain_record {
+ 'svcnum' => $self->svcnum,
+ 'reczone' => '@',
+ 'recaf' => 'IN',
+ 'rectype' => 'SOA',
+ 'recdata' => "$soamachine $soaemail ( ". time2str("%Y%m%d", time). "00 ".
+ "$soarefresh $soaretry $soaexpire $soadefaultttl )"
+ };
+ $error = $soa->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "couldn't insert SOA record for new domain: $error";
+ }
+
+ foreach my $record ( @defaultrecords ) {
+ my($zone,$af,$type,$data) = split(/\s+/,$record,4);
+ my $domain_record = new FS::domain_record {
+ 'svcnum' => $self->svcnum,
+ 'reczone' => $zone,
+ 'recaf' => $af,
+ 'rectype' => $type,
+ 'recdata' => $data,
+ };
+ my $error = $domain_record->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "couldn't insert record for new domain: $error";
+ }
+ }
+
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ ''; #no error
+}
+
+=item delete
+
+Deletes this domain from the database. If there is an error, returns the
+error, otherwise returns false.
+
+The corresponding FS::cust_svc record will be deleted as well.
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ return "Can't delete a domain which has accounts!"
+ if qsearch( 'svc_acct', { 'domsvc' => $self->svcnum } );
+
+ #return "Can't delete a domain with (domain_record) zone entries!"
+ # if qsearch('domain_record', { 'svcnum' => $self->svcnum } );
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ foreach my $domain_record ( reverse $self->domain_record ) {
+ my $error = $domain_record->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ my $error = $self->SUPER::delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+}
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+
+ return "Can't change domain - reorder."
+ if $old->getfield('domain') ne $new->getfield('domain');
+
+ # Better to do it here than to force the caller to remember that svc_domain is weird.
+ $new->setfield(action => 'M');
+ my $error = $new->SUPER::replace($old);
+ return $error if $error;
+}
+
+=item suspend
+
+Just returns false (no error) for now.
+
+Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item unsuspend
+
+Just returns false (no error) for now.
+
+Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item cancel
+
+Just returns false (no error) for now.
+
+Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item check
+
+Checks all fields to make sure this is a valid domain. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+Sets any fixed values; see L<FS::part_svc>.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $x = $self->setfixed;
+ return $x unless ref($x);
+ #my $part_svc = $x;
+
+ my $error = $self->ut_numbern('svcnum')
+ || $self->ut_numbern('catchall')
+ ;
+ return $error if $error;
+
+ #hmm
+ my $pkgnum;
+ if ( $self->svcnum ) {
+ my $cust_svc = qsearchs( 'cust_svc', { 'svcnum' => $self->svcnum } );
+ $pkgnum = $cust_svc->pkgnum;
+ } else {
+ $pkgnum = $self->pkgnum;
+ }
+
+ my($recref) = $self->hashref;
+
+ unless ( $whois_hack ) {
+ unless ( $self->email ) { #find out an email address
+ my @svc_acct;
+ foreach ( qsearch( 'cust_svc', { 'pkgnum' => $pkgnum } ) ) {
+ my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $_->svcnum } );
+ push @svc_acct, $svc_acct if $svc_acct;
+ }
+
+ if ( scalar(@svc_acct) == 0 ) {
+ return "Must order an account in package ". $pkgnum. " first";
+ } elsif ( scalar(@svc_acct) > 1 ) {
+ return "More than one account in package ". $pkgnum. ": specify admin contact email";
+ } else {
+ $self->email($svc_acct[0]->email );
+ }
+ }
+ }
+
+ #if ( $recref->{domain} =~ /^([\w\-\.]{1,22})\.(com|net|org|edu)$/ ) {
+ if ( $recref->{domain} =~ /^([\w\-]{1,63})\.(com|net|org|edu)$/ ) {
+ $recref->{domain} = "$1.$2";
+ # hmmmmmmmm.
+ } elsif ( $whois_hack && $recref->{domain} =~ /^([\w\-\.]+)$/ ) {
+ $recref->{domain} = $1;
+ } else {
+ return "Illegal domain ". $recref->{domain}.
+ " (or unknown registry - try \$whois_hack)";
+ }
+
+ $recref->{action} =~ /^(M|N)$/
+ or return "Illegal action: ". $recref->{action};
+ $recref->{action} = $1;
+
+ if ( $recref->{catchall} ne '' ) {
+ my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $recref->{catchall} } );
+ return "Unknown catchall" unless $svc_acct;
+ }
+
+ $self->ut_textn('purpose')
+ or $self->SUPER::check;
+
+}
+
+=item domain_record
+
+=cut
+
+sub domain_record {
+ my $self = shift;
+
+ my %order = (
+ SOA => 1,
+ NS => 2,
+ MX => 3,
+ CNAME => 4,
+ A => 5,
+ );
+
+ sort { $order{$a->rectype} <=> $order{$b->rectype} }
+ qsearch('domain_record', { svcnum => $self->svcnum } );
+
+}
+
+sub catchall_svc_acct {
+ my $self = shift;
+ if ( $self->catchall ) {
+ qsearchs( 'svc_acct', { 'svcnum' => $self->catchall } );
+ } else {
+ '';
+ }
+}
+
+=item whois
+
+# Returns the Net::Whois::Domain object (see L<Net::Whois>) for this domain, or
+# undef if the domain is not found in whois.
+
+(If $FS::svc_domain::whois_hack is true, returns that in all cases instead.)
+
+=cut
+
+sub whois {
+ #$whois_hack or new Net::Whois::Domain $_[0]->domain;
+ $whois_hack or die "whois_hack not set...\n";
+}
+
+=item _whois
+
+Depriciated.
+
+=cut
+
+sub _whois {
+ die "_whois depriciated";
+}
+
+=item submit_internic
+
+Submits a registration email for this domain.
+
+=cut
+
+sub submit_internic {
+ #my $self = shift;
+ carp "submit_internic depreciated";
+}
+
+=back
+
+=head1 BUGS
+
+Delete doesn't send a registration template.
+
+All registries should be supported.
+
+Should change action to a real field.
+
+The $recref stuff in sub check should be cleaned up.
+
+=head1 SEE ALSO
+
+L<FS::svc_Common>, L<FS::Record>, L<FS::Conf>, L<FS::cust_svc>,
+L<FS::part_svc>, L<FS::cust_pkg>, L<Net::Whois>, schema.html from the base
+documentation, config.html from the base documentation.
+
+=cut
+
+1;
+
+
diff --git a/FS/FS/svc_external.pm b/FS/FS/svc_external.pm
new file mode 100644
index 0000000..b97e12b
--- /dev/null
+++ b/FS/FS/svc_external.pm
@@ -0,0 +1,180 @@
+package FS::svc_external;
+
+use strict;
+use vars qw(@ISA); # $conf
+use FS::UID;
+#use FS::Record qw( qsearch qsearchs dbh);
+use FS::svc_Common;
+
+@ISA = qw( FS::svc_Common );
+
+#FS::UID::install_callback( sub {
+# $conf = new FS::Conf;
+#};
+
+=head1 NAME
+
+FS::svc_external - Object methods for svc_external records
+
+=head1 SYNOPSIS
+
+ use FS::svc_external;
+
+ $record = new FS::svc_external \%hash;
+ $record = new FS::svc_external { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $error = $record->cancel;
+
+=head1 DESCRIPTION
+
+An FS::svc_external object represents a externally tracked service.
+FS::svc_external inherits from FS::svc_Common. The following fields are
+currently supported:
+
+=over 4
+
+=item svcnum - primary key
+
+=item id - unique number of external record
+
+=item title - for invoice line items
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new external service. To add the external service to the database,
+see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'svc_external'; }
+
+=item insert [ , OPTION => VALUE ... ]
+
+Adds this external service to the database. If there is an error, returns the
+error, otherwise returns false.
+
+The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+Currently available options are: I<depend_jobnum>
+
+If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
+jobnums), all provisioning jobs will have a dependancy on the supplied
+jobnum(s) (they will not run until the specific job(s) complete(s)).
+
+=cut
+
+#sub insert {
+# my $self = shift;
+# my $error;
+#
+# $error = $self->SUPER::insert(@_);
+# return $error if $error;
+#
+# '';
+#}
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+#sub delete {
+# my $self = shift;
+# my $error;
+#
+# $error = $self->SUPER::delete;
+# return $error if $error;
+#
+# '';
+#}
+
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+#sub replace {
+# my ( $new, $old ) = ( shift, shift );
+# my $error;
+#
+# $error = $new->SUPER::replace($old);
+# return $error if $error;
+#
+# '';
+#}
+
+=item suspend
+
+Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item unsuspend
+
+Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item cancel
+
+Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item check
+
+Checks all fields to make sure this is a valid external service. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and repalce methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $x = $self->setfixed;
+ return $x unless ref($x);
+ my $part_svc = $x;
+
+ my $error =
+ $self->ut_numbern('svcnum')
+ || $self->ut_number('id')
+ || $self->ut_textn('title')
+ ;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::svc_Common>, L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>,
+L<FS::cust_pkg>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/svc_forward.pm b/FS/FS/svc_forward.pm
new file mode 100644
index 0000000..b8d55fe
--- /dev/null
+++ b/FS/FS/svc_forward.pm
@@ -0,0 +1,306 @@
+package FS::svc_forward;
+
+use strict;
+use vars qw( @ISA );
+use FS::Conf;
+use FS::Record qw( fields qsearch qsearchs dbh );
+use FS::svc_Common;
+use FS::cust_svc;
+use FS::svc_acct;
+use FS::svc_domain;
+
+@ISA = qw( FS::svc_Common );
+
+=head1 NAME
+
+FS::svc_forward - Object methods for svc_forward records
+
+=head1 SYNOPSIS
+
+ use FS::svc_forward;
+
+ $record = new FS::svc_forward \%hash;
+ $record = new FS::svc_forward { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $error = $record->cancel;
+
+=head1 DESCRIPTION
+
+An FS::svc_forward object represents a mail forwarding alias. FS::svc_forward
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item svcnum - primary key (assigned automatcially for new accounts)
+
+=item srcsvc - svcnum of the source of the forward (see L<FS::svc_acct>)
+
+=item src - literal source (username or full email address)
+
+=item dstsvc - svcnum of the destination of the forward (see L<FS::svc_acct>)
+
+=item dst - literal destination (username or full email address)
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new mail forwarding alias. To add the mail forwarding alias to the
+database, see L<"insert">.
+
+=cut
+
+sub table { 'svc_forward'; }
+
+=item insert [ , OPTION => VALUE ... ]
+
+Adds this mail forwarding alias to the database. If there is an error, returns
+the error, otherwise returns false.
+
+The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+Currently available options are: I<depend_jobnum>
+
+If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
+jobnums), all provisioning jobs will have a dependancy on the supplied
+jobnum(s) (they will not run until the specific job(s) complete(s)).
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ $error = $self->check;
+ return $error if $error;
+
+ $error = $self->SUPER::insert(@_);
+ if ($error) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ ''; #no error
+
+}
+
+=item delete
+
+Deletes this mail forwarding alias from the database. If there is an error,
+returns the error, otherwise returns false.
+
+The corresponding FS::cust_svc record will be deleted as well.
+
+=cut
+
+sub delete {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::Autocommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+}
+
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+
+ if ( $new->srcsvc != $old->srcsvc
+ && ( $new->dstsvc != $old->dstsvc
+ || ! $new->dstsvc && $new->dst ne $old->dst
+ )
+ ) {
+ return "Can't change both source and destination of a mail forward!"
+ }
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $new->SUPER::replace($old);
+ if ($error) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+}
+
+=item suspend
+
+Just returns false (no error) for now.
+
+Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item unsuspend
+
+Just returns false (no error) for now.
+
+Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item cancel
+
+Just returns false (no error) for now.
+
+Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item check
+
+Checks all fields to make sure this is a valid mail forwarding alias. If there
+is an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+Sets any fixed values; see L<FS::part_svc>.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $x = $self->setfixed;
+ return $x unless ref($x);
+ #my $part_svc = $x;
+
+ my $error = $self->ut_numbern('svcnum')
+ || $self->ut_numbern('srcsvc')
+ || $self->ut_numbern('dstsvc')
+ ;
+ return $error if $error;
+
+ return "Both srcsvc and src were defined; only one can be specified"
+ if $self->srcsvc && $self->src;
+
+ return "one of srcsvc or src is required"
+ unless $self->srcsvc || $self->src;
+
+ return "Unknown srcsvc: ". $self->srcsvc
+ unless ! $self->srcsvc || $self->srcsvc_acct;
+
+ return "Both dstsvc and dst were defined; only one can be specified"
+ if $self->dstsvc && $self->dst;
+
+ return "one of dstsvc or dst is required"
+ unless $self->dstsvc || $self->dst;
+
+ return "Unknown dstsvc: ". $self->dstsvc
+ unless ! $self->dstsvc || $self->dstsvc_acct;
+ #return "Unknown dstsvc"
+ # unless qsearchs('svc_acct', { 'svcnum' => $self->dstsvc } )
+ # || ! $self->dstsvc;
+
+ if ( $self->src ) {
+ $self->src =~ /^([\w\.\-\&]*)(\@([\w\-]+\.)+\w+)?$/
+ or return "Illegal src: ". $self->dst;
+ $self->src("$1$2");
+ } else {
+ $self->src('');
+ }
+
+ if ( $self->dst ) {
+ $self->dst =~ /^([\w\.\-\&]*)(\@([\w\-]+\.)+\w+)?$/
+ or return "Illegal dst: ". $self->dst;
+ $self->dst("$1$2");
+ } else {
+ $self->dst('');
+ }
+
+ $self->SUPER::check;
+}
+
+=item srcsvc_acct
+
+Returns the FS::svc_acct object referenced by the srcsvc column, or false for
+literally specified forwards.
+
+=cut
+
+sub srcsvc_acct {
+ my $self = shift;
+ qsearchs('svc_acct', { 'svcnum' => $self->srcsvc } );
+}
+
+=item dstsvc_acct
+
+Returns the FS::svc_acct object referenced by the srcsvc column, or false for
+literally specified forwards.
+
+=cut
+
+sub dstsvc_acct {
+ my $self = shift;
+ qsearchs('svc_acct', { 'svcnum' => $self->dstsvc } );
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::Conf>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>,
+L<FS::svc_acct>, L<FS::svc_domain>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/svc_www.pm b/FS/FS/svc_www.pm
new file mode 100644
index 0000000..6c276a1
--- /dev/null
+++ b/FS/FS/svc_www.pm
@@ -0,0 +1,284 @@
+package FS::svc_www;
+
+use strict;
+use vars qw(@ISA $conf $apacheip);
+#use FS::Record qw( qsearch qsearchs );
+use FS::Record qw( qsearchs dbh );
+use FS::svc_Common;
+use FS::cust_svc;
+use FS::domain_record;
+use FS::svc_acct;
+use FS::svc_domain;
+
+@ISA = qw( FS::svc_Common );
+
+#ask FS::UID to run this stuff for us later
+$FS::UID::callback{'FS::svc_www'} = sub {
+ $conf = new FS::Conf;
+ $apacheip = $conf->config('apacheip');
+};
+
+=head1 NAME
+
+FS::svc_www - Object methods for svc_www records
+
+=head1 SYNOPSIS
+
+ use FS::svc_www;
+
+ $record = new FS::svc_www \%hash;
+ $record = new FS::svc_www { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $error = $record->cancel;
+
+=head1 DESCRIPTION
+
+An FS::svc_www object represents an web virtual host. FS::svc_www inherits
+from FS::svc_Common. The following fields are currently supported:
+
+=over 4
+
+=item svcnum - primary key
+
+=item recnum - DNS `A' record corresponding to this web virtual host. (see L<FS::domain_record>)
+
+=item usersvc - account (see L<FS::svc_acct>) corresponding to this web virtual host.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new web virtual host. To add the record to the database, see
+L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'svc_www'; }
+
+=item insert [ , OPTION => VALUE ... ]
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+Currently available options are: I<depend_jobnum>
+
+If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
+jobnums), all provisioning jobs will have a dependancy on the supplied
+jobnum(s) (they will not run until the specific job(s) complete(s)).
+
+
+=cut
+
+sub insert {
+ my $self = shift;
+
+ my $error = $self->check;
+ return $error if $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ #if ( $self->recnum =~ /^([\w\-]+|\@)\.(([\w\.\-]+\.)+\w+)$/ ) {
+ if ( $self->recnum =~ /^([\w\-]+|\@)\.(\d+)$/ ) {
+ my( $reczone, $domain_svcnum ) = ( $1, $2 );
+ unless ( $apacheip ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Configuration option apacheip not set; can't autocreate A record";
+ #"for $reczone". $svc_domain->domain;
+ }
+ my $domain_record = new FS::domain_record {
+ 'svcnum' => $domain_svcnum,
+ 'reczone' => $reczone,
+ 'recaf' => 'IN',
+ 'rectype' => 'A',
+ 'recdata' => $apacheip,
+ };
+ $error = $domain_record->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ $self->recnum($domain_record->recnum);
+ }
+
+ $error = $self->SUPER::insert(@_);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+}
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+sub delete {
+ my $self = shift;
+ my $error;
+
+ $error = $self->SUPER::delete;
+ return $error if $error;
+
+ '';
+}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+ my $error;
+
+ $error = $new->SUPER::replace($old);
+ return $error if $error;
+
+ '';
+}
+
+=item suspend
+
+Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item unsuspend
+
+Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item cancel
+
+Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item check
+
+Checks all fields to make sure this is a valid web virtual host. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and repalce methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $x = $self->setfixed;
+ return $x unless ref($x);
+ #my $part_svc = $x;
+
+ my $error =
+ $self->ut_numbern('svcnum')
+# || $self->ut_number('recnum')
+ || $self->ut_number('usersvc')
+ ;
+ return $error if $error;
+
+ if ( $self->recnum =~ /^(\d+)$/ ) {
+
+ $self->recnum($1);
+ return "Unknown recnum: ". $self->recnum
+ unless qsearchs('domain_record', { 'recnum' => $self->recnum } );
+
+ } elsif ( $self->recnum =~ /^([\w\-]+|\@)\.(([\w\.\-]+\.)+\w+)$/ ) {
+
+ my( $reczone, $domain ) = ( $1, $2 );
+
+ my $svc_domain = qsearchs( 'svc_domain', { 'domain' => $domain } )
+ or return "unknown domain $domain (recnum $1.$2)";
+
+ my $domain_record = qsearchs( 'domain_record', {
+ 'reczone' => $reczone,
+ 'svcnum' => $svc_domain->svcnum,
+ });
+
+ if ( $domain_record ) {
+ $self->recnum($domain_record->recnum);
+ } else {
+ #insert will create it
+ #$self->recnum("$reczone.$domain");
+ $self->recnum("$reczone.". $svc_domain->svcnum);
+ }
+
+ } else {
+ return "Illegal recnum: ". $self->recnum;
+ }
+
+ return "Unknown usersvc (svc_acct.svcnum): ". $self->usersvc
+ unless qsearchs('svc_acct', { 'svcnum' => $self->usersvc } );
+
+ $self->SUPER::check;
+
+}
+
+=item domain_record
+
+Returns the FS::domain_record record for this web virtual host's zone (see
+L<FS::domain_record>).
+
+=cut
+
+sub domain_record {
+ my $self = shift;
+ qsearchs('domain_record', { 'recnum' => $self->recnum } );
+}
+
+=item svc_acct
+
+Returns the FS::svc_acct record for this web virtual host's owner (see
+L<FS::svc_acct>).
+
+=cut
+
+sub svc_acct {
+ my $self = shift;
+ qsearchs('svc_acct', { 'svcnum' => $self->usersvc } );
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::svc_Common>, L<FS::Record>, L<FS::domain_record>, L<FS::cust_svc>,
+L<FS::part_svc>, L<FS::cust_pkg>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/type_pkgs.pm b/FS/FS/type_pkgs.pm
new file mode 100644
index 0000000..5b3b11c
--- /dev/null
+++ b/FS/FS/type_pkgs.pm
@@ -0,0 +1,126 @@
+package FS::type_pkgs;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearchs );
+use FS::agent_type;
+use FS::part_pkg;
+
+@ISA = qw( FS::Record );
+
+=head1 NAME
+
+FS::type_pkgs - Object methods for type_pkgs records
+
+=head1 SYNOPSIS
+
+ use FS::type_pkgs;
+
+ $record = new FS::type_pkgs \%hash;
+ $record = new FS::type_pkgs { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::type_pkgs record links an agent type (see L<FS::agent_type>) to a
+billing item definition (see L<FS::part_pkg>). FS::type_pkgs inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item typenum - Agent type, see L<FS::agent_type>
+
+=item pkgpart - Billing item definition, see L<FS::part_pkg>
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Create a new record. To add the record to the database, see L<"insert">.
+
+=cut
+
+sub table { 'type_pkgs'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_number('typenum')
+ || $self->ut_number('pkgpart')
+ ;
+ return $error if $error;
+
+ return "Unknown typenum"
+ unless qsearchs( 'agent_type', { 'typenum' => $self->typenum } );
+
+ return "Unknown pkgpart"
+ unless qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
+
+ $self->SUPER::check;
+}
+
+=item part_pkg
+
+Returns the FS::part_pkg object associated with this record.
+
+=cut
+
+sub part_pkg {
+ my $self = shift;
+ qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } );
+}
+
+=cut
+
+=back
+
+=head1 VERSION
+
+$Id: type_pkgs.pm,v 1.3 2003-08-05 00:20:48 khoff Exp $
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::agent_type>, L<FS::part_pkgs>, schema.html from the base
+documentation.
+
+=cut
+
+1;
+
diff --git a/FS/MANIFEST b/FS/MANIFEST
new file mode 100644
index 0000000..24fc1d1
--- /dev/null
+++ b/FS/MANIFEST
@@ -0,0 +1,210 @@
+Changes
+MANIFEST
+MANIFEST.SKIP
+Makefile.PL
+README
+bin/freeside-addoutsource
+bin/freeside-addoutsourceuser
+bin/freeside-adduser
+bin/freeside-apply-credits
+bin/freeside-bill
+bin/freeside-count-active-customers
+bin/freeside-daily
+bin/freeside-deloutsource
+bin/freeside-deloutsourceuser
+bin/freeside-deluser
+bin/freeside-email
+bin/freeside-expiration-alerter
+bin/freeside-queued
+bin/freeside-radgroup
+bin/freeside-reexport
+bin/freeside-selfservice-server
+bin/freeside-setinvoice
+bin/freeside-setup
+bin/freeside-sqlradius-radacctd
+bin/freeside-sqlradius-reset
+bin/freeside-sqlradius-seconds
+FS.pm
+FS/CGI.pm
+FS/InitHandler.pm
+FS/ClientAPI.pm
+FS/ClientAPI/passwd.pm
+FS/ClientAPI/MyAccount.pm
+FS/Conf.pm
+FS/ConfItem.pm
+FS/Misc.pm
+FS/Record.pm
+FS/Report.pm
+FS/Report/Table.pm
+FS/Report/Table/Monthly.pm
+FS/SearchCache.pm
+FS/UI/Base.pm
+FS/UI/CGI.pm
+FS/UI/Gtk.pm
+FS/UI/agent.pm
+FS/UID.pm
+FS/Msgcat.pm
+FS/acct_snarf.pm
+FS/agent.pm
+FS/agent_type.pm
+FS/cust_bill.pm
+FS/cust_bill_pkg.pm
+FS/cust_bill_pkg_detail.pm
+FS/cust_credit.pm
+FS/cust_credit_bill.pm
+FS/cust_main.pm
+FS/cust_main_county.pm
+FS/cust_main_invoice.pm
+FS/cust_pay.pm
+FS/cust_bill_event.pm
+FS/cust_bill_pay.pm
+FS/cust_pay_batch.pm
+FS/cust_pkg.pm
+FS/cust_refund.pm
+FS/cust_credit_refund.pm
+FS/cust_svc.pm
+FS/part_bill_event.pm
+FS/export_svc.pm
+FS/part_export.pm
+FS/part_export_option.pm
+FS/part_export/acct_sql.pm
+FS/part_export/apache.pm
+FS/part_export/bind.pm
+FS/part_export/bind_slave.pm
+FS/part_export/bsdshell.pm
+FS/part_export/communigate_pro.pm
+FS/part_export/communigate_pro_singledomain.pm
+FS/part_export/cp.pm
+FS/part_export/cyrus.pm
+FS/part_export/domain_shellcommands.pm
+FS/part_export/forward_shellcommands.pm
+FS/part_export/http.pm
+FS/part_export/infostreet.pm
+FS/part_export/ldap.pm
+FS/part_export/null.pm
+FS/part_export/shellcommands.pm
+FS/part_export/shellcommands_withdomain.pm
+FS/part_export/sqlmail.pm
+FS/part_export/sqlradius.pm
+FS/part_export/sysvshell.pm
+FS/part_export/textradius.pm
+FS/part_export/vpopmail.pm
+FS/part_export/www_shellcommands.pm
+FS/part_pkg.pm
+FS/part_pop_local.pm
+FS/part_referral.pm
+FS/part_svc.pm
+FS/part_svc_column.pm
+FS/part_svc_router.pm
+FS/part_virtual_field.pm
+FS/pkg_svc.pm
+FS/svc_Common.pm
+FS/svc_acct.pm
+FS/svc_acct_pop.pm
+FS/svc_broadband.pm
+FS/svc_domain.pm
+FS/svc_external.pm
+FS/router.pm
+FS/type_pkgs.pm
+FS/nas.pm
+FS/port.pm
+FS/session.pm
+FS/domain_record.pm
+FS/prepay_credit.pm
+FS/svc_www.pm
+FS/svc_forward.pm
+FS/raddb.pm
+FS/radius_usergroup.pm
+FS/queue.pm
+FS/queue_arg.pm
+FS/queue_depend.pm
+FS/msgcat.pm
+FS/cust_tax_exempt.pm
+t/agent.t
+t/agent_type.t
+t/CGI.t
+t/InitHandler.t
+t/ClientAPI.t
+t/Conf.t
+t/ConfItem.t
+t/Misc.t
+t/Record.t
+t/Report.t
+t/Report-Table.t
+t/Report-Table-Monthly.t
+t/UID.t
+t/Msgcat.t
+t/SearchCache.t
+t/cust_bill.t
+t/cust_bill_event.t
+t/cust_bill_pay.t
+t/cust_bill_pkg.t
+t/cust_bill_pkg_detail.t
+t/cust_credit.t
+t/cust_credit_bill.t
+t/cust_credit_refund.t
+t/cust_main.t
+t/cust_main_county.t
+t/cust_main_invoice.t
+t/cust_pay.t
+t/cust_pay_batch.t
+t/cust_pkg.t
+t/cust_refund.t
+t/cust_svc.t
+t/cust_tax_exempt.t
+t/domain_record.t
+t/nas.t
+t/part_bill_event.t
+t/export_svc.t
+t/part_export.t
+t/part_export_option.t
+t/part_export-acct_sql.t
+t/part_export-apache.t
+t/part_export-bind.t
+t/part_export-bind_slave.t
+t/part_export-bsdshell.t
+t/part_export-communigate_pro.t
+t/part_export-communigate_pro_singledomain.t
+t/part_export-cp.t
+t/part_export-cyrus.t
+t/part_export-domain_shellcommands.t
+t/part_export-forward_shellcommands.t
+t/part_export-http.t
+t/part_export-infostreet.t
+t/part_export-ldap.t
+t/part_export-null.t
+t/part_export-passwdfile.t
+t/part_export-postfix.t
+t/part_export-router.t
+t/part_export-shellcommands.t
+t/part_export-shellcommands_withdomain.t
+t/part_export-sqlmail.t
+t/part_export-sqlradius.t
+t/part_export-sysvshell.t
+t/part_export-textradius.t
+t/part_export-vpopmail.t
+t/part_export-www_shellcommands.t
+t/part_pkg.t
+t/part_pop_local.t
+t/part_referral.t
+t/part_svc.t
+t/part_svc_column.t
+t/pkg_svc.t
+t/port.t
+t/prepay_credit.t
+t/radius_usergroup.t
+t/session.t
+t/svc_acct.t
+t/svc_acct_pop.t
+t/svc_broadband.t
+t/svc_Common.t
+t/svc_domain.t
+t/svc_external.t
+t/svc_forward.t
+t/svc_www.t
+t/type_pkgs.t
+t/queue.t
+t/queue_arg.t
+t/queue_depend.t
+t/msgcat.t
+t/raddb.t
diff --git a/FS/MANIFEST.SKIP b/FS/MANIFEST.SKIP
new file mode 100644
index 0000000..ae335e7
--- /dev/null
+++ b/FS/MANIFEST.SKIP
@@ -0,0 +1 @@
+CVS/
diff --git a/FS/Makefile.PL b/FS/Makefile.PL
new file mode 100644
index 0000000..1647f8e
--- /dev/null
+++ b/FS/Makefile.PL
@@ -0,0 +1,10 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'FS',
+ 'VERSION_FROM' => 'FS.pm', # finds $VERSION
+ 'EXE_FILES' => [ glob 'bin/*' ],
+ 'INSTALLSCRIPT' => '/usr/local/bin',
+ 'INSTALLSITEBIN' => '/usr/local/bin',
+);
diff --git a/FS/README b/FS/README
new file mode 100644
index 0000000..d4c35ac
--- /dev/null
+++ b/FS/README
@@ -0,0 +1,6 @@
+This is the Perl module section of Freeside.
+
+perl Makefile.PL
+make
+make test
+make install
diff --git a/FS/bin/freeside-addoutsource b/FS/bin/freeside-addoutsource
new file mode 100644
index 0000000..5cec17f
--- /dev/null
+++ b/FS/bin/freeside-addoutsource
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+domain=$1
+
+createdb $domain && \
+\
+mkdir /usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=$domain && \
+\
+chown freeside /usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=$domain && \
+\
+cp /home/ivan/freeside/conf/[a-z]* /usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=$domain && \
+\
+touch /usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=$domain/secrets && \
+\
+chown freeside /usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=$domain/secrets && \
+\
+chmod 600 /usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=$domain/secrets && \
+\
+echo -e "DBI:Pg:host=localhost;dbname=$domain\nfreeside\n" >/usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=$domain/secrets && \
+\
+mkdir /usr/local/etc/freeside/counters.DBI:Pg:host=localhost\;dbname=$domain && \
+mkdir /usr/local/etc/freeside/cache.DBI:Pg:host=localhost\;dbname=$domain && \
+mkdir /usr/local/etc/freeside/export.DBI:Pg:host=localhost\;dbname=$domain
+
diff --git a/FS/bin/freeside-addoutsourceuser b/FS/bin/freeside-addoutsourceuser
new file mode 100644
index 0000000..abb515b
--- /dev/null
+++ b/FS/bin/freeside-addoutsourceuser
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+username=$1
+domain=$2
+password=$3
+
+freeside-adduser -h /usr/local/etc/freeside/htpasswd \
+ -s conf.DBI:Pg:host=localhost\;dbname=$domain/secrets \
+ -b \
+ $username $password 2>/dev/null
+
+[ -e /usr/local/etc/freeside/dbdef.DBI:Pg:host=localhost\;dbname=$domain ] \
+ || ( freeside-setup -s $username 2>/dev/null; \
+ /home/ivan/freeside/bin/populate-msgcat $username 2>/dev/null )
+
diff --git a/FS/bin/freeside-adduser b/FS/bin/freeside-adduser
new file mode 100644
index 0000000..c3ee05b
--- /dev/null
+++ b/FS/bin/freeside-adduser
@@ -0,0 +1,63 @@
+#!/usr/bin/perl -w
+#
+# $Id: freeside-adduser,v 1.8 2002-09-27 05:36:29 ivan Exp $
+
+use strict;
+use vars qw($opt_h $opt_b $opt_c $opt_s);
+use Fcntl qw(:flock);
+use Getopt::Std;
+
+my $FREESIDE_CONF = "/usr/local/etc/freeside";
+
+getopts("bch:s:");
+die &usage if $opt_c && ! $opt_h;
+my $user = shift or die &usage;
+
+if ( $opt_h ) {
+ my @args = ( 'htpasswd' );
+ push @args, '-b' if $opt_b;
+ push @args, '-c' if $opt_c;
+ push @args, $opt_h, $user;
+ push @args, shift if $opt_b;
+ system(@args) == 0 or die "htpasswd failed: $?";
+}
+
+my $secretfile = $opt_s || 'secrets';
+
+open(MAPSECRETS,">>$FREESIDE_CONF/mapsecrets")
+ and flock(MAPSECRETS,LOCK_EX)
+ or die "can't open $FREESIDE_CONF/mapsecrets: $!";
+print MAPSECRETS "$user $secretfile\n";
+close MAPSECRETS or die "can't close $FREESIDE_CONF/mapsecrets: $!";
+
+sub usage {
+ die "Usage:\n\n freeside-adduser [ -h htpasswd_file [ -c ] [ -b ] ] [ -s secretfile ] username"
+}
+
+=head1 NAME
+
+freeside-adduser - Command line interface to add (freeside) users.
+
+=head1 SYNOPSIS
+
+ freeside-adduser [ -h htpasswd_file [ -c ] ] [ -s secretfile ] username
+
+=head1 DESCRIPTION
+
+Adds a user to the Freeside billing system. This is for adding users (internal
+sales/tech folks) to the web interface, not for adding customer accounts.
+
+ -h: Also call htpasswd for this user with the given filename
+
+ -c: Passed to htpasswd(1)
+
+ -s: Specify an alternate secret file
+
+ -b: same as htpasswd(1), probably insecure, not recommended
+
+=head1 SEE ALSO
+
+L<htpasswd>(1), base Freeside documentation
+
+=cut
+
diff --git a/FS/bin/freeside-apply-credits b/FS/bin/freeside-apply-credits
new file mode 100755
index 0000000..ea6a7bd
--- /dev/null
+++ b/FS/bin/freeside-apply-credits
@@ -0,0 +1,21 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use vars qw( $user $cust_main @customers );
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch);
+use FS::cust_main;
+
+$user = shift or die &usage;
+&adminsuidsetup( $user );
+
+my @customers = qsearch('cust_main', {} );
+die "No customers" unless (scalar(@customers) > 0);
+
+foreach $cust_main (@customers) {
+ print "Applying credits for customer #". $cust_main->custnum;
+ $cust_main->apply_credits;
+}
+
+
+
diff --git a/FS/bin/freeside-bill b/FS/bin/freeside-bill
new file mode 100755
index 0000000..49ad4a7
--- /dev/null
+++ b/FS/bin/freeside-bill
@@ -0,0 +1,128 @@
+#!/usr/bin/perl -w
+# don't take any world-facing input
+#!/usr/bin/perl -Tw
+
+use strict;
+use Fcntl qw(:flock);
+use Date::Parse;
+use Getopt::Std;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch qsearchs);
+use FS::cust_main;
+
+&untaint_argv; #what it sounds like (eww)
+use vars qw($opt_a $opt_c $opt_d $opt_p);
+getopts("acd:p");
+my $user = shift or die &usage;
+
+adminsuidsetup $user;
+
+my %bill_only = map { $_ => 1 } (
+ @ARGV ? @ARGV : ( map $_->custnum, qsearch('cust_main', {} ) )
+);
+
+#we're at now now (and later).
+my($time)= $opt_d ? str2time($opt_d) : $^T;
+
+# find packages w/ bill < time && cancel != '', and create corresponding
+# customer objects
+
+my($cust_main,%saw);
+foreach $cust_main (
+ map {
+ unless ( exists $saw{ $_->custnum } && defined $saw{ $_->custnum} ) {
+ $saw{ $_->custnum } = 0; # to avoid 'use of uninitialized value' errors
+ }
+ if (
+ ( $opt_a || ( ( $_->getfield('bill') || 0 ) <= $time ) )
+ && $bill_only{ $_->custnum }
+ && !$saw{ $_->custnum }++
+ ) {
+ qsearchs('cust_main',{'custnum'=> $_->custnum } );
+ } else {
+ ();
+ }
+ } ( qsearch('cust_pkg', { 'cancel' => '' }),
+ qsearch('cust_pkg', { 'cancel' => 0 }),
+ )
+) {
+
+ # and bill them
+
+ print "Billing customer #" . $cust_main->getfield('custnum') . "\n";
+
+ my($error);
+
+ $error=$cust_main->bill('time'=>$time);
+ warn "Error billing, customer #" . $cust_main->getfield('custnum') .
+ ":" . $error if $error;
+
+ if ($opt_p) {
+ $cust_main->apply_payments;
+ $cust_main->apply_credits;
+ }
+
+ if ($opt_c) {
+ $error=$cust_main->collect( 'invoice_time' => $time);
+ warn "Error collecting from customer #" . $cust_main->custnum. ":$error"
+ if $error;
+
+ #sleep 1;
+ }
+
+}
+
+# subroutines
+
+sub untaint_argv {
+ foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
+ #$ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
+ # Date::Parse
+ $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
+ $ARGV[$_]=$1;
+ }
+}
+
+sub usage {
+ die "Usage:\n\n freeside-bill [ -c [ -p ] ] [ -d 'date' ] user [ custnum custnum ... ]\n";
+}
+
+=head1 NAME
+
+freeside-bill - Command line (crontab, script) interface to customer billing.
+
+=head1 SYNOPSIS
+
+ freeside-bill [ -c [ -p ] [ -a ] ] [ -d 'date' ] user [ custnum custnum ... ]
+
+=head1 DESCRIPTION
+
+This script is deprecated in 1.4.0. You should use freeside-daily instead.
+
+Bills customers. Searches for customers who are due for billing and calls
+the bill and collect methods of a cust_main object. See L<FS::cust_main>.
+
+ -c: Turn on collecting (you probably want this).
+
+ -p: Apply unapplied payments and credits before collecting (you probably want
+ this too)
+
+ -a: Call collect even if there isn't a new invoice (probably a bad idea for
+ daily use)
+
+ -d: Pretend it's 'date'. Date is in any format Date::Parse is happy with,
+ but be careful.
+
+user: From the mapsecrets file - see config.html from the base documentation
+
+custnum: if one or more customer numbers are specified, only bills those
+customers. Otherwise, bills all customers.
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<freeside-daily>, L<FS::cust_main>, config.html from the base documentation
+
+=cut
+
diff --git a/FS/bin/freeside-count-active-customers b/FS/bin/freeside-count-active-customers
new file mode 100755
index 0000000..759085a
--- /dev/null
+++ b/FS/bin/freeside-count-active-customers
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+domain=$1
+
+echo "\t
+select count(*) from cust_main where
+ 0 < ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ AND ( cust_pkg.cancel IS NULL
+ OR cust_pkg.cancel = 0
+ )
+ )
+ OR 0 = ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ );
+" | psql -U freeside -q $domain | head -1
+
diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily
new file mode 100755
index 0000000..00de298
--- /dev/null
+++ b/FS/bin/freeside-daily
@@ -0,0 +1,141 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Fcntl qw(:flock);
+use Date::Parse;
+use Getopt::Std;
+use FS::UID qw(adminsuidsetup driver_name dbh datasrc);
+use FS::Record qw(qsearch qsearchs);
+use FS::Conf;
+use FS::cust_main;
+
+&untaint_argv; #what it sounds like (eww)
+use vars qw($opt_d $opt_v $opt_p $opt_s $opt_y);
+getopts("p:d:vsy:");
+my $user = shift or die &usage;
+
+adminsuidsetup $user;
+
+$FS::cust_main::DEBUG = 1 if $opt_v;
+
+my %search;
+$search{'payby'} = $opt_p if $opt_p;
+
+my @cust_main = @ARGV
+ ? map { qsearchs('cust_main', { custnum => $_, %search } ) } @ARGV
+ : qsearch('cust_main', \%search )
+;
+
+#we're at now now (and later).
+my($time)= $opt_d ? str2time($opt_d) : $^T;
+$time += $opt_y * 86400 if $opt_y;
+
+my($cust_main,%saw);
+foreach $cust_main ( @cust_main ) {
+
+ # $^T not $time because -d is for pre-printing invoices
+ foreach my $cust_pkg (
+ grep { $_->expire && $_->expire <= $^T } $cust_main->ncancelled_pkgs
+ ) {
+ my $error = $cust_pkg->cancel;
+ warn "Error cancelling expired pkg ". $cust_pkg->pkgnum. " for custnum ".
+ $cust_main->custnum. ": $error"
+ if $error;
+ }
+
+ my $error = $cust_main->bill( 'time' => $time,
+ 'resetup' => $opt_s, );
+ warn "Error billing, custnum ". $cust_main->custnum. ": $error" if $error;
+
+ $cust_main->apply_payments;
+ $cust_main->apply_credits;
+
+ $error = $cust_main->collect( 'invoice_time' => $time );
+ warn "Error collecting, custnum". $cust_main->custnum. ": $error" if $error;
+
+}
+
+if ( driver_name eq 'Pg' ) {
+ dbh->{AutoCommit} = 1; #so we can vacuum
+ foreach my $statement ( 'vacuum', 'vacuum analyze' ) {
+ my $sth = dbh->prepare($statement) or die dbh->errstr;
+ $sth->execute or die $sth->errstr;
+ }
+}
+
+#local hack
+my $conf = new FS::Conf;
+my $dest = $conf->config('dump-scpdest');
+if ( $dest ) {
+ datasrc =~ /dbname=([\w\.]+)$/ or die "unparsable datasrc ". datasrc;
+ my $database = $1;
+ eval "use Net::SCP qw(scp);";
+ if ( driver_name eq 'Pg' ) {
+ system("pg_dump $database >/var/tmp/$database.sql")
+ } else {
+ die "database dumps not yet supported for ". driver_name;
+ }
+ scp("/var/tmp/$database.sql", $dest);
+ unlink "/var/tmp/$database.sql" or die $!;
+}
+
+# subroutines
+
+sub untaint_argv {
+ foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
+ #$ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
+ # Date::Parse
+ $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
+ $ARGV[$_]=$1;
+ }
+}
+
+sub usage {
+ die "Usage:\n\n freeside-daily [ -d 'date' ] user [ custnum custnum ... ]\n";
+}
+
+=head1 NAME
+
+freeside-daily - Run daily billing and invoice collection events.
+
+=head1 SYNOPSIS
+
+ freeside-daily [ -d 'date' ] [ -y days ] [ -p 'payby' ] [ -s ] [ -v ] user [ custnum custnum ... ]
+
+=head1 DESCRIPTION
+
+Bills customers and runs invoice collection events. Should be run from
+crontab daily.
+
+This script replaces freeside-bill from 1.3.1.
+
+Bills customers. Searches for customers who are due for billing and calls
+the bill and collect methods of a cust_main object. See L<FS::cust_main>.
+
+ -d: Pretend it's 'date'. Date is in any format Date::Parse is happy with,
+ but be careful.
+
+ -y: In addition to -d, which specifies an absolute date, the -y switch
+ specifies an offset, in days. For example, "-y 15" would increment the
+ "pretend date" 15 days from whatever was specified by the -d switch
+ (or now, if no -d switch was given).
+
+ -p: Only process customers with the specified payby (I<CARD>, I<DCRD>, I<CHEK>, I<DCHK>, I<BILL>, I<COMP>, I<LECB>)
+
+ -s: re-charge setup fees
+
+ -v: enable debugging
+
+user: From the mapsecrets file - see config.html from the base documentation
+
+custnum: if one or more customer numbers are specified, only bills those
+customers. Otherwise, bills all customers.
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::cust_main>, config.html from the base documentation
+
+=cut
+
diff --git a/FS/bin/freeside-deloutsource b/FS/bin/freeside-deloutsource
new file mode 100644
index 0000000..5618535
--- /dev/null
+++ b/FS/bin/freeside-deloutsource
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+domain=$1
+
+dropdb $domain && \
+rm -rf /usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=$domain && \
+rm -rf /usr/local/etc/freeside/counters.DBI:Pg:host=localhost\;dbname=$domain && \
+rm -rf /usr/local/etc/freeside/cache.DBI:Pg:host=localhost\;dbname=$domain && \
+rm -rf /usr/local/etc/freeside/export.DBI:Pg:host=localhost\;dbname=$domain && \
+rm /usr/local/etc/freeside/dbdef.DBI:Pg:host=localhost\;dbname=$domain
+
diff --git a/FS/bin/freeside-deloutsourceuser b/FS/bin/freeside-deloutsourceuser
new file mode 100644
index 0000000..96871e5
--- /dev/null
+++ b/FS/bin/freeside-deloutsourceuser
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+username=$1
+
+freeside-deluser -h /usr/local/etc/freeside/htpasswd $username 2>/dev/null
+
diff --git a/FS/bin/freeside-deluser b/FS/bin/freeside-deluser
new file mode 100644
index 0000000..57d6ce1
--- /dev/null
+++ b/FS/bin/freeside-deluser
@@ -0,0 +1,64 @@
+#!/usr/bin/perl -w
+
+use strict;
+use vars qw($opt_h);
+use Fcntl qw(:flock);
+use Getopt::Std;
+
+my $FREESIDE_CONF = "/usr/local/etc/freeside";
+
+getopts("h:");
+my $user = shift or die &usage;
+
+if ( $opt_h ) {
+ open(HTPASSWD,"<$opt_h")
+ and flock(HTPASSWD,LOCK_EX)
+ or die "can't open $opt_h: $!";
+ open(HTPASSWD_TMP,">$opt_h.tmp") or die "can't open $opt_h.tmp: $!";
+ while (<HTPASSWD>) {
+ print HTPASSWD_TMP $_ unless /^$user:/;
+ }
+ close HTPASSWD_TMP;
+ rename "$opt_h.tmp", "$opt_h" or die $!;
+ flock(HTPASSWD,LOCK_UN);
+ close HTPASSWD;
+}
+
+open(MAPSECRETS,"<$FREESIDE_CONF/mapsecrets")
+ and flock(MAPSECRETS,LOCK_EX)
+ or die "can't open $FREESIDE_CONF/mapsecrets: $!";
+open(MAPSECRETS_TMP,">>$FREESIDE_CONF/mapsecrets.tmp")
+ or die "can't open $FREESIDE_CONF/mapsecrets.tmp: $!";
+while (<MAPSECRETS>) {
+ print MAPSECRETS_TMP $_ unless /^$user\s/;
+}
+close MAPSECRETS_TMP;
+rename "$FREESIDE_CONF/mapsecrets.tmp", "$FREESIDE_CONF/mapsecrets" or die $!;
+flock(MAPSECRETS,LOCK_UN);
+close MAPSECRETS;
+
+sub usage {
+ die "Usage:\n\n freeside-deluser [ -h htpasswd_file ] username"
+}
+
+=head1 NAME
+
+freeside-deluser - Command line interface to add (freeside) users.
+
+=head1 SYNOPSIS
+
+ freeside-deluser [ -h htpasswd_file ] username
+
+=head1 DESCRIPTION
+
+Adds a user to the Freeside billing system. This is for adding users (internal
+sales/tech folks) to the web interface, not for adding customer accounts.
+
+ -h: Also delete from the given htpasswd filename
+
+=head1 SEE ALSO
+
+L<freeside-adduser>, L<htpasswd>(1), base Freeside documentation
+
+=cut
+
diff --git a/FS/bin/freeside-email b/FS/bin/freeside-email
new file mode 100755
index 0000000..400dc2a
--- /dev/null
+++ b/FS/bin/freeside-email
@@ -0,0 +1,59 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::Conf;
+use FS::Record qw(qsearch);
+use FS::svc_acct;
+
+&untaint_argv; #what it sounds like (eww)
+my $user = shift or die &usage;
+
+adminsuidsetup $user;
+
+my $conf = new FS::Conf;
+
+my @svc_acct = qsearch('svc_acct', {});
+my @emails = map $_->email, @svc_acct;
+
+print join("\n", @emails), "\n";
+
+# subroutines
+
+sub untaint_argv {
+ foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
+ #$ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
+ # Date::Parse
+ $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
+ $ARGV[$_]=$1;
+ }
+}
+
+sub usage {
+ die "Usage:\n\n freeside-email user\n";
+}
+
+=head1 NAME
+
+freeside-email - Prints email addresses of all users on STDOUT
+
+=head1 SYNOPSIS
+
+ freeside-email user
+
+=head1 DESCRIPTION
+
+Prints the email addresses of all customers on STDOUT, separated by newlines.
+
+user: From the mapsecrets file - see config.html from the base documentation
+
+=head1 VERSION
+
+$Id: freeside-email,v 1.2 2002-09-18 22:50:44 ivan Exp $
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+=cut
+
diff --git a/FS/bin/freeside-expiration-alerter b/FS/bin/freeside-expiration-alerter
new file mode 100755
index 0000000..691fd3a
--- /dev/null
+++ b/FS/bin/freeside-expiration-alerter
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use Date::Format;
+use Time::Local;
+use Text::Template;
+use Getopt::Std;
+use Net::SMTP;
+use Mail::Header;
+use Mail::Internet;
+use FS::Conf;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch);
+use FS::cust_main;
+
+use vars qw($smtpmachine @body);
+
+#hush, perl!
+$FS::alerter::_template::first = "";
+$FS::alerter::_template::last = "";
+$FS::alerter::_template::company = "";
+$FS::alerter::_template::payby = "";
+$FS::alerter::_template::expdate = "";
+
+# Set the mail program and other variables
+my $mail_sender = "billing\@mydomain.tld"; # or invoice_from if available
+my $failure_recipient = "postmaster"; # or invoice_from if available
+my $warning_time = 30 * 24 * 60 * 60;
+my $urgent_time = 15 * 24 * 60 * 60;
+my $panic_time = 5 * 24 * 60 * 60;
+my $window_time = 24 * 60 * 60;
+
+&untaint_argv; #what it sounds like (eww)
+
+#we're at now now (and later).
+my($_date)= $^T;
+
+# Get the current month
+my ($sec,$min,$hour,$mday,$mon,$year) =
+ (localtime($_date) )[0,1,2,3,4,5];
+$mon++;
+
+# Login to the database
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+# Get the needed configuration files
+my $conf = new FS::Conf;
+$smtpmachine = $conf->config('smtpmachine');
+$mail_sender = $conf->config('invoice_from')
+ if $conf->exists('invoice_from');
+$failure_recipient = $conf->config('invoice_from')
+ if $conf->exists('invoice_from');
+
+
+my(@customers)=qsearch('cust_main',{});
+if (scalar(@customers) == 0)
+{
+ exit 1;
+}
+
+# Prepare for sending email
+
+$ENV{MAILADDRESS} = $mail_sender;
+my $header = new Mail::Header ( [
+ "From: Account Processor",
+ "To: $failure_recipient",
+ "Sender: $mail_sender",
+ "Reply-To: $mail_sender",
+ "Subject: Unnotified Billing Arrangement Expirations",
+] );
+
+my @alerter_template = $conf->config('alerter_template')
+ or die "cannot load config file alerter_template";
+
+my $alerter = new Text::Template (TYPE => 'ARRAY', SOURCE => [ map "$_\n", @alerter_template ])
+ or die "can't create new Text::Template object: Text::Template::ERROR";
+$alerter->compile() or die "can't compile template: Text::Template::ERROR";
+
+# Now I can start looping
+foreach my $customer (@customers)
+{
+ my $paydate = $customer->getfield('paydate');
+ next if $paydate =~ /^\s*$/; #skip empty expiration dates
+
+ my $custnum = $customer->getfield('custnum');
+ my $first = $customer->getfield('first');
+ my $last = $customer->getfield('last');
+ my $company = $customer->getfield('company');
+ my $payby = $customer->getfield('payby');
+ my $payinfo = $customer->getfield('payinfo');
+ my $daytime = $customer->getfield('daytime');
+ my $night = $customer->getfield('night');
+
+ my ($payyear,$paymonth,$payday) = split (/-/,$paydate);
+
+ my $expire_time = timelocal(0,0,0,$payday,--$paymonth,$payyear);
+
+ #credit cards expire at the end of the month/year of their exp date
+ if ($payby eq 'CARD' || $payby eq 'DCRD') {
+ ($paymonth < 11) ? $paymonth++ : ($paymonth=0, $payyear++);
+ $expire_time = timelocal(0,0,0,$payday,$paymonth,$payyear);
+ $expire_time--;
+ }
+
+ if (($expire_time < $_date + $warning_time &&
+ $expire_time > $_date + $warning_time - $window_time) ||
+ ($expire_time < $_date + $urgent_time &&
+ $expire_time > $_date + $urgent_time - $window_time) ||
+ ($expire_time < $_date + $panic_time &&
+ $expire_time > $_date + $panic_time - $window_time)) {
+
+
+
+ my @packages = $customer->ncancelled_pkgs;
+ if (scalar(@packages) != 0) {
+ my @invoicing_list = $customer->invoicing_list;
+ if ( grep { $_ ne 'POST' } @invoicing_list ) {
+ my $header = new Mail::Header ( [
+ "From: $mail_sender",
+ "To: ". join(', ', grep { $_ ne 'POST' } @invoicing_list ),
+ "Sender: $mail_sender",
+ "Reply-To: $mail_sender",
+ "Date: ". time2str("%a, %d %b %Y %X %z", time),
+ "Subject: Billing Arrangement Expiration",
+ ] );
+ $FS::alerter::_template::first = $first;
+ $FS::alerter::_template::last = $last;
+ $FS::alerter::_template::company = $company;
+ if ($payby eq 'CARD' || $payby eq 'DCRD') {
+ $FS::alerter::_template::payby = "credit card (" .
+ substr($payinfo, 0, 2) . "xxxxxxxxxx" .
+ substr($payinfo, -4) . ")";
+ }elsif ($payby eq 'COMP') {
+ $FS::alerter::_template::payby = "complimentary account";
+ }else{
+ $FS::alerter::_template::payby = "current method";
+ }
+ $FS::alerter::_template::expdate = $expire_time;
+
+ my $message = new Mail::Internet (
+ 'Header' => $header,
+ 'Body' => [ $alerter->fill_in( PACKAGE => 'FS::alerter::_template' ) ],
+ );
+ $!=0;
+ $message->smtpsend( Host => $smtpmachine )
+ or $message->smtpsend( Host => $smtpmachine, Debug => 1 )
+ or die "Can't send expiration email: $!";
+
+ } elsif ( ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list ) {
+ push @body, sprintf(qq{%5d %-32.32s %4s %10s %12s %12s},
+ $custnum,
+ $first . " " . $last . " " . $company,
+ $payby,
+ $paydate,
+ $daytime,
+ $night);
+ }
+ }
+ }
+}
+
+# Now I need to send EMAIL
+if (scalar(@body)) {
+ my $message = new Mail::Internet (
+ 'Header' => $header,
+ 'Body' => [ (@body) ],
+ );
+ $!=0;
+ $message->smtpsend( Host => $smtpmachine )
+ or $message->smtpsend( Host => $smtpmachine, Debug => 1 )
+ or die "can't send alerter failure email to $failure_recipient".
+ " via server $smtpmachine with SMTP: $!";
+}
+
+# subroutines
+sub untaint_argv {
+ foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
+ $ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal argument \"$ARGV[$_]\"";
+ $ARGV[$_]=$1;
+ }
+}
+
+sub usage {
+ die "Usage:\n\n freeside-expiration-alerter user\n";
+}
+
+=head1 NAME
+
+freeside-expiration-alerter - Emails notifications of credit card expirations.
+
+=head1 SYNOPSIS
+
+ freeside-expiration-alerter user
+
+=head1 DESCRIPTION
+
+Emails customers notice that their credit card or other billing arrangement
+is about to expire. Usually run as a cron job.
+
+user: From the mapsecrets file - see config.html from the base documentation
+
+=head1 VERSION
+
+$Id: freeside-expiration-alerter,v 1.5 2003-04-21 20:53:57 ivan Exp $
+
+=head1 BUGS
+
+Yes..... Use at your own risk. No guarantees or warrantees of any
+kind apply to this program. Parts of this program are hacked from
+other GNU licensed software created mainly by Ivan Kohler.
+
+This is released under the GNU Public License. See www.gnu.org
+for more information regarding this license.
+
+=head1 SEE ALSO
+
+L<FS::cust_main>, config.html from the base documentation
+
+=head1 AUTHOR
+
+Jeff Finucane <jeff@cmh.net>
+
+=cut
+
+
diff --git a/FS/bin/freeside-queued b/FS/bin/freeside-queued
new file mode 100644
index 0000000..6ea27c0
--- /dev/null
+++ b/FS/bin/freeside-queued
@@ -0,0 +1,267 @@
+#!/usr/bin/perl -w
+
+use strict;
+use vars qw( $log_file $sigterm $sigint $kids $max_kids %kids );
+use subs qw( _die _logmsg );
+use Fcntl qw(:flock);
+use POSIX qw(:sys_wait_h setsid);
+use Date::Format;
+use IO::File;
+use FS::UID qw(adminsuidsetup forksuidsetup driver_name dbh);
+use FS::Record qw(qsearch qsearchs);
+use FS::queue;
+use FS::queue_depend;
+
+# no autoloading just yet
+use FS::cust_main;
+use FS::svc_acct;
+use Net::SSH 0.07;
+use FS::part_export;
+
+$max_kids = '10'; #guess it should be a config file...
+$kids = 0;
+
+my $user = shift or die &usage;
+
+#my $pid_file = "/var/run/freeside-queued.$user.pid";
+my $pid_file = "/var/run/freeside-queued.pid";
+
+&daemonize1;
+
+#sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; }
+#$SIG{CHLD} = \&REAPER;
+
+$sigterm = 0;
+$sigint = 0;
+$SIG{INT} = sub { warn "SIGINT received; shutting down\n"; $sigint++; };
+$SIG{TERM} = sub { warn "SIGTERM received; shutting down\n"; $sigterm++; };
+
+my $freeside_gid = scalar(getgrnam('freeside'))
+ or die "can't setgid to freeside group\n";
+$) = $freeside_gid;
+$( = $freeside_gid;
+#if freebsd can't setuid(), presumably it can't setgid() either. grr fleabsd
+($(,$)) = ($),$();
+$) = $freeside_gid;
+
+$> = $FS::UID::freeside_uid;
+$< = $FS::UID::freeside_uid;
+#freebsd is sofa king broken, won't setuid()
+($<,$>) = ($>,$<);
+$> = $FS::UID::freeside_uid;
+
+$ENV{HOME} = (getpwuid($>))[7]; #for ssh
+adminsuidsetup $user;
+
+$log_file = "/usr/local/etc/freeside/queuelog.". $FS::UID::datasrc;
+
+&daemonize2;
+
+$SIG{__DIE__} = \&_die;
+$SIG{__WARN__} = \&_logmsg;
+
+warn "freeside-queued starting\n";
+
+my $warnkids=0;
+while (1) {
+
+ &reap_kids;
+ #prevent runaway forking
+ if ( $kids >= $max_kids ) {
+ warn "WARNING: maximum $kids children reached\n" unless $warnkids++;
+ &reap_kids;
+ sleep 1; #waiting for signals is cheap
+ next;
+ }
+ $warnkids=0;
+
+ my $nodepend = driver_name eq 'mysql'
+ ? ''
+ : 'AND 0 = ( SELECT COUNT(*) FROM queue_depend'.
+ ' WHERE queue_depend.jobnum = queue.jobnum ) ';
+
+ #my($job, $ljob);
+ #{
+ # my $oldAutoCommit = $FS::UID::AutoCommit;
+ # local $FS::UID::AutoCommit = 0;
+ $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $job = qsearchs(
+ 'queue',
+ { 'status' => 'new' },
+ '',
+ driver_name eq 'mysql'
+ ? "$nodepend ORDER BY jobnum LIMIT 1 FOR UPDATE"
+ : "$nodepend ORDER BY jobnum FOR UPDATE LIMIT 1"
+ ) or do {
+ $dbh->commit or die $dbh->errstr; #if $oldAutoCommit;
+ sleep 5; #connecting to db is expensive
+ next;
+ };
+
+ if ( driver_name eq 'mysql'
+ && qsearch('queue_depend', { 'jobnum' => $job->jobnum } ) ) {
+ $dbh->commit or die $dbh->errstr; #if $oldAutoCommit;
+ sleep 5; #would be better if mysql could do everything in query above
+ next;
+ }
+
+ my %hash = $job->hash;
+ $hash{'status'} = 'locked';
+ my $ljob = new FS::queue ( \%hash );
+ my $error = $ljob->replace($job);
+ die $error if $error;
+
+ $dbh->commit or die $dbh->errstr; #if $oldAutoCommit;
+
+ $FS::UID::AutoCommit = 1;
+ #}
+
+ my @args = $ljob->args;
+
+ defined( my $pid = fork ) or do {
+ warn "WARNING: can't fork: $!\n";
+ my %hash = $job->hash;
+ $hash{'status'} = 'failed';
+ $hash{'statustext'} = "[freeside-queued] can't fork: $!";
+ my $ljob = new FS::queue ( \%hash );
+ my $error = $ljob->replace($job);
+ die $error if $error;
+ next; #don't increment the kid counter
+ };
+
+ if ( $pid ) {
+ $kids++;
+ $kids{$pid} = 1;
+ } else { #kid time
+
+ #get new db handle
+ $FS::UID::dbh->{InactiveDestroy} = 1;
+
+ forksuidsetup($user);
+
+ #auto-use export classes...
+ if ( $ljob->job =~ /(FS::part_export::\w+)::/ ) {
+ my $class = $1;
+ eval "use $class;";
+ if ( $@ ) {
+ warn "job use $class failed";
+ my %hash = $ljob->hash;
+ $hash{'status'} = 'failed';
+ $hash{'statustext'} = $@;
+ my $fjob = new FS::queue( \%hash );
+ my $error = $fjob->replace($ljob);
+ die $error if $error;
+ exit; #end-of-kid
+ };
+ }
+
+ my $eval = "&". $ljob->job. '(@args);';
+ warn "running $eval";
+ eval $eval; #throw away return value? suppose so
+ if ( $@ ) {
+ warn "job $eval failed";
+ my %hash = $ljob->hash;
+ $hash{'status'} = 'failed';
+ $hash{'statustext'} = $@;
+ my $fjob = new FS::queue( \%hash );
+ my $error = $fjob->replace($ljob);
+ die $error if $error;
+ } else {
+ $ljob->delete;
+ }
+
+ exit;
+ #end-of-kid
+ }
+
+} continue {
+ if ( $sigterm ) {
+ warn "received TERM signal; exiting\n";
+ exit;
+ }
+ if ( $sigint ) {
+ warn "received INT signal; exiting\n";
+ exit;
+ }
+}
+
+sub usage {
+ die "Usage:\n\n freeside-queued user\n";
+}
+
+sub _die {
+ my $msg = shift;
+ unlink $pid_file if -e $pid_file;
+ _logmsg($msg);
+}
+
+sub _logmsg {
+ chomp( my $msg = shift );
+ my $log = new IO::File ">>$log_file";
+ flock($log, LOCK_EX);
+ seek($log, 0, 2);
+ print $log "[". time2str("%a %b %e %T %Y",time). "] [$$] $msg\n";
+ flock($log, LOCK_UN);
+ close $log;
+}
+
+sub daemonize1 {
+
+ chdir "/" or die "Can't chdir to /: $!";
+ open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
+ defined(my $pid = fork) or die "Can't fork: $!";
+ if ( $pid ) {
+ print "freeside-queued started with pid $pid\n"; #logging to $log_file\n";
+ exit unless $pid_file;
+ my $pidfh = new IO::File ">$pid_file" or exit;
+ print $pidfh "$pid\n";
+ exit;
+ }
+ #open STDOUT, '>/dev/null'
+ # or die "Can't write to /dev/null: $!";
+ #setsid or die "Can't start a new session: $!";
+ #open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
+
+}
+
+sub daemonize2 {
+ open STDOUT, '>/dev/null'
+ or die "Can't write to /dev/null: $!";
+ setsid or die "Can't start a new session: $!";
+ open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
+}
+
+sub reap_kids {
+ foreach my $pid ( keys %kids ) {
+ my $kid = waitpid($pid, WNOHANG);
+ if ( $kid > 0 ) {
+ $kids--;
+ delete $kids{$kid};
+ }
+ }
+}
+
+=head1 NAME
+
+freeside-queued - Job queue daemon
+
+=head1 SYNOPSIS
+
+ freeside-queued user
+
+=head1 DESCRIPTION
+
+Job queue daemon. Should be running at all times.
+
+user: from the mapsecrets file - see config.html from the base documentation
+
+=head1 VERSION
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+=cut
+
diff --git a/FS/bin/freeside-radgroup b/FS/bin/freeside-radgroup
new file mode 100644
index 0000000..ed85626
--- /dev/null
+++ b/FS/bin/freeside-radgroup
@@ -0,0 +1,76 @@
+#!/usr/bin/perl -w
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch);
+use FS::cust_svc;
+use FS::svc_acct;
+
+&untaint_argv; #what it sounds like (eww)
+
+my($user, $action, $groupname, $svcpart) = @ARGV;
+
+adminsuidsetup $user;
+
+my @svc_acct = map { $_->svc_x } qsearch('cust_svc', { svcpart => $svcpart } );
+
+if ( lc($action) eq 'add' ) {
+ foreach my $svc_acct ( @svc_acct ) {
+ my @groups = $svc_acct->radius_groups;
+ next if grep { $_ eq $groupname } @groups;
+ push @groups, $groupname;
+ my %hash = $svc_acct->hash;
+ $hash{usergroup} = \@groups;
+ my $new = new FS::svc_acct \%hash;
+ my $error = $new->replace($svc_acct);
+ die $error if $error;
+ }
+} else {
+ die &usage;
+}
+
+# subroutines
+
+sub untaint_argv {
+ foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
+ $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
+ $ARGV[$_]=$1;
+ }
+}
+
+sub usage {
+ die "Usage:\n\n freeside-radgroup user action groupname svcpart\n";
+}
+
+=head1 NAME
+
+freeside-radgroup - Command line utility to manipulate radius groups
+
+=head1 SYNOPSIS
+
+ freeside-addgroup user action groupname svcpart
+
+=head1 DESCRIPTION
+
+ B<user> is a freeside user as added with freeside-adduser.
+
+ B<command> is the action to take. Available actions are: I<add>
+
+ B<groupname> is the group to add (or remove, etc.)
+
+ B<svcpart> specifies which accounts will be updated.
+
+=head1 EXAMPLES
+
+freeside-radgroup freesideuser add groupname 3
+
+Adds I<groupname> to all accounts with service definition 3.
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<freeside-adduser>, L<FS::svc_acct>, L<FS::part_svc>
+
+=cut
+
diff --git a/FS/bin/freeside-reexport b/FS/bin/freeside-reexport
new file mode 100644
index 0000000..54af9dd
--- /dev/null
+++ b/FS/bin/freeside-reexport
@@ -0,0 +1,71 @@
+#!/usr/bin/perl -w
+
+use strict;
+use vars qw($opt_s $opt_u $opt_p);
+use Getopt::Std;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch qsearchs);
+use FS::part_export;
+use FS::svc_acct;
+use FS::cust_svc;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+my $export_x = shift or die &usage;
+my @part_export;
+if ( $export_x =~ /^(\d+)$/ ) {
+ @part_export = qsearchs('part_export', { exportnum=>$1 } )
+ or die "exportnum $export_x not found\n";
+} else {
+ @part_export = qsearch('part_export', { exporttype=>$export_x } )
+ or die "no exports of type $export_x found\n";
+}
+
+getopts('s:u:p:');
+
+my @svc_x = ();
+if ( $opt_s ) {
+ my $cust_svc = qsearchs('cust_svc', { svcnum=>$opt_s } )
+ or die "svcnum $opt_s not found\n";
+ push @svc_x, $cust_svc->svc_x;
+} elsif ( $opt_u ) {
+ my $svc_x = qsearchs('svc_acct', { username=>$opt_u } )
+ or die "username $opt_u not found\n";
+ push @svc_x, $svc_x;
+} elsif ( $opt_p ) {
+ push @svc_x, map { $_->svc_x } qsearch('cust_svc', { svcpart=>$opt_p } );
+ die "no services with svcpart $opt_p found\n" unless @svc_x;
+}
+
+foreach my $part_export ( @part_export ) {
+ foreach my $svc_x ( @svc_x ) {
+ my $error = $part_export->export_insert($svc_x);
+ die $error if $error;
+ }
+}
+
+
+sub usage {
+ die "Usage:\n\n freeside-reexport user exportnum|exporttype [ -s svcnum | -u username | -p svcpart ]\n";
+}
+
+=head1 NAME
+
+freeside-reexport - Command line tool to re-trigger export jobs for existing services
+
+=head1 SYNOPSIS
+
+ freeside-reexport user exportnum|exporttype [ -s svcnum | -u username | -p svcpart ]
+
+=head1 DESCRIPTION
+
+ Re-queues the export job for the specified exportnum or exporttype(s) and
+ specified service (selected by svcnum or username).
+
+=head1 SEE ALSO
+
+L<freeside-sqlradius-reset>, L<FS::part_export>
+
+=cut
+
diff --git a/FS/bin/freeside-selfservice-server b/FS/bin/freeside-selfservice-server
new file mode 100644
index 0000000..864c2d4
--- /dev/null
+++ b/FS/bin/freeside-selfservice-server
@@ -0,0 +1,266 @@
+#!/usr/bin/perl -w
+#
+# freeside-selfservice-server
+
+# alas, much false laziness with freeside-queued and fs_signup_server. at
+# least it is slated to replace fs_{signup,passwd,mailadmin}_server
+# should probably generalize the version in here, or better yet use
+# Proc::Daemon or somesuch
+
+use strict;
+use vars qw( $Debug %kids $kids $max_kids $shutdown $log_file $ssh_pid );
+use subs qw( lock_write unlock_write );
+use Fcntl qw(:flock);
+use POSIX qw(:sys_wait_h setsid);
+use IO::Handle;
+use IO::Select;
+use IO::File;
+use Storable 2.09 qw(nstore_fd fd_retrieve);
+use Net::SSH qw(sshopen2);
+use FS::UID qw(adminsuidsetup forksuidsetup);
+use FS::ClientAPI;
+
+use FS::Conf;
+use FS::cust_bill;
+use FS::cust_pkg;
+
+$Debug = 1; # >= 2 will log packet contents, including potentially compromising
+ # information
+
+$shutdown = 0;
+$max_kids = '10'; #?
+$kids = 0;
+
+my $user = shift or die &usage;
+my $machine = shift or die &usage;
+my $tag = scalar(@ARGV) ? shift : '';
+
+# $FS::UID::datasrc not posible
+my $pid_file = "/var/run/freeside-selfservice-server.$user.$machine.pid";
+
+my $lock_file = "/usr/local/etc/freeside/selfservice.$machine.writelock";
+open(LOCKFILE,">$lock_file") or die "can't open $lock_file: $!";
+
+&init($user);
+
+my $conf = new FS::Conf;
+
+my $clientd = "/usr/local/sbin/freeside-selfservice-clientd"; #better name?
+
+my $warnkids=0;
+while (1) {
+ my($writer,$reader,$error) = (new IO::Handle, new IO::Handle, new IO::Handle);
+ warn "connecting to $machine\n" if $Debug;
+
+ $ssh_pid = sshopen2($machine,$reader,$writer,$clientd,$tag);
+
+# nstore_fd(\*writer, {'hi'=>'there'});
+
+ warn "entering main loop\n" if $Debug;
+ my $undisp = 0;
+ my $s = IO::Select->new( $reader );
+ while (1) {
+
+ &reap_kids;
+
+ warn "waiting for packet from client\n" if $Debug && !$undisp;
+ $undisp = 1;
+ my @handles = $s->can_read(5);
+ unless ( @handles ) {
+ &shutdown if $shutdown;
+ next;
+ }
+
+ $undisp = 0;
+
+ warn "receiving packet from client\n" if $Debug;
+
+ my $packet = eval { fd_retrieve($reader); };
+ if ( $@ ) {
+ warn "Storable error receiving packet from client".
+ " (assuming lost connection): $@\n"
+ if $Debug;
+ if ( $ssh_pid ) {
+ warn "sending TERM signal to ssh process $ssh_pid\n" if $Debug;
+ kill 'TERM', $ssh_pid;
+ $ssh_pid = 0;
+ }
+ last;
+ }
+ warn "packet received\n".
+ join('', map { " $_=>$packet->{$_}\n" } keys %$packet )
+ if $Debug > 1;
+
+ #prevent runaway forking
+ my $warnkids = 0;
+ while ( $kids >= $max_kids ) {
+ warn "WARNING: maximum $kids children reached\n" unless $warnkids++;
+ &reap_kids;
+ sleep 1;
+ }
+
+ warn "forking child\n" if $Debug;
+ defined( my $pid = fork ) or die "can't fork: $!";
+ if ( $pid ) {
+ $kids++;
+ $kids{$pid} = 1;
+ warn "child $pid spawned\n" if $Debug;
+ } else { #kid time
+
+ #get new db handle
+ $FS::UID::dbh->{InactiveDestroy} = 1;
+ forksuidsetup($user);
+
+ my $type = $packet->{_packet};
+ warn "calling $type handler\n" if $Debug;
+ my $rv = eval { FS::ClientAPI->dispatch($type, $packet); };
+ if ( $@ ) {
+ warn my $error = "WARNING: error dispatching $type: $@";
+ $rv = { _error => $error };
+ }
+ $rv->{_token} = $packet->{_token}; #identifier
+
+ warn "sending response\n" if $Debug;
+ lock_write;
+ nstore_fd($rv, $writer) or die "FATAL: can't send response: $!";
+ $writer->flush or die "FATAL: can't flush: $!";
+ unlock_write;
+
+ warn "child exiting\n" if $Debug;
+ exit; #end-of-kid
+ }
+
+ }
+
+ warn "connection lost, reconnecting\n" if $Debug;
+ sleep 3;
+
+}
+
+###
+# utility subroutines
+###
+
+sub reap_kids {
+ #warn "reaping kids\n";
+ foreach my $pid ( keys %kids ) {
+ my $kid = waitpid($pid, WNOHANG);
+ if ( $kid > 0 ) {
+ $kids--;
+ delete $kids{$kid};
+ }
+ }
+ #warn "done reaping\n";
+}
+
+sub init {
+ my $user = shift;
+
+ chdir "/" or die "Can't chdir to /: $!";
+ open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
+ defined(my $pid = fork) or die "Can't fork: $!";
+ if ( $pid ) {
+ print "freeside-selfservice-server to $machine started with pid $pid\n"; #logging to $log_file
+ exit unless $pid_file;
+ my $pidfh = new IO::File ">$pid_file" or exit;
+ print $pidfh "$pid\n";
+ exit;
+ }
+
+# sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; }
+# #sub REAPER { my $pid = wait; $kids--; $SIG{CHLD} = \&REAPER; }
+# $SIG{CHLD} = \&REAPER;
+
+ $shutdown = 0;
+ $SIG{HUP} = sub { warn "SIGHUP received; shutting down\n"; $shutdown++; };
+ $SIG{INT} = sub { warn "SIGINT received; shutting down\n"; $shutdown++; };
+ $SIG{TERM} = sub { warn "SIGTERM received; shutting down\n"; $shutdown++; };
+ $SIG{QUIT} = sub { warn "SIGQUIT received; shutting down\n"; $shutdown++; };
+ $SIG{PIPE} = sub { warn "SIGPIPE received; shutting down\n"; $shutdown++; };
+
+ #false laziness w/freeside-queued
+ my $freeside_gid = scalar(getgrnam('freeside'))
+ or die "can't setgid to freeside group\n";
+ $) = $freeside_gid;
+ $( = $freeside_gid;
+ #if freebsd can't setuid(), presumably it can't setgid() either. grr fleabsd
+ ($(,$)) = ($),$();
+ $) = $freeside_gid;
+
+ $> = $FS::UID::freeside_uid;
+ $< = $FS::UID::freeside_uid;
+ #freebsd is sofa king broken, won't setuid()
+ ($<,$>) = ($>,$<);
+ $> = $FS::UID::freeside_uid;
+ #eslaf
+
+ $ENV{HOME} = (getpwuid($>))[7]; #for ssh
+ adminsuidsetup $user;
+
+ #$log_file = "/usr/local/etc/freeside/selfservice.". $FS::UID::datasrc; #MACHINE NAME
+ $log_file = "/usr/local/etc/freeside/selfservice.$machine.log";
+
+ open STDOUT, '>/dev/null'
+ or die "Can't write to /dev/null: $!";
+ setsid or die "Can't start a new session: $!";
+ open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
+
+ $SIG{__DIE__} = \&_die;
+ $SIG{__WARN__} = \&_logmsg;
+
+ warn "freeside-selfservice-server starting\n";
+
+}
+
+sub shutdown {
+ my $wait = 12; #wait up to 1 minute
+ while ( $kids > 0 && $wait-- ) {
+ warn "waiting for $kids children to terminate";
+ sleep 5;
+ }
+ warn "abandoning $kids children" if $kids;
+ kill 'TERM', $ssh_pid if $ssh_pid;
+ die "exiting";
+}
+
+sub _die {
+ my $msg = shift;
+ unlink $pid_file if -e $pid_file;
+ _logmsg($msg);
+}
+
+sub _logmsg {
+ chomp( my $msg = shift );
+ _do_logmsg( "[server] [". scalar(localtime). "] [$$] $msg\n" );
+}
+
+sub _do_logmsg {
+ chomp( my $msg = shift );
+ my $log = new IO::File ">>$log_file";
+ flock($log, LOCK_EX);
+ seek($log, 0, 2);
+ print $log "$msg\n";
+ flock($log, LOCK_UN);
+ close $log;
+}
+
+sub lock_write {
+ #broken on freebsd?
+ #flock($writer, LOCK_EX) or die "FATAL: can't lock write stream: $!";
+
+ flock(LOCKFILE, LOCK_EX) or die "FATAL: can't lock $lock_file: $!";
+
+}
+
+sub unlock_write {
+ #broken on freebsd?
+ #flock($writer, LOCK_UN) or die "WARNING: can't release write lock: $!";
+
+ flock(LOCKFILE, LOCK_UN) or die "FATAL: can't unlock $lock_file: $!";
+
+}
+
+sub usage {
+ die "Usage:\n\n freeside-selfservice-server user machine\n";
+}
+
diff --git a/FS/bin/freeside-setinvoice b/FS/bin/freeside-setinvoice
new file mode 100644
index 0000000..708e2fa
--- /dev/null
+++ b/FS/bin/freeside-setinvoice
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::Conf;
+use FS::Record qw(qsearch qsearchs);
+use FS::cust_main;
+use FS::svc_acct;
+
+&untaint_argv; #what it sounds like (eww)
+my $user = shift or die &usage;
+
+adminsuidsetup $user;
+
+foreach my $cust_main (
+ grep { ! scalar($_->invoicing_list) }
+ qsearch( 'cust_main', {} )
+) {
+ my @dest;
+ my @cust_pkg = $cust_main->ncancelled_pkgs;
+ foreach my $cust_pkg ( @cust_pkg ) {
+ foreach my $cust_svc ( $cust_pkg->cust_svc ) {
+ my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $cust_svc->svcnum } );
+ push @dest, $svc_acct->svcnum if $svc_acct;
+ }
+ }
+ push @dest, 'POST' unless @dest;
+ $cust_main->invoicing_list(\@dest);
+}
+
+sub untaint_argv {
+ foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
+ $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
+ $ARGV[$_]=$1;
+ }
+}
+
+sub usage {
+ die "Usage:\n\n freeside-setinvoice user\n";
+}
+
+
diff --git a/FS/bin/freeside-setup b/FS/bin/freeside-setup
new file mode 100755
index 0000000..522c0a1
--- /dev/null
+++ b/FS/bin/freeside-setup
@@ -0,0 +1,1123 @@
+#!/usr/bin/perl -Tw
+
+#to delay loading dbdef until we're ready
+BEGIN { $FS::Record::setup_hack = 1; }
+
+use strict;
+use vars qw($opt_s);
+use Getopt::Std;
+use Locale::Country;
+use Locale::SubCountry;
+use DBI;
+use DBIx::DBSchema 0.21;
+use DBIx::DBSchema::Table;
+use DBIx::DBSchema::Column;
+use DBIx::DBSchema::ColGroup::Unique;
+use DBIx::DBSchema::ColGroup::Index;
+use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets);
+use FS::Record;
+use FS::cust_main_county;
+use FS::raddb;
+use FS::part_bill_event;
+
+die "Not running uid freeside!" unless checkeuid();
+
+my %attrib2db =
+ map { lc($FS::raddb::attrib{$_}) => $_ } keys %FS::raddb::attrib;
+
+getopts("s");
+my $user = shift or die &usage;
+getsecrets($user);
+
+#needs to match FS::Record
+my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc;
+
+###
+
+#print "\nEnter the maximum username length: ";
+#my($username_len)=&getvalue;
+my $username_len = 32; #usernamemax config file
+
+#print "\n\n", <<END, ":";
+#Freeside tracks the RADIUS User-Name, check attribute Password and
+#reply attribute Framed-IP-Address for each user. You can specify additional
+#check and reply attributes (or you can add them later with the
+#fs-radius-add-check and fs-radius-add-reply programs).
+#
+#First enter any additional RADIUS check attributes you need to track for each
+#user, separated by whitespace.
+#END
+#my @check_attributes = map { $attrib2db{lc($_)} or die "unknown attribute $_"; }
+# split(" ",&getvalue);
+#
+#print "\n\n", <<END, ":";
+#Now enter any additional reply attributes you need to track for each user,
+#separated by whitespace.
+#END
+#my @attributes = map { $attrib2db{lc($_)} or die "unknown attribute $_"; }
+# split(" ",&getvalue);
+#
+#print "\n\n", <<END, ":";
+#Do you wish to enable the tracking of a second, separate shipping/service
+#address?
+#END
+#my $ship = &_yesno;
+#
+#sub getvalue {
+# my($x)=scalar(<STDIN>);
+# chop $x;
+# $x;
+#}
+#
+#sub _yesno {
+# print " [y/N]:";
+# my $x = scalar(<STDIN>);
+# $x =~ /^y/i;
+#}
+
+my @check_attributes = (); #add later
+my @attributes = (); #add later
+my $ship = $opt_s;
+
+###
+
+my($char_d) = 80; #default maxlength for text fields
+
+#my(@date_type) = ( 'timestamp', '', '' );
+my(@date_type) = ( 'int', 'NULL', '' );
+my(@perl_type) = ( 'text', 'NULL', '' );
+my @money_type = ( 'decimal', '', '10,2' );
+
+###
+# create a dbdef object from the old data structure
+###
+
+my(%tables)=&tables_hash_hack;
+
+#turn it into objects
+my($dbdef) = new DBIx::DBSchema ( map {
+ my(@columns);
+ while (@{$tables{$_}{'columns'}}) {
+ my($name,$type,$null,$length)=splice @{$tables{$_}{'columns'}}, 0, 4;
+ push @columns, new DBIx::DBSchema::Column ( $name,$type,$null,$length );
+ }
+ DBIx::DBSchema::Table->new(
+ $_,
+ $tables{$_}{'primary_key'},
+ DBIx::DBSchema::ColGroup::Unique->new($tables{$_}{'unique'}),
+ DBIx::DBSchema::ColGroup::Index->new($tables{$_}{'index'}),
+ @columns,
+ );
+} (keys %tables) );
+
+my $cust_main = $dbdef->table('cust_main');
+unless ($ship) { #remove ship_ from cust_main
+ $cust_main->delcolumn($_) foreach ( grep /^ship_/, $cust_main->columns );
+} else { #add indices
+ push @{$cust_main->index->lol_ref},
+ map { [ "ship_$_" ] } qw( last company daytime night fax );
+}
+
+#add radius attributes to svc_acct
+
+my($svc_acct)=$dbdef->table('svc_acct');
+
+my($attribute);
+foreach $attribute (@attributes) {
+ $svc_acct->addcolumn ( new DBIx::DBSchema::Column (
+ 'radius_'. $attribute,
+ 'varchar',
+ 'NULL',
+ $char_d,
+ ));
+}
+
+foreach $attribute (@check_attributes) {
+ $svc_acct->addcolumn( new DBIx::DBSchema::Column (
+ 'rc_'. $attribute,
+ 'varchar',
+ 'NULL',
+ $char_d,
+ ));
+}
+
+#create history tables (false laziness w/create-history-tables)
+foreach my $table ( grep { ! /^h_/ } $dbdef->tables ) {
+ my $tableobj = $dbdef->table($table)
+ or die "unknown table $table";
+
+ die "unique->lol_ref undefined for $table"
+ unless defined $tableobj->unique->lol_ref;
+ die "index->lol_ref undefined for $table"
+ unless defined $tableobj->index->lol_ref;
+
+ my $h_tableobj = DBIx::DBSchema::Table->new( {
+ name => "h_$table",
+ primary_key => 'historynum',
+ unique => DBIx::DBSchema::ColGroup::Unique->new( [] ),
+ 'index' => DBIx::DBSchema::ColGroup::Index->new( [
+ @{$tableobj->unique->lol_ref},
+ @{$tableobj->index->lol_ref}
+ ] ),
+ columns => [
+ DBIx::DBSchema::Column->new( {
+ 'name' => 'historynum',
+ 'type' => 'serial',
+ 'null' => 'NOT NULL',
+ 'length' => '',
+ 'default' => '',
+ 'local' => '',
+ } ),
+ DBIx::DBSchema::Column->new( {
+ 'name' => 'history_date',
+ 'type' => 'int',
+ 'null' => 'NULL',
+ 'length' => '',
+ 'default' => '',
+ 'local' => '',
+ } ),
+ DBIx::DBSchema::Column->new( {
+ 'name' => 'history_user',
+ 'type' => 'varchar',
+ 'null' => 'NOT NULL',
+ 'length' => '80',
+ 'default' => '',
+ 'local' => '',
+ } ),
+ DBIx::DBSchema::Column->new( {
+ 'name' => 'history_action',
+ 'type' => 'varchar',
+ 'null' => 'NOT NULL',
+ 'length' => '80',
+ 'default' => '',
+ 'local' => '',
+ } ),
+ map {
+ my $column = $tableobj->column($_);
+
+ #clone so as to not disturb the original
+ $column = DBIx::DBSchema::Column->new( {
+ map { $_ => $column->$_() }
+ qw( name type null length default local )
+ } );
+
+ $column->type('int')
+ if $column->type eq 'serial';
+ #$column->default('')
+ # if $column->default =~ /^nextval\(/i;
+ #( my $local = $column->local ) =~ s/AUTO_INCREMENT//i;
+ #$column->local($local);
+ $column;
+ } $tableobj->columns
+ ],
+ } );
+ $dbdef->addtable($h_tableobj);
+}
+
+#important
+$dbdef->save($dbdef_file);
+&FS::Record::reload_dbdef($dbdef_file);
+
+###
+# create 'em
+###
+
+my($dbh)=adminsuidsetup $user;
+
+#create tables
+$|=1;
+
+foreach my $statement ( $dbdef->sql($dbh) ) {
+ $dbh->do( $statement )
+ or die "CREATE error: ". $dbh->errstr. "\ndoing statement: $statement";
+}
+
+#cust_main_county
+foreach my $country ( sort map uc($_), all_country_codes ) {
+
+ my $subcountry = eval { new Locale::SubCountry($country) };
+ my @states = $subcountry ? $subcountry->all_codes : undef;
+
+ if ( !scalar(@states) || ( scalar(@states) == 1 && !defined($states[0]) ) ) {
+
+ my $cust_main_county = new FS::cust_main_county({
+ 'tax' => 0,
+ 'country' => $country,
+ });
+ my $error = $cust_main_county->insert;
+ die $error if $error;
+
+ } else {
+
+ if ( $states[0] =~ /^(\d+|\w)$/ ) {
+ @states = map $subcountry->full_name($_), @states
+ }
+
+ foreach my $state ( @states ) {
+
+ my $cust_main_county = new FS::cust_main_county({
+ 'state' => $state,
+ 'tax' => 0,
+ 'country' => $country,
+ });
+ my $error = $cust_main_county->insert;
+ die $error if $error;
+
+ }
+
+ }
+}
+
+#billing events
+foreach my $aref (
+ [ 'COMP', 'Comp invoice', '$cust_bill->comp();', 30, 'comp' ],
+ [ 'CARD', 'Batch card', '$cust_bill->batch_card();', 40, 'batch-card' ],
+ [ 'BILL', 'Send invoice', '$cust_bill->send();', 50, 'send' ],
+ [ 'DCRD', 'Send invoice', '$cust_bill->send();', 50, 'send' ],
+ [ 'DCHK', 'Send invoice', '$cust_bill->send();', 50, 'send' ],
+) {
+
+ my $part_bill_event = new FS::part_bill_event({
+ 'payby' => $aref->[0],
+ 'event' => $aref->[1],
+ 'eventcode' => $aref->[2],
+ 'seconds' => 0,
+ 'weight' => $aref->[3],
+ 'plan' => $aref->[4],
+ });
+ my($error);
+ $error=$part_bill_event->insert;
+ die $error if $error;
+
+}
+
+$dbh->commit or die $dbh->errstr;
+$dbh->disconnect or die $dbh->errstr;
+
+#print "Freeside database initialized sucessfully\n";
+
+sub usage {
+ die "Usage:\n freeside-setup [ -s ] user\n";
+}
+
+###
+# Now it becomes an object. much better.
+###
+sub tables_hash_hack {
+
+ #note that s/(date|change)/_$1/; to avoid keyword conflict.
+ #put a kludge in FS::Record to catch this or? (pry need some date-handling
+ #stuff anyway also)
+
+ my(%tables)=( #yech.}
+
+ 'agent' => {
+ 'columns' => [
+ 'agentnum', 'serial', '', '',
+ 'agent', 'varchar', '', $char_d,
+ 'typenum', 'int', '', '',
+ 'freq', 'int', 'NULL', '',
+ 'prog', @perl_type,
+ 'disabled', 'char', 'NULL', 1,
+ 'username', 'varchar', 'NULL', $char_d,
+ '_password','varchar', 'NULL', $char_d,
+ ],
+ 'primary_key' => 'agentnum',
+ 'unique' => [],
+ 'index' => [ ['typenum'], ['disabled'] ],
+ },
+
+ 'agent_type' => {
+ 'columns' => [
+ 'typenum', 'serial', '', '',
+ 'atype', 'varchar', '', $char_d,
+ ],
+ 'primary_key' => 'typenum',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ 'type_pkgs' => {
+ 'columns' => [
+ 'typenum', 'int', '', '',
+ 'pkgpart', 'int', '', '',
+ ],
+ 'primary_key' => '',
+ 'unique' => [ ['typenum', 'pkgpart'] ],
+ 'index' => [ ['typenum'] ],
+ },
+
+ 'cust_bill' => {
+ 'columns' => [
+ 'invnum', 'serial', '', '',
+ 'custnum', 'int', '', '',
+ '_date', @date_type,
+ 'charged', @money_type,
+ 'printed', 'int', '', '',
+ 'closed', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'invnum',
+ 'unique' => [],
+ 'index' => [ ['custnum'], ['_date'] ],
+ },
+
+ 'cust_bill_event' => {
+ 'columns' => [
+ 'eventnum', 'serial', '', '',
+ 'invnum', 'int', '', '',
+ 'eventpart', 'int', '', '',
+ '_date', @date_type,
+ 'status', 'varchar', '', $char_d,
+ 'statustext', 'text', 'NULL', '',
+ ],
+ 'primary_key' => 'eventnum',
+ #no... there are retries now #'unique' => [ [ 'eventpart', 'invnum' ] ],
+ 'unique' => [],
+ 'index' => [ ['invnum'], ['status'] ],
+ },
+
+ 'part_bill_event' => {
+ 'columns' => [
+ 'eventpart', 'serial', '', '',
+ 'payby', 'char', '', 4,
+ 'event', 'varchar', '', $char_d,
+ 'eventcode', @perl_type,
+ 'seconds', 'int', 'NULL', '',
+ 'weight', 'int', '', '',
+ 'plan', 'varchar', 'NULL', $char_d,
+ 'plandata', 'text', 'NULL', '',
+ 'disabled', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'eventpart',
+ 'unique' => [],
+ 'index' => [ ['payby'], ['disabled'], ],
+ },
+
+ 'cust_bill_pkg' => {
+ 'columns' => [
+ 'pkgnum', 'int', '', '',
+ 'invnum', 'int', '', '',
+ 'setup', @money_type,
+ 'recur', @money_type,
+ 'sdate', @date_type,
+ 'edate', @date_type,
+ 'itemdesc', 'varchar', 'NULL', $char_d,
+ ],
+ 'primary_key' => '',
+ 'unique' => [],
+ 'index' => [ ['invnum'] ],
+ },
+
+ 'cust_bill_pkg_detail' => {
+ 'columns' => [
+ 'detailnum', 'serial', '', '',
+ 'pkgnum', 'int', '', '',
+ 'invnum', 'int', '', '',
+ 'detail', 'varchar', '', $char_d,
+ ],
+ 'primary_key' => 'detailnum',
+ 'unique' => [],
+ 'index' => [ [ 'pkgnum', 'invnum' ] ],
+ },
+
+ 'cust_credit' => {
+ 'columns' => [
+ 'crednum', 'serial', '', '',
+ 'custnum', 'int', '', '',
+ '_date', @date_type,
+ 'amount', @money_type,
+ 'otaker', 'varchar', '', 32,
+ 'reason', 'text', 'NULL', '',
+ 'closed', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'crednum',
+ 'unique' => [],
+ 'index' => [ ['custnum'] ],
+ },
+
+ 'cust_credit_bill' => {
+ 'columns' => [
+ 'creditbillnum', 'serial', '', '',
+ 'crednum', 'int', '', '',
+ 'invnum', 'int', '', '',
+ '_date', @date_type,
+ 'amount', @money_type,
+ ],
+ 'primary_key' => 'creditbillnum',
+ 'unique' => [],
+ 'index' => [ ['crednum'], ['invnum'] ],
+ },
+
+ 'cust_main' => {
+ 'columns' => [
+ 'custnum', 'serial', '', '',
+ 'agentnum', 'int', '', '',
+# 'titlenum', 'int', 'NULL', '',
+ 'last', 'varchar', '', $char_d,
+# 'middle', 'varchar', 'NULL', $char_d,
+ 'first', 'varchar', '', $char_d,
+ 'ss', 'varchar', 'NULL', 11,
+ 'company', 'varchar', 'NULL', $char_d,
+ 'address1', 'varchar', '', $char_d,
+ 'address2', 'varchar', 'NULL', $char_d,
+ 'city', 'varchar', '', $char_d,
+ 'county', 'varchar', 'NULL', $char_d,
+ 'state', 'varchar', 'NULL', $char_d,
+ 'zip', 'varchar', '', 10,
+ 'country', 'char', '', 2,
+ 'daytime', 'varchar', 'NULL', 20,
+ 'night', 'varchar', 'NULL', 20,
+ 'fax', 'varchar', 'NULL', 12,
+ 'ship_last', 'varchar', 'NULL', $char_d,
+# 'ship_middle', 'varchar', 'NULL', $char_d,
+ 'ship_first', 'varchar', 'NULL', $char_d,
+ 'ship_company', 'varchar', 'NULL', $char_d,
+ 'ship_address1', 'varchar', 'NULL', $char_d,
+ 'ship_address2', 'varchar', 'NULL', $char_d,
+ 'ship_city', 'varchar', 'NULL', $char_d,
+ 'ship_county', 'varchar', 'NULL', $char_d,
+ 'ship_state', 'varchar', 'NULL', $char_d,
+ 'ship_zip', 'varchar', 'NULL', 10,
+ 'ship_country', 'char', 'NULL', 2,
+ 'ship_daytime', 'varchar', 'NULL', 20,
+ 'ship_night', 'varchar', 'NULL', 20,
+ 'ship_fax', 'varchar', 'NULL', 12,
+ 'payby', 'char', '', 4,
+ 'payinfo', 'varchar', 'NULL', $char_d,
+ 'paycvv', 'varchar', 'NULL', 4,
+ #'paydate', @date_type,
+ 'paydate', 'varchar', 'NULL', 10,
+ 'payname', 'varchar', 'NULL', $char_d,
+ 'tax', 'char', 'NULL', 1,
+ 'otaker', 'varchar', '', 32,
+ 'refnum', 'int', '', '',
+ 'referral_custnum', 'int', 'NULL', '',
+ 'comments', 'text', 'NULL', '',
+ ],
+ 'primary_key' => 'custnum',
+ 'unique' => [],
+ #'index' => [ ['last'], ['company'] ],
+ 'index' => [ ['last'], [ 'company' ], [ 'referral_custnum' ],
+ [ 'daytime' ], [ 'night' ], [ 'fax' ],
+ ],
+ },
+
+ 'cust_main_invoice' => {
+ 'columns' => [
+ 'destnum', 'serial', '', '',
+ 'custnum', 'int', '', '',
+ 'dest', 'varchar', '', $char_d,
+ ],
+ 'primary_key' => 'destnum',
+ 'unique' => [],
+ 'index' => [ ['custnum'], ],
+ },
+
+ 'cust_main_county' => { #county+state+country are checked off the
+ #cust_main_county for validation and to provide
+ # a tax rate.
+ 'columns' => [
+ 'taxnum', 'serial', '', '',
+ 'state', 'varchar', 'NULL', $char_d,
+ 'county', 'varchar', 'NULL', $char_d,
+ 'country', 'char', '', 2,
+ 'taxclass', 'varchar', 'NULL', $char_d,
+ 'exempt_amount', @money_type,
+ 'tax', 'real', '', '', #tax %
+ 'taxname', 'varchar', 'NULL', $char_d,
+ 'setuptax', 'char', 'NULL', 1, # Y = setup tax exempt
+ 'recurtax', 'char', 'NULL', 1, # Y = recur tax exempt
+ ],
+ 'primary_key' => 'taxnum',
+ 'unique' => [],
+ # 'unique' => [ ['taxnum'], ['state', 'county'] ],
+ 'index' => [],
+ },
+
+ 'cust_pay' => {
+ 'columns' => [
+ 'paynum', 'serial', '', '',
+ #now cust_bill_pay #'invnum', 'int', '', '',
+ 'custnum', 'int', '', '',
+ 'paid', @money_type,
+ '_date', @date_type,
+ 'payby', 'char', '', 4, # CARD/BILL/COMP, should be index into
+ # payment type table.
+ 'payinfo', 'varchar', 'NULL', $char_d, #see cust_main above
+ 'paybatch', 'varchar', 'NULL', $char_d, #for auditing purposes.
+ 'closed', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'paynum',
+ 'unique' => [],
+ 'index' => [ [ 'custnum' ], [ 'paybatch' ], [ 'payby' ], [ '_date' ] ],
+ },
+
+ 'cust_bill_pay' => {
+ 'columns' => [
+ 'billpaynum', 'serial', '', '',
+ 'invnum', 'int', '', '',
+ 'paynum', 'int', '', '',
+ 'amount', @money_type,
+ '_date', @date_type
+ ],
+ 'primary_key' => 'billpaynum',
+ 'unique' => [],
+ 'index' => [ [ 'paynum' ], [ 'invnum' ] ],
+ },
+
+ 'cust_pay_batch' => { #what's this used for again? list of customers
+ #in current CARD batch? (necessarily CARD?)
+ 'columns' => [
+ 'paybatchnum', 'serial', '', '',
+ 'invnum', 'int', '', '',
+ 'custnum', 'int', '', '',
+ 'last', 'varchar', '', $char_d,
+ 'first', 'varchar', '', $char_d,
+ 'address1', 'varchar', '', $char_d,
+ 'address2', 'varchar', 'NULL', $char_d,
+ 'city', 'varchar', '', $char_d,
+ 'state', 'varchar', 'NULL', $char_d,
+ 'zip', 'varchar', '', 10,
+ 'country', 'char', '', 2,
+# 'trancode', 'int', '', '',
+ 'cardnum', 'varchar', '', 16,
+ #'exp', @date_type,
+ 'exp', 'varchar', '', 11,
+ 'payname', 'varchar', 'NULL', $char_d,
+ 'amount', @money_type,
+ ],
+ 'primary_key' => 'paybatchnum',
+ 'unique' => [],
+ 'index' => [ ['invnum'], ['custnum'] ],
+ },
+
+ 'cust_pkg' => {
+ 'columns' => [
+ 'pkgnum', 'serial', '', '',
+ 'custnum', 'int', '', '',
+ 'pkgpart', 'int', '', '',
+ 'otaker', 'varchar', '', 32,
+ 'setup', @date_type,
+ 'bill', @date_type,
+ 'last_bill', @date_type,
+ 'susp', @date_type,
+ 'cancel', @date_type,
+ 'expire', @date_type,
+ 'manual_flag', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'pkgnum',
+ 'unique' => [],
+ 'index' => [ ['custnum'] ],
+ },
+
+ 'cust_refund' => {
+ 'columns' => [
+ 'refundnum', 'serial', '', '',
+ #now cust_credit_refund #'crednum', 'int', '', '',
+ 'custnum', 'int', '', '',
+ '_date', @date_type,
+ 'refund', @money_type,
+ 'otaker', 'varchar', '', 32,
+ 'reason', 'varchar', '', $char_d,
+ 'payby', 'char', '', 4, # CARD/BILL/COMP, should be index
+ # into payment type table.
+ 'payinfo', 'varchar', 'NULL', $char_d, #see cust_main above
+ 'paybatch', 'varchar', 'NULL', $char_d,
+ 'closed', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'refundnum',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ 'cust_credit_refund' => {
+ 'columns' => [
+ 'creditrefundnum', 'serial', '', '',
+ 'crednum', 'int', '', '',
+ 'refundnum', 'int', '', '',
+ 'amount', @money_type,
+ '_date', @date_type
+ ],
+ 'primary_key' => 'creditrefundnum',
+ 'unique' => [],
+ 'index' => [ [ 'crednum', 'refundnum' ] ],
+ },
+
+
+ 'cust_svc' => {
+ 'columns' => [
+ 'svcnum', 'serial', '', '',
+ 'pkgnum', 'int', 'NULL', '',
+ 'svcpart', 'int', '', '',
+ ],
+ 'primary_key' => 'svcnum',
+ 'unique' => [],
+ 'index' => [ ['svcnum'], ['pkgnum'], ['svcpart'] ],
+ },
+
+ 'part_pkg' => {
+ 'columns' => [
+ 'pkgpart', 'serial', '', '',
+ 'pkg', 'varchar', '', $char_d,
+ 'comment', 'varchar', '', $char_d,
+ 'setup', @perl_type,
+ 'freq', 'varchar', '', $char_d, #billing frequency
+ 'recur', @perl_type,
+ 'setuptax', 'char', 'NULL', 1,
+ 'recurtax', 'char', 'NULL', 1,
+ 'plan', 'varchar', 'NULL', $char_d,
+ 'plandata', 'text', 'NULL', '',
+ 'disabled', 'char', 'NULL', 1,
+ 'taxclass', 'varchar', 'NULL', $char_d,
+ ],
+ 'primary_key' => 'pkgpart',
+ 'unique' => [],
+ 'index' => [ [ 'disabled' ], ],
+ },
+
+# 'part_title' => {
+# 'columns' => [
+# 'titlenum', 'int', '', '',
+# 'title', 'varchar', '', $char_d,
+# ],
+# 'primary_key' => 'titlenum',
+# 'unique' => [ [] ],
+# 'index' => [ [] ],
+# },
+
+ 'pkg_svc' => {
+ 'columns' => [
+ 'pkgpart', 'int', '', '',
+ 'svcpart', 'int', '', '',
+ 'quantity', 'int', '', '',
+ 'primary_svc','char', 'NULL', 1,
+ ],
+ 'primary_key' => '',
+ 'unique' => [ ['pkgpart', 'svcpart'] ],
+ 'index' => [ ['pkgpart'] ],
+ },
+
+ 'part_referral' => {
+ 'columns' => [
+ 'refnum', 'serial', '', '',
+ 'referral', 'varchar', '', $char_d,
+ 'disabled', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'refnum',
+ 'unique' => [],
+ 'index' => [ ['disabled'] ],
+ },
+
+ 'part_svc' => {
+ 'columns' => [
+ 'svcpart', 'serial', '', '',
+ 'svc', 'varchar', '', $char_d,
+ 'svcdb', 'varchar', '', $char_d,
+ 'disabled', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'svcpart',
+ 'unique' => [],
+ 'index' => [ [ 'disabled' ] ],
+ },
+
+ 'part_svc_column' => {
+ 'columns' => [
+ 'columnnum', 'serial', '', '',
+ 'svcpart', 'int', '', '',
+ 'columnname', 'varchar', '', 64,
+ 'columnvalue', 'varchar', 'NULL', $char_d,
+ 'columnflag', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'columnnum',
+ 'unique' => [ [ 'svcpart', 'columnname' ] ],
+ 'index' => [ [ 'svcpart' ] ],
+ },
+
+ #(this should be renamed to part_pop)
+ 'svc_acct_pop' => {
+ 'columns' => [
+ 'popnum', 'serial', '', '',
+ 'city', 'varchar', '', $char_d,
+ 'state', 'varchar', '', $char_d,
+ 'ac', 'char', '', 3,
+ 'exch', 'char', '', 3,
+ 'loc', 'char', 'NULL', 4, #NULL for legacy purposes
+ ],
+ 'primary_key' => 'popnum',
+ 'unique' => [],
+ 'index' => [ [ 'state' ] ],
+ },
+
+ 'part_pop_local' => {
+ 'columns' => [
+ 'localnum', 'serial', '', '',
+ 'popnum', 'int', '', '',
+ 'city', 'varchar', 'NULL', $char_d,
+ 'state', 'char', 'NULL', 2,
+ 'npa', 'char', '', 3,
+ 'nxx', 'char', '', 3,
+ ],
+ 'primary_key' => 'localnum',
+ 'unique' => [],
+ 'index' => [ [ 'npa', 'nxx' ], [ 'popnum' ] ],
+ },
+
+ 'svc_acct' => {
+ 'columns' => [
+ 'svcnum', 'int', '', '',
+ 'username', 'varchar', '', $username_len, #unique (& remove dup code)
+ '_password', 'varchar', '', 72, #13 for encryped pw's plus ' *SUSPENDED* (md5 passwords can be 34, blowfish 60)
+ 'sec_phrase', 'varchar', 'NULL', $char_d,
+ 'popnum', 'int', 'NULL', '',
+ 'uid', 'int', 'NULL', '',
+ 'gid', 'int', 'NULL', '',
+ 'finger', 'varchar', 'NULL', $char_d,
+ 'dir', 'varchar', 'NULL', $char_d,
+ 'shell', 'varchar', 'NULL', $char_d,
+ 'quota', 'varchar', 'NULL', $char_d,
+ 'slipip', 'varchar', 'NULL', 15, #four TINYINTs, bah.
+ 'seconds', 'int', 'NULL', '', #uhhhh
+ 'domsvc', 'int', '', '',
+ ],
+ 'primary_key' => 'svcnum',
+ #'unique' => [ [ 'username', 'domsvc' ] ],
+ 'unique' => [],
+ 'index' => [ ['username'], ['domsvc'] ],
+ },
+
+ #'svc_charge' => {
+ # 'columns' => [
+ # 'svcnum', 'int', '', '',
+ # 'amount', @money_type,
+ # ],
+ # 'primary_key' => 'svcnum',
+ # 'unique' => [ [] ],
+ # 'index' => [ [] ],
+ #},
+
+ 'svc_domain' => {
+ 'columns' => [
+ 'svcnum', 'int', '', '',
+ 'domain', 'varchar', '', $char_d,
+ 'catchall', 'int', 'NULL', '',
+ ],
+ 'primary_key' => 'svcnum',
+ 'unique' => [ ['domain'] ],
+ 'index' => [],
+ },
+
+ 'domain_record' => {
+ 'columns' => [
+ 'recnum', 'serial', '', '',
+ 'svcnum', 'int', '', '',
+ #'reczone', 'varchar', '', $char_d,
+ 'reczone', 'varchar', '', 255,
+ 'recaf', 'char', '', 2,
+ 'rectype', 'varchar', '', 5,
+ #'recdata', 'varchar', '', $char_d,
+ 'recdata', 'varchar', '', 255,
+ ],
+ 'primary_key' => 'recnum',
+ 'unique' => [],
+ 'index' => [ ['svcnum'] ],
+ },
+
+ 'svc_forward' => {
+ 'columns' => [
+ 'svcnum', 'int', '', '',
+ 'srcsvc', 'int', 'NULL', '',
+ 'src', 'varchar', 'NULL', 255,
+ 'dstsvc', 'int', 'NULL', '',
+ 'dst', 'varchar', 'NULL', 255,
+ ],
+ 'primary_key' => 'svcnum',
+ 'unique' => [],
+ 'index' => [ ['srcsvc'], ['dstsvc'] ],
+ },
+
+ 'svc_www' => {
+ 'columns' => [
+ 'svcnum', 'int', '', '',
+ 'recnum', 'int', '', '',
+ 'usersvc', 'int', '', '',
+ ],
+ 'primary_key' => 'svcnum',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ #'svc_wo' => {
+ # 'columns' => [
+ # 'svcnum', 'int', '', '',
+ # 'svcnum', 'int', '', '',
+ # 'svcnum', 'int', '', '',
+ # 'worker', 'varchar', '', $char_d,
+ # '_date', @date_type,
+ # ],
+ # 'primary_key' => 'svcnum',
+ # 'unique' => [ [] ],
+ # 'index' => [ [] ],
+ #},
+
+ 'prepay_credit' => {
+ 'columns' => [
+ 'prepaynum', 'serial', '', '',
+ 'identifier', 'varchar', '', $char_d,
+ 'amount', @money_type,
+ 'seconds', 'int', 'NULL', '',
+ ],
+ 'primary_key' => 'prepaynum',
+ 'unique' => [ ['identifier'] ],
+ 'index' => [],
+ },
+
+ 'port' => {
+ 'columns' => [
+ 'portnum', 'serial', '', '',
+ 'ip', 'varchar', 'NULL', 15,
+ 'nasport', 'int', 'NULL', '',
+ 'nasnum', 'int', '', '',
+ ],
+ 'primary_key' => 'portnum',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ 'nas' => {
+ 'columns' => [
+ 'nasnum', 'serial', '', '',
+ 'nas', 'varchar', '', $char_d,
+ 'nasip', 'varchar', '', 15,
+ 'nasfqdn', 'varchar', '', $char_d,
+ 'last', 'int', '', '',
+ ],
+ 'primary_key' => 'nasnum',
+ 'unique' => [ [ 'nas' ], [ 'nasip' ] ],
+ 'index' => [ [ 'last' ] ],
+ },
+
+ 'session' => {
+ 'columns' => [
+ 'sessionnum', 'serial', '', '',
+ 'portnum', 'int', '', '',
+ 'svcnum', 'int', '', '',
+ 'login', @date_type,
+ 'logout', @date_type,
+ ],
+ 'primary_key' => 'sessionnum',
+ 'unique' => [],
+ 'index' => [ [ 'portnum' ] ],
+ },
+
+ 'queue' => {
+ 'columns' => [
+ 'jobnum', 'serial', '', '',
+ 'job', 'text', '', '',
+ '_date', 'int', '', '',
+ 'status', 'varchar', '', $char_d,
+ 'statustext', 'text', 'NULL', '',
+ 'svcnum', 'int', 'NULL', '',
+ ],
+ 'primary_key' => 'jobnum',
+ 'unique' => [],
+ 'index' => [ [ 'svcnum' ], [ 'status' ] ],
+ },
+
+ 'queue_arg' => {
+ 'columns' => [
+ 'argnum', 'serial', '', '',
+ 'jobnum', 'int', '', '',
+ 'arg', 'text', 'NULL', '',
+ ],
+ 'primary_key' => 'argnum',
+ 'unique' => [],
+ 'index' => [ [ 'jobnum' ] ],
+ },
+
+ 'queue_depend' => {
+ 'columns' => [
+ 'dependnum', 'serial', '', '',
+ 'jobnum', 'int', '', '',
+ 'depend_jobnum', 'int', '', '',
+ ],
+ 'primary_key' => 'dependnum',
+ 'unique' => [],
+ 'index' => [ [ 'jobnum' ], [ 'depend_jobnum' ] ],
+ },
+
+ 'export_svc' => {
+ 'columns' => [
+ 'exportsvcnum' => 'serial', '', '',
+ 'exportnum' => 'int', '', '',
+ 'svcpart' => 'int', '', '',
+ ],
+ 'primary_key' => 'exportsvcnum',
+ 'unique' => [ [ 'exportnum', 'svcpart' ] ],
+ 'index' => [ [ 'exportnum' ], [ 'svcpart' ] ],
+ },
+
+ 'part_export' => {
+ 'columns' => [
+ 'exportnum', 'serial', '', '',
+ #'svcpart', 'int', '', '',
+ 'machine', 'varchar', '', $char_d,
+ 'exporttype', 'varchar', '', $char_d,
+ 'nodomain', 'char', 'NULL', 1,
+ ],
+ 'primary_key' => 'exportnum',
+ 'unique' => [],
+ 'index' => [ [ 'machine' ], [ 'exporttype' ] ],
+ },
+
+ 'part_export_option' => {
+ 'columns' => [
+ 'optionnum', 'serial', '', '',
+ 'exportnum', 'int', '', '',
+ 'optionname', 'varchar', '', $char_d,
+ 'optionvalue', 'text', 'NULL', '',
+ ],
+ 'primary_key' => 'optionnum',
+ 'unique' => [],
+ 'index' => [ [ 'exportnum' ], [ 'optionname' ] ],
+ },
+
+ 'radius_usergroup' => {
+ 'columns' => [
+ 'usergroupnum', 'serial', '', '',
+ 'svcnum', 'int', '', '',
+ 'groupname', 'varchar', '', $char_d,
+ ],
+ 'primary_key' => 'usergroupnum',
+ 'unique' => [],
+ 'index' => [ [ 'svcnum' ], [ 'groupname' ] ],
+ },
+
+ 'msgcat' => {
+ 'columns' => [
+ 'msgnum', 'serial', '', '',
+ 'msgcode', 'varchar', '', $char_d,
+ 'locale', 'varchar', '', 16,
+ 'msg', 'text', '', '',
+ ],
+ 'primary_key' => 'msgnum',
+ 'unique' => [ [ 'msgcode', 'locale' ] ],
+ 'index' => [],
+ },
+
+ 'cust_tax_exempt' => {
+ 'columns' => [
+ 'exemptnum', 'serial', '', '',
+ 'custnum', 'int', '', '',
+ 'taxnum', 'int', '', '',
+ 'year', 'int', '', '',
+ 'month', 'int', '', '',
+ 'amount', @money_type,
+ ],
+ 'primary_key' => 'exemptnum',
+ 'unique' => [ [ 'custnum', 'taxnum', 'year', 'month' ] ],
+ 'index' => [],
+ },
+
+ 'router' => {
+ 'columns' => [
+ 'routernum', 'serial', '', '',
+ 'routername', 'varchar', '', $char_d,
+ 'svcnum', 'int', 'NULL', '',
+ ],
+ 'primary_key' => 'routernum',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ 'part_svc_router' => {
+ 'columns' => [
+ 'svcpart', 'int', '', '',
+ 'routernum', 'int', '', '',
+ ],
+ 'primary_key' => '',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ 'addr_block' => {
+ 'columns' => [
+ 'blocknum', 'serial', '', '',
+ 'routernum', 'int', '', '',
+ 'ip_gateway', 'varchar', '', 15,
+ 'ip_netmask', 'int', '', '',
+ ],
+ 'primary_key' => 'blocknum',
+ 'unique' => [ [ 'blocknum', 'routernum' ] ],
+ 'index' => [],
+ },
+
+ 'svc_broadband' => {
+ 'columns' => [
+ 'svcnum', 'int', '', '',
+ 'blocknum', 'int', '', '',
+ 'speed_up', 'int', '', '',
+ 'speed_down', 'int', '', '',
+ 'ip_addr', 'varchar', '', 15,
+ ],
+ 'primary_key' => 'svcnum',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ 'part_virtual_field' => {
+ 'columns' => [
+ 'vfieldpart', 'int', '', '',
+ 'dbtable', 'varchar', '', 32,
+ 'name', 'varchar', '', 32,
+ 'check_block', 'text', 'NULL', '',
+ 'length', 'int', 'NULL', '',
+ 'list_source', 'text', 'NULL', '',
+ 'label', 'varchar', 'NULL', 80,
+ ],
+ 'primary_key' => 'vfieldpart',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ 'virtual_field' => {
+ 'columns' => [
+ 'recnum', 'int', '', '',
+ 'vfieldpart', 'int', '', '',
+ 'value', 'varchar', '', 128,
+ ],
+ 'primary_key' => '',
+ 'unique' => [ [ 'vfieldpart', 'recnum' ] ],
+ 'index' => [],
+ },
+
+ 'acct_snarf' => {
+ 'columns' => [
+ 'snarfnum', 'int', '', '',
+ 'svcnum', 'int', '', '',
+ 'machine', 'varchar', '', 255,
+ 'protocol', 'varchar', '', $char_d,
+ 'username', 'varchar', '', $char_d,
+ '_password', 'varchar', '', $char_d,
+ ],
+ 'primary_key' => 'snarfnum',
+ 'unique' => [],
+ 'index' => [ [ 'svcnum' ] ],
+ },
+
+ 'svc_external' => {
+ 'columns' => [
+ 'svcnum', 'int', '', '',
+ 'id', 'int', '', '',
+ 'title', 'varchar', 'NULL', $char_d,
+ ],
+ 'primary_key' => 'svcnum',
+ 'unique' => [],
+ 'index' => [],
+ },
+
+ );
+
+ %tables;
+
+}
+
diff --git a/FS/bin/freeside-sqlradius-radacctd b/FS/bin/freeside-sqlradius-radacctd
new file mode 100644
index 0000000..4e8d57c
--- /dev/null
+++ b/FS/bin/freeside-sqlradius-radacctd
@@ -0,0 +1,180 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use vars qw( $log_file $sigterm $sigint );
+use subs qw( _die _logmsg );
+use Fcntl qw(:flock);
+use POSIX qw(setsid);
+use Date::Format;
+use IO::File;
+use FS::UID qw(adminsuidsetup);
+#use FS::Record qw(qsearch qsearchs);
+#use FS::part_export;
+#use FS::svc_acct;
+#use FS::cust_svc;
+
+#lots of false laziness w/freeside-queued
+
+my $user = shift or die &usage;
+
+#my $pid_file = "/var/run/freeside-sqlradius-radacctd.$user.pid";
+my $pid_file = "/var/run/freeside-sqlradius-radacctd.pid";
+
+&daemonize1;
+
+#sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; }
+#$SIG{CHLD} = \&REAPER;
+
+$sigterm = 0;
+$sigint = 0;
+$SIG{INT} = sub { warn "SIGINT received; shutting down\n"; $sigint++; };
+$SIG{TERM} = sub { warn "SIGTERM received; shutting down\n"; $sigterm++; };
+
+my $freeside_gid = scalar(getgrnam('freeside'))
+ or die "can't setgid to freeside group\n";
+$) = $freeside_gid;
+$( = $freeside_gid;
+#if freebsd can't setuid(), presumably it can't setgid() either. grr fleabsd
+($(,$)) = ($),$();
+$) = $freeside_gid;
+
+$> = $FS::UID::freeside_uid;
+$< = $FS::UID::freeside_uid;
+#freebsd is sofa king broken, won't setuid()
+($<,$>) = ($>,$<);
+$> = $FS::UID::freeside_uid;
+
+#$ENV{HOME} = (getpwuid($>))[7]; #for ssh
+adminsuidsetup $user;
+
+$log_file= "/usr/local/etc/freeside/sqlradius-radacctd-log.". $FS::UID::datasrc;
+
+&daemonize2;
+
+$SIG{__DIE__} = \&_die;
+$SIG{__WARN__} = \&_logmsg;
+
+warn "freeside-sqlradius-radacctd starting\n";
+
+#eslaf
+
+#my $machine = shift or die &usage; #would need to be up higher for real
+my @exports = qsearch('part_export', { 'exporttype' => 'sqlradius' } );
+
+while (1) {
+
+ my %seen = ();
+ foreach my $export ( @exports ) {
+ next if $seen{$export->option('datasrc')}++;
+ my $dbh = DBI->connect(
+ map { $export->option($_) } qw( datasrc username password )
+ ) or do {
+ warn "can't connect to ". $export->option('datasrc'). ": ". $DBI::errstr;
+ next;
+ }
+
+ # find old radacct position
+ #$lastid = 0;
+
+ # get new radacct records
+ my $sth = $dbh->prepare('SELECT * FROM radacct WHERE radacctid > ?') or do {
+ warn "can't select in radacct table from ". $export->option('datasrc').
+ ": ". $dbh->errstr;
+ next;
+ };
+
+ while ( my $radacct = $sth->fetchrow_arrayref({}) ) {
+
+ my $session = new FS::session {
+ portnum =>
+ svcnum =>
+ login =>
+ #logout =>
+ };
+
+ }
+
+ # look for updated radacct records & replace them
+
+ }
+
+ sleep 5;
+
+}
+
+#more false laziness w/freeside-queued
+
+sub usage {
+ die "Usage:\n\n freeside-sqlradius-radacctd user\n";
+}
+
+sub _die {
+ my $msg = shift;
+ unlink $pid_file if -e $pid_file;
+ _logmsg($msg);
+}
+
+sub _logmsg {
+ chomp( my $msg = shift );
+ my $log = new IO::File ">>$log_file";
+ flock($log, LOCK_EX);
+ seek($log, 0, 2);
+ print $log "[". time2str("%a %b %e %T %Y",time). "] [$$] $msg\n";
+ flock($log, LOCK_UN);
+ close $log;
+}
+
+sub daemonize1 {
+
+ chdir "/" or die "Can't chdir to /: $!";
+ open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
+ defined(my $pid = fork) or die "Can't fork: $!";
+ if ( $pid ) {
+ print "freeside-sqlradius-radacctd started with pid $pid\n";
+ #logging to $log_file\n";
+ exit unless $pid_file;
+ my $pidfh = new IO::File ">$pid_file" or exit;
+ print $pidfh "$pid\n";
+ exit;
+ }
+ #open STDOUT, '>/dev/null'
+ # or die "Can't write to /dev/null: $!";
+ #setsid or die "Can't start a new session: $!";
+ #open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
+
+}
+
+sub daemonize2 {
+ open STDOUT, '>/dev/null'
+ or die "Can't write to /dev/null: $!";
+ setsid or die "Can't start a new session: $!";
+ open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
+}
+
+
+#eslaf
+
+=head1 NAME
+
+freeside-sqlradius-radacctd - Real-time radacct import daemon
+
+=head1 SYNOPSIS
+
+ freeside-sqlradius-radacctd username
+
+=head1 DESCRIPTION
+
+Imports records from an SQL radacct table in real-time into the session
+monitor.
+
+This enables per-minute or per-hour charges as well as the
+"View active NAS ports" function.
+
+B<username> is a username added by freeside-adduser.
+
+=head1 SEE ALSO
+
+session.html from the base documentation.
+
+=cut
+
diff --git a/FS/bin/freeside-sqlradius-reset b/FS/bin/freeside-sqlradius-reset
new file mode 100755
index 0000000..74f90a5
--- /dev/null
+++ b/FS/bin/freeside-sqlradius-reset
@@ -0,0 +1,76 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch qsearchs);
+use FS::part_export;
+use FS::svc_acct;
+use FS::cust_svc;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+#my $machine = shift or die &usage;
+
+my @exports = qsearch('part_export', { exporttype=>'sqlradius' } );
+push @exports, qsearch('part_export', { exporttype=>'sqlradius_withdomain' } );
+
+
+foreach my $export ( @exports ) {
+ my $icradius_dbh = DBI->connect(
+ map { $export->option($_) } qw( datasrc username password )
+ ) or die $DBI::errstr;
+ for my $table (qw( radcheck radreply usergroup )) {
+ my $sth = $icradius_dbh->prepare("DELETE FROM $table");
+ $sth->execute or die "Can't reset $table table: ". $sth->errstr;
+ }
+ $icradius_dbh->disconnect;
+}
+
+foreach my $export ( @exports ) {
+
+ #my @svcparts = map { $_->svcpart } $export->export_svc;
+
+ my @svc_acct =
+ map { qsearchs('svc_acct', { 'svcnum' => $_->svcnum } ) }
+ map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
+ grep { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
+ $export->export_svc;
+
+ foreach my $svc_acct ( @svc_acct ) {
+
+ #false laziness with FS::svc_acct::insert (like it matters)
+ my $error = $export->export_insert($svc_acct);
+ die $error if $error;
+
+ }
+}
+
+sub usage {
+ #die "Usage:\n\n sqlradius_reset user machine\n";
+ die "Usage:\n\n freeside-sqlradius-reset user\n";
+}
+
+=head1 NAME
+
+freeside-sqlradius-reset - Command line interface to reset and recreate RADIUS SQL tables
+
+=head1 SYNOPSIS
+
+ freeside-sqlradius-reset username
+
+=head1 DESCRIPTION
+
+Deletes the radcheck, radreply and usergroup tables and repopulates them from
+the Freeside database, for all sqlradius exports.
+
+B<username> is a username added by freeside-adduser.
+
+=head1 SEE ALSO
+
+L<freeside-reexport>, L<FS::part_export>, L<FS::part_export::sqlradius>
+
+=cut
+
+
+
diff --git a/FS/bin/freeside-sqlradius-seconds b/FS/bin/freeside-sqlradius-seconds
new file mode 100644
index 0000000..1c978fa
--- /dev/null
+++ b/FS/bin/freeside-sqlradius-seconds
@@ -0,0 +1,58 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use Date::Parse;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearchs);
+use FS::svc_acct;
+
+my $fs_user = shift or die &usage;
+adminsuidsetup( $fs_user );
+
+my $target_user = shift or die &usage;
+my $start = shift or die &usage;
+$start = str2time($start);
+my $stop = scalar(@ARGV) ? str2time(shift) : time;
+
+my $svc_acct = qsearchs( 'svc_acct', { 'username' => $target_user } );
+die "username $target_user not found\n" unless $svc_acct;
+
+print $svc_acct->seconds_since_sqlradacct( $start, $stop ). "\n";
+
+sub usage {
+ die "Usage:\n\n freeside-sqlradius-seconds freeside_username target_username start_date stop_date\n";
+}
+
+
+=head1 NAME
+
+freeside-sqlradius-seconds - Real-time radacct import daemon
+
+=head1 SYNOPSIS
+
+ freeside-sqlradius-seconds freeside_username target_username start_date [ stop_date ]
+
+=head1 DESCRIPTION
+
+Returns the number of seconds the specified username has been online between
+start_date (inclusive) and stop_date (exclusive).
+See L<FS::svc_acct/seconds_since_sqlradacct>
+
+B<freeside_username> is a username added by freeside-adduser.
+B<target_username> is the username of the user account to query.
+B<start_date> and B<stop_date> are in any format Date::Parse is happy with.
+B<stop_date> defaults to now if not specified.
+
+=head1 BUGS
+
+Selection of the account in question is rather simplistic in that
+B<target_username> doesn't necessarily identify a unique account (and wouldn't
+even if a domain was specified), and no sqlradius export is checked for.
+
+=head1 SEE ALSO
+
+L<FS::svc_acct/seconds_since_sqlradacct>
+
+=cut
+
+1;
diff --git a/FS/t/CGI.t b/FS/t/CGI.t
new file mode 100644
index 0000000..1b4e238
--- /dev/null
+++ b/FS/t/CGI.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::CGI;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/ClientAPI.t b/FS/t/ClientAPI.t
new file mode 100644
index 0000000..973d8da
--- /dev/null
+++ b/FS/t/ClientAPI.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::ClientAPI;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/Conf.t b/FS/t/Conf.t
new file mode 100644
index 0000000..a9f7653
--- /dev/null
+++ b/FS/t/Conf.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::Conf;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/ConfItem.t b/FS/t/ConfItem.t
new file mode 100644
index 0000000..c7932d7
--- /dev/null
+++ b/FS/t/ConfItem.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::ConfItem;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/InitHandler.t b/FS/t/InitHandler.t
new file mode 100644
index 0000000..0ce60c8
--- /dev/null
+++ b/FS/t/InitHandler.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::InitHandler;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/Misc.t b/FS/t/Misc.t
new file mode 100644
index 0000000..cc7751a
--- /dev/null
+++ b/FS/t/Misc.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::Misc;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/Msgcat.t b/FS/t/Msgcat.t
new file mode 100644
index 0000000..29e71b3
--- /dev/null
+++ b/FS/t/Msgcat.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::Msgcat;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/Record.t b/FS/t/Record.t
new file mode 100644
index 0000000..00de1ed
--- /dev/null
+++ b/FS/t/Record.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::Record;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/Report-Table-Monthly.t b/FS/t/Report-Table-Monthly.t
new file mode 100644
index 0000000..6ff365d
--- /dev/null
+++ b/FS/t/Report-Table-Monthly.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::Report::Table::Monthly;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/Report-Table.t b/FS/t/Report-Table.t
new file mode 100644
index 0000000..866d498
--- /dev/null
+++ b/FS/t/Report-Table.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::Report::Table;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/Report.t b/FS/t/Report.t
new file mode 100644
index 0000000..76d6ea4
--- /dev/null
+++ b/FS/t/Report.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::Report;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/SearchCache.t b/FS/t/SearchCache.t
new file mode 100644
index 0000000..3c26f35
--- /dev/null
+++ b/FS/t/SearchCache.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::SearchCache;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/UID.t b/FS/t/UID.t
new file mode 100644
index 0000000..9f7da4e
--- /dev/null
+++ b/FS/t/UID.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::UID;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/acct_snarf.t b/FS/t/acct_snarf.t
new file mode 100644
index 0000000..642760f
--- /dev/null
+++ b/FS/t/acct_snarf.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::acct_snarf;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/agent.t b/FS/t/agent.t
new file mode 100644
index 0000000..769cce2
--- /dev/null
+++ b/FS/t/agent.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::agent;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/agent_type.t b/FS/t/agent_type.t
new file mode 100644
index 0000000..99c66a1
--- /dev/null
+++ b/FS/t/agent_type.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::agent_type;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_bill.t b/FS/t/cust_bill.t
new file mode 100644
index 0000000..b43f08e
--- /dev/null
+++ b/FS/t/cust_bill.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_bill;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_bill_event.t b/FS/t/cust_bill_event.t
new file mode 100644
index 0000000..0e2ca3e
--- /dev/null
+++ b/FS/t/cust_bill_event.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_bill_event;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_bill_pay.t b/FS/t/cust_bill_pay.t
new file mode 100644
index 0000000..001eed0
--- /dev/null
+++ b/FS/t/cust_bill_pay.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_bill_pay;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_bill_pkg.t b/FS/t/cust_bill_pkg.t
new file mode 100644
index 0000000..0e45bdb
--- /dev/null
+++ b/FS/t/cust_bill_pkg.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_bill_pkg;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_bill_pkg_detail.t b/FS/t/cust_bill_pkg_detail.t
new file mode 100644
index 0000000..ea6e3d1
--- /dev/null
+++ b/FS/t/cust_bill_pkg_detail.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_bill_pkg_detail;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_credit.t b/FS/t/cust_credit.t
new file mode 100644
index 0000000..cddf75c
--- /dev/null
+++ b/FS/t/cust_credit.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_credit;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_credit_bill.t b/FS/t/cust_credit_bill.t
new file mode 100644
index 0000000..0ef54c3
--- /dev/null
+++ b/FS/t/cust_credit_bill.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_credit_bill;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_credit_refund.t b/FS/t/cust_credit_refund.t
new file mode 100644
index 0000000..6b2b599
--- /dev/null
+++ b/FS/t/cust_credit_refund.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_credit_refund;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_main.t b/FS/t/cust_main.t
new file mode 100644
index 0000000..b0ffbdb
--- /dev/null
+++ b/FS/t/cust_main.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_main;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_main_county.t b/FS/t/cust_main_county.t
new file mode 100644
index 0000000..dd61199
--- /dev/null
+++ b/FS/t/cust_main_county.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_main_county;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_main_invoice.t b/FS/t/cust_main_invoice.t
new file mode 100644
index 0000000..9661620
--- /dev/null
+++ b/FS/t/cust_main_invoice.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_main_invoice;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_pay.t b/FS/t/cust_pay.t
new file mode 100644
index 0000000..f6d0b75
--- /dev/null
+++ b/FS/t/cust_pay.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_pay;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_pay_batch.t b/FS/t/cust_pay_batch.t
new file mode 100644
index 0000000..02b572c
--- /dev/null
+++ b/FS/t/cust_pay_batch.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_pay_batch;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_pkg.t b/FS/t/cust_pkg.t
new file mode 100644
index 0000000..c6a6860
--- /dev/null
+++ b/FS/t/cust_pkg.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_pkg;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_refund.t b/FS/t/cust_refund.t
new file mode 100644
index 0000000..91583da
--- /dev/null
+++ b/FS/t/cust_refund.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_refund;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_svc.t b/FS/t/cust_svc.t
new file mode 100644
index 0000000..267d731
--- /dev/null
+++ b/FS/t/cust_svc.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_svc;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_tax_exempt.pm b/FS/t/cust_tax_exempt.pm
new file mode 100644
index 0000000..8af13e3
--- /dev/null
+++ b/FS/t/cust_tax_exempt.pm
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_tax_exempt;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/cust_tax_exempt.t b/FS/t/cust_tax_exempt.t
new file mode 100644
index 0000000..8af13e3
--- /dev/null
+++ b/FS/t/cust_tax_exempt.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_tax_exempt;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/domain_record.t b/FS/t/domain_record.t
new file mode 100644
index 0000000..794518c
--- /dev/null
+++ b/FS/t/domain_record.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::domain_record;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/export_svc.t b/FS/t/export_svc.t
new file mode 100644
index 0000000..773c5de
--- /dev/null
+++ b/FS/t/export_svc.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::export_svc;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/msgcat.t b/FS/t/msgcat.t
new file mode 100644
index 0000000..c38c639
--- /dev/null
+++ b/FS/t/msgcat.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::msgcat;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/nas.t b/FS/t/nas.t
new file mode 100644
index 0000000..6f8ae36
--- /dev/null
+++ b/FS/t/nas.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::nas;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_bill_event.t b/FS/t/part_bill_event.t
new file mode 100644
index 0000000..5626a9f
--- /dev/null
+++ b/FS/t/part_bill_event.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_bill_event;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-acct_sql.t b/FS/t/part_export-acct_sql.t
new file mode 100644
index 0000000..9eed472
--- /dev/null
+++ b/FS/t/part_export-acct_sql.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::acct_sql;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-apache.t b/FS/t/part_export-apache.t
new file mode 100644
index 0000000..b999508
--- /dev/null
+++ b/FS/t/part_export-apache.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::apache;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-bind.t b/FS/t/part_export-bind.t
new file mode 100644
index 0000000..d0c96be
--- /dev/null
+++ b/FS/t/part_export-bind.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::bind;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-bind_slave.t b/FS/t/part_export-bind_slave.t
new file mode 100644
index 0000000..c6a0386
--- /dev/null
+++ b/FS/t/part_export-bind_slave.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::bind_slave;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-bsdshell.t b/FS/t/part_export-bsdshell.t
new file mode 100644
index 0000000..eaf417a
--- /dev/null
+++ b/FS/t/part_export-bsdshell.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::bsdshell;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-communigate_pro.t b/FS/t/part_export-communigate_pro.t
new file mode 100644
index 0000000..88b8b64
--- /dev/null
+++ b/FS/t/part_export-communigate_pro.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::communigate_pro;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-communigate_pro_singledomain.t b/FS/t/part_export-communigate_pro_singledomain.t
new file mode 100644
index 0000000..6f8a64e
--- /dev/null
+++ b/FS/t/part_export-communigate_pro_singledomain.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::communigate_pro_singledomain;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-cp.t b/FS/t/part_export-cp.t
new file mode 100644
index 0000000..bbefa6c
--- /dev/null
+++ b/FS/t/part_export-cp.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::cp;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-cyrus.t b/FS/t/part_export-cyrus.t
new file mode 100644
index 0000000..e0b3f35
--- /dev/null
+++ b/FS/t/part_export-cyrus.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::cyrus;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-domain_shellcommands.t b/FS/t/part_export-domain_shellcommands.t
new file mode 100644
index 0000000..a2a44fb
--- /dev/null
+++ b/FS/t/part_export-domain_shellcommands.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::domain_shellcommands;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-forward_shellcommands.t b/FS/t/part_export-forward_shellcommands.t
new file mode 100644
index 0000000..78ca68d
--- /dev/null
+++ b/FS/t/part_export-forward_shellcommands.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::forward_shellcommands;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-http.t b/FS/t/part_export-http.t
new file mode 100644
index 0000000..ea41b93
--- /dev/null
+++ b/FS/t/part_export-http.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::http;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-infostreet.t b/FS/t/part_export-infostreet.t
new file mode 100644
index 0000000..1b33418
--- /dev/null
+++ b/FS/t/part_export-infostreet.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::infostreet;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-ldap.t b/FS/t/part_export-ldap.t
new file mode 100644
index 0000000..826c341
--- /dev/null
+++ b/FS/t/part_export-ldap.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::ldap;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-null.t b/FS/t/part_export-null.t
new file mode 100644
index 0000000..055cdce
--- /dev/null
+++ b/FS/t/part_export-null.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::null;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-passwdfile.t b/FS/t/part_export-passwdfile.t
new file mode 100644
index 0000000..0f18f30
--- /dev/null
+++ b/FS/t/part_export-passwdfile.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::passwdfile;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-postfix.t b/FS/t/part_export-postfix.t
new file mode 100644
index 0000000..9518caa
--- /dev/null
+++ b/FS/t/part_export-postfix.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::postfix;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-router.t b/FS/t/part_export-router.t
new file mode 100644
index 0000000..54e4b63
--- /dev/null
+++ b/FS/t/part_export-router.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::router;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-shellcommands.t b/FS/t/part_export-shellcommands.t
new file mode 100644
index 0000000..7bb47d3
--- /dev/null
+++ b/FS/t/part_export-shellcommands.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::shellcommands;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-shellcommands_withdomain.t b/FS/t/part_export-shellcommands_withdomain.t
new file mode 100644
index 0000000..c0bd1bb
--- /dev/null
+++ b/FS/t/part_export-shellcommands_withdomain.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::shellcommands_withdomain;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-sqlmail.t b/FS/t/part_export-sqlmail.t
new file mode 100644
index 0000000..b048a75
--- /dev/null
+++ b/FS/t/part_export-sqlmail.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::sqlmail;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-sqlradius.t b/FS/t/part_export-sqlradius.t
new file mode 100644
index 0000000..5fb23a5
--- /dev/null
+++ b/FS/t/part_export-sqlradius.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::sqlradius;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-sqlradius_withdomain.t b/FS/t/part_export-sqlradius_withdomain.t
new file mode 100644
index 0000000..504bf67
--- /dev/null
+++ b/FS/t/part_export-sqlradius_withdomain.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::sqlradius_withdomain;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-sysvshell.t b/FS/t/part_export-sysvshell.t
new file mode 100644
index 0000000..7fc24ac
--- /dev/null
+++ b/FS/t/part_export-sysvshell.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::sysvshell;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-textradius.t b/FS/t/part_export-textradius.t
new file mode 100644
index 0000000..d8a48a0
--- /dev/null
+++ b/FS/t/part_export-textradius.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::textradius;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-vpopmail.t b/FS/t/part_export-vpopmail.t
new file mode 100644
index 0000000..2e37114
--- /dev/null
+++ b/FS/t/part_export-vpopmail.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::vpopmail;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export-www_shellcommands.t b/FS/t/part_export-www_shellcommands.t
new file mode 100644
index 0000000..2ea79cf
--- /dev/null
+++ b/FS/t/part_export-www_shellcommands.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export::www_shellcommands;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export.t b/FS/t/part_export.t
new file mode 100644
index 0000000..26b3987
--- /dev/null
+++ b/FS/t/part_export.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_export_option.t b/FS/t/part_export_option.t
new file mode 100644
index 0000000..13200c2
--- /dev/null
+++ b/FS/t/part_export_option.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export_option;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_pkg.t b/FS/t/part_pkg.t
new file mode 100644
index 0000000..fd96073
--- /dev/null
+++ b/FS/t/part_pkg.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_pkg;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_pop_local.t b/FS/t/part_pop_local.t
new file mode 100644
index 0000000..4e4ad17
--- /dev/null
+++ b/FS/t/part_pop_local.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_pop_local;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_referral.t b/FS/t/part_referral.t
new file mode 100644
index 0000000..d20b979
--- /dev/null
+++ b/FS/t/part_referral.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_referral;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_svc.t b/FS/t/part_svc.t
new file mode 100644
index 0000000..bdb2a7a
--- /dev/null
+++ b/FS/t/part_svc.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_svc;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/part_svc_column.t b/FS/t/part_svc_column.t
new file mode 100644
index 0000000..467025c
--- /dev/null
+++ b/FS/t/part_svc_column.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_svc_column;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/pkg_svc.t b/FS/t/pkg_svc.t
new file mode 100644
index 0000000..77d3429
--- /dev/null
+++ b/FS/t/pkg_svc.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::pkg_svc;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/port.t b/FS/t/port.t
new file mode 100644
index 0000000..46377aa
--- /dev/null
+++ b/FS/t/port.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::port;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/prepay_credit.t b/FS/t/prepay_credit.t
new file mode 100644
index 0000000..e7626bd
--- /dev/null
+++ b/FS/t/prepay_credit.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::prepay_credit;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/queue.t b/FS/t/queue.t
new file mode 100644
index 0000000..43e3373
--- /dev/null
+++ b/FS/t/queue.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::queue;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/queue_arg.t b/FS/t/queue_arg.t
new file mode 100644
index 0000000..cf3f91d
--- /dev/null
+++ b/FS/t/queue_arg.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::queue_arg;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/queue_depend.t b/FS/t/queue_depend.t
new file mode 100644
index 0000000..8eaa2cd
--- /dev/null
+++ b/FS/t/queue_depend.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::queue_depend;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/raddb.t b/FS/t/raddb.t
new file mode 100644
index 0000000..ac28d07
--- /dev/null
+++ b/FS/t/raddb.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::raddb;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/radius_usergroup.t b/FS/t/radius_usergroup.t
new file mode 100644
index 0000000..325742c
--- /dev/null
+++ b/FS/t/radius_usergroup.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::radius_usergroup;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/session.t b/FS/t/session.t
new file mode 100644
index 0000000..c4b714e
--- /dev/null
+++ b/FS/t/session.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::session;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_Common.t b/FS/t/svc_Common.t
new file mode 100644
index 0000000..ed49e1e
--- /dev/null
+++ b/FS/t/svc_Common.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_Common;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_acct.t b/FS/t/svc_acct.t
new file mode 100644
index 0000000..9ca78c9
--- /dev/null
+++ b/FS/t/svc_acct.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_acct;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_acct_pop.t b/FS/t/svc_acct_pop.t
new file mode 100644
index 0000000..e612c40
--- /dev/null
+++ b/FS/t/svc_acct_pop.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_acct_pop;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_broadband.t b/FS/t/svc_broadband.t
new file mode 100644
index 0000000..02dc112
--- /dev/null
+++ b/FS/t/svc_broadband.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_broadband;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_domain.t b/FS/t/svc_domain.t
new file mode 100644
index 0000000..4d91898
--- /dev/null
+++ b/FS/t/svc_domain.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_domain;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_external.t b/FS/t/svc_external.t
new file mode 100644
index 0000000..20a6767
--- /dev/null
+++ b/FS/t/svc_external.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_external;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_forward.t b/FS/t/svc_forward.t
new file mode 100644
index 0000000..d653d34
--- /dev/null
+++ b/FS/t/svc_forward.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_forward;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_www.t b/FS/t/svc_www.t
new file mode 100644
index 0000000..eb4e83f
--- /dev/null
+++ b/FS/t/svc_www.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_www;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/type_pkgs.t b/FS/t/type_pkgs.t
new file mode 100644
index 0000000..9840180
--- /dev/null
+++ b/FS/t/type_pkgs.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::type_pkgs;
+$loaded=1;
+print "ok 1\n";
diff --git a/GPL b/GPL
new file mode 100644
index 0000000..e77696a
--- /dev/null
+++ b/GPL
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..4b9b085
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1 @@
+See httemplate/docs/index.html
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..77a5a48
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,294 @@
+#!/usr/bin/make
+
+DATASOURCE = DBI:Pg:dbname=freeside
+#DATASOURCE=DBI:mysql:freeside
+
+DB_USER = freeside
+DB_PASSWORD=
+
+#TEMPLATE = asp
+TEMPLATE = mason
+
+ASP_GLOBAL = /usr/local/etc/freeside/asp-global
+MASON_HANDLER = /usr/local/etc/freeside/handler.pl
+MASONDATA = /usr/local/etc/freeside/masondata
+
+#deb
+FREESIDE_DOCUMENT_ROOT = /var/www/freeside
+#redhat, fedora, mandrake
+#FREESIDE_DOCUMENT_ROOT = /var/www/html/freeside
+#freebsd
+#FREESIDE_DOCUMENT_ROOT = /usr/local/www/data/freeside
+#openbsd
+#FREESIDE_DOCUMENT_ROOT = /var/www/htdocs/freeside
+#suse
+#FREESIDE_DOCUMENT_ROOT = /srv/www/htdocs/freeside
+#apache
+#FREESIDE_DOCUMENT_ROOT = /usr/local/apache/htdocs/freeside
+
+#deb, redhat, fedora, mandrake, suse, others?
+INIT_FILE = /etc/init.d/freeside
+#freebsd
+#INIT_FILE = /usr/local/etc/rc.d/011.freeside.sh
+
+#deb, suse
+HTTPD_RESTART = /etc/init.d/apache restart
+#redhat, fedora, mandrake
+#HTTPD_RESTART = /etc/init.d/httpd restart
+#freebsd
+#HTTPD_RESTART = /usr/local/etc/rc.d/apache.sh stop; sleep 1; /usr/local/etc/rc.d/apache.sh start
+#openbsd
+#HTTPD_RESTART = kill -TERM `cat /var/www/logs/httpd.pid`; sleep 1; /usr/sbin/httpd -u -DSSL
+#apache
+#HTTPD_RESTART = /usr/local/apache/bin/apachectl restart
+
+FREESIDE_RESTART = ${INIT_FILE} restart
+
+#deb, redhat, fedora, mandrake, suse, others?
+INSTALLGROUP = root
+#freebsd, openbsd
+#INSTALLGROUP = wheel
+
+#edit the stuff below to have the daemons start
+
+QUEUED_USER=fs_queue
+
+#eventually this shouldn't be needed
+FREESIDE_PATH = `pwd`
+
+SELFSERVICE_USER = fs_selfservice
+#never run on the same machine in production!!!
+SELFSERVICE_MACHINES = localhost
+# SELFSERVICE_MACHINES = www.example.com
+# SELFSERVICE_MACHINES = web1.example.com web2.example.com
+
+#user with sudo access on SELFSERVICE_MACHINES for automated self-service
+#installation.
+SELFSERVICE_INSTALL_USER = ivan
+SELFSERVICE_INSTALL_USERADD = /usr/sbin/useradd
+#SELFSERVICE_INSTALL_USERADD = "/usr/sbin/pw useradd"
+
+RT_ENABLED = 0
+#RT_ENABLED = 1
+RT_DOMAIN = example.com
+RT_TIMEZONE = US/Pacific;
+#RT_TIMEZONE = US/Eastern;
+
+#---
+
+#not changable yet
+FREESIDE_CONF = /usr/local/etc/freeside
+#rt/config.layout.in
+RT_PATH = /opt/rt3
+
+VERSION=1.5.0pre5
+TAG=freeside_1_5_0pre5
+
+help:
+ @echo "supported targets: aspdocs masondocs alldocs docs install-docs"
+ @echo " htmlman"
+ @echo " perl-modules install-perl-modules"
+ @echo " install deploy"
+ @echo " create-database"
+ @echo " configure-rt create-rt"
+ @echo " clean"
+
+aspdocs: htmlman httemplate/* httemplate/*/* httemplate/*/*/* httemplate/*/*/*/* httemplate/*/*/*/*/*
+ rm -rf aspdocs
+ cp -pr httemplate aspdocs
+ perl -p -i -e "\
+ s/%%%VERSION%%%/${VERSION}/g;\
+ " aspdocs/index.html
+ touch aspdocs
+
+
+masondocs: htmlman httemplate/* httemplate/*/* httemplate/*/*/* httemplate/*/*/*/* httemplate/*/*/*/*/*
+ rm -rf masondocs
+ cp -pr httemplate masondocs
+ ( cd masondocs; \
+ ../bin/masonize; \
+ )
+ perl -p -i -e "\
+ s/%%%VERSION%%%/${VERSION}/g;\
+ " masondocs/index.html
+ touch masondocs
+
+alldocs: aspdocs masondocs
+
+docs:
+ make ${TEMPLATE}docs
+
+htmlman:
+ [ -e ./httemplate/docs/man ] || mkdir httemplate/docs/man
+ [ -e ./httemplate/docs/man/bin ] || mkdir httemplate/docs/man/bin
+ [ -e ./httemplate/docs/man/FS ] || mkdir httemplate/docs/man/FS
+ [ -e ./httemplate/docs/man/FS/UI ] || mkdir httemplate/docs/man/FS/UI
+ [ -e ./httemplate/docs/man/FS/part_export ] || mkdir httemplate/docs/man/FS/part_export
+ chmod a+rx bin/pod2x
+ [ -e DONT_REBUILD_DOCS ] || bin/pod2x
+
+forcehtmlman:
+ [ -e ./httemplate/docs/man ] || mkdir httemplate/docs/man
+ [ -e ./httemplate/docs/man/bin ] || mkdir httemplate/docs/man/bin
+ [ -e ./httemplate/docs/man/FS ] || mkdir httemplate/docs/man/FS
+ [ -e ./httemplate/docs/man/FS/UI ] || mkdir httemplate/docs/man/FS/UI
+ [ -e ./httemplate/docs/man/FS/part_export ] || mkdir httemplate/docs/man/FS/part_export
+ bin/pod2x
+
+install-docs: docs
+ [ -e ${FREESIDE_DOCUMENT_ROOT} ] && mv ${FREESIDE_DOCUMENT_ROOT} ${FREESIDE_DOCUMENT_ROOT}.`date +%Y%m%d%H%M%S` || true
+ cp -r ${TEMPLATE}docs ${FREESIDE_DOCUMENT_ROOT}
+ [ "${TEMPLATE}" = "asp" -a ! -e ${ASP_GLOBAL} ] && mkdir ${ASP_GLOBAL} || true
+ [ "${TEMPLATE}" = "asp" ] && chown -R freeside ${ASP_GLOBAL} || true
+ [ "${TEMPLATE}" = "asp" ] && cp htetc/global.asa ${ASP_GLOBAL} || true
+ [ "${TEMPLATE}" = "asp" ] && \
+ perl -p -i -e "\
+ s'%%%FREESIDE_DOCUMENT_ROOT%%%'${FREESIDE_DOCUMENT_ROOT}'g; \
+ " ${ASP_GLOBAL}/global.asa || true
+ [ "${TEMPLATE}" = "mason" ] && cp htetc/handler.pl ${MASON_HANDLER} || true
+ [ "${TEMPLATE}" = "mason" ] && \
+ perl -p -i -e "\
+ s'%%%FREESIDE_DOCUMENT_ROOT%%%'${FREESIDE_DOCUMENT_ROOT}'g; \
+ s'%%%RT_ENABLED%%%'${RT_ENABLED}'g; \
+ " ${MASON_HANDLER} || true
+ [ "${TEMPLATE}" = "mason" -a ! -e ${MASONDATA} ] && mkdir ${MASONDATA} || true
+ [ "${TEMPLATE}" = "mason" ] && chown -R freeside ${MASONDATA} || true
+
+perl-modules:
+ cd FS; \
+ [ -e Makefile ] || perl Makefile.PL; \
+ make
+
+install-perl-modules: perl-modules
+ cd FS; \
+ make install UNINST=1
+
+install-init:
+ #[ -e ${INIT_FILE} ] || install -o root -g ${INSTALLGROUP} -m 711 init.d/freeside-init ${INIT_FILE}
+ install -o root -g ${INSTALLGROUP} -m 711 init.d/freeside-init ${INIT_FILE}
+ perl -p -i -e "\
+ s/%%%QUEUED_USER%%%/${QUEUED_USER}/g;\
+ s'%%%FREESIDE_PATH%%%'${FREESIDE_PATH}'g;\
+ s/%%%SELFSERVICE_USER%%%/${SELFSERVICE_USER}/g;\
+ s/%%%SELFSERVICE_MACHINES%%%/${SELFSERVICE_MACHINES}/g;\
+ " ${INIT_FILE}
+
+install-selfservice:
+ [ -e ~freeside/.ssh/id_dsa.pub ] || su -c 'ssh-keygen -t dsa' - freeside
+ for MACHINE in ${SELFSERVICE_MACHINES}; do \
+ scp -r fs_selfservice/FS-SelfService ${SELFSERVICE_INSTALL_USER}@$$MACHINE:. ;\
+ ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "cd FS-SelfService; perl Makefile.PL && make" ;\
+ ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "cd FS-SelfService; sudo make install" ;\
+ scp ~freeside/.ssh/id_dsa.pub ${SELFSERVICE_INSTALL_USER}@$$MACHINE:. ;\
+ ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "sudo ${SELFSERVICE_INSTALL_USERADD} freeside; sudo install -D -o freeside -m 600 ./id_dsa.pub ~freeside/.ssh/authorized_keys" ;\
+ ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "sudo install -o freeside -d /usr/local/freeside" ;\
+ done
+
+update-selfservice:
+ for MACHINE in ${SELFSERVICE_MACHINES}; do \
+ rsync -rlptz fs_selfservice/FS-SelfService/ ${SELFSERVICE_INSTALL_USER}@$$MACHINE:FS-SelfService ;\
+ ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "cd FS-SelfService; perl Makefile.PL && make" ;\
+ ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "cd FS-SelfService; sudo make install" ;\
+ done
+
+install: install-perl-modules install-docs install-init install-rt
+
+deploy: install
+ ${HTTPD_RESTART}
+ ${FREESIDE_RESTART}
+
+create-database:
+ perl -e 'use DBIx::DataSource qw( create_database ); create_database( "${DATASOURCE}", "${DB_USER}", "${DB_PASSWORD}" ) or die $$DBIx::DataSource::errstr;'
+
+create-config: install-perl-modules
+ [ -e ${FREESIDE_CONF} ] && mv ${FREESIDE_CONF} ${FREESIDE_CONF}.`date +%Y%m%d%H%M%S` || true
+ install -d -o freeside ${FREESIDE_CONF}
+
+ touch ${FREESIDE_CONF}/secrets
+ chown freeside ${FREESIDE_CONF}/secrets
+ chmod 600 ${FREESIDE_CONF}/secrets
+
+ echo -e "${DATASOURCE}\n${DB_USER}\n${DB_PASSWORD}" >${FREESIDE_CONF}/secrets
+ chmod 600 ${FREESIDE_CONF}/secrets
+ chown freeside ${FREESIDE_CONF}/secrets
+
+ mkdir "${FREESIDE_CONF}/conf.${DATASOURCE}"
+ rm -rf conf/registries #old dirs just won't go away
+ #cp conf/[a-z]* "${FREESIDE_CONF}/conf.${DATASOURCE}"
+ cp `ls -d conf/[a-z]* | grep -v CVS` "${FREESIDE_CONF}/conf.${DATASOURCE}"
+ chown -R freeside "${FREESIDE_CONF}/conf.${DATASOURCE}"
+
+ mkdir "${FREESIDE_CONF}/counters.${DATASOURCE}"
+ chown freeside "${FREESIDE_CONF}/counters.${DATASOURCE}"
+
+ mkdir "${FREESIDE_CONF}/cache.${DATASOURCE}"
+ chown freeside "${FREESIDE_CONF}/cache.${DATASOURCE}"
+
+ mkdir "${FREESIDE_CONF}/export.${DATASOURCE}"
+ chown freeside "${FREESIDE_CONF}/export.${DATASOURCE}"
+
+configure-rt:
+ cd rt; \
+ cp config.layout.in config.layout; \
+ perl -p -i -e "\
+ s'%%%FREESIDE_DOCUMENT_ROOT%%%'${FREESIDE_DOCUMENT_ROOT}'g;\
+ s'%%%MASONDATA%%%'${MASONDATA}'g;\
+ " config.layout; \
+ ./configure --enable-layout=Freeside\
+ --with-db-type=Pg \
+ --with-db-dba=${DB_USER} \
+ --with-db-database=freeside \
+ --with-db-rt-user=${DB_USER} \
+ --with-db-rt-pass=${DB_PASSWORD} \
+ --with-web-user=freeside \
+ --with-web-group=freeside \
+ --with-rt-group=freeside
+
+create-rt: configure-rt
+ cd rt; make install
+ echo -e "${DB_PASSWORD}\n\\d sessions"\
+ | psql -U ${DB_USER} -W freeside 2>&1\
+ | grep '^Did not find'\
+ && rt/sbin/rt-setup-database --dba '${DB_USER}' \
+ --dba-password '${DB_PASSWORD}' \
+ --action schema \
+ || true
+ rt/sbin/rt-setup-database --action insert_initial \
+ && rt/sbin/rt-setup-database --action insert --datafile ${RT_PATH}/etc/initialdata \
+ || true
+ perl -p -i -e "\
+ s'%%%RT_DOMAIN%%%'${RT_DOMAIN}'g;\
+ s'%%%RT_TIMEZONE%%%'${RT_TIMEZONE}'g;\
+ " ${RT_PATH}/etc/RT_SiteConfig.pm
+
+install-rt:
+ [ ${RT_ENABLED} -eq 1 ] && ( cd rt; make install ) || true
+
+clean:
+ rm -rf aspdocs masondocs
+ cd FS; \
+ make clean
+
+#these are probably only useful if you're me...
+
+upload-docs: forcehtmlman
+ ssh pouncequick.420.am rm -rf /var/www/www.sisd.com/freeside/devdocs
+ scp -pr httemplate/docs pouncequick.420.am:/var/www/www.sisd.com/freeside/devdocs
+
+release: upload-docs
+ cd /home/ivan/freeside
+ #cvs tag ${TAG}
+ cvs tag -F ${TAG}
+
+ #cd /home/ivan
+ cvs export -r ${TAG} -d freeside-${VERSION} freeside
+ tar czvf freeside-${VERSION}.tar.gz freeside-${VERSION}
+
+ scp freeside-${VERSION}.tar.gz ivan@pouncequick.420.am:/var/www/sisd.420.am/freeside/
+ mv freeside-${VERSION} freeside-${VERSION}.tar.gz ..
+
+update-webdemo:
+ ssh ivan@pouncequick.420.am '( cd freeside; cvs update -d -P )'
+ #ssh root@pouncequick.420.am '( cd /home/ivan/freeside; make clean; make deploy )'
+ ssh root@pouncequick.420.am '( cd /home/ivan/freeside; make deploy )'
+
diff --git a/README b/README
new file mode 100644
index 0000000..1030b38
--- /dev/null
+++ b/README
@@ -0,0 +1,43 @@
+Freeside
+
+Copyright (C) 2000,2001,2002,2003 Ivan Kohler
+Copyright (C) 1999 Silicon Interactive Software Design
+All rights reserved
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of:
+
+ a) the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any
+ later version
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program, in the file `GPL'; if not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite
+ 330, Boston, MA 02111-1307, USA.
+
+Freeside is a billing and administration package for Internet Service
+Providers.
+
+The Freeside home page is at `http://www.sisd.com/freeside'.
+
+The documentation is in `httemplate/docs'.
+
+A mailing list for users is available. Send a blank message to
+<ivan-freeside-subscribe@sisd.com> to subscribe.
+
+A mailing list for developers is available. It is intended to be lower volume
+and higher SNR than the users list. Send a blank message to
+<ivan-freeside-devel-subscribe@sisd.com> to subscribe.
+
+Commercial support is available from Ivan Kohler <ivan@sisd.com>. Requests for
+free support sent to me directly will be ignored. Please subscribe to the the
+user mailing list to request free support!
+
+Ivan Kohler <ivan-freeside_readme@420.am>
+
diff --git a/README.1.5.0pre1 b/README.1.5.0pre1
new file mode 100644
index 0000000..0de86bc
--- /dev/null
+++ b/README.1.5.0pre1
@@ -0,0 +1,17 @@
+preliminary upgrade instructions
+
+schema changes:
+ *** get svc_broadband changes from pc-intouch
+ *** otaker changes s/8/32 all otkaer fields
+ *** optional: sequence changes
+ *** add column cust_main_county.taxname
+ *** add column cust_bill_pkg.itemdesc
+ *** drop index cust_bill_pkg1
+ *** add index part_pkg1 and part_svc1
+
+install DBIx::DBSchema 0.21
+install NetAddr::IP
+
+Run dbdef-create
+something about history tables
+Restart apache and freeside-queued
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..4c582c9
--- /dev/null
+++ b/TODO
@@ -0,0 +1,9 @@
+$Id: TODO,v 1.68 2002-02-16 18:14:23 ivan Exp $
+
+The TODO list / bug-tracking is now kept in a database. See
+http://pouncequick.420.am/rt/
+
+If you are interested in helping with any of these, please join the
+*development* mailing list (send a blank message to
+ivan-freeside-devel-subscribe@sisd.com) to avoid duplication of effort.
+
diff --git a/bin/apache.export b/bin/apache.export
new file mode 100755
index 0000000..47863a9
--- /dev/null
+++ b/bin/apache.export
@@ -0,0 +1,67 @@
+#!/usr/bin/perl -w
+
+use strict;
+#use File::Path;
+use File::Rsync;
+use Net::SSH qw(ssh);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch qsearchs);
+use FS::part_export;
+use FS::cust_svc;
+use FS::svc_www;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+#needs the export number in there somewhere too...?
+my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/apache";
+mkdir $spooldir, 0700 unless -d $spooldir;
+
+my @exports = qsearch('part_export', { 'exporttype' => 'apache' } );
+
+my $rsync = File::Rsync->new({
+ rsh => 'ssh',
+# dry_run => 1,
+});
+
+foreach my $export ( @exports ) {
+
+ my $machine = $export->machine;
+ my $file = "$spooldir/$machine.conf";
+
+ open(HTTPD_CONF,">$file") or die "can't open $file: $!";
+
+ my $template = $export->option('template');
+
+ my @svc_www = $export->svc_x;
+
+ foreach my $svc_www ( @svc_www ) {
+ use vars qw($zone $username);
+ $zone = $svc_www->domain_record->zone;
+ $username = $svc_www->svc_acct->username;
+ print HTTPD_CONF eval(qq("$template")). "\n\n";
+ }
+
+ my $user = $export->option('user');
+ my $httpd_conf = $export->option('httpd_conf');
+
+ $rsync->exec( {
+ src => $file,
+ dest => "$user\@$machine:$httpd_conf",
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+ # warn $rsync->out;
+
+ my $restart = $export->option('restart') || 'apachectl graceful';
+
+ ssh("root\@$machine", $restart);
+
+}
+
+close HTTPD_CONF;
+
+# -----
+
+sub usage {
+ die "Usage:\n apache.export user\n";
+}
+
diff --git a/bin/bind.export b/bin/bind.export
new file mode 100755
index 0000000..d0b9379
--- /dev/null
+++ b/bin/bind.export
@@ -0,0 +1,191 @@
+#!/usr/bin/perl -w
+
+use strict;
+use File::Path;
+use File::Rsync;
+use Net::SSH qw(ssh);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch qsearchs);
+use FS::part_export;
+use FS::cust_pkg;
+use FS::cust_svc;
+use FS::svc_domain;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/bind";
+mkdir $spooldir, 0700 unless -d $spooldir;
+
+my @exports = qsearch('part_export', { 'exporttype' => 'bind' } );
+my @sexports = qsearch('part_export', { 'exporttype' => 'bind_slave' } );
+
+my $rsync = File::Rsync->new({
+ rsh => 'ssh',
+# dry_run => 1,
+});
+
+foreach my $export ( @exports ) {
+
+ my $machine = $export->machine;
+ my $prefix = "$spooldir/$machine";
+
+ my $bind_rel = $export->option('bind_release');
+ my $ndc_cmd = $export->option('reload')
+ || ( ($bind_rel eq 'BIND9') ? 'rndc' : 'ndc' );
+ my $minttl = $export->option('bind9_minttl');
+
+ #prevent old domain files from piling up
+ #rmtree "$prefix" or die "can't rmtree $prefix.db: $!";
+
+ mkdir $prefix, 0700 unless -d $prefix;
+
+ open(NAMED_CONF,">$prefix/named.conf")
+ or die "can't open $prefix/named.conf: $!";
+
+ open(CONF_HEADER,"<$prefix/named.conf.HEADER")
+ or die "can't open $prefix/named.conf.HEADER: $!";
+ while (<CONF_HEADER>) { print NAMED_CONF $_; }
+ close CONF_HEADER;
+
+ my $zonepath = $export->option('zonepath');
+ $zonepath =~ s/\/$//;
+
+ my @svc_domain = $export->svc_x;
+
+ foreach my $svc_domain ( @svc_domain ) {
+ my $domain = $svc_domain->domain;
+ my @masters = qsearch('domain_record', {
+ 'svcnum' => $svc_domain->svcnum,
+ 'rectype' => '_mstr',
+ } );
+ if ( @masters ) {
+ my $masters = join('; ', map { $_->recdata } @masters );
+
+ print NAMED_CONF <<END;
+zone "$domain" {
+ type slave;
+ file "db.$domain";
+ masters { $masters; };
+};
+
+END
+
+ } else {
+
+ print NAMED_CONF <<END;
+zone "$domain" {
+ type master;
+ file "$zonepath/db.$domain";
+};
+
+END
+
+ open (DB_MASTER,">$prefix/db.$domain")
+ or die "can't open $prefix/db.$domain: $!";
+
+ if ($bind_rel eq 'BIND9') {
+ print DB_MASTER "\$TTL $minttl\n\$ORIGIN $domain.\n";
+ }
+
+ my @domain_records =
+ qsearch('domain_record', { 'svcnum' => $svc_domain->svcnum } );
+ foreach my $domain_record (
+ sort { $b->rectype cmp $a->rectype } @domain_records
+ ) {
+ #if ( $domain_record->rectype eq 'SOA' ) {
+ # print DB_MASTER join("\t", $domain_record-> reczone
+ #} else {
+ print DB_MASTER join("\t",
+ map { $domain_record->getfield($_) }
+ qw( reczone recaf rectype recdata )
+ ), "\n";
+ #}
+ }
+
+ close DB_MASTER;
+
+ }
+
+ }
+
+ $rsync->exec( {
+ src => "$prefix/",
+ recursive => 1,
+ dest => "root\@$machine:$zonepath/",
+ exclude => [qw( *.import named.conf.HEADER named.conf )],
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+ # warn $rsync->out;
+
+ $rsync->exec( {
+ src => "$prefix/named.conf",
+ dest => "root\@$machine:". $export->option('named_conf'),
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+# warn $rsync->out;
+
+ ssh("root\@$machine", "$ndc_cmd reload");
+
+}
+
+close NAMED_CONF;
+
+foreach my $sexport ( @sexports ) { #false laziness with above
+
+ my $machine = $sexport->machine;
+ my $prefix = "$spooldir/$machine";
+
+ my $bind_rel = $sexport->option('bind_release');
+ my $ndc_cmd = ($bind_rel eq 'BIND9') ? 'rndc' : 'ndc';
+
+ #prevent old domain files from piling up
+ #rmtree "$prefix" or die "can't rmtree $prefix.db: $!";
+
+ mkdir $prefix, 0700 unless -d $prefix;
+
+ open(NAMED_CONF,">$prefix/named.conf")
+ or die "can't open $prefix/named.conf: $!";
+
+ open(CONF_HEADER,"<$prefix/named.conf.HEADER")
+ or die "can't open $prefix/named.conf.HEADER: $!";
+ while (<CONF_HEADER>) { print NAMED_CONF $_; }
+ close CONF_HEADER;
+
+ my $masters = $sexport->option('master');
+
+ #false laziness with freeside-sqlradius-reset
+ my @svc_domain =
+ map { qsearchs('svc_domain', { 'svcnum' => $_->svcnum } ) }
+ map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
+ grep { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
+ $sexport->export_svc;
+
+ foreach my $svc_domain ( @svc_domain ) {
+ my $domain = $svc_domain->domain;
+ print NAMED_CONF <<END;
+zone "$domain" {
+ type slave;
+ file "db.$domain";
+ masters { $masters; };
+};
+
+END
+
+ }
+
+ $rsync->exec( {
+ src => "$prefix/named.conf",
+ dest => "root\@$machine:". $sexport->option('named_conf'),
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+# warn $rsync->out;
+
+ ssh("root\@$machine", "$ndc_cmd reload");
+
+}
+close NAMED_CONF;
+
+# -----
+
+sub usage {
+ die "Usage:\n bind.export user\n";
+}
+
diff --git a/bin/bind.import b/bin/bind.import
new file mode 100755
index 0000000..41313fb
--- /dev/null
+++ b/bin/bind.import
@@ -0,0 +1,214 @@
+#!/usr/bin/perl -w
+#
+# -s: import slave zones as master. useful if you need to recreate your
+# primary nameserver from a secondary
+# -c chroot_dir: import data from chrooted bind (corrects the path for
+# downloading zone files
+#
+# need to manually put header in
+# /usr/local/etc/freeside/export.<datasrc./bind/<machine>/named.conf.HEADER
+
+use strict;
+use vars qw( %d_part_svc );
+use Getopt::Std;
+use Term::Query qw(query);
+#use BIND::Conf_Parser;
+#use DNS::ZoneParse 0.81;
+
+#use Net::SCP qw(iscp);
+use Net::SCP qw(scp);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch); #qsearchs);
+#use FS::svc_acct_sm;
+use FS::svc_domain;
+use FS::domain_record;
+#use FS::svc_acct;
+#use FS::part_svc;
+
+use vars qw($opt_s $opt_c);
+getopts("sc:");
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+$FS::svc_Common::noexport_hack = 1;
+$FS::domain_record::noserial_hack = 1;
+
+use vars qw($spooldir);
+$spooldir = "/usr/local/etc/freeside/export.". datasrc. "/bind";
+mkdir $spooldir unless -d $spooldir;
+
+%d_part_svc =
+ map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_domain'});
+
+print "\n\n",
+ ( join "\n", map "$_: ".$d_part_svc{$_}->svc, sort keys %d_part_svc ),
+ "\n\n";
+use vars qw($domain_svcpart);
+$^W=0; #Term::Query isn't -w-safe
+$domain_svcpart =
+ query "Enter part number for domains: ", 'irk', [ keys %d_part_svc ];
+$^W=1;
+
+print "\n\n", <<END;
+Enter the location and name of your primary named.conf file, for example
+"ns.isp.com:/var/named/named.conf"
+END
+my($named_conf)=&getvalue(":");
+
+use vars qw($named_machine $prefix);
+$named_machine = (split(/:/, $named_conf))[0];
+$prefix = "$spooldir/$named_machine";
+mkdir $prefix unless -d $prefix;
+
+#iscp("root\@$named_conf","$prefix/named.conf.import");
+scp("root\@$named_conf","$prefix/named.conf.import");
+
+
+sub getvalue {
+ my $prompt = shift;
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query $prompt, '';
+ $^W=1;
+ $return;
+}
+
+print "\n\n";
+
+##
+
+$FS::svc_domain::whois_hack=1;
+
+my $p = Parser->new;
+$p->parse_file("$prefix/named.conf.import");
+
+print "\nBIND import completed.\n";
+
+##
+
+sub usage {
+ die "Usage:\n\n bind.import user\n";
+}
+
+########
+BEGIN {
+
+ package Parser;
+ use BIND::Conf_Parser;
+ use vars qw(@ISA $named_dir);
+ @ISA = qw(BIND::Conf_Parser);
+
+ sub handle_option {
+ my($self, $option, $argument) = @_;
+ return unless $option eq "directory";
+ $named_dir = $argument;
+ }
+
+ sub handle_zone {
+ my($self, $name, $class, $type, $options) = @_;
+ return unless $class eq 'in';
+ return if grep { $name eq $_ } (qw(
+ . localhost 127.in-addr.arpa 0.in-addr.arpa 255.in-addr.arpa
+ 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa
+ 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.int
+ ));
+
+ use FS::Record qw(qsearchs);
+ use FS::svc_domain;
+
+ my $domain =
+ qsearchs('svc_domain', { 'domain' => $name } )
+ || new FS::svc_domain( {
+ svcpart => $main::domain_svcpart,
+ domain => $name,
+ action => 'N',
+ } );
+ unless ( $domain->svcnum ) {
+ my $error = $domain->insert;
+ die $error if $error;
+ }
+
+ if ( $type eq 'slave' && !$main::opt_s ) {
+
+ #use Data::Dumper;
+ #print Dumper($options);
+ #exit;
+
+ foreach my $master ( @{ $options->{masters} } ) {
+ my $domain_record = new FS::domain_record( {
+ 'svcnum' => $domain->svcnum,
+ 'reczone' => '@',
+ 'recaf' => 'IN',
+ 'rectype' => '_mstr',
+ 'recdata' => $master,
+ } );
+ my $error = $domain_record->insert;
+ die $error if $error;
+ }
+
+ } elsif ( $type eq 'master' || ( $type eq 'slave' && $main::opt_s ) ) {
+
+ my $file = $options->{file};
+
+ use File::Basename;
+ my $basefile = basename($file);
+ my $sourcefile = $file;
+ $sourcefile = "$named_dir/$sourcefile" unless $file =~ /^\//;
+ $sourcefile = "$main::opt_c/$sourcefile" if $main::opt_c;
+
+ use Net::SCP qw(iscp scp);
+ scp("root\@$main::named_machine:$sourcefile",
+ "$main::prefix/$basefile.import");
+
+ use DNS::ZoneParse 0.84;
+ my $zone = DNS::ZoneParse->new("$main::prefix/$basefile.import");
+
+ my $dump = $zone->dump;
+
+ #use Data::Dumper;
+ #print "$name: ". Dumper($dump);
+ #exit;
+
+ foreach my $rectype ( keys %$dump ) {
+ if ( $rectype =~ /^SOA$/i ) {
+ my $rec = $dump->{$rectype};
+ my $domain_record = new FS::domain_record( {
+ 'svcnum' => $domain->svcnum,
+ 'reczone' => $rec->{origin},
+ 'recaf' => 'IN',
+ 'rectype' => $rectype,
+ 'recdata' =>
+ $rec->{primary}. ' '. $rec->{email}. ' ( '.
+ join(' ', map $rec->{$_},
+ qw( serial refresh retry expire minimumTTL ) ).
+ ' )',
+ } );
+ my $error = $domain_record->insert;
+ die $error if $error;
+ } else {
+ #die $dump->{$rectype};
+ foreach my $rec ( @{ $dump->{$rectype} } ) {
+ my $domain_record = new FS::domain_record( {
+ 'svcnum' => $domain->svcnum,
+ 'reczone' => $rec->{name},
+ 'recaf' => $rec->{class},
+ 'rectype' => $rectype,
+ 'recdata' => ( $rectype =~ /^MX$/i
+ ? $rec->{priority}. ' '. $rec->{host}
+ : $rec->{host} ),
+ } );
+ my $error = $domain_record->insert;
+ die $error if $error;
+ }
+ }
+ }
+
+ #} else {
+ # die "unrecognized type $type\n";
+ }
+
+ }
+
+}
+#########
+
diff --git a/bin/bsdshell.export b/bin/bsdshell.export
new file mode 100755
index 0000000..6e0d103
--- /dev/null
+++ b/bin/bsdshell.export
@@ -0,0 +1,114 @@
+#!/usr/bin/perl -w
+
+# bsdshell export
+
+use strict;
+use File::Rsync;
+use Net::SSH qw(ssh);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch qsearchs);
+use FS::part_export;
+use FS::cust_svc;
+use FS::svc_acct;
+
+my @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+my $spooldir = "/usr/local/etc/freeside/export.". datasrc;
+#my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/shell";
+
+my @bsd_exports = qsearch('part_export', { 'exporttype' => 'bsdshell' } );
+
+my $rsync = File::Rsync->new({
+ rsh => 'ssh',
+# dry_run => 1,
+});
+
+foreach my $export ( @bsd_exports ) {
+ my $machine = $export->machine;
+ my $prefix = "$spooldir/$machine";
+ mkdir $prefix, 0700 unless -d $prefix;
+
+ #LOCKING!!!
+
+ ( open(MASTER,">$prefix/master.passwd")
+ #!!! and flock(MASTER,LOCK_EX|LOCK_NB)
+ ) or die "Can't open $prefix/master.passwd: $!";
+ ( open(PASSWD,">$prefix/passwd")
+ #!!! and flock(PASSWD,LOCK_EX|LOCK_NB)
+ ) or die "Can't open $prefix/passwd: $!";
+
+ chmod 0644, "$prefix/passwd";
+ chmod 0600, "$prefix/master.passwd";
+
+ my @svc_acct = $export->svc_x;
+
+ next unless @svc_acct;
+
+ foreach my $svc_acct ( sort { $a->uid <=> $b->uid } @svc_acct ) {
+
+ my $password = $svc_acct->_password;
+ my $cpassword;
+ #if ( ( length($password) <= 8 )
+ if ( ( length($password) <= 12 )
+ && ( $password ne '*' )
+ && ( $password ne '!!' )
+ && ( $password ne '' )
+ ) {
+ $cpassword=crypt($password,
+ $saltset[int(rand(64))].$saltset[int(rand(64))]
+ );
+ # MD5 !!!!
+ } else {
+ $cpassword=$password;
+ }
+
+ ###
+ # FORMAT OF THE PASSWD FILE HERE
+ print PASSWD join(":",
+ $svc_acct->username,
+ 'x', # "##". $username,
+ $svc_acct->uid,
+ $svc_acct->gid,
+ $svc_acct->finger,
+ $svc_acct->dir,
+ $svc_acct->shell,
+ ), "\n";
+
+ ###
+ # FORMAT OF FreeBSD MASTER PASSWD FILE HERE
+ print MASTER join(":",
+ $svc_acct->username, # User name
+ $cpassword, # Encrypted password
+ $svc_acct->uid, # User ID
+ $svc_acct->gid, # Group ID
+ "", # Login Class
+ "0", # Password Change Time
+ "0", # Password Expiration Time
+ $svc_acct->finger, # Users name
+ $svc_acct->dir, # Users home directory
+ $svc_acct->shell, # shell
+ ), "\n" ;
+
+ }
+
+ #!!! flock(MASTER,LOCK_UN);
+ #!!! flock(PASSWD,LOCK_UN);
+ close MASTER;
+ close PASSWD;
+
+ $rsync->exec( {
+ src => "$prefix/passwd",
+ dest => "root\@$machine:/etc/passwd"
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+
+ $rsync->exec( {
+ src => "$prefix/master.passwd",
+ dest => "root\@$machine:/etc/master.passwd.new"
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+ ssh("root\@$machine", "pwd_mkdb /etc/master.passwd.new");
+
+ # UNLOCK!!
+}
diff --git a/bin/create-fetchmailrc b/bin/create-fetchmailrc
new file mode 100644
index 0000000..11bde0c
--- /dev/null
+++ b/bin/create-fetchmailrc
@@ -0,0 +1,47 @@
+#!/usr/bin/perl -w
+# this quick hack helps you generate/maintain .fetchmailrc files from
+# FS::acct_snarf data. it is run from a shellcommands export as:
+# create-fetchmailrc $username $dir $snarf_machine1 $snarf_username1 $snarf__password1 $snarf_machine2 $snarf_username2 $snarf__password2 ...
+
+use strict;
+use POSIX qw( setuid setgid );
+
+my $header = <<END;
+# Configuration created by create-fetchmailrc
+set postmaster "postmaster"
+set bouncemail
+set no spambounce
+set properties ""
+set daemon 240
+END
+
+my $username = shift @ARGV or die "no username specified\n";
+my $homedir = shift @ARGV or die "no homedir specified\n";
+my $filename = "$homedir/.fetchmailrc";
+
+my $gid = scalar(getgrnam($username)) or die "can't find $username's gid\n";
+my $uid = scalar(getpwnam($username)) or die "can't find $username's uid\n";
+
+exit unless $ARGV[0];
+
+open(FETCHMAILRC, ">$filename") or die "can't open $filename: $!\n";
+chown $uid, $gid, $filename or die "can't chown $uid.$gid $filename: $!\n";
+chmod 0600, $filename or die "can't chmod 600 $filename: $!\n";
+print FETCHMAILRC $header;
+
+while ($ARGV[0]) {
+ my( $s_machine, $s_username, $s_password ) = splice( @ARGV, 0, 3 );
+ print FETCHMAILRC <<END;
+poll $s_machine
+ user '$s_username' there with password '$s_password' is '$username' here
+END
+}
+
+close FETCHMAILRC;
+
+setgid($gid) or die "can't setgid $gid\n";
+setuid($uid) or die "can't setuid $uid\n";
+$ENV{HOME} = $homedir;
+
+system(qq(fetchmail -a -K --antispam "550,451" -d 180 -f $filename));
+
diff --git a/bin/create-history-tables b/bin/create-history-tables
new file mode 100755
index 0000000..39248bf
--- /dev/null
+++ b/bin/create-history-tables
@@ -0,0 +1,93 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use DBI;
+use DBIx::DBSchema 0.21;
+use DBIx::DBSchema::Table;
+use DBIx::DBSchema::Column;
+use DBIx::DBSchema::ColGroup::Unique;
+use DBIx::DBSchema::ColGroup::Index;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(dbdef);
+
+my $user = shift or die &usage;
+my $dbh = adminsuidsetup $user;
+
+my $schema = dbdef();
+
+#false laziness w/fs-setup
+my @tables = scalar(@ARGV)
+ ? @ARGV
+ : grep { ! /^(h|pg)_/ } $schema->tables;
+foreach my $table ( @tables ) {
+ next if grep { /^h_$table/ } $schema->tables;
+ warn "creating history table for $table\n";
+ my $tableobj = $schema->table($table)
+ or die "unknown table $table (did you run dbdef-create?)\n";
+ my $h_tableobj = DBIx::DBSchema::Table->new( {
+ name => "h_$table",
+ primary_key => 'historynum',
+ unique => DBIx::DBSchema::ColGroup::Unique->new( [] ),
+ 'index' => DBIx::DBSchema::ColGroup::Index->new( [
+ @{$tableobj->unique->lol_ref},
+ @{$tableobj->index->lol_ref}
+ ] ),
+ columns => [
+ DBIx::DBSchema::Column->new( {
+ 'name' => 'historynum',
+ 'type' => 'serial',
+ 'null' => 'NOT NULL',
+ 'length' => '',
+ 'default' => '',
+ 'local' => '',
+ } ),
+ DBIx::DBSchema::Column->new( {
+ 'name' => 'history_date',
+ 'type' => 'int',
+ 'null' => 'NULL',
+ 'length' => '',
+ 'default' => '',
+ 'local' => '',
+ } ),
+ DBIx::DBSchema::Column->new( {
+ 'name' => 'history_user',
+ 'type' => 'varchar',
+ 'null' => 'NOT NULL',
+ 'length' => '80',
+ 'default' => '',
+ 'local' => '',
+ } ),
+ DBIx::DBSchema::Column->new( {
+ 'name' => 'history_action',
+ 'type' => 'varchar',
+ 'null' => 'NOT NULL',
+ 'length' => '80',
+ 'default' => '',
+ 'local' => '',
+ } ),
+ map {
+ my $column = $tableobj->column($_);
+ $column->type('int')
+ if $column->type eq 'serial';
+ $column->default('')
+ if $column->default =~ /^nextval\(/i;
+ ( my $local = $column->local ) =~ s/AUTO_INCREMENT//i;
+ $column->local($local);
+ $column;
+ } $tableobj->columns
+ ],
+ } );
+ foreach my $statement ( $h_tableobj->sql_create_table($dbh) ) {
+ $dbh->do( $statement )
+ or die "CREATE error: ". $dbh->errstr. "\ndoing statement: $statement";
+ }
+
+}
+
+$dbh->commit or die $dbh->errstr;
+$dbh->disconnect or die $dbh->errstr;
+
+sub usage {
+ die "Usage:\n create-history-tables user [ table table ... ] \n";
+}
+
diff --git a/bin/dbdef-create b/bin/dbdef-create
new file mode 100755
index 0000000..a449d67
--- /dev/null
+++ b/bin/dbdef-create
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use DBI;
+use DBIx::DBSchema 0.22;
+use FS::UID qw(adminsuidsetup datasrc driver_name);
+
+my $user = shift or die &usage;
+
+my($dbh)=adminsuidsetup $user;
+
+#needs to match FS::Record
+my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc;
+
+my $dbdef = new_native DBIx::DBSchema $dbh;
+
+#print $dbdef->pretty_print;
+
+#important
+$dbdef->save($dbdef_file);
+
+sub usage {
+ die "Usage:\n dbdef-create user\n";
+}
diff --git a/bin/fix-sequences b/bin/fix-sequences
new file mode 100755
index 0000000..2ff89d3
--- /dev/null
+++ b/bin/fix-sequences
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -Tw
+
+# run dbdef-create first!
+
+use strict;
+use DBI;
+use DBIx::DBSchema 0.21;
+use DBIx::DBSchema::Table;
+use DBIx::DBSchema::Column;
+use DBIx::DBSchema::ColGroup::Unique;
+use DBIx::DBSchema::ColGroup::Index;
+use FS::UID qw(adminsuidsetup driver_name);
+use FS::Record qw(dbdef);
+
+my $user = shift or die &usage;
+my $dbh = adminsuidsetup $user;
+
+my $schema = dbdef();
+
+#false laziness w/fs-setup
+my @tables = scalar(@ARGV)
+ ? @ARGV
+ : grep { ! /^h_/ } $schema->tables;
+foreach my $table ( @tables ) {
+ my $tableobj = $schema->table($table)
+ or die "unknown table $table (did you run dbdef-create?)\n";
+
+ my $primary_key = $tableobj->primary_key;
+ next unless $primary_key;
+
+ my $col = $tableobj->column($primary_key);
+
+
+ next unless uc($col->type) eq 'SERIAL'
+ || ( driver_name eq 'Pg'
+ && defined($col->default)
+ && $col->default =~ /^nextval\(/i
+ )
+ || ( driver_name eq 'mysql'
+ && defined($col->local)
+ && $col->local =~ /AUTO_INCREMENT/i
+ );
+
+ my $seq = "${table}_${primary_key}_seq";
+ if ( driver_name eq 'Pg'
+ && defined($col->default)
+ && $col->default =~ /^nextval\('"(public\.)?(\w+_seq)"'::text\)$/
+ ) {
+ $seq = $2;
+ }
+
+ warn "fixing sequence for $table\n";
+
+
+ my $sql = "SELECT setval( '$seq',
+ ( SELECT max($primary_key) FROM $table ) );";
+
+ #warn $col->default. " $seq\n$sql\n";
+ $dbh->do( $sql ) or die $dbh->errstr;
+
+}
+
+$dbh->commit or die $dbh->errstr;
+$dbh->disconnect or die $dbh->errstr;
+
+sub usage {
+ die "Usage:\n fix-sequences user [ table table ... ] \n";
+}
+
diff --git a/bin/freeside-init b/bin/freeside-init
new file mode 100755
index 0000000..fe12931
--- /dev/null
+++ b/bin/freeside-init
@@ -0,0 +1,60 @@
+#! /bin/sh
+#
+# start the freeside job queue daemon
+
+#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/local/bin/freeside-queued
+NAME=freeside-queued
+DESC="freeside job queue daemon"
+USER="ivan"
+
+test -f $DAEMON || exit 0
+
+set -e
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC: "
+# start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid -b -m\
+# --exec $DAEMON
+ $DAEMON $USER &
+ echo "$NAME."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \
+ --exec $DAEMON
+ echo "$NAME."
+ rm /var/run/$NAME.pid
+ ;;
+ #reload)
+ #
+ # If the daemon can reload its config files on the fly
+ # for example by sending it SIGHUP, do it here.
+ #
+ # If the daemon responds to changes in its config file
+ # directly anyway, make this a do-nothing entry.
+ #
+ # echo "Reloading $DESC configuration files."
+ # start-stop-daemon --stop --signal 1 --quiet --pidfile \
+ # /var/run/$NAME.pid --exec $DAEMON
+ #;;
+ restart|force-reload)
+ #
+ # If the "reload" option is implemented, move the "force-reload"
+ # option to the "reload" entry above. If not, "force-reload" is
+ # just the same as "restart".
+ #
+ $0 stop
+ sleep 1
+ $0 start
+ ;;
+ *)
+ N=/etc/init.d/$NAME
+ # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
+ echo "Usage: $N {start|stop|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/bin/freeside-session-kill b/bin/freeside-session-kill
new file mode 100755
index 0000000..d5fd703
--- /dev/null
+++ b/bin/freeside-session-kill
@@ -0,0 +1,103 @@
+#!/usr/bin/perl -w
+
+use strict;
+use vars qw($conf);
+use Fcntl qw(:flock);
+use FS::UID qw(adminsuidsetup datasrc dbh);
+use FS::Record qw(dbdef qsearch fields);
+use FS::session;
+use FS::svc_acct;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+my $sessionlock = "/usr/local/etc/freeside/session-kill.lock.". datasrc;
+
+open(LOCK,"+>>$sessionlock") or die "Can't open $sessionlock: $!";
+select(LOCK); $|=1; select(STDOUT);
+unless ( flock(LOCK,LOCK_EX|LOCK_NB) ) {
+ seek(LOCK,0,0);
+ my($pid)=<LOCK>;
+ chop($pid);
+ #no reason to start loct of blocking processes
+ die "Is another session kill process running under pid $pid?\n";
+}
+seek(LOCK,0,0);
+print LOCK $$,"\n";
+
+$FS::UID::AutoCommit = 0;
+
+my $now = time;
+
+#uhhhhh
+
+use DBIx::DBSchema;
+use DBIx::DBSchema::Table; #down this path lies madness
+use DBIx::DBSchema::Column;
+
+my $dbdef = dbdef or die;
+#warn $dbdef;
+#warn $dbdef->{'tables'};
+#warn keys %{$dbdef->{'tables'}};
+my $session_table = $dbdef->table('session') or die;
+my $svc_acct_table = $dbdef->table('svc_acct') or die;
+
+my $session_svc_acct = new DBIx::DBSchema::Table ( 'session,svc_acct', '', '', '',
+ map( DBIx::DBSchema::Column->new( "session.$_",
+ $session_table->column($_)->type,
+ $session_table->column($_)->null,
+ $session_table->column($_)->length,
+ ), $session_table->columns() ),
+ map( DBIx::DBSchema::Column->new( "svc_acct.$_",
+ $svc_acct_table->column($_)->type,
+ $svc_acct_table->column($_)->null,
+ $svc_acct_table->column($_)->length,
+ ), $svc_acct_table->columns ),
+# map("svc_acct.$_", $svc_acct_table->columns),
+);
+
+$dbdef->addtable($session_svc_acct); #madness, i tell you
+
+$FS::Record::DEBUG = 1;
+my @session = qsearch('session,svc_acct', {}, '', ' WHERE '. join(' AND ',
+ 'svc_acct.svcnum = session.svcnum',
+ '( session.logout IS NULL OR session.logout = 0 )',
+ "( $now - session.login ) >= svc_acct.seconds"
+). " FOR UPDATE" );
+
+my $dbh = dbh;
+
+foreach my $join ( @session ) {
+
+ my $session = new FS::session ( {
+ map { $_ => $join->{'Hash'}{"session.$_"} } fields('session')
+ } ); #see no evil
+
+ my $svc_acct = new FS::svc_acct ( {
+ map { $_ => $join->{'Hash'}{"svc_acct.$_"} } fields('svc_acct')
+ } );
+
+ #false laziness w/ fs_session_server
+ my $nsession = new FS::session ( { $session->hash } );
+ my $error = $nsession->replace($session);
+ if ( $error ) {
+ $dbh->rollback;
+ die $error;
+ }
+ my $time = $nsession->logout - $nsession->login;
+ my $new_svc_acct = new FS::svc_acct ( { $svc_acct->hash } );
+ my $seconds = $new_svc_acct->seconds;
+ $seconds -= $time;
+ $seconds = 0 if $seconds < 0;
+ $new_svc_acct->seconds( $seconds );
+ $error = $new_svc_acct->replace( $svc_acct );
+ warn "can't debit time from ". $svc_acct->username. ": $error\n"; #don't want to rollback, though
+ #ssenizal eslaf
+
+}
+
+$dbh->commit or die $dbh->errstr;
+
+sub usage {
+ die "Usage:\n\n freeside-session-kill user\n";
+}
diff --git a/bin/freeside.import b/bin/freeside.import
new file mode 100644
index 0000000..fdfcc08
--- /dev/null
+++ b/bin/freeside.import
@@ -0,0 +1,146 @@
+#!/usr/bin/perl -w
+
+use strict;
+use DBI;
+
+my $s_datasrc = 'DBI:mysql:host=ns1.enetonline.net;port=3307;user=ivan;dbname=freeside';
+my $s_dbuser = 'ivan';
+my $s_dbpass = '';
+
+my $d_datasrc = 'DBI:Pg:dbname=freeside';
+my $d_dbuser = 'freeside';
+my $d_dbpass = '';
+
+#my @tables = qw(
+#addr_block
+#agent
+#agent_type
+#cust_bill
+#cust_bill_event
+#cust_bill_pay
+#cust_bill_pkg
+#cust_bill_pkg_detail
+#cust_credit
+#cust_credit_bill
+#cust_credit_refund
+#cust_main
+#cust_main_county
+#cust_main_invoice
+#cust_pay
+#cust_pay_batch
+#cust_pkg
+#cust_refund
+#cust_svc
+#cust_tax_exempt
+#domain_record
+#export_svc
+#h_addr_block
+#h_agent
+#h_agent_type
+#h_cust_bill
+#h_cust_bill_event
+#h_cust_bill_pay
+#h_cust_bill_pkg
+#h_cust_bill_pkg_detail
+#h_cust_credit
+#h_cust_credit_bill
+#h_cust_credit_refund
+#h_cust_main
+#h_cust_main_county
+#h_cust_main_invoice
+#h_cust_pay
+#h_cust_pay_batch
+#h_cust_pkg
+#h_cust_refund
+#h_cust_svc
+#h_cust_tax_exempt
+#h_domain_record
+#h_export_svc
+#h_msgcat
+#h_nas
+#h_part_bill_event
+#h_part_export
+#h_part_export_option
+#h_part_pkg
+#h_part_pop_local
+#h_part_referral
+#h_part_svc
+#h_part_svc_column
+#h_part_svc_router
+#h_pkg_svc
+#h_port
+#h_prepay_credit
+#h_queue
+#h_queue_arg
+#h_queue_depend
+#h_radius_usergroup
+#h_router
+#h_router_field
+#h_sb_field
+#h_session
+#h_svc_acct
+#h_svc_acct_pop
+#h_svc_broadband
+#h_svc_domain
+#h_svc_forward
+#h_svc_www
+#h_type_pkgs
+#msgcat
+#nas
+#part_bill_event
+#part_export
+#part_export_option
+#part_pkg
+
+my @tables = qw(
+part_pop_local
+part_referral
+part_router_field
+part_sb_field
+part_svc
+part_svc_column
+part_svc_router
+pkg_svc
+port
+prepay_credit
+queue
+queue_arg
+queue_depend
+radius_usergroup
+router
+router_field
+sb_field
+session
+svc_acct
+svc_acct_pop
+svc_broadband
+svc_domain
+svc_forward
+svc_www
+type_pkgs
+);
+
+my $s_dbh = DBI->connect($s_datasrc, $s_dbuser, $s_dbpass) or die $DBI::errstr;
+my $d_dbh = DBI->connect($d_datasrc, $d_dbuser, $d_dbpass) or die $DBI::errstr;
+
+foreach my $table ( @tables ) {
+ $d_dbh->do("delete from $table");
+
+ my $s_sth = $s_dbh->prepare("select * from $table");
+ $s_sth->execute or die $s_sth->errstr;
+
+ my $row;
+ while ( $row = $s_sth->fetchrow_arrayref ) {
+ my $d_sth = $d_dbh->prepare(
+ "insert into $table ( ".
+ join(', ', @{$s_sth->{NAME}} ).
+ ' ) VALUES ( '.
+ join(', ', map { '?' } @{$s_sth->{NAME}} ).
+ ' )'
+ ) or die $d_dbh->errstr;
+
+ $d_sth->execute(@$row) or die $d_sth->errstr;
+
+ }
+}
+
diff --git a/bin/fs-migrate-part_svc b/bin/fs-migrate-part_svc
new file mode 100755
index 0000000..b0f3ac5
--- /dev/null
+++ b/bin/fs-migrate-part_svc
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch fields);
+use FS::part_svc;
+
+my $user = shift or die &usage;
+my $dbh = adminsuidsetup $user;
+
+my $oldAutoCommit = $FS::UID::AutoCommit;
+local $FS::UID::AutoCommit = 0;
+
+foreach my $part_svc ( qsearch('part_svc', {} ) ) {
+ foreach my $field (
+ grep { defined($part_svc->getfield($part_svc->svcdb.'__'.$_.'_flag') ) }
+ fields($part_svc->svcdb)
+ ) {
+ my $flag = $part_svc->getfield($part_svc->svcdb.'__'.$field.'_flag');
+ if ( uc($flag) =~ /^([DF])$/ ) {
+ my $part_svc_column = new FS::part_svc_column {
+ 'svcpart' => $part_svc->svcpart,
+ 'columnname' => $field,
+ 'columnflag' => $1,
+ 'columnvalue' => $part_svc->getfield($part_svc->svcdb.'__'.$field),
+ };
+ my $error = $part_svc_column->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ die $error;
+ }
+ }
+ }
+}
+
+$dbh->commit or die $dbh->errstr;
+
+sub usage {
+ die "Usage:\n fs-migrate-part_svc user\n";
+}
+
diff --git a/bin/fs-migrate-payref b/bin/fs-migrate-payref
new file mode 100755
index 0000000..1584197
--- /dev/null
+++ b/bin/fs-migrate-payref
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch);
+use FS::cust_pay;
+use FS::cust_refund;
+
+my $user = shift or die &usage;
+my $dbh = adminsuidsetup $user;
+
+# apply payments to invoices
+
+foreach my $cust_pay ( qsearch('cust_pay', {} ) ) {
+ my $error = $cust_pay->upgrade_replace;
+ warn $error if $error;
+}
+
+# apply refunds to credits
+
+foreach my $cust_refund ( qsearch('cust_refund') ) {
+ my $error = $cust_refund->upgrade_replace;
+ warn $error if $error;
+}
+
+# ? apply credits to invoices
+
+sub usage {
+ die "Usage:\n fs-migrate-payref user\n";
+}
+
diff --git a/bin/fs-migrate-svc_acct_sm b/bin/fs-migrate-svc_acct_sm
new file mode 100755
index 0000000..e34b235
--- /dev/null
+++ b/bin/fs-migrate-svc_acct_sm
@@ -0,0 +1,229 @@
+#!/usr/bin/perl -Tw
+#
+# $Id: fs-migrate-svc_acct_sm,v 1.4 2002-06-21 09:13:16 ivan Exp $
+#
+# jeff@cmh.net 01-Jul-20
+
+#to delay loading dbdef until we're ready
+#BEGIN { $FS::Record::setup_hack = 1; }
+
+use strict;
+use Term::Query qw(query);
+#use DBI;
+#use DBIx::DBSchema;
+#use DBIx::DBSchema::Table;
+#use DBIx::DBSchema::Column;
+#use DBIx::DBSchema::ColGroup::Unique;
+#use DBIx::DBSchema::ColGroup::Index;
+use FS::Conf;
+use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets);
+use FS::Record qw(qsearch qsearchs);
+use FS::svc_domain;
+use FS::svc_forward;
+use vars qw( $conf $old_default_domain %part_domain_svc %part_acct_svc %part_forward_svc $svc_acct $svc_acct_sm $error);
+
+die "Not running uid freeside!" unless checkeuid();
+
+my $user = shift or die &usage;
+getsecrets($user);
+
+$conf = new FS::Conf;
+$old_default_domain = $conf->config('domain');
+
+#needs to match FS::Record
+#my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc;
+
+###
+# This section would be the appropriate place to manipulate
+# the schema & tables.
+###
+
+## we need to add the domsvc to svc_acct
+## we must add a svc_forward record....
+## I am thinking that the fields svcnum (int), destsvc (int), and
+## dest (varchar (80)) are appropriate, with destsvc/dest an either/or
+## much in the spirit of cust_main_invoice
+
+###
+# massage the data
+###
+
+my($dbh)=adminsuidsetup $user;
+
+$|=1;
+
+$FS::svc_Common::noexport_hack = 1;
+$FS::svc_domain::whois_hack = 1;
+
+%part_domain_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_domain'});
+%part_acct_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+%part_forward_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_forward'});
+
+die "No services with svcdb svc_domain!\n" unless %part_domain_svc;
+die "No services with svcdb svc_acct!\n" unless %part_acct_svc;
+die "No services with svcdb svc_forward!\n" unless %part_forward_svc;
+
+my($svc_domain) = qsearchs('svc_domain', { 'domain' => $old_default_domain });
+if (! $svc_domain || $svc_domain->domain != $old_default_domain) {
+ print <<EOF;
+
+Your database currently does not contain a svc_domain record for the
+domain $old_default_domain. Would you like me to add one for you?
+EOF
+
+ my($response)=scalar(<STDIN>);
+ chop $response;
+ if ($response =~ /^[yY]/) {
+ print "\n\n", &menu_domain_svc, "\n", <<END;
+I need to create new domain accounts. Which service shall I use for that?
+END
+ my($domain_svcpart)=&getdomainpart;
+
+ $svc_domain = new FS::svc_domain {
+ 'domain' => $old_default_domain,
+ 'svcpart' => $domain_svcpart,
+ 'action' => 'M',
+ };
+# $error=$svc_domain->insert && die "Error adding domain $old_default_domain: $error";
+ $error=$svc_domain->insert;
+ die "Error adding domain $old_default_domain: $error" if $error;
+ }else{
+ print <<EOF;
+
+ This program cannot function properly until a svc_domain record matching
+your conf_dir/domain file exists.
+EOF
+
+ exit 1;
+ }
+}
+
+print "\n\n", &menu_acct_svc, "\n", <<END;
+I may need to create some new pop accounts and set up forwarding to them
+for some users. Which service shall I use for that?
+END
+my($pop_svcpart)=&getacctpart;
+
+print "\n\n", &menu_forward_svc, "\n", <<END;
+I may need to create some new forwarding for some users. Which service
+shall I use for that?
+END
+my($forward_svcpart)=&getforwardpart;
+
+sub menu_domain_svc {
+ ( join "\n", map "$_: ".$part_domain_svc{$_}->svc, sort keys %part_domain_svc ). "\n";
+}
+sub menu_acct_svc {
+ ( join "\n", map "$_: ".$part_acct_svc{$_}->svc, sort keys %part_acct_svc ). "\n";
+}
+sub menu_forward_svc {
+ ( join "\n", map "$_: ".$part_forward_svc{$_}->svc, sort keys %part_forward_svc ). "\n";
+}
+sub getdomainpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_domain_svc ];
+ $^W=1;
+ $return;
+}
+sub getacctpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_acct_svc ];
+ $^W=1;
+ $return;
+}
+sub getforwardpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_forward_svc ];
+ $^W=1;
+ $return;
+}
+
+
+#migrate data
+
+my(@svc_accts) = qsearch('svc_acct', {});
+foreach $svc_acct (@svc_accts) {
+ my(@svc_acct_sms) = qsearch('svc_acct_sm', {
+ domuid => $svc_acct->getfield('uid'),
+ }
+ );
+
+ # Ok.. we've got the svc_acct record, and an array of svc_acct_sm's
+ # What do we do from here?
+
+ # The intuitive:
+ # plop the svc_acct into the 'default domain'
+ # and then represent the svc_acct_sm's with svc_forwards
+ # they can be gussied up manually, later
+ #
+ # Perhaps better:
+ # when no svc_acct_sm exists, place svc_acct in 'default domain'
+ # when one svc_acct_sm exists, place svc_acct in corresponding
+ # domain & possibly create a svc_forward in 'default domain'
+ # when multiple svc_acct_sm's exists (in different domains) we'd
+ # better use the 'intuitive' approach.
+ #
+ # Specific way:
+ # as 'perhaps better,' but we may be able to guess which domain
+ # is correct by comparing the svcnum of domains to the username
+ # of the svc_acct
+ #
+
+ # The intuitive way:
+
+ my $def_acct = new FS::svc_acct ( { $svc_acct->hash } );
+ $def_acct->setfield('domsvc' => $svc_domain->getfield('svcnum'));
+ $error = $def_acct->replace($svc_acct);
+ die "Error replacing svc_acct for " . $def_acct->username . " : $error" if $error;
+
+ foreach $svc_acct_sm (@svc_acct_sms) {
+
+ my($domrec)=qsearchs('svc_domain', {
+ svcnum => $svc_acct_sm->getfield('domsvc'),
+ }) || die "svc_acct_sm references invalid domsvc $svc_acct_sm->getfield('domsvc')\n";
+
+ if ($svc_acct_sm->getfield('domuser') =~ /^\*$/) {
+
+ my($newdom) = new FS::svc_domain ( { $domrec->hash } );
+ $newdom->setfield('catchall', $svc_acct->svcnum);
+ $newdom->setfield('action', "M");
+ $error = $newdom->replace($domrec);
+ die "Error replacing svc_domain for (anything)@" . $domrec->domain . " : $error" if $error;
+
+ } else {
+
+ my($newacct) = new FS::svc_acct {
+ 'svcpart' => $pop_svcpart,
+ 'username' => $svc_acct_sm->getfield('domuser'),
+ 'domsvc' => $svc_acct_sm->getfield('domsvc'),
+ 'dir' => '/dev/null',
+ };
+ $error = $newacct->insert;
+ die "Error adding svc_acct for " . $newacct->username . " : $error" if $error;
+
+ my($newforward) = new FS::svc_forward {
+ 'svcpart' => $forward_svcpart,
+ 'srcsvc' => $newacct->getfield('svcnum'),
+ 'dstsvc' => $def_acct->getfield('svcnum'),
+ };
+ $error = $newforward->insert;
+ die "Error adding svc_forward for " . $newacct->username ." : $error" if $error;
+ }
+
+ $error = $svc_acct_sm->delete;
+ die "Error deleting svc_acct_sm for " . $svc_acct_sm->domuser ." : $error" if $error;
+
+ };
+
+};
+
+
+$dbh->commit or die $dbh->errstr;
+$dbh->disconnect or die $dbh->errstr;
+
+print "svc_acct_sm records sucessfully migrated\n";
+
+sub usage {
+ die "Usage:\n fs-migrate-svc_acct_sm user\n";
+}
+
diff --git a/bin/fs-radius-add-check b/bin/fs-radius-add-check
new file mode 100755
index 0000000..4e4769e
--- /dev/null
+++ b/bin/fs-radius-add-check
@@ -0,0 +1,68 @@
+#!/usr/bin/perl -Tw
+
+# quick'n'dirty hack of fs-setup to add radius attributes
+
+use strict;
+use DBI;
+use FS::UID qw(adminsuidsetup checkeuid getsecrets);
+use FS::raddb;
+
+die "Not running uid freeside!" unless checkeuid();
+
+my %attrib2db =
+ map { lc($FS::raddb::attrib{$_}) => $_ } keys %FS::raddb::attrib;
+
+my $user = shift or die &usage;
+getsecrets($user);
+
+my $dbh = adminsuidsetup $user;
+
+###
+
+print "\n\n", <<END, ":";
+Enter the additional RADIUS check attributes you need to track for
+each user, separated by whitespace.
+END
+my @attributes = map { $attrib2db{lc($_)} or die "unknown attribute $_"; }
+ split(" ",&getvalue);
+
+sub getvalue {
+ my($x)=scalar(<STDIN>);
+ chop $x;
+ $x;
+}
+
+###
+
+my($char_d) = 80; #default maxlength for text fields
+
+###
+
+foreach my $attribute ( @attributes ) {
+
+ my $statement =
+ "ALTER TABLE svc_acct ADD COLUMN rc_$attribute varchar($char_d) NULL";
+ my $sth = $dbh->prepare( $statement )
+ or warn "Error preparing $statement: ". $dbh->errstr;
+ my $rc = $sth->execute
+ or warn "Error executing $statement: ". $sth->errstr;
+
+ $statement =
+ "ALTER TABLE h_svc_acct ADD COLUMN rc_$attribute varchar($char_d) NULL";
+ $sth = $dbh->prepare( $statement )
+ or warn "Error preparing $statement: ". $dbh->errstr;
+ $rc = $sth->execute
+ or warn "Error executing $statement: ". $sth->errstr;
+
+}
+
+$dbh->commit or die $dbh->errstr;
+
+$dbh->disconnect or die $dbh->errstr;
+
+print "\n\n", "Now you must run dbdef-create.\n\n";
+
+sub usage {
+ die "Usage:\n fs-radius-add-check user\n";
+}
+
diff --git a/bin/fs-radius-add-reply b/bin/fs-radius-add-reply
new file mode 100755
index 0000000..3de0137
--- /dev/null
+++ b/bin/fs-radius-add-reply
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -Tw
+
+# quick'n'dirty hack of fs-setup to add radius attributes
+
+use strict;
+use DBI;
+use FS::UID qw(adminsuidsetup checkeuid getsecrets);
+use FS::raddb;
+
+die "Not running uid freeside!" unless checkeuid();
+
+my %attrib2db =
+ map { lc($FS::raddb::attrib{$_}) => $_ } keys %FS::raddb::attrib;
+
+my $user = shift or die &usage;
+getsecrets($user);
+
+my $dbh = adminsuidsetup $user;
+
+###
+
+print "\n\n", <<END, ":";
+Enter the additional RADIUS reply attributes you need to track for
+each user, separated by whitespace.
+END
+my @attributes = map { $attrib2db{lc($_)} or die "unknown attribute $_"; }
+ split(" ",&getvalue);
+
+sub getvalue {
+ my($x)=scalar(<STDIN>);
+ chop $x;
+ $x;
+}
+
+###
+
+my($char_d) = 80; #default maxlength for text fields
+
+###
+
+foreach my $attribute ( @attributes ) {
+
+ my $statement =
+ "ALTER TABLE svc_acct ADD COLUMN radius_$attribute varchar($char_d) NULL";
+ my $sth = $dbh->prepare( $statement )
+ or warn "Error preparing $statement: ". $dbh->errstr;
+ my $rc = $sth->execute
+ or warn "Error executing $statement: ". $sth->errstr;
+
+ $statement =
+ "ALTER TABLE h_svc_acct ADD COLUMN radius_$attribute varchar($char_d) NULL";
+ $sth = $dbh->prepare( $statement )
+ or warn "Error preparing $statement: ". $dbh->errstr;
+ $rc = $sth->execute
+ or warn "Error executing $statement: ". $sth->errstr;
+
+}
+
+$dbh->commit or die $dbh->errstr;
+
+$dbh->disconnect or die $dbh->errstr;
+
+print "\n\n", "Now you must run dbdef-create.\n\n";
+
+sub usage {
+ die "Usage:\n fs-radius-add-reply user\n";
+}
+
+
diff --git a/bin/generate-prepay b/bin/generate-prepay
new file mode 100755
index 0000000..cb4ba7f
--- /dev/null
+++ b/bin/generate-prepay
@@ -0,0 +1,35 @@
+#!/usr/bin/perl -w
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::prepay_credit;
+
+require 5.004; #srand(time|$$);
+
+my $user = shift or die &usage;
+&adminsuidsetup( $user );
+
+my $amount = shift or die &usage;
+
+my $seconds = shift or die &usage;
+
+my $num_digits = shift or die &usage;
+
+my $num_entries = shift or die &usage;
+
+for ( 1 .. $num_entries ) {
+ my $identifier = join( '', map int(rand(10)), ( 1 .. $num_digits ) );
+ my $prepay_credit = new FS::prepay_credit {
+ 'identifier' => $identifier,
+ 'amount' => $amount,
+ 'seconds' => $seconds,
+ };
+ my $error = $prepay_credit->insert;
+ die $error if $error;
+ print "$identifier\n";
+}
+
+sub usage {
+ die "Usage:\n\n generate-prepay user amount seconds num_digits num_entries";
+}
+
diff --git a/bin/generate-raddb b/bin/generate-raddb
new file mode 100755
index 0000000..f946b05
--- /dev/null
+++ b/bin/generate-raddb
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+# usage: generate-raddb radius-server/raddb/dictionary* >raddb.pm
+# i.e.: generate-raddb ~/src/freeradius-0.2/raddb/dictionary* >FS/raddb.pm
+
+print <<END;
+package FS::raddb;
+use vars qw(%attrib);
+
+%attrib = (
+END
+
+while (<>) {
+ next if /^(#|\s*$|\$INCLUDE\s+)/;
+ next if /^(VALUE|VENDOR|BEGIN\-VENDOR|END\-VENDOR)\s+/;
+ /^(ATTRIBUTE|ATTRIB_NMC)\s+([\w\-\/]+)\s+/ or die $_;
+ $attrib = $2;
+ $dbname = lc($2);
+ $dbname =~ s/[\-\/]/_/g;
+ $dbname = substr($dbname,0,24);
+ while ( exists $hash{$dbname} ) {
+ #warn $dbname;
+ $dbname =~ s/(.)$//;
+ my $w = $1;
+ $w =~ tr/_a-z0-9/a-z0-9_/;
+ $dbname = "$dbname$w";
+ }
+ $hash{$dbname} = $attrib;
+ #print "$2\n";
+}
+
+foreach ( keys %hash ) {
+# print "$_\n" if length($_)>24;
+# print substr($_,0,24),"\n" if length($_)>24;
+# $max = length($_) if length($_)>$max;
+# have to fudge things since everything >24 is *not* unique
+
+ #print " '". substr($_,0,24). "' => '$hash{$_}',\n";
+ print " '$_' => '$hash{$_}',\n";
+}
+
+print <<END;
+);
+
+1;
+END
+
diff --git a/bin/generate-tests b/bin/generate-tests
new file mode 100755
index 0000000..73fd29e
--- /dev/null
+++ b/bin/generate-tests
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+@files = glob('FS/*.pm');
+foreach (@files) {
+# warn $_;
+ chomp;
+ s/^FS\///;
+ $f=$_;
+ $f=~s/pm$/t/;
+ $m=$_;
+ $m=~s/\.pm$//;
+ open(TEST,">t/$f");
+ print "t/$f\n";
+ print TEST
+ 'BEGIN { $| = 1; print "1..1\n" }'. "\n".
+ 'END {print "not ok 1\n" unless $loaded;}'. "\n".
+ "use FS::$m;\n".
+ '$loaded=1;'. "\n".
+ 'print "ok 1\n";'. "\n"
+ ;
+ close TEST;
+}
diff --git a/bin/masonize b/bin/masonize
new file mode 100755
index 0000000..169ba71
--- /dev/null
+++ b/bin/masonize
@@ -0,0 +1,80 @@
+#!/usr/bin/perl
+
+foreach $file ( split(/\n/, `find . -depth -print`) ) {
+ next unless $file =~ /(cgi|html)$/;
+ open(F,$file) or die "can't open $file for reading: $!";
+ @file = <F>;
+ #print "$file ". scalar(@file). "\n";
+ close $file;
+ $newline = ''; #avoid prepending extraneous newlines
+ $all = join('',@file);
+
+ $w = '';
+
+ $mode = 'html';
+ while ( length($all) ) {
+
+ if ( $mode eq 'html' ) {
+
+ if ( $all =~ /^(.+?)(<%=?.*)$/s && $1 !~ /<%/s ) {
+ $w .= $1;
+ $all = $2;
+ next;
+ } elsif ( $all =~ /^<%=(.*)$/s ) {
+ $w .= '<%';
+ $all = $1;
+ $mode = 'perlv';
+ #die;
+ next;
+ } elsif ( $all =~ /^<%(.*)$/s ) {
+ $w .= $newline; $newline = "\n";
+ $all = $1;
+ $mode = 'perlc';
+
+ #avoid newline prepend fix from borking indented first <%
+ $w =~ s/\n\s+\z/\n/;
+ $w .= "\n" if $w =~ /.+\z/;
+
+ next;
+ } elsif ( $all !~ /<%/s ) {
+ $w .= $all;
+ last;
+ } else {
+ warn length($all); die;
+ }
+ die;
+
+ } elsif ( $mode eq 'perlv' ) {
+
+ if ( $all =~ /^(.*?%>)(.*)$/s ) {
+ $w .= $1;
+ $all=$2;
+ $mode = 'html';
+ next;
+ }
+ die 'unterminated <%= ???';
+
+ } elsif ( $mode eq 'perlc' ) {
+
+ if ( $all =~ /^([^\n]*?)%>(.*)$/s ) {
+ $w .= "%$1\n";
+ $all=$2;
+ $mode='html';
+ next;
+ }
+ if ( $all =~ /^([^\n]*)\n(.*)$/s ) {
+ $w .= "%$1\n";
+ $all=$2;
+ next;
+ }
+
+ } else { die };
+
+ }
+
+ system("chmod u+w $file");
+ select W; $| = 1; select STDOUT;
+ open(W,">$file") or die "can't open $file for writing: $!";
+ print W $w;
+ close W;
+}
diff --git a/bin/passwd.import b/bin/passwd.import
new file mode 100755
index 0000000..093f8ba
--- /dev/null
+++ b/bin/passwd.import
@@ -0,0 +1,120 @@
+#!/usr/bin/perl -Tw
+# $Id: passwd.import,v 1.8 2003-06-12 14:08:00 ivan Exp $
+
+use strict;
+use vars qw(%part_svc);
+use Date::Parse;
+use Term::Query qw(query);
+use Net::SCP qw(iscp);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch qsearchs);
+use FS::svc_acct;
+use FS::part_svc;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+push @FS::svc_acct::shells, qw(/bin/sync /sbin/shutdown /bin/halt /sbin/halt); #others?
+
+my($spooldir)="/usr/local/etc/freeside/export.". datasrc;
+
+#$FS::svc_acct::nossh_hack = 1;
+$FS::svc_Common::noexport_hack = 1;
+
+###
+
+%part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+
+die "No services with svcdb svc_acct!\n" unless %part_svc;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Enter part number to import.
+END
+my($shell_svcpart)=&getpart;
+
+print "\n\n", <<END;
+Enter the location and name of your _user_ passwd file, for example
+"mail.isp.com:/etc/passwd" or "nis.isp.com:/etc/global/passwd"
+END
+my($loc_passwd)=&getvalue(":");
+iscp("root\@$loc_passwd", "$spooldir/passwd.import");
+
+print "\n\n", <<END;
+Enter the location and name of your _user_ shadow file, for example
+"mail.isp.com:/etc/shadow" or "bsd.isp.com:/etc/master.passwd"
+END
+my($loc_shadow)=&getvalue(":");
+iscp("root\@$loc_shadow", "$spooldir/shadow.import");
+
+sub menu_svc {
+ ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n";
+}
+sub getpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_svc ];
+ $^W=1;
+ $return;
+}
+sub getvalue {
+ my $prompt = shift;
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query $prompt, '';
+ $^W=1;
+ $return;
+}
+
+print "\n\n";
+
+###
+
+open(PASSWD,"<$spooldir/passwd.import");
+open(SHADOW,"<$spooldir/shadow.import");
+
+my(%password);
+while (<SHADOW>) {
+ chop;
+ my($username,$password)=split(/:/);
+ #$password =~ s/^\!$/\*/;
+ #$password =~ s/\!+/\*SUSPENDED\* /;
+ $password{$username}=$password;
+}
+
+while (<PASSWD>) {
+ chop;
+ my($username,$x,$uid,$gid,$finger,$dir,$shell) = split(/:/);
+ my $password = $password{$username};
+
+ my $svcpart = $shell_svcpart;
+
+ #if ( qsearchs('svc_acct', { 'username' => $username } ) ) {
+ # warn "warning: $username already exists; skipping\n";
+ # next;
+ #}
+
+ my($svc_acct) = new FS::svc_acct ({
+ 'svcpart' => $svcpart,
+ 'username' => $username,
+ '_password' => $password,
+ 'uid' => $uid,
+ 'gid' => $gid,
+ 'finger' => $finger,
+ 'dir' => $dir,
+ 'shell' => $shell,
+ #%{$allparam{$username}},
+ });
+ my($error);
+ $error=$svc_acct->insert;
+ if ( $error ) {
+ if ( $error =~ /duplicate/i ) {
+ warn "$username: $error";
+ } else {
+ die "$username: $error";
+ }
+ }
+
+}
+
+sub usage {
+ die "Usage:\n\n passwd.import user\n";
+}
+
diff --git a/bin/pod2x b/bin/pod2x
new file mode 100755
index 0000000..46ccc77
--- /dev/null
+++ b/bin/pod2x
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+#use Pod::Text;
+#$Pod::Text::termcap=1;
+
+my $site_perl = "./FS";
+#my $catman = "./catman";
+#my $catman = "./htdocs/docs/man";
+#my $html = "./htdocs/docs/man";
+my $html = "./httemplate/docs/man";
+
+$|=1;
+
+die "Can't find $site_perl" unless -d $site_perl;
+#die "Can't find $catman" unless -d $catman;
+die "Can't find $html" unless -d $html;
+
+#make some useless links
+foreach my $file (
+ glob("$site_perl/bin/freeside-*"),
+) {
+ next if $file =~ /\.pod$/;
+ #symlink $file, "$file.pod"; # or die "link $file to $file.pod: $!";
+ system("cp $file $file.pod");
+}
+
+foreach my $file (
+ glob("$site_perl/*.pm"),
+ glob("$site_perl/*/*.pm"),
+ glob("$site_perl/*/*/*.pm"),
+ glob("$site_perl/bin/*.pod"),
+ glob("./fs_sesmon/FS-SessionClient/*.pm"),
+ glob("./fs_signup/FS-SignupClient/*.pm"),
+ glob("./fs_selfadmin/FS-MailAdminServer/*.pm"),
+) {
+ next if $file =~ /(^|\/)blib\//;
+ #$file =~ /\/([\w\-]+)\.pm$/ or die "oops file $file";
+ my $name;
+ if ( $file =~ /fs_\w+\/FS\-\w+\/(.*)\.pm$/ ) {
+ $name = "FS/$1";
+ } elsif ( $file =~ /$site_perl\/(.*)\.(pm|pod)$/ ) {
+ $name = $1;
+ } else {
+ die "oops file $file";
+ }
+ print "$name\n";
+ my $htmlroot = join('/', map '..',1..(scalar($file =~ tr/\///)-2)) || '.';
+# system "pod2text $file >$catman/$name.txt";
+ system "pod2html --podroot=$site_perl --podpath=./FS:./FS/UI:.:./bin --norecurse --htmlroot=$htmlroot $file >$html/$name.html";
+ #system "pod2html --podroot=$site_perl --htmlroot=$htmlroot $file >$html/$name.html";
+# system "pod2html $file >$html/$name.html";
+}
+
+#remove the useless links
+unlink glob("$site_perl/bin/*.pod");
+
diff --git a/bin/populate-msgcat b/bin/populate-msgcat
new file mode 100755
index 0000000..719d330
--- /dev/null
+++ b/bin/populate-msgcat
@@ -0,0 +1,127 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch);
+use FS::msgcat;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+foreach my $del_msgcat ( qsearch('msgcat', {}) ) {
+ my $error = $del_msgcat->delete;
+ die $error if $error;
+}
+
+my %messages = messages();
+
+foreach my $msgcode ( keys %messages ) {
+ foreach my $locale ( keys %{$messages{$msgcode}} ) {
+ my $msgcat = new FS::msgcat( {
+ 'msgcode' => $msgcode,
+ 'locale' => $locale,
+ 'msg' => $messages{$msgcode}{$locale},
+ });
+ my $error = $msgcat->insert;
+ die $error if $error;
+ }
+}
+
+#print "Message catalog initialized sucessfully\n";
+
+sub messages {
+
+ # 'msgcode' => {
+ # 'en_US' => 'Message',
+ # },
+
+ (
+
+ 'passwords_dont_match' => {
+ 'en_US' => "Passwords don't match",
+ },
+
+ 'invalid_card' => {
+ 'en_US' => 'Invalid credit card number',
+ },
+
+ 'unknown_card_type' => {
+ 'en_US' => 'Unknown card type',
+ },
+
+ 'not_a' => {
+ 'en_US' => 'Not a ',
+ },
+
+ 'empty_password' => {
+ 'en_US' => 'Empty password',
+ },
+
+ 'no_access_number_selected' => {
+ 'en_US' => 'No access number selected',
+ },
+
+ 'illegal_text' => {
+ 'en_US' => 'Illegal (text)',
+ #'en_US' => 'Only letters, numbers, spaces, and the following punctuation symbols are permitted: ! @ # $ % & ( ) - + ; : \' " , . ? / in field',
+ },
+
+ 'illegal_or_empty_text' => {
+ 'en_US' => 'Illegal or empty (text)',
+ #'en_US' => 'Only letters, numbers, spaces, and the following punctuation symbols are permitted: ! @ # $ % & ( ) - + ; : \' " , . ? / in required field',
+ },
+
+ 'illegal_username' => {
+ 'en_US' => 'Illegal username',
+ },
+
+ 'illegal_password' => {
+ 'en_US' => 'Illegal password (',
+ },
+
+ 'illegal_password_characters' => {
+ 'en_US' => ' characters)',
+ },
+
+ 'username_in_use' => {
+ 'en_US' => 'Username in use',
+ },
+
+ 'illegal_email_invoice_address' => {
+ 'en_US' => 'Illegal email invoice address',
+ },
+
+ 'illegal_name' => {
+ 'en_US' => 'Illegal (name)',
+ #'en_US' => 'Only letters, numbers, spaces and the following punctuation symbols are permitted: , . - \' in field',
+ },
+
+ 'illegal_phone' => {
+ 'en_US' => 'Illegal (phone)',
+ #'en_US' => '',
+ },
+
+ 'illegal_zip' => {
+ 'en_US' => 'Illegal (zip)',
+ #'en_US' => '',
+ },
+
+ 'expired_card' => {
+ 'en_US' => 'Expired card',
+ },
+
+ 'daytime' => {
+ 'en_US' => 'Day Phone',
+ },
+
+ 'night' => {
+ 'en_US' => 'Night Phone',
+ },
+
+ );
+}
+
+sub usage {
+ die "Usage:\n\n populate-msgcat user\n";
+}
+
diff --git a/bin/postfix.export b/bin/postfix.export
new file mode 100755
index 0000000..dbb08ce
--- /dev/null
+++ b/bin/postfix.export
@@ -0,0 +1,122 @@
+#!/usr/bin/perl -w
+
+use strict;
+#use File::Path;
+use File::Rsync;
+use Net::SSH qw(ssh);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch); # qsearchs);
+use FS::part_export;
+#use FS::cust_pkg;
+use FS::cust_svc;
+#use FS::svc_domain;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/postfix";
+mkdir $spooldir, 0700 unless -d $spooldir;
+
+my @exports = qsearch('part_export', { 'exporttype' => 'postfix' } );
+
+my $rsync = File::Rsync->new({
+ rsh => 'ssh',
+# dry_run => 1,
+});
+
+foreach my $export ( @exports ) {
+
+ my $machine = $export->machine;
+ my $prefix = "$spooldir/$machine";
+ mkdir $prefix, 0700 unless -d $prefix;
+
+ #construct %domain hash
+
+ my $mydomain = $export->option('mydomain');
+ my %domain;
+ foreach my $svc_forward ( $export->svc_x ) {
+
+ my( $username, $domain );
+ my $srcsvc_acct = $svc_forward->srcsvc_acct;
+ if ( $srcsvc_acct ) {
+ ( $username, $domain ) = ( $srcsvc_acct->username, $srcsvc_acct->domain );
+ } elsif ( $svc_forward->src =~ /([^@]*)\@([^@]+)$/ ) {
+ ( $username, $domain ) = ( $1, $2 );
+ } else {
+ die "bad svc_forward record? svcnum ". $svc_forward->svcnum. "\n";
+ }
+
+ my( $dusername, $ddomain );
+ my $dstsvc_acct = $svc_forward->dstsvc_acct;
+ if ( $dstsvc_acct ) {
+ $dusername = $dstsvc_acct->username;
+ $ddomain = $dstsvc_acct->domain;
+ } elsif ( $svc_forward->dst =~ /([^@]+)\@([^@]+)$/ ) {
+ ( $dusername, $ddomain ) = ( $1, $2 );
+ } else {
+ die "bad svc_forward record? svcnum ". $svc_forward->svcnum. "\n";
+ }
+ my $dest;
+ if ( $ddomain eq $mydomain ) {
+ $dest = $dusername;
+ } else {
+ $dest = "$dusername\@$ddomain";
+ }
+
+ push @{$domain{$domain}{$username}}, $dest;
+
+ }
+
+ #write aliases
+
+ my $aliases = delete $domain{$mydomain};
+ open(ALIASES, ">$prefix/aliases") or die "can't open $prefix/aliases: $!";
+ foreach my $alias ( keys %$aliases ) {
+ print ALIASES "$alias: ". join(',', @{ $aliases->{$alias} } ). "\n";
+ }
+ close ALIASES;
+
+ #write virtual
+
+ open(VIRTUAL, ">$prefix/virtual") or die "can't open $prefix/virtual: $!";
+ foreach my $domain ( keys %domain ) {
+ print VIRTUAL "$domain DOMAIN\n";
+ #foreach my $virtual ( sort { $a ne '' <=> $b ne '' } keys %{$domain{$domain}} ) {
+ foreach my $virtual ( sort { ( ($b ne '') <=> ($a ne '') ) || $a cmp $b } keys %{$domain{$domain}} ) {
+ print VIRTUAL "$virtual\@$domain ".
+ join(',', @{ $domain{$domain}{$virtual} } ). "\n";
+ }
+ print VIRTUAL "\n";
+ }
+ close VIRTUAL;
+
+ #rsync
+
+ my $user = $export->option('user');
+ $rsync->exec( {
+ src => "$prefix/aliases",
+ dest => "$user\@$machine:". $export->option('aliases'),
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+# warn $rsync->out;
+
+ ssh("$user\@$machine", $export->option('newaliases') || 'newaliases');
+# ssh("$user\@$machine", "postfix reload");
+
+ $rsync->exec( {
+ src => "$prefix/virtual",
+ dest => "$user\@$machine:". $export->option('virtual'),
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+# warn $rsync->out;
+ ssh("$user\@$machine", $export->option('postmap')
+ || 'postmap hash:/etc/postfix/virtual');
+ ssh("$user\@$machine", $export->option('reload') || 'postfix reload');
+
+}
+
+# -----
+
+sub usage {
+ die "Usage:\n postfix.export user\n";
+}
+
+
diff --git a/bin/postfix_courierimap.import b/bin/postfix_courierimap.import
new file mode 100755
index 0000000..12c138b
--- /dev/null
+++ b/bin/postfix_courierimap.import
@@ -0,0 +1,137 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use vars qw(%part_svc %domain_part_svc);
+#use Date::Parse;
+use DBI;
+use Term::Query qw(query);
+use FS::UID qw(adminsuidsetup); #datasrc
+use FS::Record qw(qsearch qsearchs);
+use FS::svc_acct;
+use FS::part_svc;
+use FS::svc_domain;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+#push @FS::svc_acct::shells, qw(/bin/sync /sbin/shutdown /bin/halt /sbin/halt); #others?
+
+$FS::svc_Common::noexport_hack = 1;
+$FS::svc_domain::whois_hack = 1;
+
+###
+
+%part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+
+die "No services with svcdb svc_acct!\n" unless %part_svc;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Enter part number to import.
+END
+my $mailbox_svcpart = &getpart;
+
+%domain_part_svc = map { $_->svcpart, $_ }
+ qsearch('part_svc', { 'svcdb' => 'svc_domain'} );
+
+die "No services with svcdb svc_domain!\n" unless %domain_part_svc;
+
+print "\n\n", &menu_domain_svc, "\n", <<END;
+Enter part number for domains.
+END
+my $domain_svcpart = &getdomainpart;
+
+my $datasrc = &getvalue("\n\nEnter the DBI datasource:");
+my $db_user = &getvalue("\n\nEnter the database user:");
+my $db_pass = &getvalue("\n\nEnter the database password:");
+
+sub menu_svc {
+ ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n";
+}
+sub menu_domain_svc {
+ ( join "\n", map "$_: ".$domain_part_svc{$_}->svc, sort keys %domain_part_svc ). "\n";
+}
+sub getpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_svc ];
+ $^W=1;
+ $return;
+}
+sub getdomainpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %domain_part_svc ];
+ $^W=1;
+ $return;
+}
+sub getvalue {
+ my $prompt = shift;
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query $prompt, '';
+ $^W=1;
+ $return;
+}
+
+print "\n\n";
+
+###
+
+my $dbh = DBI->connect( $datasrc, $db_user, $db_pass )
+ or die $DBI::errstr;
+
+my $sth = $dbh->prepare('SELECT username, password, crypt, name, domain FROM mailbox')
+ or die $dbh->errstr;
+$sth->execute or die $sth->errstr;
+
+my $row;
+while ( defined ( $row = $sth->fetchrow_arrayref ) ) {
+ my( $r_username, $password, $crypt, $finger, $r_domain ) = @$row;
+
+ my( $username, $domain );
+ if ( $r_username =~ /^([^@]+)\@([^@]+)$/ ) {
+ $username = $1;
+ $domain = $2;
+ } else {
+ $username = $r_username;
+ $domain = $r_domain;
+ }
+ my $svc_domain = qsearchs('svc_domain', { 'domain' => $domain } )
+ || new FS::svc_domain {
+ 'domain' => $domain,
+ 'svcpart' => $domain_svcpart,
+ 'action' => 'N',
+ };
+ unless ( $svc_domain->svcnum ) {
+ my $error = $svc_domain->insert;
+ if ( $error ) {
+ die "can't insert domain $domain: $error\n";
+ }
+ }
+
+ $password = $crypt if $password eq '*CRYPTED*';
+
+ $finger =~ s/Outdoor Power.*$/Outdoor Power/;
+
+ my $svc_acct = new FS::svc_acct {
+ 'svcpart' => $mailbox_svcpart,
+ 'username' => $username,
+ 'domsvc' => $svc_domain->svcnum,
+ '_password' => $password,
+ 'finger' => $finger,
+ };
+
+ my $error = $svc_acct->insert;
+ #my $error = $svc_acct->check;
+ if ( $error ) {
+ if ( $error =~ /duplicate/i ) {
+ warn "$r_username / $r_domain: $error";
+ } else {
+ die "$r_username / $r_domain: $error";
+ }
+ }
+
+}
+
+sub usage {
+ die "Usage:\n\n postfix_courierimap.import user\n";
+}
+
+
diff --git a/bin/sendmail.import b/bin/sendmail.import
new file mode 100644
index 0000000..ef745fc
--- /dev/null
+++ b/bin/sendmail.import
@@ -0,0 +1,178 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Term::Query qw(query);
+use Net::SCP qw(iscp);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch qsearchs);
+##use FS::svc_acct_sm;
+#use FS::svc_domain;
+#use FS::domain_record;
+use FS::svc_acct;
+##use FS::part_svc;
+use FS::svc_forward;
+use FS::svc_domain;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+#$FS::svc_Common::noexport_hack = 1;
+#$FS::domain_record::noserial_hack = 1;
+
+use vars qw($defaultdomain);
+$defaultdomain = '295.ca';
+
+use vars qw(@svcpart $forward_svcpart);
+@svcpart = qw( 2 4 );
+$forward_svcpart = 7;
+
+use vars qw($spooldir);
+$spooldir = "/usr/local/etc/freeside/export.". datasrc. "/sendmail";
+mkdir($spooldir, 0755) unless -d $spooldir;
+
+print "\n\n", <<END;
+Enter the location and name of your Sendmail aliases file, for example
+"mail.isp.com:/etc/mail/aliases"
+END
+my($aliases)=&getvalue(":");
+
+use vars qw($aliases_machine $aliases_prefix);
+$aliases_machine = (split(/:/, $aliases))[0];
+$aliases_prefix = "$spooldir/$aliases_machine";
+mkdir($aliases_prefix, 0755) unless -d $aliases_prefix;
+
+#iscp("root\@$aliases","$aliases_prefix/aliases.import");
+iscp("ivan\@$aliases","$aliases_prefix/aliases.import");
+
+print "\n\n", <<END;
+Enter the location and name of your Sendmail virtusertable directory, for example
+"mail.isp.com:/etc/mail/virtusertable"
+END
+my($virtusertable)=&getvalue(":");
+
+use vars qw($virtusertable_machine $virtusertable_prefix);
+$virtusertable_machine = (split(/:/, $virtusertable))[0];
+$virtusertable_prefix = "$spooldir/$virtusertable_machine";
+mkdir($virtusertable_prefix, 0755) unless -d $virtusertable_prefix;
+mkdir("$virtusertable_prefix/virtusertable.import", 0755)
+ unless -d "$virtusertable_prefix/virtusertable.import";
+
+#iscp("root\@$virtusertable/*","$aliases_prefix/virtusertable.import/");
+iscp("ivan\@$virtusertable/*","$aliases_prefix/virtusertable.import/");
+
+sub getvalue {
+ my $prompt = shift;
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query $prompt, '';
+ $^W=1;
+ $return;
+}
+
+print "\n\n";
+
+##
+
+foreach my $file (
+ "$aliases_prefix/aliases.import",
+ glob("$aliases_prefix/virtusertable.import/*"),
+) {
+
+ warn "importing $file\n";
+
+ open(FILE,"<$file") or die $!;
+ while (<FILE>) {
+ next if /^\s*#/ || /^\s*$/; #skip comments & blank lines
+
+ unless ( /^([\w\@\.\-]+)[:\s]\s*(.*\S)\s*$/ ) {
+ warn "Unparsable line: $_";
+ next;
+ }
+ my($rawusername, $rawdest) = ($1, $2);
+
+ my($username, $domain);
+ if ( $rawusername =~ /^([\w\-\.\&]*)\@([\w\.\-]+)$/ ) {
+ $username = $1;
+ $domain = $2;
+ } elsif ( $rawusername =~ /\@/ ) {
+ die "Unparsable username: $rawusername\n";
+ } else {
+ $username = $rawusername;
+ $domain = $defaultdomain;
+ }
+
+ #find svc_acct record or set $src
+ my($srcsvc, $src) = &svcnum_or_literal($username, $domain);
+
+ foreach my $dest ( split(/,/, $rawdest) ) {
+
+ my($dusername, $ddomain);
+ if ( $dest =~ /^([\w\-\.\&]+)\@([\w\.\-]+)$/ ) {
+ $dusername = $1;
+ $ddomain = $2;
+ } elsif ( $dest =~ /\@/ ) {
+ die "Unparsable username: $dest\n";
+ } else {
+ $dusername = $dest;
+ $ddomain = $defaultdomain;
+ }
+ my($dstsvc, $dst) = &svcnum_or_literal($dusername, $ddomain);
+
+ my $svc_forward = new FS::svc_forward ({
+ svcpart => $forward_svcpart,
+ srcsvc => $srcsvc,
+ src => $src,
+ dstsvc => $dstsvc,
+ dst => $dst,
+ });
+ my $error = $svc_forward->insert;
+ #my $error = $svc_forward->check;
+ if ( $error ) {
+ die "$rawusername: $rawdest: $error\n";
+ }
+ }
+
+
+ } #next entry
+
+} #next file
+
+##
+
+sub svcnum_or_literal {
+ my($username, $domain) = @_;
+
+ my $svc_domain = qsearchs('svc_domain', { 'domain' => $domain } );
+ my $domsvc = $svc_domain ? $svc_domain->svcnum : '';
+
+ my @svc_acct = grep { my $svc_acct = $_;
+ grep { $svc_acct->cust_svc->svcpart == $_ } @svcpart
+ }
+ qsearch('svc_acct', {
+ 'username' => $username,
+ 'domsvc' => $domsvc,
+ });
+
+ if ( scalar(@svc_acct) > 1 ) {
+ die "multiple sources found for $username\@$domain !\n";
+ }
+
+ my( $svcnum, $literal ) = ('', '');
+ if ( @svc_acct ) {
+ my $svc_acct = $svc_acct[0];
+ $svcnum = $svc_acct->svcnum;
+ } else {
+ $literal = "$username\@$domain";
+ }
+
+ return( $svcnum, $literal );
+
+}
+
+sub usage {
+ die "Usage:\n\n sendmail.import user\n";
+}
+
+
+
+
+
diff --git a/bin/sequences.reset b/bin/sequences.reset
new file mode 100644
index 0000000..2dc1d3b
--- /dev/null
+++ b/bin/sequences.reset
@@ -0,0 +1,32 @@
+#!/usr/bin/perl
+
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(dbdef dbh);
+
+my $user = shift;
+adminsuidsetup $user or die;
+
+foreach my $table ( dbdef->tables ) {
+ my $primary_key = dbdef->table($table)->primary_key;
+ next unless $primary_key;
+ #my $local = dbdef->table($table)->column($primary_key)->local;
+ ##next unless $default =~ /nextval/;
+ #print "$local\n";
+
+ my $statement = "select setval('${table}_${primary_key}_seq', ( select max($primary_key) from $table ) )";
+
+ print "$statement;\n";
+ next;
+
+ my $sth = dbh->prepare($statement) or do {
+ warn dbh->errstr. " preparing $statement\n";
+ next;
+ };
+ $sth->execute or do {
+ warn dbh->errstr. " executing $statement\n";
+ dbh->commit;
+ next;
+ }
+
+}
+
diff --git a/bin/shadow.reimport b/bin/shadow.reimport
new file mode 100755
index 0000000..7957011
--- /dev/null
+++ b/bin/shadow.reimport
@@ -0,0 +1,125 @@
+#!/usr/bin/perl -w
+#
+# -d: dry-run: make no changes
+# -r: replace: overwrite existing passwords (otherwise only "*" passwords will
+# be changed)
+# -b: blowfish replace: overwrite existing passwords only if they are
+# blowfish-encrypted
+
+use strict;
+use vars qw(%part_svc);
+use Getopt::Std;
+use Term::Query qw(query);
+use Net::SCP qw(iscp);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch qsearchs);
+use FS::svc_acct;
+use FS::part_svc;
+
+use vars qw($opt_d $opt_r $opt_b);
+getopts("drb");
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+push @FS::svc_acct::shells, qw(/bin/sync /sbin/shutdown /bin/halt /sbin/halt); #others?
+
+my($spooldir)="/usr/local/etc/freeside/export.". datasrc;
+
+#$FS::svc_acct::nossh_hack = 1;
+$FS::svc_Common::noexport_hack = 1;
+
+###
+
+%part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+
+die "No services with svcdb svc_acct!\n" unless %part_svc;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Enter part number or part numbers to import.
+END
+my($shell_svcpart)=&getvalue;
+my @shell_svcpart = split(/[,\s]+/, $shell_svcpart);
+
+print "\n\n", <<END;
+Enter the location and name of your _user_ shadow file, for example
+"mail.isp.com:/etc/shadow" or "bsd.isp.com:/etc/master.passwd"
+END
+my($loc_shadow)=&getvalue(":");
+iscp("root\@$loc_shadow", "$spooldir/shadow.import");
+
+sub menu_svc {
+ ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n";
+}
+sub getpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_svc ];
+ $^W=1;
+ $return;
+}
+sub getvalue {
+ my $prompt = shift;
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query $prompt, '';
+ $^W=1;
+ $return;
+}
+
+print "\n\n";
+
+###
+
+open(SHADOW,"<$spooldir/shadow.import");
+
+my($line, $updated);
+while (<SHADOW>) {
+ $line++;
+ chop;
+ my($username,$password)=split(/:/);
+
+# my @svc_acct = grep { $_->cust_svc->svcpart == $shell_svcpart }
+# qsearch('svc_acct', { 'username' => $username } );
+ my @svc_acct = grep {
+ my $svcpart = $_->cust_svc->svcpart;
+ grep { $_ == $svcpart } @shell_svcpart;
+ } qsearch('svc_acct', { 'username' => $username } );
+
+ next unless @svc_acct;
+
+ if ( scalar(@svc_acct) > 1 ) {
+ die "more than one $username found!\n";
+ next;
+ }
+
+ my $svc_acct = shift @svc_acct;
+
+ next unless $svc_acct->_password eq '*'
+ || $opt_r
+ || ( $opt_b && $svc_acct->_password =~ /^\$2a?\$/ );
+
+ next if $svc_acct->username eq 'root';
+
+ next if $password eq 'NP' || $password eq '*LK*';
+
+ next if $svc_acct->_password eq $password;
+ next if $svc_acct->_password =~ /^\*SUSPENDED\*/;
+
+ my $new_svc_acct = new FS::svc_acct( { $svc_acct->hash } );
+ $new_svc_acct->_password($password);
+ #warn "$username: ". $svc_acct->_password. " -> $password\n";
+ warn "changing password for $username\n";
+ unless ( $opt_d ) {
+ my $error = $new_svc_acct->replace($svc_acct);
+ die "$username: $error" if $error;
+ }
+
+ $updated++;
+
+}
+
+warn "$updated of $line passwords changed\n";
+
+sub usage {
+ die "Usage:\n\n shadow.reimport [ -d ] [ -r ] user\n";
+}
+
diff --git a/bin/sqlradius-norealm.reimport b/bin/sqlradius-norealm.reimport
new file mode 100755
index 0000000..b7d0166
--- /dev/null
+++ b/bin/sqlradius-norealm.reimport
@@ -0,0 +1,113 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use vars qw(%part_svc);
+#use Date::Parse;
+use DBI;
+use Term::Query qw(query);
+use FS::UID qw(adminsuidsetup); #datasrc
+use FS::Record qw(qsearch qsearchs);
+use FS::svc_acct;
+use FS::part_svc;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+#push @FS::svc_acct::shells, qw(/bin/sync /sbin/shutdown /bin/halt /sbin/halt); #others?
+
+$FS::svc_Common::noexport_hack = 1;
+
+###
+
+%part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+
+die "No services with svcdb svc_acct!\n" unless %part_svc;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Enter part number to import.
+END
+my $sqlradius_svcpart = &getpart;
+
+my $datasrc = &getvalue("\n\nEnter the DBI datasource:");
+my $db_user = &getvalue("\n\nEnter the database user:");
+my $db_pass = &getvalue("\n\nEnter the database password:");
+
+sub menu_svc {
+ ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n";
+}
+sub getpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_svc ];
+ $^W=1;
+ $return;
+}
+sub getvalue {
+ my $prompt = shift;
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query $prompt, '';
+ $^W=1;
+ $return;
+}
+
+print "\n\n";
+
+###
+
+my $dbh = DBI->connect( $datasrc, $db_user, $db_pass )
+ or die $DBI::errstr;
+
+my $sth = $dbh->prepare('SELECT DISTINCT UserName FROM radcheck')
+ or die $dbh->errstr;
+$sth->execute or die $sth->errstr;
+
+my $row;
+while ( defined ( $row = $sth->fetchrow_arrayref ) ) {
+ my( $username ) = @$row;
+
+ my( $password, $group ) = ( '', '', '' );
+
+ my $rc_sth = $dbh->prepare(
+ 'SELECT Attribute, Value'.
+ ' FROM radcheck'.
+ ' WHERE UserName = ?'
+ ) or die $dbh->errstr;
+ $rc_sth->execute($username) or die $rc_sth->errstr;
+
+ foreach my $rc_row ( @{$rc_sth->fetchall_arrayref} ) {
+ my($attribute, $value) = @$rc_row;
+ if ( $attribute =~ /^((Crypt|User)-)?Password$/ ) {
+ $password = $value unless $password && !$1;
+ } else {
+ #handle other params!
+ }
+ }
+
+ my @svc_acct = grep { $_->cust_svc->svcpart == $sqlradius_svcpart }
+ qsearch('svc_acct', { 'username' => $username, } );
+
+ #print "$r_username / $realm: $password / $finger: ";
+ print "$username: $password: ";
+ if ( scalar(@svc_acct) == 0 ) {
+ print "not found\n";
+ next;
+ } elsif ( scalar(@svc_acct) > 1 ) {
+ print "multiple matches found?!?!\n";
+ next;
+ } else {
+ #print "correcting password and name\n";
+ print "correcting password\n";
+ }
+
+ my $svc_acct = $svc_acct[0];
+ #my $new = new FS::svc_acct { $svc_acct->hash, '_password' => $password, 'finger' => $finger };
+ my $new = new FS::svc_acct { $svc_acct->hash, '_password' => $password };
+ my $error = $new->replace($svc_acct);
+ #my $error = $new->check;
+ die "$username: $error" if $error;
+
+}
+
+sub usage {
+ die "Usage:\n\n sqlradius-norealm.reimport user\n";
+}
+
diff --git a/bin/sqlradius.import b/bin/sqlradius.import
new file mode 100644
index 0000000..e75f65b
--- /dev/null
+++ b/bin/sqlradius.import
@@ -0,0 +1,152 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use vars qw(%part_svc %domain_part_svc);
+#use Date::Parse;
+use DBI;
+use Term::Query qw(query);
+use FS::UID qw(adminsuidsetup); #datasrc
+use FS::Record qw(qsearch qsearchs);
+use FS::svc_acct;
+use FS::part_svc;
+use FS::svc_domain;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+#push @FS::svc_acct::shells, qw(/bin/sync /sbin/shutdown /bin/halt /sbin/halt); #others?
+
+$FS::svc_Common::noexport_hack = 1;
+$FS::svc_domain::whois_hack = 1;
+
+###
+
+%part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+
+die "No services with svcdb svc_acct!\n" unless %part_svc;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Enter part number to import.
+END
+my $sqlradius_svcpart = &getpart;
+
+%domain_part_svc = map { $_->svcpart, $_ }
+ qsearch('part_svc', { 'svcdb' => 'svc_domain'} );
+
+die "No services with svcdb svc_domain!\n" unless %domain_part_svc;
+
+print "\n\n", &menu_domain_svc, "\n", <<END;
+Enter part number for domains.
+END
+my $domain_svcpart = &getdomainpart;
+
+my $datasrc = &getvalue("\n\nEnter the DBI datasource:");
+my $db_user = &getvalue("\n\nEnter the database user:");
+my $db_pass = &getvalue("\n\nEnter the database password:");
+
+sub menu_svc {
+ ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n";
+}
+sub menu_domain_svc {
+ ( join "\n", map "$_: ".$domain_part_svc{$_}->svc, sort keys %domain_part_svc ). "\n";
+}
+sub getpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_svc ];
+ $^W=1;
+ $return;
+}
+sub getdomainpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %domain_part_svc ];
+ $^W=1;
+ $return;
+}
+sub getvalue {
+ my $prompt = shift;
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query $prompt, '';
+ $^W=1;
+ $return;
+}
+
+print "\n\n";
+
+###
+
+my $dbh = DBI->connect( $datasrc, $db_user, $db_pass )
+ or die $DBI::errstr;
+
+my $sth = $dbh->prepare('SELECT DISTINCT UserName, Realm FROM radcheck')
+ or die $dbh->errstr;
+$sth->execute or die $sth->errstr;
+
+my $row;
+while ( defined ( $row = $sth->fetchrow_arrayref ) ) {
+ my( $r_username, $realm ) = @$row;
+
+ my( $username, $domain );
+ if ( $r_username =~ /^([^@]+)\@([^@]+)$/ ) {
+ $username = $1;
+ $domain = $2;
+ } else {
+ $username = $r_username;
+ $domain = $realm;
+ }
+ my $svc_domain = qsearchs('svc_domain', { 'domain' => $domain } )
+ || new FS::svc_domain {
+ 'domain' => $domain,
+ 'svcpart' => $domain_svcpart,
+ 'action' => 'N',
+ };
+ unless ( $svc_domain->svcnum ) {
+ my $error = $svc_domain->insert;
+ if ( $error ) {
+ die "can't insert domain $domain: $error\n";
+ }
+ }
+
+ my( $password, $finger, $group ) = ( '', '', '' );
+
+ my $rc_sth = $dbh->prepare(
+ 'SELECT Attribute, Value, Name, GroupName'.
+ ' FROM radcheck'.
+ ' WHERE UserName = ? and Realm = ?'
+ ) or die $dbh->errstr;
+ $rc_sth->execute($r_username, $realm) or die $rc_sth->errstr;
+
+ foreach my $rc_row ( @{$rc_sth->fetchall_arrayref} ) {
+ my($attribute, $value, $name, $groupname) = @$rc_row;
+ if ( $attribute =~ /^((User|Crypt)-)?Password$/ ) {
+ $password = $value;
+ $finger = $name;
+ $group = $groupname;
+ } else {
+ #handle other params!
+ }
+ }
+
+ my $svc_acct = new FS::svc_acct {
+ 'svcpart' => $sqlradius_svcpart,
+ 'username' => $username,
+ 'domsvc' => $svc_domain->svcnum,
+ '_password' => $password,
+ 'finger' => $finger,
+ };
+
+ my $error = $svc_acct->insert;
+ #my $error = $svc_acct->check;
+ if ( $error ) {
+ if ( $error =~ /duplicate/i ) {
+ warn "$r_username / $realm: $error";
+ } else {
+ die "$r_username / $realm: $error";
+ }
+ }
+
+}
+
+sub usage {
+ die "Usage:\n\n sqlradius.import user\n";
+}
+
diff --git a/bin/sqlradius.reimport b/bin/sqlradius.reimport
new file mode 100755
index 0000000..2218a3f
--- /dev/null
+++ b/bin/sqlradius.reimport
@@ -0,0 +1,160 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use vars qw(%part_svc %domain_part_svc);
+#use Date::Parse;
+use DBI;
+use Term::Query qw(query);
+use FS::UID qw(adminsuidsetup); #datasrc
+use FS::Record qw(qsearch qsearchs);
+use FS::svc_acct;
+use FS::part_svc;
+use FS::svc_domain;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+#push @FS::svc_acct::shells, qw(/bin/sync /sbin/shutdown /bin/halt /sbin/halt); #others?
+
+$FS::svc_Common::noexport_hack = 1;
+$FS::svc_domain::whois_hack = 1;
+
+###
+
+%part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+
+die "No services with svcdb svc_acct!\n" unless %part_svc;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Enter part number to import.
+END
+my $sqlradius_svcpart = &getpart;
+
+%domain_part_svc = map { $_->svcpart, $_ }
+ qsearch('part_svc', { 'svcdb' => 'svc_domain'} );
+
+die "No services with svcdb svc_domain!\n" unless %domain_part_svc;
+
+print "\n\n", &menu_domain_svc, "\n", <<END;
+Enter part number for domains.
+END
+my $domain_svcpart = &getdomainpart;
+
+my $datasrc = &getvalue("\n\nEnter the DBI datasource:");
+my $db_user = &getvalue("\n\nEnter the database user:");
+my $db_pass = &getvalue("\n\nEnter the database password:");
+
+sub menu_svc {
+ ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n";
+}
+sub menu_domain_svc {
+ ( join "\n", map "$_: ".$domain_part_svc{$_}->svc, sort keys %domain_part_svc ). "\n";
+}
+sub getpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_svc ];
+ $^W=1;
+ $return;
+}
+sub getdomainpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %domain_part_svc ];
+ $^W=1;
+ $return;
+}
+sub getvalue {
+ my $prompt = shift;
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query $prompt, '';
+ $^W=1;
+ $return;
+}
+
+print "\n\n";
+
+###
+
+my $dbh = DBI->connect( $datasrc, $db_user, $db_pass )
+ or die $DBI::errstr;
+
+my $sth = $dbh->prepare('SELECT DISTINCT UserName, Realm FROM radcheck')
+ or die $dbh->errstr;
+$sth->execute or die $sth->errstr;
+
+my $row;
+while ( defined ( $row = $sth->fetchrow_arrayref ) ) {
+ my( $r_username, $realm ) = @$row;
+
+ my( $username, $domain );
+ if ( $r_username =~ /^([^@]+)\@([^@]+)$/ ) {
+ $username = $1;
+ $domain = $2;
+ } else {
+ $username = $r_username;
+ $domain = $realm;
+ }
+ my $svc_domain = qsearchs('svc_domain', { 'domain' => $domain } )
+ || new FS::svc_domain {
+ 'domain' => $domain,
+ 'svcpart' => $domain_svcpart,
+ 'action' => 'N',
+ };
+ unless ( $svc_domain->svcnum ) {
+ die "new domain? wtf";
+ my $error = $svc_domain->insert;
+ if ( $error ) {
+ die "can't insert domain $domain: $error\n";
+ }
+ }
+
+ #my( $password, $finger, $group ) = ( '', '', '' );
+ my( $password, $group ) = ( '', '', '' );
+
+ my $rc_sth = $dbh->prepare(
+ 'SELECT Attribute, Value, Name, GroupName'.
+ ' FROM radcheck'.
+ ' WHERE UserName = ? and Realm = ?'
+ ) or die $dbh->errstr;
+ $rc_sth->execute($r_username, $realm) or die $rc_sth->errstr;
+
+ foreach my $rc_row ( @{$rc_sth->fetchall_arrayref} ) {
+ my($attribute, $value, $name, $groupname) = @$rc_row;
+ if ( $attribute =~ /^((Crypt|User)-)?Password$/ ) {
+ $password = $value;
+ #$finger = $name;
+ $group = $groupname;
+ } else {
+ #handle other params!
+ }
+ }
+
+ my @svc_acct = grep { $_->cust_svc->svcpart == $sqlradius_svcpart }
+ qsearch('svc_acct', { 'username' => $username,
+ 'domsvc' => $svc_domain->svcnum, } );
+
+ #print "$r_username / $realm: $password / $finger: ";
+ print "$r_username / $realm: $password: ";
+ if ( scalar(@svc_acct) == 0 ) {
+ print "not found\n";
+ next;
+ } elsif ( scalar(@svc_acct) > 1 ) {
+ print "multiple matches found?!?!\n";
+ next;
+ } else {
+ #print "correcting password and name\n";
+ print "correcting password\n";
+ }
+
+ my $svc_acct = $svc_acct[0];
+ #my $new = new FS::svc_acct { $svc_acct->hash, '_password' => $password, 'finger' => $finger };
+ my $new = new FS::svc_acct { $svc_acct->hash, '_password' => $password };
+ my $error = $new->replace($svc_acct);
+ #my $error = $new->check;
+ die "$r_username / $realm: $error" if $error;
+
+}
+
+sub usage {
+ die "Usage:\n\n sqlradius.reimport user\n";
+}
+
diff --git a/bin/svc_acct.export b/bin/svc_acct.export
new file mode 100755
index 0000000..0bc370f
--- /dev/null
+++ b/bin/svc_acct.export
@@ -0,0 +1,641 @@
+#!/usr/bin/perl -w
+#
+# $Id: svc_acct.export,v 1.36 2002-05-16 14:28:35 ivan Exp $
+#
+# Create and export password, radius and vpopmail password files:
+# passwd, passwd.adjunct, shadow, acp_passwd, acp_userinfo, acp_dialup
+# users/assign, domains/vdomain/vpasswd
+# Also export sendmail and qmail config files.
+
+use strict;
+use vars qw($conf);
+use Fcntl qw(:flock);
+use File::Path;
+use IO::Handle;
+use FS::Conf;
+use Net::SSH qw(ssh);
+use Net::SCP qw(scp);
+use FS::UID qw(adminsuidsetup datasrc dbh);
+use FS::Record qw(qsearch qsearchs fields);
+use FS::svc_acct;
+use FS::svc_domain;
+use FS::svc_forward;
+
+my $ssh='ssh';
+my $rsync='rsync';
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+$conf = new FS::Conf;
+
+my $userpolicy = $conf->config('username_policy')
+ if $conf->exists('username_policy');
+
+my @shellmachines = $conf->config('shellmachines')
+ if $conf->exists('shellmachines');
+
+my @bsdshellmachines = $conf->config('bsdshellmachines')
+ if $conf->exists('bsdshellmachines');
+
+my @nismachines = $conf->config('nismachines')
+ if $conf->exists('nismachines');
+
+my @erpcdmachines = $conf->config('erpcdmachines')
+ if $conf->exists('erpcdmachines');
+
+my @radiusmachines = $conf->config('radiusmachines')
+ if $conf->exists('radiusmachines');
+
+my $textradiusprepend =
+ $conf->exists('textradiusprepend')
+ ? $conf->config('textradiusprepend')
+ : '';
+
+warn "using depriciated textradiusprepend file" if $textradiusprepend;
+
+
+my $radiusprepend =
+ $conf->exists('radiusprepend')
+ ? join("\n", $conf->config('radiusprepend'))
+ : '';
+
+my @vpopmailmachines = $conf->config('vpopmailmachines')
+ if $conf->exists('vpopmailmachines');
+my $vpopmailrestart = '';
+$vpopmailrestart = $conf->config('vpopmailrestart')
+ if $conf->exists('vpopmailrestart');
+
+my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachines[0]) if $vpopmailmachines[0];
+
+my($shellmachine, @qmailmachines);
+if ( $conf->exists('qmailmachines') ) {
+ $shellmachine = $conf->config('shellmachine');
+ @qmailmachines = $conf->config('qmailmachines');
+}
+
+my(@sendmailmachines, $sendmailconfigpath, $sendmailrestart);
+if ( $conf->exists('sendmailmachines') ) {
+ @sendmailmachines = $conf->config('sendmailmachines');
+ $sendmailconfigpath = $conf->config('sendmailconfigpath') || '/etc';
+ $sendmailrestart = $conf->config('sendmailrestart');
+}
+
+my $mydomain = $conf->config('domain') if $conf->exists('domain');
+
+
+
+
+my(@saltset)= ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+require 5.004; #srand(time|$$);
+
+my $spooldir = "/usr/local/etc/freeside/export.". datasrc;
+my $spoollock = "/usr/local/etc/freeside/svc_acct.export.lock.". datasrc;
+
+open(EXPORT,"+>>$spoollock") or die "Can't open $spoollock: $!";
+select(EXPORT); $|=1; select(STDOUT);
+unless ( flock(EXPORT,LOCK_EX|LOCK_NB) ) {
+ seek(EXPORT,0,0);
+ my($pid)=<EXPORT>;
+ chop($pid);
+ #no reason to start lots of blocking processes
+ die "Is another export process running under pid $pid?\n";
+}
+seek(EXPORT,0,0);
+print EXPORT $$,"\n";
+
+my(@svc_domain)=qsearch('svc_domain',{});
+
+( open(MASTER,">$spooldir/master.passwd")
+ and flock(MASTER,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/.master.passwd: $!";
+( open(PASSWD,">$spooldir/passwd")
+ and flock(PASSWD,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/passwd: $!";
+( open(SHADOW,">$spooldir/shadow")
+ and flock(SHADOW,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/shadow: $!";
+( open(ACP_PASSWD,">$spooldir/acp_passwd")
+ and flock(ACP_PASSWD,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/acp_passwd: $!";
+( open(ACP_DIALUP,">$spooldir/acp_dialup")
+ and flock(ACP_DIALUP,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/acp_dialup: $!";
+( open(USERS,">$spooldir/users")
+ and flock(USERS,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/users: $!";
+
+( open(ASSIGN,">$spooldir/assign")
+ and flock(ASSIGN,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/assign: $!";
+( open(RCPTHOSTS,">$spooldir/rcpthosts")
+ and flock(RCPTHOSTS,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/rcpthosts: $!";
+( open(VPOPRCPTHOSTS,">$spooldir/vpoprcpthosts")
+ and flock(VPOPRCPTHOSTS,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/rcpthosts: $!";
+( open(RECIPIENTMAP,">$spooldir/recipientmap")
+ and flock(RECIPIENTMAP,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/recipientmap: $!";
+( open(VIRTUALDOMAINS,">$spooldir/virtualdomains")
+ and flock(VIRTUALDOMAINS,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/virtualdomains: $!";
+( open(VPOPVIRTUALDOMAINS,">$spooldir/vpopvirtualdomains")
+ and flock(VPOPVIRTUALDOMAINS,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/virtualdomains: $!";
+( open(VIRTUSERTABLE,">$spooldir/virtusertable")
+ and flock(VIRTUSERTABLE,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/virtusertable: $!";
+( open(SENDMAIL_CW,">$spooldir/sendmail.cw")
+ and flock(SENDMAIL_CW,LOCK_EX|LOCK_NB)
+) or die "Can't open $spooldir/sendmail.cw: $!";
+
+
+
+chmod 0644, "$spooldir/passwd",
+ "$spooldir/acp_dialup",
+ "$spooldir/assign",
+ "$spooldir/sendmail.cw",
+ "$spooldir/virtusertable",
+ "$spooldir/rcpthosts",
+ "$spooldir/vpoprcpthosts",
+ "$spooldir/recipientmap",
+ "$spooldir/virtualdomains",
+ "$spooldir/vpopvirtualdomains",
+
+;
+chmod 0600, "$spooldir/master.passwd",
+ "$spooldir/acp_passwd",
+ "$spooldir/shadow",
+ "$spooldir/users",
+;
+
+rmtree"$spooldir/domains", 0, 1;
+mkdir "$spooldir/domains", 0700;
+
+setpriority(0,0,10);
+
+print USERS "$radiusprepend\n";
+
+my %usernames; ## this hack helps keep the passwd files sane
+my @sendmail;
+
+my $svc_domain;
+foreach $svc_domain (sort {$a->domain cmp $b->domain} @svc_domain) {
+
+ my($domain)=$svc_domain->domain;
+ print RCPTHOSTS "$domain\n.$domain\n";
+ print VPOPRCPTHOSTS "$domain\n";
+ print SENDMAIL_CW "$domain\n";
+
+ ###
+ # FORMAT OF THE ASSIGN/USERS FILE HERE
+ print ASSIGN join(":",
+ "+" . $domain . "-",
+ $domain,
+ $vpopuid,
+ $vpopgid,
+ $vpopdir . "/domains/" . $domain,
+ "-",
+ "",
+ "",
+ ), "\n" if $vpopmailmachines[0];
+
+ (mkdir "$spooldir/domains/" . $domain, 0700)
+ or die "Can't create $spooldir/domains/" . $domain .": $!";
+
+ ( open(QMAILDEFAULT,">$spooldir/domains/" . $domain . "/.qmail-default")
+ and flock(QMAILDEFAULT,LOCK_EX|LOCK_NB)
+ ) or die "Can't open $spooldir/domains/" . $domain . "/.qmail-default: $!";
+
+ ( open(VPASSWD,">$spooldir/domains/" . $domain . "/vpasswd")
+ and flock(VPASSWD,LOCK_EX|LOCK_NB)
+ ) or die "Can't open $spooldir/domains/" . $domain . "/vpasswd: $!";
+
+ my ($svc_acct);
+
+ if ($svc_domain->getfield('catchall')) {
+ $svc_acct = qsearchs('svc_acct', {'svcnum' => $svc_domain->catchall});
+ die "Cannot find catchall account for domain $domain\n" unless $svc_acct;
+
+ my $username = $svc_acct->username;
+ push @sendmail, "\@$domain\t$username\n";
+ print VIRTUALDOMAINS "$domain:$username-$domain\n",
+ ".$domain:$username-$domain\n",
+ ;
+
+ ###
+ # FORMAT OF THE .QMAIL-DEFAULT FILE HERE
+ print QMAILDEFAULT "| $vpopdir/bin/vdelivermail \"\" " . $svc_acct->email . "\n"
+ if $vpopmailmachines[0];
+
+ }else{
+ ###
+ # FORMAT OF THE .QMAIL-DEFAULT FILE HERE
+ print QMAILDEFAULT "| $vpopdir/bin/vdelivermail \"\" bounce-no-mailbox\n"
+ if $vpopmailmachines[0];
+ }
+
+ print VPOPVIRTUALDOMAINS "$domain:$domain\n";
+
+ foreach $svc_acct (qsearch('svc_acct', {'domsvc' => $svc_domain->svcnum})) {
+ my($password)=$svc_acct->getfield('_password');
+ my($cpassword,$rpassword);
+ #if ( ( length($password) <= 8 )
+ if ( ( length($password) <= 12 )
+ && ( $password ne '*' )
+ && ( $password ne '!!' )
+ && ( $password ne '' )
+ ) {
+ $cpassword=crypt($password,
+ $saltset[int(rand(64))].$saltset[int(rand(64))]
+ );
+ $rpassword=$password;
+ } else {
+ $cpassword=$password;
+ $rpassword='UNIX';
+ }
+
+ my $username;
+
+ if ($mydomain && ($mydomain eq $svc_domain->domain)) {
+ $username=$svc_acct->username;
+ } elsif ($userpolicy =~ /^prepend domsvc$/) {
+ $username=$svc_acct->domsvc . $svc_acct->username;
+ } elsif ($userpolicy =~ /^append domsvc$/) {
+ $username=$svc_acct->username . $svc_acct->domsvc;
+ } elsif ($userpolicy =~ /^append domain$/) {
+ $username=$svc_acct->username . $svc_domain->domain;
+ } elsif ($userpolicy =~ /^append domain$/) {
+ $username=$svc_acct->username . $svc_domain->domain;
+ } elsif ($userpolicy =~ /^append \@domain$/) {
+ $username=$svc_acct->username . '@'. $svc_domain->domain;
+ } else {
+ die "Unknown policy in username_policy\n";
+ }
+
+ if ($svc_acct->dir ne '/dev/null' || $svc_acct->slipip ne '') {
+ if ($usernames{$username}++) {
+ die "Duplicate username detected: $username\n";
+ }
+ }
+
+ if ( $svc_acct->uid =~ /^(\d+)$/ ) {
+
+ die "Non-root user ". $svc_acct->username. " has 0 UID!"
+ if $svc_acct->uid == 0 && $svc_acct->username ne 'root';
+
+ if ( $svc_acct->dir ne "/dev/null") {
+
+ ###
+ # FORMAT OF FreeBSD MASTER PASSWD FILE HERE
+ print MASTER join(":",
+ $username, # User name
+ $cpassword, # Encrypted password
+ $svc_acct->uid, # User ID
+ $svc_acct->gid, # Group ID
+ "", # Login Class
+ "0", # Password Change Time
+ "0", # Password Expiration Time
+ $svc_acct->finger, # Users name
+ $svc_acct->dir, # Users home directory
+ $svc_acct->shell, # shell
+ ), "\n" ;
+
+
+ ###
+ # FORMAT OF THE PASSWD FILE HERE
+ print PASSWD join(":",
+ $username,
+ 'x', # "##". $username,
+ $svc_acct->uid,
+ $svc_acct->gid,
+ $svc_acct->finger,
+ $svc_acct->dir,
+ $svc_acct->shell,
+ ), "\n";
+
+ ###
+ # FORMAT OF THE SHADOW FILE HERE
+ print SHADOW join(":",
+ $username,
+ $cpassword,
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ ), "\n";
+ }
+ }
+
+ ###
+ # FORMAT OF THE VPASSWD FILE HERE
+ print VPASSWD join(":",
+ $svc_acct->username,
+ $cpassword,
+ '1',
+ '0',
+ $svc_acct->username,
+ "$vpopdir/domains/" . $svc_domain->domain ."/" . $svc_acct->username,
+ 'NOQUOTA',
+ ), "\n";
+
+
+ if ( $svc_acct->slipip ne '' ) {
+
+ ###
+ # FORMAT OF THE ACP_* FILES HERE
+ print ACP_PASSWD join(":",
+ $username,
+ $cpassword,
+ "0",
+ "0",
+ "",
+ "",
+ "",
+ ), "\n";
+
+ my($ip)=$svc_acct->slipip;
+
+ unless ( $ip eq '0.0.0.0' || $svc_acct->slipip eq '0e0' ) {
+ print ACP_DIALUP $username, "\t*\t", $svc_acct->slipip, "\n";
+ }
+
+ my %radreply = $svc_acct->radius_reply;
+ my %radcheck = $svc_acct->radius_check;
+
+ my $radcheck = join ", ", map { qq($_ = "$radcheck{$_}") } keys %radcheck;
+ $radcheck .= ", " if $radcheck;
+
+ ###
+ # FORMAT OF THE USERS FILE HERE
+ print USERS
+ $username,
+ qq(\t${textradiusprepend}),
+ $radcheck,
+# qq(Password = "$rpassword"\n\t),
+ join ",\n\t", map { qq($_ = "$radreply{$_}") } keys %radreply;
+
+ #if ( $ip && $ip ne '0e0' ) {
+ # #print USERS qq(,\n\tFramed-Address = "$ip"\n\n);
+ # print USERS qq(,\n\tFramed-IP-Address = "$ip"\n\n);
+ #} else {
+ print USERS qq(\n\n);
+ #}
+
+ }
+
+ ###
+ # vpopmail directory structure creation
+
+ (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username, 0700)
+ or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . ": $!";
+ (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir", 0700)
+ or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir: $!";
+ (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir/cur", 0700)
+ or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir/cur: $!";
+ (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir/new", 0700)
+ or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir/new: $!";
+ (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir/tmp", 0700)
+ or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir/tmp: $!";
+
+ ( open(DOTQMAIL,">$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/.qmail")
+ and flock(DOTQMAIL,LOCK_EX|LOCK_NB)
+ ) or die "Can't open $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/.qmail: $!";
+
+ my($svc_forward);
+ foreach $svc_forward (qsearch('svc_forward', {'srcsvc' => $svc_acct->svcnum})) {
+ my($destination);
+ if ($svc_forward->dstsvc) {
+ my $dst_acct = qsearchs('svc_acct', {'svcnum' => $svc_forward->dstsvc});
+ my $dst_domain = qsearchs('svc_domain', {'svcnum' => $dst_acct->domsvc});
+ $destination = $dst_acct->username . '@' . $dst_domain->domain;
+
+ if ($dst_domain->domain eq $mydomain) {
+ print VIRTUSERTABLE $svc_acct->username . "@" . $svc_domain->domain .
+ "\t" . $dst_acct->username . "\n";
+ print RECIPIENTMAP $svc_acct->username . "@" . $svc_domain->domain .
+ ":$destination\n";
+ }
+ } else {
+ $destination = $svc_forward->dst;
+ }
+
+ ###
+ # FORMAT OF .QMAIL FILES HERE
+ print DOTQMAIL "$destination\n";
+ }
+
+ flock(DOTQMAIL,LOCK_UN);
+ close DOTQMAIL;
+
+ }
+
+ flock(VPASSWD,LOCK_UN);
+ flock(QMAILDEFAULT,LOCK_UN);
+ close VPASSWD;
+ close QMAILDEFAULT;
+
+}
+
+###
+# FORMAT OF THE ASSIGN/USERS FILE FINAL LINE HERE
+print ASSIGN ".\n";
+
+print VIRTUSERTABLE @sendmail;
+
+flock(MASTER,LOCK_UN);
+flock(PASSWD,LOCK_UN);
+flock(SHADOW,LOCK_UN);
+flock(ACP_DIALUP,LOCK_UN);
+flock(ACP_PASSWD,LOCK_UN);
+flock(USERS,LOCK_UN);
+flock(ASSIGN,LOCK_UN);
+flock(SENDMAIL_CW,LOCK_UN);
+flock(VIRTUSERTABLE,LOCK_UN);
+flock(RCPTHOSTS,LOCK_UN);
+flock(VPOPRCPTHOSTS,LOCK_UN);
+flock(RECIPIENTMAP,LOCK_UN);
+flock(VPOPVIRTUALDOMAINS,LOCK_UN);
+
+close MASTER;
+close PASSWD;
+close SHADOW;
+close ACP_DIALUP;
+close ACP_PASSWD;
+close USERS;
+close ASSIGN;
+close SENDMAIL_CW;
+close VIRTUSERTABLE;
+close RCPTHOSTS;
+close VPOPRCPTHOSTS;
+close RECIPIENTMAP;
+close VPOPVIRTUALDOMAINS;
+
+###
+# export stuff
+#
+
+my($ashellmachine);
+foreach $ashellmachine (@shellmachines) {
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/passwd","root\@$ashellmachine:/etc/passwd.new")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/shadow","root\@$ashellmachine:/etc/shadow.new")
+ or die "scp error: ". $scp->{errstr};
+ ssh("root\@$ashellmachine",
+ "( ".
+ "mv /etc/passwd.new /etc/passwd; ".
+ "mv /etc/shadow.new /etc/shadow; ".
+ " )"
+ )
+ == 0 or die "ssh error: $!";
+}
+
+my($bsdshellmachine);
+foreach $bsdshellmachine (@bsdshellmachines) {
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/passwd","root\@$bsdshellmachine:/etc/passwd.new")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/master.passwd","root\@$bsdshellmachine:/etc/master.passwd.new")
+ or die "scp error: ". $scp->{errstr};
+ ssh("root\@$bsdshellmachine",
+ "( ".
+ "mv /etc/passwd.new /etc/passwd; ".
+ #"mv /etc/master.passwd.new /etc/master.passwd; ".
+ "pwd_mkdb /etc/master.passwd.new; ".
+ " )"
+ )
+ == 0 or die "ssh error: $!";
+}
+
+my($nismachine);
+foreach $nismachine (@nismachines) {
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/passwd","root\@$nismachine:/etc/global/passwd")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/shadow","root\@$nismachine:/etc/global/shadow")
+ or die "scp error: ". $scp->{errstr};
+ ssh("root\@$nismachine",
+ "( ".
+ "cd /var/yp; make; ".
+ " )"
+ )
+ == 0 or die "ssh error: $!";
+}
+
+my($erpcdmachine);
+foreach $erpcdmachine (@erpcdmachines) {
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/acp_passwd","root\@$erpcdmachine:/usr/annex/acp_passwd")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/acp_dialup","root\@$erpcdmachine:/usr/annex/acp_dialup")
+ or die "scp error: ". $scp->{errstr};
+ ssh("root\@$erpcdmachine",
+ "( ".
+ "kill -USR1 \`cat /usr/annex/erpcd.pid\'".
+ " )"
+ )
+ == 0 or die "ssh error: $!";
+}
+
+my($radiusmachine);
+foreach $radiusmachine (@radiusmachines) {
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/users","root\@$radiusmachine:/etc/raddb/users")
+ or die "scp error: ". $scp->{errstr};
+ ssh("root\@$radiusmachine",
+ "( ".
+ "builddbm".
+ " )"
+ )
+ == 0 or die "ssh error: $!";
+}
+
+#my @args = ("/bin/tar", "c", "--force-local", "-C", "$spooldir", "-f", "$spooldir/vpoptarball", "domains");
+
+#system {$args[0]} @args;
+
+my($vpopmailmachine);
+foreach $vpopmailmachine (@vpopmailmachines) {
+ my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachine);
+ my $scp = new Net::SCP;
+# $scp->scp("$spooldir/vpoptarball","root\@$machine:vpoptarball")
+# or die "scp error: ". $scp->{errstr};
+# ssh("root\@$machine",
+# "( ".
+# "rm -rf domains; ".
+# "tar xf vpoptarball; ".
+# "chown -R $vpopuid:$vpopgid domains; ".
+# "tar cf vpoptarball domains; ".
+# "cd $vpopdir; ".
+# "tar xf ~/vpoptarball; ".
+# " )"
+# )
+# == 0 or die "ssh error: $!";
+
+ chdir $spooldir;
+ my @args = ("$rsync", "-rlpt", "-e", "$ssh", "domains/", "vpopmail\@$machine:$vpopdir/domains/");
+
+ system {$args[0]} @args;
+
+ $scp->scp("$spooldir/assign","root\@$machine:/var/qmail/users/assign")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/vpopvirtualdomains","root\@$machine:/var/qmail/control/virtualdomains")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/vpoprcpthosts","root\@$machine:/var/qmail/control/rcpthosts")
+ or die "scp error: ". $scp->{errstr};
+
+ ssh("root\@$machine",
+ "( ".
+ $vpopmailrestart .
+ " )"
+ )
+ == 0 or die "ssh error: $!";
+
+
+}
+
+my($sendmailmachine);
+foreach $sendmailmachine (@sendmailmachines) {
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/sendmail.cw","root\@$sendmailmachine:$sendmailconfigpath/sendmail.cw.new")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/virtusertable","root\@$sendmailmachine:$sendmailconfigpath/virtusertable.new")
+ or die "scp error: ". $scp->{errstr};
+ ssh("root\@$sendmailmachine",
+ "( ".
+ "mv $sendmailconfigpath/sendmail.cw.new $sendmailconfigpath/sendmail.cw; ".
+ "mv $sendmailconfigpath/virtusertable.new $sendmailconfigpath/virtusertable; ".
+ $sendmailrestart.
+ " )"
+ )
+ == 0 or die "ssh error: $!";
+}
+
+my($qmailmachine);
+foreach $qmailmachine (@qmailmachines) {
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/recipientmap","root\@$qmailmachine:/var/qmail/control/recipientmap")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/virtualdomains","root\@$qmailmachine:/var/qmail/control/virtualdomains")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/rcpthosts","root\@$qmailmachine:/var/qmail/control/rcpthosts")
+ or die "scp error: ". $scp->{errstr};
+ #ssh("root\@$qmailmachine","/etc/init.d/qmail restart")
+ # == 0 or die "ssh error: $!";
+}
+
+unlink $spoollock;
+flock(EXPORT,LOCK_UN);
+close EXPORT;
+
+#
+
+sub usage {
+ die "Usage:\n\n svc_acct.export user\n";
+}
+
diff --git a/bin/svc_acct.import b/bin/svc_acct.import
new file mode 100755
index 0000000..eb94e1c
--- /dev/null
+++ b/bin/svc_acct.import
@@ -0,0 +1,238 @@
+#!/usr/bin/perl -Tw
+# $Id: svc_acct.import,v 1.17 2001-08-19 10:25:44 ivan Exp $
+
+use strict;
+use vars qw(%part_svc);
+use Date::Parse;
+use Term::Query qw(query);
+use Net::SCP qw(iscp);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch);
+use FS::svc_acct;
+use FS::part_svc;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+push @FS::svc_acct::shells, qw(/bin/sync /sbin/shuddown /bin/halt); #others?
+
+my($spooldir)="/usr/local/etc/freeside/export.". datasrc;
+
+$FS::svc_acct::nossh_hack = 1;
+
+###
+
+%part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+
+die "No services with svcdb svc_acct!\n" unless %part_svc;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Most accounts probably have entries in passwd and users (with Port-Limit
+nonexistant or 1).
+END
+my($ppp_svcpart)=&getpart;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Some accounts have entries in passwd and users, but with Port-Limit 2 (or
+more).
+END
+my($isdn_svcpart)=&getpart;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Some accounts might have entries in users only (Port-Limit 1)
+END
+my($oppp_svcpart)=&getpart;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Some accounts might have entries in users only (Port-Limit >= 2)
+END
+my($oisdn_svcpart)=&getpart;
+
+print "\n\n", &menu_svc, "\n", <<END;
+POP mail accounts have entries in passwd only, and have a particular shell.
+END
+my($pop_shell)=&getvalue("Enter that shell:");
+my($popmail_svcpart)=&getpart;
+
+print "\n\n", &menu_svc, "\n", <<END;
+Everything else in passwd is a shell account.
+END
+my($shell_svcpart)=&getpart;
+
+print "\n\n", <<END;
+Enter the location and name of your _user_ passwd file, for example
+"mail.isp.com:/etc/passwd" or "nis.isp.com:/etc/global/passwd"
+END
+my($loc_passwd)=&getvalue(":");
+iscp("root\@$loc_passwd", "$spooldir/passwd.import");
+
+print "\n\n", <<END;
+Enter the location and name of your _user_ shadow file, for example
+"mail.isp.com:/etc/shadow" or "bsd.isp.com:/etc/master.passwd"
+END
+my($loc_shadow)=&getvalue(":");
+iscp("root\@$loc_shadow", "$spooldir/shadow.import");
+
+print "\n\n", <<END;
+Enter the location and name of your radius "users" file, for example
+"radius.isp.com:/etc/raddb/users"
+END
+my($loc_users)=&getvalue(":");
+iscp("root\@$loc_users", "$spooldir/users.import");
+
+sub menu_svc {
+ ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n";
+}
+sub getpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_svc ];
+ $^W=1;
+ $return;
+}
+sub getvalue {
+ my $prompt = shift;
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query $prompt, '';
+ $^W=1;
+ $return;
+}
+
+print "\n\n";
+
+###
+
+open(PASSWD,"<$spooldir/passwd.import");
+open(SHADOW,"<$spooldir/shadow.import");
+open(USERS,"<$spooldir/users.import");
+
+my(%upassword,%ip,%allparam);
+my(%param,$username);
+while (<USERS>) {
+ chop;
+ next if /^\s*$/;
+ next if /^\s*#/;
+ if ( /^\S/ ) {
+ /^(\w+)\s+(Auth-Type\s+=\s+Local,\s+)?Password\s+=\s+"([^"]+)"(,\s+Expiration\s+=\s+"([^"]*")\s*)?$/
+ or die "1Unexpected line in users.import: $_";
+ my($password,$expiration);
+ ($username,$password,$expiration)=(lc($1),$3,$5);
+ $password = '' if $password eq 'UNIX';
+ $upassword{$username}=$password;
+ undef %param;
+ } else {
+ die "2Unexpected line in users.import: $_";
+ }
+ while (<USERS>) {
+ chop;
+ if ( /^\s*$/ ) {
+ if ( defined $param{'radius_Framed_IP_Address'} ) {
+ $ip{$username} = $param{'radius_Framed_IP_Address'};
+ delete $param{'radius_Framed_IP_Address'};
+ } else {
+ $ip{$username} = '0e0';
+ }
+ $allparam{$username}={ %param };
+ last;
+ } elsif ( /^\s+([\w\-]+)\s=\s"?([\w\.\-\s]+)"?,?\s*$/ ) {
+ my($attribute,$value)=($1,$2);
+ $attribute =~ s/\-/_/g;
+ $param{'radius_'.$attribute}=$value;
+ } else {
+ die "3Unexpected line in users.import: $_";
+ }
+ }
+}
+#? incase there isn't a terminating blank line ?
+if ( defined $param{'radius_Framed_IP_Address'} ) {
+ $ip{$username} = $param{'radius_Framed_IP_Address'};
+ delete $param{'radius_Framed_IP_Address'};
+} else {
+ $ip{$username} = '0e0';
+}
+$allparam{$username}={ %param };
+
+my(%password);
+while (<SHADOW>) {
+ chop;
+ my($username,$password)=split(/:/);
+ #$password =~ s/^\!$/\*/;
+ #$password =~ s/\!+/\*SUSPENDED\* /;
+ $password{$username}=$password;
+}
+
+while (<PASSWD>) {
+ chop;
+ my($username,$x,$uid,$gid,$finger,$dir,$shell)=split(/:/);
+ my($password)=$upassword{$username} || $password{$username};
+
+ my($maxb)=${$allparam{$username}}{'radius_Port_Limit'};
+ my($svcpart);
+ if ( exists $upassword{$username} ) {
+ if ( $maxb >= 2 ) {
+ $svcpart = $isdn_svcpart
+ } elsif ( ! $maxb || $maxb == 1 ) {
+ $svcpart = $ppp_svcpart
+ } else {
+ die "Illegal Port-Limit in users ($username)!\n";
+ }
+ } elsif ( $shell eq $pop_shell ) {
+ $svcpart = $popmail_svcpart;
+ } else {
+ $svcpart = $shell_svcpart;
+ }
+
+ my($svc_acct) = new FS::svc_acct ({
+ 'svcpart' => $svcpart,
+ 'username' => $username,
+ '_password' => $password,
+ 'uid' => $uid,
+ 'gid' => $gid,
+ 'finger' => $finger,
+ 'dir' => $dir,
+ 'shell' => $shell,
+ 'slipip' => $ip{$username},
+ %{$allparam{$username}},
+ });
+ my($error);
+ $error=$svc_acct->insert;
+ die $error if $error;
+
+ delete $allparam{$username};
+ delete $upassword{$username};
+}
+
+#my($username);
+foreach $username ( keys %upassword ) {
+ my($password)=$upassword{$username};
+
+ my($maxb)=${$allparam{$username}}{'radius_Port_Limit'} || 0;
+ my($svcpart);
+ if ( $maxb == 2 ) {
+ $svcpart = $oisdn_svcpart
+ } elsif ( ! $maxb || $maxb == 1 ) {
+ $svcpart = $oppp_svcpart
+ } else {
+ die "Illegal Port-Limit in users!\n";
+ }
+
+ my($svc_acct) = new FS::svc_acct ({
+ 'svcpart' => $svcpart,
+ 'username' => $username,
+ '_password' => $password,
+ 'slipip' => $ip{$username},
+ %{$allparam{$username}},
+ });
+ my($error);
+ $error=$svc_acct->insert;
+ die $error, if $error;
+
+ delete $allparam{$username};
+ delete $upassword{$username};
+}
+
+#
+
+sub usage {
+ die "Usage:\n\n svc_acct.import user\n";
+}
+
diff --git a/bin/svc_domain.erase b/bin/svc_domain.erase
new file mode 100755
index 0000000..c023661
--- /dev/null
+++ b/bin/svc_domain.erase
@@ -0,0 +1,17 @@
+#!/usr/bin/perl -w
+#
+# $Id: svc_domain.erase,v 1.1 2002-04-20 11:57:35 ivan Exp $
+
+use strict;
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw(qsearch);
+
+use FS::domain_record;
+use FS::svc_domain;
+
+adminsuidsetup(shift @ARGV) or die "Usage: svc_domain.erase user\n";
+
+foreach my $record ( qsearch('domain_record',{}), qsearch('svc_domain', {} ) ) {
+ my $error = $record->delete;
+ die $error if $error;
+}
diff --git a/bin/sysvshell.export b/bin/sysvshell.export
new file mode 100755
index 0000000..c13912c
--- /dev/null
+++ b/bin/sysvshell.export
@@ -0,0 +1,112 @@
+#!/usr/bin/perl -w
+
+# sysvshell export
+
+use strict;
+use File::Rsync;
+use Net::SSH qw(ssh);
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(qsearch qsearchs);
+use FS::part_export;
+use FS::cust_svc;
+use FS::svc_acct;
+
+my @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+my $spooldir = "/usr/local/etc/freeside/export.". datasrc;
+#my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/shell";
+
+my @sysv_exports = qsearch('part_export', { 'exporttype' => 'sysvshell' } );
+
+my $rsync = File::Rsync->new({
+ rsh => 'ssh',
+# dry_run => 1,
+});
+
+foreach my $export ( @sysv_exports ) {
+ my $machine = $export->machine;
+ my $prefix = "$spooldir/$machine";
+ mkdir $prefix, 0700 unless -d $prefix;
+
+ #LOCKING!!!
+
+ ( open(SHADOW,">$prefix/shadow")
+ #!!! and flock(SHADOW,LOCK_EX|LOCK_NB)
+ ) or die "Can't open $prefix/shadow: $!";
+ ( open(PASSWD,">$prefix/passwd")
+ #!!! and flock(PASSWD,LOCK_EX|LOCK_NB)
+ ) or die "Can't open $prefix/passwd: $!";
+
+ chmod 0644, "$prefix/passwd";
+ chmod 0600, "$prefix/shadow";
+
+ my @svc_acct = $export->svc_x;
+
+ next unless @svc_acct;
+
+ foreach my $svc_acct ( sort { $a->uid <=> $b->uid } @svc_acct ) {
+
+ my $password = $svc_acct->_password;
+ my $cpassword;
+ #if ( ( length($password) <= 8 )
+ if ( ( length($password) <= 12 )
+ && ( $password ne '*' )
+ && ( $password ne '!!' )
+ && ( $password ne '' )
+ ) {
+ $cpassword=crypt($password,
+ $saltset[int(rand(64))].$saltset[int(rand(64))]
+ );
+ # MD5 !!!!
+ } else {
+ $cpassword=$password;
+ }
+
+ ###
+ # FORMAT OF THE PASSWD FILE HERE
+ print PASSWD join(":",
+ $svc_acct->username,
+ 'x', # "##". $username,
+ $svc_acct->uid,
+ $svc_acct->gid,
+ $svc_acct->finger,
+ $svc_acct->dir,
+ $svc_acct->shell,
+ ), "\n";
+
+ ###
+ # FORMAT OF THE SHADOW FILE HERE
+ print SHADOW join(":",
+ $svc_acct->username,
+ $cpassword,
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ ), "\n";
+
+ }
+
+ #!!! flock(SHADOW,LOCK_UN);
+ #!!! flock(PASSWD,LOCK_UN);
+ close SHADOW;
+ close PASSWD;
+
+ $rsync->exec( {
+ src => "$prefix/shadow",
+ dest => "root\@$machine:/etc/shadow"
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+
+ $rsync->exec( {
+ src => "$prefix/passwd",
+ dest => "root\@$machine:/etc/passwd"
+ } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err);
+
+ # UNLOCK!!
+}
diff --git a/conf/agent_defaultpkg b/conf/agent_defaultpkg
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/conf/agent_defaultpkg
diff --git a/conf/alerter_template b/conf/alerter_template
new file mode 100644
index 0000000..4d8a012
--- /dev/null
+++ b/conf/alerter_template
@@ -0,0 +1,20 @@
+
+
+Ivan Kohler
+1339 Hayes St.
+San Francisco, CA 94117
+
+
+{ $first; } { $last; }:
+
+ We thank you for your continuing patronage. This notice is to remind you
+that your { $payby } used to pay SISD.COM for Internet
+service will expire on { use Date::Format; time2str("%x", $expdate); }. Please provide us with new billing
+information so that we may continue your service uninterrupted.
+
+Very Truly Yours,
+
+ SISD Service Team
+
+
+
diff --git a/conf/declinetemplate b/conf/declinetemplate
new file mode 100644
index 0000000..14b8c60
--- /dev/null
+++ b/conf/declinetemplate
@@ -0,0 +1,10 @@
+Hi,
+
+Your credit card could not be processed for the following reason:
+ { $error }
+
+Please provide us with new billing information so that we may continue your
+service uninterrupted.
+
+Thanks.
+
diff --git a/conf/home b/conf/home
new file mode 100644
index 0000000..05280cb
--- /dev/null
+++ b/conf/home
@@ -0,0 +1 @@
+/home
diff --git a/conf/invoice_from b/conf/invoice_from
new file mode 100644
index 0000000..110ec8f
--- /dev/null
+++ b/conf/invoice_from
@@ -0,0 +1 @@
+ivan-unconfigured-freeside-installation@420.am
diff --git a/conf/invoice_latex b/conf/invoice_latex
new file mode 100644
index 0000000..195f8fb
--- /dev/null
+++ b/conf/invoice_latex
@@ -0,0 +1,155 @@
+%% file: Standard Multipage.tex
+%% Purpose: Multipage bill template for e-Bills
+%%
+%% Created by Mark Asplen-Taylor
+%% Asplen Management Ltd
+%% www.asplen.co.uk
+%%
+%% Modified for Freeside by Ivan Kohler
+%%
+%% Changes
+%% 0.1 4/12/00 Created
+%% 0.2 18/10/01 More fields added
+%% 1.0 16/11/01 RELEASED
+%% 1.2 16/10/02 Invoice number added
+%% 1.3 2/12/02 Logo graphic added
+%% 1.4 7/2/03 Multipage headers/footers added
+%% n/a 10/12/03 forked for Freeside; checked into CVS
+%%
+
+\documentclass[letterpaper]{article}
+
+\usepackage{fancyhdr,lastpage,ifthen,longtable,afterpage}
+\usepackage{graphicx} % required for logo graphic
+
+\addtolength{\voffset}{-0.0in} % top margin to top of header
+\addtolength{\hoffset}{-0.60in} %left margin on page
+\addtolength{\topmargin}{-0.6in} % top margin to top of header
+\setlength{\headheight}{1in} % height of header
+\setlength{\headsep}{0.5in} % between header and text
+\addtolength{\textheight}{-0.4in} % height of main text
+
+\addtolength{\textheight}{-0.5in} % height of main text
+\setlength{\footskip}{0.5in} % bottom of footer from bottom of text
+
+\addtolength{\textwidth}{2.1in} % width of text
+\setlength{\oddsidemargin}{0in} % odd page left margin
+\setlength{\evensidemargin}{0in} % even page left margin
+
+\renewcommand{\headrulewidth}{0pt}
+\renewcommand{\footrulewidth}{1pt}
+
+ % New command for address lines i.e. skip them if blank
+
+\newcommand{\addressline}[1]{\ifthenelse{\equal{#1}{}}{}{#1\newline}}
+\newcommand{\dollar}[1][]{\symbol{36}} % Inserts dollar symbol
+
+\pagestyle{fancy}
+
+%% Font options are:
+%% bch Bitsream Charter
+%% put Utopia
+%% phv Adobe Helvetica
+%% pnc New Century Schoolbook
+%% ptm Times
+%% pcr Courier
+
+\renewcommand{\familydefault}{phv}
+
+\begin{document}
+%
+%% Headers and footers defined for the first page
+\fancyfoot[CO,CE]{\small{
+\begin{tabular}{c}
+$footer
+\end{tabular}}}
+%
+%% The LH Heading comprising logo
+%% UNCOMMENT the following FOUR lines and change the path if necssary to provide a logo
+\fancyhead[LO,LE]{
+\begin{tabular}{l}
+\includegraphics{/usr/local/etc/freeside/conf.DBI:Pg:dbname=freeside/logo.eps}
+\end{tabular}}
+%
+%% The Heading comprising isue date, customer ref & INVOICE name
+\fancyhead[RO,RE]{
+\begin{tabular}{rcl}
+Invoice date & & Invoice number \\
+\vspace{0.2cm}
+\textbf{$date} & & \textbf{$invnum} \\\hline
+\rule{0pt}{5ex} &~~ \huge{\textsc{Invoice}}& \\
+\vspace{-0.2cm}
+ & & \\\hline
+\end{tabular}}
+%
+%% Header & footer changes for subsequent pages
+%
+\afterpage{ \fancyfoot[RO,RE]{\small{\thepage\ of \pageref{LastPage}}} }
+\afterpage{ \fancyfoot[CO,CE]{\small{$smallfooter}} }
+\afterpage{ \fancyhead[LO,LE]{\small{}} }
+\afterpage{ \fancyhead[RO,RE]{\small{
+\begin{tabular}{ll}
+Invoice date & Invoice number\\
+\textbf{$date} & \textbf{$invnum}\\
+\end{tabular}}} }
+%
+%
+\makebox{
+\begin{minipage}[t]{2.9in}
+\vspace{0.20in}
+\textbf{$payname}\\
+\addressline{$company}
+\addressline{$address1}
+\addressline{$address2}
+\addressline{$city, $state $zip}
+\addressline{$country}
+\end{minipage}}
+\hfill
+\makebox{
+\begin{minipage}[t]{2.5in}
+\begin{flushright}
+Terms: $terms\\
+$po_line\\
+\end{flushright}
+\end{minipage}}
+\vspace{0.5cm}
+%
+\section*{\textsc{Charges}}
+\begin{longtable}{|c|l|c|r|r|}
+\hline
+\rule{0pt}{2.5ex}
+\makebox[1.4cm]{\textbf{Ref}} &
+\makebox[7.9cm][l]{\textbf{Description}} &
+\makebox[1.3cm][c]{\textbf{Quantity}} &
+\makebox[2.5cm][r]{\textbf{Unit Price}} &
+\makebox[2.5cm][r]{\textbf{Amount}} \\
+\hline
+\endfirsthead
+\multicolumn{5}{r}{\rule{0pt}{2.5ex}Continued from previous page}\\
+\hline
+\rule{0pt}{2.5ex}
+\makebox[1.4cm]{\textbf{Ref}} &
+\makebox[7.9cm][l]{\textbf{Description}} &
+\makebox[1.3cm][c]{\textbf{Quantity}} &
+\makebox[2.5cm][r]{\textbf{Unit Price}} &
+\makebox[2.5cm][r]{\textbf{Amount}} \\
+\hline
+\endhead
+\multicolumn{5}{r}{\rule{0pt}{2.5ex}/cont...}\\
+\endfoot
+%%TotalDetails
+ & \multicolumn{3}{l}{$total_item} & $total_amount\\
+%%EndTotalDetails
+\hline
+\endlastfoot
+%%Detail
+\rule{0pt}{2.5ex}$ref &
+\begin{tabular}{l}
+$description\tabularnewline
+\end{tabular}
+& $quantity & \dollar $amount & \dollar $amount\\\hline
+%%EndDetail
+\end{longtable}
+\vfill
+$notes
+\end{document}
diff --git a/conf/invoice_latexfooter b/conf/invoice_latexfooter
new file mode 100644
index 0000000..110b1e6
--- /dev/null
+++ b/conf/invoice_latexfooter
@@ -0,0 +1,5 @@
+Ivan Kohler\\
+P.O. Box 1272\\
+Carnelian Bay, CA~~96140\\
+ivan@sisd.com~~~~+1 415 462 1624\\
+Freeside - open-source billing - http://www.sisd.com/freeside\\
diff --git a/conf/invoice_latexnotes b/conf/invoice_latexnotes
new file mode 100644
index 0000000..29e1731
--- /dev/null
+++ b/conf/invoice_latexnotes
@@ -0,0 +1,9 @@
+%%
+%% Add any customer specific notes in here
+%%
+\section*{\textsc{Notes}}
+\begin{enumerate}
+\item PLEASE NOTE NEW ADDRESS BELOW!
+\item Please make your check payable to \textbf{Ivan Kohler}.
+\item If you have any questions please email or telephone.
+\end{enumerate}
diff --git a/conf/invoice_latexsmallfooter b/conf/invoice_latexsmallfooter
new file mode 100644
index 0000000..527c356
--- /dev/null
+++ b/conf/invoice_latexsmallfooter
@@ -0,0 +1 @@
+Ivan Kohler~~~Freeside - open-source billing
diff --git a/conf/invoice_template b/conf/invoice_template
new file mode 100644
index 0000000..e226d63
--- /dev/null
+++ b/conf/invoice_template
@@ -0,0 +1,27 @@
+
+ Invoice
+ { substr("Page $page of $total_pages ", 0, 19); } { use Date::Format; time2str("%x", $date); } FS-{ $invnum; }
+
+
+Ivan Kohler
+1339 Hayes St.
+San Francisco, CA 94117
+
+
+{ $address[0]; }
+{ $address[1]; }
+{ $address[2]; }
+{ $address[3]; }
+{ $address[4]; }
+{ $address[5]; }
+
+{
+ join("\n",
+ map {
+ my ( $desc, $price ) = @{$_};
+ " ". substr( $desc. " "x65, 0, 65). " ". substr( $price. " "x11, 0, 11);
+ } invoice_lines(31)
+ );
+}
+
+ -=> Freeside - open-source billing for ISPs - http://www.sisd.com/freeside <=-
diff --git a/conf/locale b/conf/locale
new file mode 100644
index 0000000..7741b83
--- /dev/null
+++ b/conf/locale
@@ -0,0 +1 @@
+en_US
diff --git a/conf/logo.eps b/conf/logo.eps
new file mode 100644
index 0000000..8eb14e8
--- /dev/null
+++ b/conf/logo.eps
@@ -0,0 +1,1267 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: GIMP PostScript file plugin V 1.15 by Peter Kirchgessner
+%%Title: /home/ivan/freeside/httemplate/images/mid-logo2.eps
+%%CreationDate: Sun Oct 12 23:47:59 2003
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%Pages: 1
+%%BoundingBox: 14 14 140 157
+%%EndComments
+%%BeginPreview: 255 256 1 256
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000e04000000000000000000000000000000000000000
+% 0000000000000000000000c0e000000000000000000000000000000000000000
+% 0000000000000000000060604000000000000000000000000000000000000000
+% 0000000000000000000070e00000000000000000000000000000000000000000
+% 0000000000000000000020600008000000000000000000000000000000000000
+% 000000000000000000000060c03e03c000000000000000000000000000000000
+% 000000000000000000000060e07f07e040000000000000000000000000000000
+% 000000000000000000003060606306707e000000000000000000000000000000
+% 000000000000000000007830606306307f000006000000000000000000000000
+% 000000000000000000f8183060600c7063000002000000000000000000000000
+% 000000000000000001dc183060600e3063000000000000000000000000000000
+% 0000000000000000018c183070600c7063000050000000000000000000000000
+% 0000000000000000018c1c3060600c30c3000018000000000000000000000000
+% 000000000000000001800c1830600c60e700001c000000000000000000000000
+% 000000000000000001800c3830600c60c3000018000040000000000000000000
+% 000000000000000001c00c1870600c60c6000058300030000000000000000000
+% 000000000000000000c10e1830600c61c6000070340070000000000000000000
+% 000000000000000000ef0c1830600c61860000703f0060000000000000000000
+% 00000000000000000075061c30601c618e0000e06381f0000000000000000000
+% 00000000000000000043861830638c618c0001e06301f0000000000000000000
+% 00000000000000000001870c30631c618c000180c30380000000000000000000
+% 00000000000000000001820c30770ce38c000180c70300000000000000000000
+% 00000000000000000001c30c303e0fc30c000301860600000000000000000000
+% 00000000000000000000c30c1c1c0f831c0003038e0e00000000000000000000
+% 00000000000000000038c39e60000007180007030c0c00000000000000000000
+% 00000000000000000019c340000000011c0006031c1c0d000000000000000000
+% 0000000000000000001f8400000000000400060618181f000000000000000000
+% 0000000000000000000000000000000000000c0e307071c00000000000000000
+% 0000000000000000000000000000000000002c1c306061800000000000000000
+% 0000000000000000000000000000000000001c1860e0e3800000000000000000
+% 000000000000000000000000000000000000025860c1c3060000000000000000
+% 00000000000000000000000000000000000000f8c1c387020000000000000000
+% 0000000000000000000000000000000000000011c383ee07c000000000000000
+% 000000000000000000000000000000000000000183077c0fc000000000000000
+% 0000000000000000000000000000000000000001870e781ce000000000000000
+% 000000000000000000000000000000000000000006180070c000000000000000
+% 000000000000000000000000000000000000000007380060c000000000000000
+% 0000000000000000000000000000000000000000023000c0c000000000000000
+% 0000000000000000000000000000000000000000003101c00700000000000000
+% 0000000000000000000000000000000000000000003b83800fc0000000000000
+% 0000000000000000000000000008200000000000003f07001dc0000000000000
+% 0000000000000000000000017fffffd000000000000e0e0008c0000000000000
+% 00000000000000000000003fd5b5aabf4000000000001c0000c0000000000000
+% 0000000000000000000005eabf6f7feaf40000000000380041c0000000000000
+% 00000000000000000001ff5feadad55fafe0000000006003ff00000000000000
+% 0000000000000000000f55f55fbfbff57aba00000000200f1e00000000000000
+% 00000000000000000035ff5ff56aeaafd7ee80000000000e1c01800000000000
+% 000000000000000000ef55f55fdfbffabd5ba0000000003c380be00000000000
+% 000000000000000003baff5ff5756aafebf6e00000000038701f600000000000
+% 00000000000000000eefaaf55fdfdffabeadbc0000000070e03c700000000000
+% 00000000000000003bbaffaf40257557ebfbee0000000061c070300c00000000
+% 0000000000000000eeefaad00000affd5eaebba00000007381e0601c00000000
+% 0000000000000001bbbafd0000001aabf5fbeee00000003f0380e03c00000000
+% 00000000000000076eef4000000003feaf56bbbc0000000c0e0001f000000000
+% 0000000000000006dbba0000000000abfafdeeeb000000043c00079800000000
+% 0000000000000007b6e80000000000feafab5bbe8000000470000f1000000000
+% 00000000000000057d80000000000055fafef6eb8000000060003c0000000000
+% 00000000000001c3d74000000000007f57abadbee0000000e000780000000000
+% 0000000000000176bd00000000000055fd7efb6bb0000000c200e00380000000
+% 00000000000001ddea0000000000007f57d5aefee80000007e03c02380000000
+% 00000000000061775000000000000055fd7f7babbc0000003e1f803000000000
+% 000000000000bbdde00000000000007f57d5d6feea000000203e007000000000
+% 0000000000036d7600000000000001d5fd7f7dabbf80000001e007c000000000
+% 000000000005dbdc000000000000077f57d5d77eea80000001c00f0000000000
+% 00000000000f76b00000000000501ad5fd7f7dd5bfe0000003003c0200000000
+% 000000000015dde0000000017ffff7bf57d5d77f6ab000000300f80200000000
+% 00000000003f774000000017d5555d6afd7f7dd5dfe800000301e00700000000
+% 000000000055dd000000007d7ffff7dfabd5d77f75580000000f801e00000000
+% 00000000007f7400000001d7d5555d757ebf7dd5dff4000000be007800000000
+% 0000000000d5d8000000077d7ffff7dfd5ead77f755e000000fc00f000000000
+% 0000000001bf400000000dd7d5555d757f5fbdd5dff50000006003c1c0000000
+% 00000000036800000000377d7ffff7dfd5f56b7f755f800000201e3f20000000
+% 0000000006d0000060005dd7d5555d757f5fded5dff5400000003bf800000000
+% 0000000005000001c000777d7ffff7dfd5f575bf755fc0000000ffc000000000
+% 0000000000000002a000add7d5555d757f5fdf6adff560000001fe0000000000
+% 0000000000000007c000fb7d7ffff7dfd5f575dfb55fd0000007f000e0000000
+% 000000000000000d6000aed7d5555d757f5fdf756ff57000000b8007f8000000
+% 000000000000001bc001fbbd7ffff7dfd5f575dfdaafd8000000001fb8000000
+% 000000000000002eb00156ebd5555d757f5fdf7577fab400000000fc18000000
+% 000000000000003be001fdbebffff7dfd5f575dfdd57ec00000007f018000000
+% 000000000000006eb001576beaaaad757f5fdf7577fd5e0000003c31f0000000
+% 00000000000000dbe001fddebffffbdfd5f575dfdd57f5000000701fc0000000
+% 00000000000000f6a001ab75eaaaaeb57f5fdf7577fd5f000000601f00000000
+% 00000000000001adc0017edf5ffffbefd5f575dfdd57f5800000601800000000
+% 00000000000001fb4001d5b5f55556babf5fdf7577fd5f4000007e0000000000
+% 00000000000003578000bf7f5ffffdefeaf575dfdd57f58000003e0000000000
+% 00000000000002fd0000ead5f555575abfafdf7577fd5f600000140000000000
+% 00000002000003ab80005fbf5ffffdf7eafab5dfdd57f5c00000000000000000
+% 00000004000002fe0000156af555575d5fafef7577fd5f600000000000000000
+% 00000004000007ab00000fdfaffffdf7f57abadfdd57f5d00000000000000000
+% 000000040000057e000002b57aaaab5d5fd7efb577fd5f700000000000000000
+% 0000000c000007d5000001efd7fffef7f57d5aefdd57f5d80000000000000000
+% 0000000a000002be0000003abd5555ad5fd7f7bab7fd5f700000000000000000
+% 0000000c000007ea00000017ebffff7bf57d5d6fed57f5d80000000000000000
+% 8000001a0000055c000000055eaaaad6afd7f7dabbfd5f740000000000000000
+% 00000014000007f400000000f5ffffbdfabd5d77eeabf5dc0000000000000000
+% 8000001e000002ac000000001f55556b57ebf7dd5bfeaf740000000000000000
+% 00000034000007f800000000003fffdefd5ead77f6abfade00000020ffe00000
+% 8000003e000002a8000000000002aab5abf5fbdd5dfeafb4000000e0e0700000
+% 0000006b000001e00000000000017fef7eaf56b7f755faee000001f0c0300000
+% 8000005e000000400000000000002abad5fafded5dff57ba0000018060f00000
+% 00000075800000000000000000001fefbf57ab5bf755fd6e00000380e1e00000
+% 8000005f00000000000000000000155aeafd7ef6adff57db00000185e1c00000
+% 000000f5800000000000000000001ff7bfabd5affb55fd76000001ffe0000000
+% 0000005f40000000000000000000355d6afebf7aaeff57dd000000fe00000000
+% 800000f5c00000000000000000005ff7dfabead7fbaafd770000000000000000
+% 800000af70000000000000000000155d757ebfbd56ffabdd0000000049c00000
+% 000001fad000000000000000000007f7dfd5eaebfdaafeb70000003ffff80000
+% 800000afb800000000000000000002ad757f5fbeab7fabed0000007ffd580000
+% 000001faec00000000000000000001fbdfd5f56bfed57ebb800000e000180000
+% 80000157ba0000000000000000000056b57f5fdeabbfd5ee800000c000180000
+% 000001fd6f000000000000000000003defd5f575feeabf5b800000c000b80000
+% 80000157da800000000000000000000b5abf5fdf55bfeaf6800000f6fff00000
+% 000001fd77e00000000000000000000ef7eaf575ff6abfad8000007fffe00000
+% 80000157dd5000000000000000000003ad5fafdf55dfeafb0000001400000000
+% 000001fd77fe000000000000000000007bf57ab5ff755fae8000000000000000
+% 800001abdd55800000000000000000002eafd7ef55dff57b8000000003000000
+% 000001feb7fff80000000000000000001bfabd5aff755fd6800000d2ab000000
+% 80000155ed555780000000000000000006afebf7aadff57d800000ffffffe000
+% 000001ff5bfffd7fffffff400000000003fabead7fb55fd7000000fffffff000
+% 800001aaf6aaabdab6d555ffa00000000157ebfbd56ff57d8000000003047800
+% 000001ffaffffeb7edbfff56d400000001fd5eaebfdaafd70000000003001800
+% 800001557aaaabed5beaaafdbd0000000057f5fbeabffabd8000000007003800
+% 000001ffd7fffebbf6bfffab6be00000007d5f56bfeaafeb000000000000f000
+% 800001aabd5555eeafeaaafefebc00000017f5fdeabffabe8000000000008000
+% 000001ffebffff5bfabfffababeb0000001d5f575feaafeb0000007a00000000
+% 800001555eaaaaf6afeaaafefebfc0000017f5fdf55ffabe800000ffff000000
+% 000001fff5ffffadfabfffababeaa000000d5f575ff557eb000001d5ffffd000
+% 800001555f55557b57eaaafefebff000000bf5fdf55ffd5e0000008004fff000
+% 000000fff5ffffd7fd5fffababeaa800000eaf575ff557f5000000000003a000
+% 800001aaaf55557d57f5557efebffc000005fafdf55ffd5e0000000000010000
+% 000000fffaffffd7fd5fffd5abeaaa00000757ab5ff557f50000005000018000
+% 800000aaafaaaabd57f5557f7ebffe000005fd7ef55ffd5e000001ff00000000
+% 000000fffaffffebfd5fffd5d5eaab80000757d5aff557f400000381ffd00000
+% 8000005557aaaabeabf5557f7f5ffe800005fd7f7aaffd5c000001800ff00000
+% 0000007ffd7fffebfeafffd5d5f55580000757d5d7faabf40000018000500000
+% 8000005557d5555eabfaaabf7f5fff400005fd7f7d57feac000003fe00000000
+% 0000007ffd7ffff5feafffead5f555c00006abd5d7fd55f8000003bfe0000000
+% 8000002aabd5555f55faaabfbf5fff600005febf7d57ff5400000705ff000000
+% 0000003ffebffff5ff57ffeaeaf555c0000755ead7fd55f8000002003f000000
+% 8000002aabeaaaaf55fd555fbfafff600005ff5fbd57ff500000070001000000
+% 0000001ffebffffaff57fff56afaaac0000f55e02bfd55f0000005ff80000000
+% 8000001555eaaaafaafd555fdfafffa00005ff001eabff500000001ffc000000
+% 0000000fff5ffffaffabfff5757aaae0000f54000bfeaae000000000ffc00000
+% 8000000d55f55557aafeaaafdfd7ffa0000afe000eabffa00000000005c00000
+% 0000000bff5ffffd7fabfffab57d5560001fa80005feaac000000f0000800000
+% 80000006aaf55557d57eaaafefd7ffc0001578000755ff8000001fe000000000
+% 00000005ffaffffd7fd5fffababd5560001fd00002ff5540000038fc00000000
+% 80000003557aaaabd57f5557efebffc00015700003aaff800000303e00000000
+% 00000002ffd7fffebfd5fffd5abeaaa0003fc000037faa000000180610000000
+% 80000001aabd5555eabf5557f7ebffc0002aa00003d57e0000007f871e000000
+% 00000000ffebffff5feafffd5d5eaa80007fe01e02bfd400000043fe06000000
+% 80000000555eaaaaf55faaabf7f5ff800055407407eabc000000007e06000000
+% 000000007ff5fff7aff57ffead5f550000ffc05f055fe8000000801fce000000
+% 800000002aaf5542faafd555fbf5ff0000aaa07507f558000000e003fc000000
+% 000000003ffaffe1affabfff56af550001ffc05f055ff0000001f00078000000
+% 800000001557aaa17aafeaaafdfafe00015560750ff5500000017e0000000000
+% 000000000ffd7fc0d7fabfffab57a80003ffc01a0aafe00000000f8000000000
+% 800000000aabd5607d57eaaafefd7c0002aaa0101ffaa000000003e000000000
+% 0000000003febfd00bfd5fffababd00007ffe0002aaf80000000003f00000000
+% 800000000155eab00eabf5557efeb0000d5550003ffa00000000000fd0000000
+% 0000000001ff5fe805feafffd5abe0000bfff8006aae000000000001e0000000
+% 800000000055f5580355faaabf7e80001eaaac00dffa0000001f0000c0000000
+% 00000000007f5ff400ff57ffead5c00015fffa0175540000003fc000c0000000
+% 800000000015f55c00aafd555fbf40003f555703dff800000071e00dc0000000
+% 00000000001f5ff6003fabfff56a800055fffdaeb55000000060780f80000000
+% 800000000005f55d800afeaaafdf00007f555775ede0000000603e0600000000
+% 0000000000035ff74007abfffab40000d5fffddf58800000003c0f0000000000
+% 800000000000f55dd0003eaaafe80003bf555775c0000000000038f000000000
+% 0000000000002ff7780015fffaa00002eafffddf400000000000307800000000
+% 800000000000155dd6003f5557800007bfaaab75000000000000781800000000
+% 00000000000007f77da02afffd00000d6afffede0000000000001e1800000000
+% 80000000000000add76dffaaa800001fdfaaabb40000000000000f1800000000
+% 000000000000003b7ddb557ff0000035757ffeec00000000000003f800000000
+% 800000000000000ed777ffd54000006fdfd555b000000000000001f000000000
+% 0000000000000001bddd557fc00000fab57fff60000000000000000000000000
+% 80000000000000002b77ffd5500001afefd55580000000000000000000000000
+% 00000000000000000000017fa0000f7ababffe00000000010000000000000000
+% 800000000000000000000000000015d7efeaa80000000007c000000000000000
+% 00000000000000000000000000003f7d5abff4000000000ff000000000000000
+% 8000000000000000000000000000ead7f7eaa0000000000c3800000000000000
+% 0000000000000000000000000001bfbd5d59c0000000001c3c00000000000000
+% 80000000000000000000000000076aebf7c300000000003e0e00000000000000
+% 000000000000000000000000000ddfbead060000000000070700000000000000
+% 800000000000000000000000007b756bfa0c0000000000038380000000000000
+% 00000000000000000000000001aedfdea010000000000181c1e0000000000000
+% 8000000000000000000000005f7bb5700000000000000770387c000000000000
+% 000000000000000000000000f5d6ee8000000000000006383c1c000000000000
+% 800000000000000000000001af7da800000000000000061c0c0e000000000000
+% 0000000000000000000000037ad50000000000000000070e0f0e000000000000
+% 800000000000000000000001550000000000000000000306039e000000000000
+% 00000000000000000000000000000000000000000003c00381fc000000000000
+% 80000000000000000000000000000000000000000007e00780f4000000000000
+% 00000000000000000000000000000000000000000006700fe038000000000000
+% 800000000000000000000000000000000000001f80060038381f000000000000
+% 0000000000000000000000000000000000000019c0c7001c3803800000000000
+% 8000000000000000000000000000000000000038c183000e1801e00000000000
+% 0000000000000000000000000000000000000018078383070c00c00000000000
+% 800000000000000000000000000000000000001c00c1cf839c00000000000000
+% 000000000000000000000000000000000000001c40e0ff81f800000000000000
+% 800000000000000000000000000000000000000df06078c0f000000000000000
+% 0000000000000000000000000000000000000007f87060e00000000000000000
+% 80000000000000000000000000000000000000079c3800700000000000000000
+% 00000000000000000000000000000000000003838e0c02300000000000000000
+% 8000000000000000000000000000000000001181860e06300000000000000000
+% 000000000000000000000000000000000000f1e1c70607f00000000000000000
+% 80000000000000000000000000000000000030e0c30703e00000000000000000
+% 00000000000000000000000000000000000038e0e38300000000000000000000
+% 80000000000000000000000000000000000018f0618180000000000000000000
+% 000000000000000000000000000000000000187030c1c0000000000000000000
+% 8000000000000000000000000000000000000c7838e0e0000000000000000000
+% 0000000000000000000000000000000000000c1838e070000000000000000000
+% 800000000000000000000000000000000000061c0c3000000000000000000000
+% 000000000000000000000000000000000000070c0e3000000000000000000000
+% 800000000000000000000000000000000000030e06300c000000000000000000
+% 000000000000000000000000000000000000030607f01c000000000000000000
+% 800000000000000000000000000000000000038603e004000000000000000000
+% 0000000000000000000000000000000000000183028000000000000000000000
+% 80000000000000000000000000000000000001e3040000000000000000000000
+% 00000000000000000000000000000000000000e3800000000000000000000000
+% 80000000000000000000000000000000000000f7a00000000000000000000000
+% 0000000000000000000000000000000000000018000000000000000000000000
+% 8000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 8000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 8000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 8000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 8000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 8000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 8000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+% 8000000000000000000000000000000000000000000000000000000000000000
+% 0000000000000000000000000000000000000000000000000000000000000000
+%%EndPreview
+%%BeginProlog
+% Use own dictionary to avoid conflicts
+10 dict begin
+%%EndProlog
+%%Page: 1 1
+% Translate for offset
+14.173228346456694 14.173228346456694 translate
+% Translate to begin of first scanline
+0 142.49763779527561 translate
+124.99792789059263 -142.49763779527561 scale
+% Image geometry
+250 285 8
+% Transformation matrix
+[ 250 0 0 285 0 0 ]
+% Strings to hold RGB-samples per scanline
+/rstr 250 string def
+/gstr 250 string def
+/bstr 250 string def
+{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop}
+true 3
+%%BeginData: 46454 ASCII Bytes
+colorimage
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+XoAOuhVQ9'JcF[.J,~>
+XoAOuhVQ9'JcF[.J,~>
+XoAOun*f,rJcF[.J,~>
+XoAO;@nJ2/r;QiehWKIikl6/~>
+XoAOD@o>%?r;QiehX?$qkl6/~>
+XoAO\V3HYHr;Qimn*bi-kl6/~>
+XoAOe[8IQprVlugN&d,Rs60K5~>
+XoAOm[8Ij#rVlugN'`b[s60K5~>
+XoAOmesq*#rVluo]o9XUs60K5~>
+ZMt!hhWOk;",$qHhZ!NXk=Q"?hLY^ks*t~>
+ZMt!hhXCFC",%L`hZ!NXk>DjOhLY^ks*t~>
+ZN'pmrVlu-F-Q.mrrheTF,]R=s69Q6~>
+Zi:-jCFP5@rr[o[6Jh_A"Rh:0V>#Q@l2Q8~>
+Zi:-rCGCeHrr[ok6Jh_A"Rh:9XnRDHl2Q8~>
+Zi:-rXb=Cdrr]ZMPjeVO"8BKfc@Q#Zs*t~>
+Zi:-a.0rQErr\Js6Iu,8!U&<js6'E4~>
+Zi:-a0c3O]rr\Js9%Nt@!Unlrs6'E4~>
+Zi:-rKQECVrr]r]Pir#Fs6kO=kPp&~>
+Zi:.%HSM&hrr_Eq+gq:K!pB%@qu6iVX_X0Xp\XsnpZL,jpOWAEs*t~>
+Zi:.%KJB"qrr_F$.CK-SrpTaa"l?A&Phu03rri)Zf'i?as8W+L~>
+Zi:.%[>`-(rr__:He//q!q5mXqu6igcE4eKp\Xsmp[@;6JcG`LJ,~>
+Z2Xgmr;Ql^+UFV;rrf06CO=q:rs,r0&-rP%PkY.V#2Y#"+^1-!Jc>`MJ,~>
+Z2Xgmr;Ql^.1i$KrrfH>CO=q:rs,r0(`3fNPkY.V#2Y#".9`81Jc>`MJ,~>
+Z2Xgur;QlfHZR4+rrgWLXgRWrrrL]@rc8."^%_L*#4JsaH_naVJc>`MJ,~>
+X8`:b(^QZ2rrej5#U/('rs)^5+[RU`1$AN8!G`8G#QZ*Frr32sKNc(G^#"YHJ,~>
+X8`:j+V:1Crrej5(b+>?rs*$F.7u<31$AN8#'1=m&.g:mrr32sN*<pO`nlUQJ,~>
+X8`:jKQG04rrg?DF+j#\rs,'8KTq.2N:6`F!3Q3@!IN,krs&52SC[/[mu%-q~>
+Zi:1&]k^NJrr3)p@gIG\rri(m&0]X(rs6mn&=i4&0bBlSrs6Uf#]$8'#W_AQrs-hZ+XmsO>0cO8
+!q5=HU]5i~>
+Zi:1&]k^NJrr3)p@h==mrri(u(b+&8rs6n!(nC'70c6G[rs6n!(i-6?&45jbrs-hb.5;Yo>0cO8
+s6fs^U]5i~>
+Zi:1&eubIfrr3)pV/s'Drri)AF+i`Urs7e@F2mt2N-iSDrs7J.F03`PF,]kmrs._`KS4]*V<@7G
+!r)0XU]5i~>
+\c2Zur;Qr`@j)+]n,E=hHO)Xprr3)G3?c]Irs6:T+gq@,3=plCrs5G43S+5,(a8AHrs(Oi#U'`b
+6LXCC"Rg\8SG/iZJ,~>
+\c2Zur;Qr`@jqt!n,E=hKFg04rr3)G3@W8Qrs6Uf.CK3465Y[\rs5_D6Iu1=+XumYrs(Oq(b$:=
+6LXCC"Rh"ASG/iZJ,~>
+\c2[(r;QrhV1`odp\t0p[<%;qrr3)`N-jaers72&He/5cN,u]3rs6nsN9C5dH\D.lrs+L(F*i7T
+PkXYH"S]<o`qQ;/J,~>
+]Di#jV/rKrrVm#`HO)sprr3(I#W_AQrr_+E&=!1o'YP&$[K"fE#_`6XpN$UDn,Kd=+n,C0#<<&M
+V1]C'[I=+uefb;kkG8-.~>
+]Di#jX`LW5rVm#hHPfB3rr3(R&394Yrr_+M(mP%"'ZLt=[K#)U(khqhpN%0Tn,KdE.I[68#<<>U
+Xb7N?[I=+uegVG.n"fu6~>
+]Di$&cE5C\rVm#h[<%T$rr3).F,]kmrr__SHbKFY'\7VXf)OotF1)&JpT8M5p]&fkK_PHF#E3__
+cF&"Gf'iVAkCdo@n"fu6~>
+]`/24+V4nj+hdjS"18[`^&J$6eds:Urr3)W63qr;rtN-`+gq@MhVRGqs7]\&>5/&]#U/[9rs6"U
++gq?i3=)/DrrhM+3J?jss*t~>
+]`/24.1d=5.E;>d"18sp^&J$6eeg-err3)W8f2pSrtNHr.CK3UhVR`$s7]\.A,$"f(b+qQrs6"]
+.CK2q3>e:Trrhe33K3F&s*t~>
+]`/2UH[Bg\Hf"`$"4hgGf)G[OkBhmFrr3)hP]O83rrpu#He/5srpTme$2:9;V>(#'F+j;ers72&
+K\$1[N-!#-rrhemN4nt]s*t~>
+^&JB$3=%W\.0s,?rr3)W+X*uerr_+$#c7P#"5Z?MHiF$I]au?pqYplr=pS=+s,74,n,E=mV%>)h
+s2I&1SFQU_n,NF^f(Ys>J,~>
+^&JB,3=nMm0c4*_rr3)W.4MCurr_+,&?Ys3"5ZWeHiF$I`Y^/4qYplr=qG3<s,7dDn,E=mXV`e4
+s2I&9SFQU_n,NF^hY3fFJ,~>
+^&JB,N,sr[KQE[Prr3)hKR;;Lrr__:F3adb"7MIq[Jp1.epDbpqYplrV/r1$s1NK,p\t0uc?"Zq
+s5&]U`ps'/p\t0mkG&!,~>
+^&JA`&.k]<N!L9&rVlpk#]p"F"4e:pV>gJshEhKprr3)6(`9[WrsAF'#[6]sN!LTqrr37o&5(gZ
+c8cH4nc&Z;N7O[%J,~>
+^&JA`(`9CTN#3_?rVlps(j#]V"5Y14XoA>&hF\W3rr3)?+X+8irsAF'&7b2/N#4#4rr37o(eWZb
+c8c`<nc&ZDN7O[%J,~>
+^&JB$F*l44]lSPOrVlq`F1)#I"6Y#PcMmhGn!%n$rr3)OH[F??rsAFrF/AX2]lSl$rr38DH^+"!
+kDXK%nc&Zu^#u'gJ,~>
+^&JA`&37c1hEiZ]rVm1-#[7!&s6!8cSGrNjkAq2]rr3)6&0\IXrtY93&<-YhN!Lm$s8VOk#\3o7
+V'.#Vnc&^);B^^es*t~>
+^&JA`(cfV9hEirerVm1-&7bJ7s6!8kSGrNjmrK=mrr3)?(b)lhrtY93(l\LpN#4;<s8VOt(h<UG
+V(!kfnc&^2;CR9ms*t~>
+^&JB$F,\uUn!&LFrVm1oF/AX2s6lJ!`r>u?n#^rErr3)OH[F??rtY:)F1qVR]lSl$s8Vh`F/Ap:
+`d<C5nc&^JS:n;Ds*t~>
+^&JAh+V;?ekG@&(rVm23#VkNBs7^R?3W8saPRqX!s8TbL+gq1H'^&@2[K$8c#[6]ss6!PkHiO,!
+#U/^;"7KD!>4;Iln)q+YJ,~>
+^&JAh.2]bun#bI8rVm23&394Zs7^jW6N-ojPSe3)s8U(^.CK$P'^&@;[K$8c(g?D.s6j,.HiO,!
+&1R,K"7KD)A+0Htn$W1G~>
+^&JB$KR;;Mn':CrrVm2TF+j#^s7`pBN;`b_`cJ9Vs8UYsHe/&n'^qQ=f)Pc`F/AX2s6le*[K$97
+F+j&_"8A=,V=4Ebp[>NiJ,~>
+^&J60;@%XDq>Uc7#RK;es6k:?1&_+YPRp14s8TbL(q'5?#e_B)^&R8!#`Sc_#gP.9[K#]:#W_DS
+"18[GSGrNi]s[>%rrTlL]sdrk~>
+^&J60;Ab)]q>Uc7&.m^us6k:G3W8saPSd$Ds8U(^+gq1H#f\;B^&RP)&<-Vg#gP.A[K#]B&45md
+"18s_SGrNi`jP:.rrTlT`jYnt~>
+^&J3/S9)+5rs@7tF79//pU,'qrVm2;H^*^ns42ODf)#CPhLp7,s6lJ!^&J$;kDXc=s7`X:N:?iL
+epDJXrr3&Vf(\k;!nOL1[f:j~>
+]`/(L#YORarrDNersI=;#`Sf`pOif,p\t1!S-V.#s8TbD+gq1H#dkfm[K#DM#`Sc_#d"pe^&R7E
+#`S9Q"+(;6hZ!NY]i&@kkP+cO"Qu!uF5FG,J,~>
+]`/(L(eX8qrrDNersI=;(l\LppP]qDp\t1!S/=93s8U(U.CK$P#dl*)[K#DM&=!1o#dkg)`rG3V
+&<-,Y",%LOhZ!NY`_pU'n+ZVW"RhR0F5FG,J,~>
+]`/)9F-QFtrrDfmrsIqJF1qVRpUtX,p\t1!`cI+%s8UYsHe/&n#hF?Lf)P2tF1qSQ#gRdDf)P2l
+F1q)C"1<3/n,E=iesrT"n+Zhbn%FC^kICPB~>
+]`/Mf#RJHMn(+"^n,NFN;@%(;rr]q`+iaN]$'Yu]cN!pX(a6<`rtMja(q'D,0aNa<s7`#p.G"O^
++UFV.rr^gq#aG;f#3TbN@q12Cq>UTS8dIc/\Gq'~>
+]`/Mf(_F^en(+=on,NFV=qGKKrr^7q.E;Ae$'Z8ecN!pa+XshqrtMji+gq@50bBTLs7`$#1"QBf
+.2\TFrr^h$(mP"!#4H=^@q1JKq>UTS;A_aG\Gq'~>
+]`/N*F*$4<pZKQ0p](9^S9(h3rr_,2Hf"c%$,(\EkPtS5H[F??rtO%2He/5cN,u]4s7aN[K]iC(
+KQG0'rr_G2F1qPP#4J[IV5:lgq>UTdP]N)P\Gq'~>
+]`/c(63q(t@lY\en,NFVCC!i$s8Tbe&>fC+$+1=)cN!pX(`9[WrtMja(qot40aNa<s6!kt;ZHd:
+(a7K#rr\Js.CK-S!PKr]#QbQ0cMIPCV%=3?\,Us~>
+]`/c(65X4/CH3gun,NFVCD]t<s8U(n(o@63$+1U:cN!pa+X+8irtMji+hdp=0bBTLs6j_7;ZHdB
++Xu"4rr\c.0t$u[!QHkn&-<\@cMIPCV&1&O\,Us~>
+]`/c9P]N\@Xc.Ucp](9fX`L$$s8Ur7HcH'b$.aH^kPtS5H[F??rtO%2He/5cN,u]4s6le*SH&WG
+H\CSPrr^8fK\$,%!T&M/Erp]QkPG2\`d<'X\,Us~>
+]`/<,@gE>O#S77IXoA>,S.Hjps8UY1&=ib"$25St`rH(P&0\IXrtMja.F.tV0aO$Ds6j+sA,lRf
+#Vk3,rrh1^#\3?&rs8@/#S:K]+UF&(rrgn5#YNCOs*t~>
+]`/'%CCpI^!tZ:\[Jp14V&1Z4s8UY:(nCU*$25l'`rH(Y(b)lhrtMji1!]g^3=q_\s6j,.A,lRf
+(bsn<rrh1^(i/U>rs8@7(`6au.1hI8rrgn5(eW)_s*t~>
+]`/-/V/p^)rGqtarr3;EH\CS^s6#>f`r>uEpOnL^s8UYsHe/&n'\7VikPt"0F2n7[pSDr-s8TcR
+N:6?;"Rhk%V>'uh#kt0:H_mikF1qJN"Qt_bPioOUJ,~>
+]Di/$&0Wc3HU8!Zrr3)6.3ZD(rrZa:CZk]s,U!_hs8TbL+gq@Metp[ls-+'es8Uq)+jU,fhDkk<
+s8REO;Xa2V"18[OSGiHohDkj_n*b<';WmuX!,MQ>!CFf9s*t~>
+]Di/,(b%1CKL-Msrr3)60e'g8rr[$RC[_9&,UjS#s8U(^.CK3Uetp[ls-sous8Uq1.F.tnhEhdU
+s8R`h;Xa2V"18s_SGiHohDlF"n*b</;WmuX"`kLl&44[Ps*t~>
+]Di/VF+fLB[?Pa?rr3)OKS7qUrr]*=Xmc8hs*Gs0s8UYsHe/5skJl]bs2KDMs8VP@HftG/mu2>5
+s8TKJSG2US"4hgG`r5oDmu2=qp\1e2SF?CU!3Q6A!L2HNs*t~>
+]DiDeHaUlVpOif,n,NFN63rPLrrZa:;Wn&Z,9[>Os8TbD+gq@MN"C[BmpcVqs8So,+m8n*c3O]q
+s7\hcN:QuOpNm04kPbDePR&_ps6j+s>4;Fi#0nA/;A^Rb\Gq'~>
+]DiDeHaUl^pOj)4n,NFN8f3NdrrZaJ;XaVb,:O1_s8U(U.CK3UN#7NRmqWb<s8T2<.Hga2c4Ci4
+s7]+sN:QuOpNm`Dn,<7mS.IF3s6jG7A+0Br#0nY@;B[Ks\Gq'~>
+]DiE)[FX4's0Zp,p](9^P]OP;rr]*=SF?IW,D:-Os8UYsHe/5s]mIHmpSDqqs8UAkK^\s@kAt_$
+s7_b!^%21+pU,(,n,<7m`cHh%s7`%)V>'rg#3U>[S9oq?\Gq'~>
+])Md)rVm2;.3Z_2s6!8cF8l1ACC!i$rr42d#`SNXs%3i]n(pABK`CLN#YP-sPR&Gqs8Tb<1#Drn
++UF>'rr_FN#]otE$/Ru[K_PM[+UF>2rs%=X#YNt1[C?0d~>
+])Md)rVm2D0e(-Bs6ii&F8l1AEu7g<rr42l&<-A`s%4,en(pYRN;r?^&5*!&S.I.4s8U(M1#Ds!
+.1ha7rr_FV&:=BU$/S8cK_PM[.2\<Jrs%=X(eWZA[C?0d~>
+])Md)rVm2\KS84^s6lJ!XoA>&X`L$$rr43iF1q>Js-.lDp[=>f^&Ri'F-Q_)`cHLqs8UYkN:6f8
+KQFitrr__SF1(uH$1F+"[J0^PKQG03rs%q^F-Q.^f!k[0~>
+[Jp?[64f+Trs=o$;VqHR]b!3Lrr3$C#`Sc_*Ff@8P_:1kPlLK:&37bn=pR.Os8QR7>4;LJ+X*uY
+rr])'+jU&d$'Yu]cN!'C#X[,@rr\c&+f2RGJ,~>
+[Jp?[8f3Ndrs=o$;VqHR`Y^_]rr3$K&<-Vg*FfXIP`.%.SH&>B(cfn1@h:Zhs8QjGA+0HS.4MCi
+rr])7.F.nl$'Z8ef)P2S(dcgPrr\c..BTuWJ,~>
+[Jp?lP]OP;rs?AcSF?LXhKt4Err3%HF1qSQ*Mmh9]tK)G`rH(PF,\uEV/qUas8T3BSG3'PH[F?7
+rr^8^K]i=6$,(\EkPt"QF-Pkdrr^8fK[-t)J,~>
+[Jpg4=pS<ps8ST#0uj7nc57,#rr3%'#`Sc_*OQFa&.f+WhZ*Vh+UCD<#S;@Ws8Q7.>4;Kf&38>4
+rrZF1>4;Ij$J%NTK`D([+V9>$rr3,P3='Ep[/YX~>
+[Jpg4@i/D4s8So,3QD+!c64%4rr3%'(l\Io!4D_A(Lu>%s2HK)6<Y3;K_PNH=qFm+s.pQ!f(/hC
+=qG34rr3>^65Y[]s0X9eN;*>O"P,REC\P49J,~>
+[Jpg4V/rL%s8U)[N8FU7kBh:$rr3%rF1qSQ&_;#EHZO8)n,NFEKQEBSF*"bgrs5HBSG3''H]7.Y
+rr\d4V>'uh$KmXp^&S,`H[E0prr3,aN,u,q[/YX~>
+\c3r<[B93'[1FM$s8U@f&>f.$c4CPpkP+.d&5mkgs6ldN+XpUXrr3Z#PT^SL(g>ern)mR[N;rp2
+&44t>rrgUj+e8<+rs=W$1"QBn@gF77rVlt@#U.L"s*t~>
+\c3rD[B93'[1Fe4s8U@n(o@!,c57D+kP+.m&5n2$s6m'^.5>>qrr3Z#PURFd+_0C/n*a-kPlLcB
+&5(OFrrgUr.@g/3rs=W-1"QBn@h:*GrVltH(b*b:s*t~>
+\c3rDf%0TqeoQN$s8V8/HcGg[kBhR,n+Z:YF.BYps7ag'KS62jrr3Z+]nC`RH_p32p[=W!^&S,G
+F-PkZrrhM<HcGgZrs?AcN9C68V/q=YrVlu-F*m)Vs*t~>
+\c2q^#W_AReee[prr3NQ#\1QfV'-+[K[+pJKTr"PrVlldq>V#WPa&$-s7`?n&0\1Uk@5'MoD\sf
+HO)@Orr3;f3=(!3s1KQ]Pl:Ub[4*8`p\k*np](!!s*t~>
+\c2qg&45jcefbm4rr3NY(h:8)V(!6sK[+pJN0KjXrVlldq>V#_S<Tl=s7`X!(b)lmmpd2foD\sf
+KGZGhrr3;n3=plDs2HK)Pl:Ub[4s+pp\k*np](!!s*t~>
+\c2rCF,]knkBh:$rr3O_F/@IE`d;d/[HFrf]tMGKrVlllq>V#h`kBC\s7ag/F*l44n"kB=oD\sf
+[<%;irr3;nN,uE,s5&*D^&@s6eqAC`p\k*np](!!s*t~>
+\c3MS&."6XKErF.s6#m`+^/ZOXehl%hXBXal2M.JXdjIPs5$'JA&e99rrh1N#]ob>rs>2$.G"P!
+=pQk6rr3,a=pRIXrVm&7CL^kEpUpNV~>
+\c3MS(`84pN#3_Os6$3q.9^e_Xf\G-hXBpil2M.J[A@ris5$?bA&e99rrh1N(j#HNrs>2,1"QC)
+@h:BGrr3,a=r9ThrVm&@CL_.MpUpNV~>
+\c3MtHZQmh]lSPOs6msSKUf0af$;:dn+Z;>l2M.[cGm9Ks6l1nV;Ct>rrheTF0539rs?\dK]iC8
+V/qUYrr3,iV/qmirVm&XXehl6pUpNV~>
+\c39)=pPs3(^O=%s5'9R`olOZpYYuVn,NFV`d:$fkOniWV&1&Wrr3>^3=(T<s1KQ]K_PKG"/R.X
+V>^Dpc8#;(!>'Ujs*t~>
+\c39)=r8DT+W+D>s5'9R`p`BjpYYuVn,NFVc@ef2n+H\_XW\jqrr3>^3>d_Ls2HK)K_PKG"/RFi
+Xo88(c7p.Q&/]c,s*t~>
+\c391V/q!JHZQ%Ps6mtYhXBq-pYYuVp](9fhR/TMn+H\_c@gPqrr3>oN,u],s5&*D[J0\#"3-"@
+cMdbDkD]C]!IM5es*t~>
+\Glca;BZko;Vo7i"RfM"9'?3R$&fEUcN!Wl&44tIrr^gq#]'D=#i7QI+aZNe+kF@,J,~>
+\Glca;CNb4;Vo7i"RfM*;XaVb$&f]]cN!Wt(eWBYrr^h$&9IgM#i7lb.=4Z(.Fu34J,~>
+\GlcrS9oU9SEI`g"S\a6PjeVO$,(\EkPt:iF-Pkerr_G;F05E@#k*^nKXI%cK]g&KJ,~>
+\,QHZrj;a__#FMf+UFqDrs@OS#\3&tej9XqrVltQ#U.4ers@kA&0[;4c9_e`^&NT~>
+\,QHZrj;a__#FMn.1i?Trs@O[(h<%7ek-d4rVltY(b*K(rsA.I(b(^Dc:Sq#^&NT~>
+\,QHkrmh)<_#FN"HZR4+rsA.YF/A@*kEL&$rVlu5F*ldCrsA/%H[EI#kEL%q^&NT~>
+JcG?A"kIaJ#U.Lmrs=Vi(q'D<PRok+rr3).+V:1CrsJLj&.jNhs40LBK`:uOpVHl[~>
+JcG?A"kIaR(b*c0rs=W$+gq@EPScF3rr3)..2\TSrsJLj&/^B#s40LRK`:uOpVHl[~>
+JcG?A"m<#$F+i`Urs?A[He/5k]mG_$rr3)OH[Ed2rs?\dF1q>JkEL%qrr2um_>f#~>
+JcG?A&b!DC.70m"s5#aA9)nqJ3=(TCrrhLg#YNtQrt!C8#ZBjcpOj)$f)Pd5V8gCPJ,~>
+JcG?A&b!_T0g`#2s5$'Z9)nqJ3=q/Krrhdo(eWZart!C8(fKPspP]q<f)Pd=V8gCPJ,~>
+JcG?A&bjkYKTsdVs6knfPlLdPN,u]3rrhe\F-Q.mrt":OF.D_!pUtX$kPtSN`nnT4J,~>
+JcG9?&,3c%A'WAi&.l8Ls-*dLhZ!NlS08HWp](9^@gFg7s8ST+#__sPs7`$]f#.N<~>
+JcG9?&,4).CX14q(`9[\s-+'ThZ!NlS1,;gp](9^CCi5Gs8So=&;9fXs7`$]f#.N<~>
+JcG9?&,4qoV<@$]F*lL<s1NK4kPkJu`d<'`p](9fV/qUYs8U)cF1(cBs7aO'kJR=M~>
+JcG3='DL\8;BZ<LkPsC!&;9NPs5#11A,cK9kCaBPCZk`K63oU&rr3/rS6E>WpVm/_~>
+JcG3='DLt@;CNGdn,M62(l\4hs5#IIA,cK9mt;MpC[_;S65V`6rr3/rS7At`pVm/_~>
+JcG0<'(>"RHZQ%Ps6knn^%_R,mt>bYrr3Ap[<ltsn,MR8F,];]rrr/:SCZlt`W(G~>
+JcG*:$0R7F[K$8c&38>@rr[<J0tmSd$FM;g#U+9?@gFg7rr35tPT^ST+`$8\s*t~>
+JcG*:$0R7F[K$8c(cg1Hrr[Tb0uj4m$FMT"&1M\OCD\eOrr35tS1,9u.<Fsts*t~>
+JcG*:$1GQtf)Pc`H]7.err]BEN8FR6$J'lOF*k=XV/qUYrr35t`e8D[KWX^_s*t~>
+JcG$8%Gq-b]f?X_p](9$.1haCrsR[U#WXmV#XT[GPkY1W#JD8d#VcSr[Dr5s~>
+JcG$8%Gq-b`]4lpp](9$0bBTKrsR[](d^P+(d]Y_SG3$_#JDPt(blR=[Dr5s~>
+JcG$8%Ia>shMcNhp](9EKQFj+rsJ4ZF,Z')F-M?!`r5oBeqA*cN,s?s`rCP~>
+JcFp5(pu(APkY4@=pRIGs8Vh7#T0]#EtAT_6MLKZ$/SPc0pKs]#[6uCs*t~>
+JcFp5(pu@QPkY4@@i.hhs8Vh7(a6$<Eu5`*9)&>b$/SPk3L%fm(g?[Ss*t~>
+JcFp5(tO@e`qTN%V/qmas8VhqF*lL,Xa>,1PkY1W$1FC*N4nDEF.E!Fs*t~>
+JcFm4(?^o[[K"N,&=ie#pQQ4#K_PN0V("a^rr3>V;@#;&s8So,6Jfc_J,~>
+JcFm4(?^o[[K"N,(nCX+pRE';K_PN8V(kTnrr3>V;A_F>s8So46Jfc_J,~>
+JcFm4(@Sr,f)OolF2n7[pVqQ,[J0^ic@hGFrr3>gS9'YGs8U)cPip*eJ,~>
+JcFg2s5".`[36*ps8UA)&7aSqrrKO@rr3A_=pPCus8UqZ#YOj3s*t~>
+JcFg2s5".`[4)s4s8UA2&8U/$rrKO@rr3A_=r8*@s8Uqc(eXPCs*t~>
+JcFg2s6g?qepDc#s8V8@F/A@(s8U[LrsS:cF*#A$s6le*PkW5uJ,~>
+JcF^/$._EKA*<Si#U.4brrDfmrsFtr&:<mGs+CppV8iOc~>
+JcF^/$._E[A+0/%(b*c-rrDfmrsFu%(jk`Os,7d3V8iOc~>
+JcF^/$0ROoV=4/TF+iEIrrDfmrsHG\F1(cBs1NK#`lA%/~>
+JcF^/%/68@V>oBX#c7S$hWOh:"n.ru&;9NOrs6#!A*<mlkNC^Fs*t~>
+JcF^/%/68HV>oB`&>fF,hWOh:"n.s)(khAWrs6#)A+0Htn)rQNs*t~>
+JcF^/%/7bp`rGLKF2n7[n*g2S"o$#`HaWVIrrpu<V=4HarpS&1J,~>
+JcF[.%/6Ums4.G]^&RhJCZkZr"IpV@;WmuX$-q`6s42Np;PiR$s*t~>
+JcF[.%/6mus5":u^&RhJF6EN%"IpnX;XaP`$-q`6s42Np;Q]E4s*t~>
+JcF[.%/8'As6"HEf)PKPXmc5g"NGe0SF?CU$0UdWs6$e[SBgTJs*t~>
+SGs#ls8Vins7cQnp](9fdJjUKs8Up]#^ajD+X*uerrg=b#W^3*rrLD*rWiQBHfr]SJ,~>
+SGs#ls8Vins7cQnp](9fdJjUKs8Upm&:;]U.4MCurrg=j&38&2rrLD3rYP\[Hgf8[J,~>
+SGs#ls8Vins7cQnp](9fcMn1=F*"bP[<mSPrr3,XHZP//q#:BXN;dl"HaW=fs*t~>
+JcFO*&+=QN#U'`b>2K;Zekuc6`q]Q>ek-K6@qu>UXj6rs~>
+U]1>_rmh+iPk'b5V>\uprt"R>(`4\5(g>ers41'b3R7F"#i8/b3FchA(p2*`J,~>
+U]1>_rmh+iPk'b5V>\uprt"k+F)u\LF/A@*s6#nnN8F@0#j7G!N2<XtF4SY:J,~>
+WW)tmh>[KLg&DQ5KJ=W)F5Hrsekuc.^%_:$#JFWep\-u[F3af9~>
+WW*1shU\3DHWpD'!%IFD$4nX@0fa<%Pg8.[g&DQ=KJ=o1Hf"f&elinF^%_:$#JFomp\-ukF3af9~>
+WW*1shU\3DHWpD'!%IFD$4nX@0fa<%Pg8.[g&DQF[>]Hk[I=.qkF?UPf(\q=#M-$6p\0nn[Eef&~>
+Y5eOrYQ#%"hR257s8V7K&.jN`q#:Zps7b^Vs5u]SPg9;Z~>
+Y5eOr#4J[@=t(U+iX#Q-"BolCn*f'3%.E&\hY7'Mk=Q:&N;*,I$2=Jon,NFV64fC,s*t~>
+Y5eOr#4J[@=t(U+iX#Q-"BolCn*f'3%/95AkP,#Vn!&0?^%_=%$2=Jon,NFVP]OO`s*t~>
+Z2Xguc2Re<h#@TAhX>4c&;9iY$eCP`[HISiekubbXj6rs~>
+Z2Xt$etmF[eHc:4CRi]Eh#@TIhX>Ls(kh\a$eCPh[I=.qel!%r[Eef&~>
+Z2Xt$etmF[eHc:4CRi]Eh#IEC"S]$>HaWYK$g542f'iY=kF?U?cHcH?~>
+[/U.#V#LYUF'9^uK]i43%I]NJ&-sG+kLNfB&:<Tcs*t~>
+[/U=(]o6GM(srTl&0YPRf&$E2hK*0U(khASrseF]65UOgHgfNh(`7qhcMrC~>
+[/U=(]o6GM(srTl&0YPRf&$E2n#`F5HaW>=rse_9P^@J)[I<:TF*k=`cMrC~>
+\,QI&T`5/&3='E`qYq#nN$/HM3=laC=pP[mkKX$W~>
+\,QU*hMb&Map8+]+_.YCi;Wqf3>cQ#qYq#nN%#;e3>`TS=r7g(kKX$W~>
+\,QU*hMb&Map8+]+_.YCi;Wr2N,u,iqYq$!]mFgRN-fWRS9&bZn'1l_~>
+])Md)SGr]2>'oH0rs/"G&-u1bs-3Kg!>p1\rrMlWe,Op~>
+])Mp-kI#(S_[$?:F4Tg>rr^8NHft;+%.Aid(fJrbPSarC+aa+d!Vc'3s*t~>
+])Mp-kI#(S_[$?:F4Tg>rr_,S[I="m#PYWQF.DFn^&E'RHaWbN!Vc'3s*t~>
+JcF4!!p?*)r;R6#N"?7]f)PcX#RCugkPY>_]o6-bpXT:o~>
+]DhurN(P8.#QcH%f&H]2n!qu,rse^](`5Tjs8TJD&/]c_r;Qo5P[g6Xec1.~>
+]DhurN(P8.#QcH%f&H]2n&FPgrse_9HZPG7s8UYkF*k=`r;QoN]qraCec1.~>
+JcF0u!;HEk%HiZn#YN\Js5$WZ#__C>rs._G0b=U-F6D-SJ,~>
+^&J2tPT^mU#Qc/rhW+V9p\b%#mu/\,9%O%BhGOn%K^\m>#Nq%#(`4E;n(.Mh~>
+^&J2tPT^mU#Qc/rhW+V9p\b%#n%F'hPir)HkF?U7[I=(o#Of?bHZOP9n(.Mh~>
+JcG0<!;GIP%JPem#ZB7Rs41?Z&:=0Mrs@O[#REFo+V9>$qu6]kkMQ;i~>
+^]+AdKK6IH"!N$:pYl,]pP]q+;V(mJeliV%Hh[L=$/SPs(d_CT(l\4drrMlWhuA3~>
+^]+AdKK6IH"!N$:pYc&[]mFgjkPtSFV/p^cp\k*un!nH?N2;2K^%_C'!:ShFJ,~>
+JcG-;!;GLQ%-KVV9%O%Beli=jHggt6$h(K,#RGM&s*G#<kPP8\pRJYLs*t~>
+_>aSnPW?#T![3g&ir9GU3>bB>s8UYR(`7Vgrr3B#[9=CYF4UAE&45RWrrVqb[G_(8~>
+_>aSnPW?#T![3g&ir9GUN,t6Hs8V8PF*k=hrr3B#etmG/[HIRtF-Q.jrrVr7f&6RY~>
+_uB`2WrE(njSoUq&.lPTs6!8k.?s#prs\Y(.0qAekPtR@#W^K5rr`"K>3FlEJ,~>
+_uBi5KJ=&##QYK7pM0h&#S>\q!t\)4pZ2>^[29b#s8VOc&2B^Drr3E$XYCYIPir)HPRok3qu6cm
+N*>]/s*t~>
+_uBi5KJ=&##QYK7pM0h&#S>\q!t\)4pZ2>^epDJps8VPXH\BE-rr3E$eqA*t^$l"$]lT.qqu6cm
+]q"QMs*t~>
+JcF!p$1Bk[CX/bC#W^3/rsdgg&-t#9s8Vi$.0s,?r;Qr`KJ<aRn)F@t~>
+`;]kO;X"Gk+ZX=k^$k.Ws8V6`HXeMY#Q];/jo5YU3>cPWX\'EjcMdbPhI@*61!]h!pU)^m>4;Ch
+"n.+!&9I="s*t~>
+`;]kO;X"Gk+ZX=k^$k.Ws8V6`HXeMY#Q];/jo5Y]N,u,acBNC/kPbDin!nH?N9C6@pXY"=V=4?^
+"n/jXF1(c%s*t~>
+W;cklmf*:]f)GaEk5P[5&/[,F#W]TsrrpDP&.i?brr3,P63o$JrVm,s]jhTZ0t$c8s*t~>
+`r?,/KIQ6n"qW4]Pg8.[mf*Fac@ee$g^!sZ`qSWq#D<p;0e!Yo`r5o@c>*t.A&eNJ"P-0V0t$u[
+#PZ5J(`5!8pYu4'~>
+`r?,/KIQ6n"qW4]Pg8.[mf*Fac@ee$g^!sZ`qSWq#ISW"N-fW)f)>UPhQ:jGV:PYG"Qu"jK\$,%
+#PZfGHZP.spYu4'~>
+JcEso#MsM5#RDU!p\t0r[4r4(A)@1a"QshLXnVhp#5<d2#RF>Ri;\<~>
+a8Z4d=qL',";!Sif'hf%!p>4Rg^!p(V<7d_hK'MN&1Pp!rr3/00c1aChYmHWkAr)Sp\t0spP_*L
+&5pg3s*t~>
+a8Z4d=qL',";!Sif'hf%!p>4Rg^!p(V<7d^n#^qXF*m*Krrpu4F*"JPrVm#h[<pL!rr32s]o7#R
+SEJi1J,~>
+JcEpn"Ri0R3QD'u"l>am#VhS?rrMT>rr38m]ik[I+UCEki;\<~>
+aSu;0A*sU)&5%oEiVrr83SOf?He.B["RiHZ3R7X("l>au(bq9OrrMT>rr38m`a]Ps.1ei&i;\<~>
+aSu;0A*sU)&5%oEiVrr83SOf?He.B["S^3+N8FR6"n0HXF,[g/rrMlWrr38uetmG/KQECHi;\<~>
+JcEjl$[Z(?s8V7t(^Na9p\"OlHT;?KCRbqZXl050~>
+a8Z1!&Fg#.+`jLKhZ!Vr9%sUP>2JEA$[ZCHs8V7t+W*hZp\"OlKK0kmCRc4j[G_(8~>
+a8Z1!&Fg#.+`jLKhZ!Vr9%sUP>2JEA$FQDms8VPiHZPFso`#3)N,s?J`d<'Xi;\<~>
+[/U.#Qi@ELN4o8SCBt2UkP+]M$H?Qe#Vhk<n!&1^i;\<~>
+a8Z1J)"S"8+`ks'g]%<"1"us7;V(%2$Jp`]s6j_?(h;b'pAYKF@i-%;SF>p2Hfs>eJ,~>
+a8Z1J)"S"8+`ks'g]%<"1"us7;V(%2$Lb[bs6m(2F/A@"pAYKVV/p^:`qT5@[I<&RJ,~>
+c2Re<rr2umS,WK_jo5IR(_CKGpAY?RN%##D>2J!5J,~>
+c2S%CN-ikEs5uE8#QdVpn(7R?XUs4m![4*.jo5I[+W,"`pAY?RN%kk\>2J!5J,~>
+c2S%CN-ikEs5uE8#QdVpn(7R?XUs4m![4*.jo5J'H[Dm`pAY?c]nCHRSEJW+J,~>
+a8Z/6Jc>lA@gGEXpAY?1@h8nWPhu9:!lgb]j8XW~>
+c2S%"0aJqUf(Vf2#Qc/bn(%F=k98Ob!>qs$rrhe+&457IrrL,TrYP[#hYR6R`hh8Hs*t~>
+c2S%"0aJqUf(Vf2#Qc/bn(%F=k98Ob!>qs$rri(mF-Q.ers%>VHZOPIkPG2[hT"a=s*t~>
+])Md)NrKCR@gGEXn"l!+r;R#rPUQkD9"jutrs$dKs7\Mb6KA)r~>
+c2Rgq.K0SS.<AD^#QdW#pXK3Dk98La!?nT.rs8(/&5(gJV2Xm@rs/:_0c1Ho`qTH3#1!8KpGj'_
+j8XW~>
+c2Rgq.K0SS.<AD^#QdW#pXK3Dk98La!?nT.rs8@qF-Q.f`kCj=rs&52KQD4!hYdBXkPtSVN-gfL
+s*t~>
+JcFX-!;G^W#IP]\69,SgHiF$MpUs01#Uu#4qu6k(XoJ,E#W^rFJ,~>
+dJj@#[I=-co*>C@F6D!O!TtWY#Qc0>pZVV^[4)YZ3=m$\rr35t`_$dZ0pMG0rruZ7s7\5b3TL-i~>
+dJj@#[I=-co*>C@F6D!O!TtWY#Qc0>pZVV^eqA+/N-fWRrr35thNWA.KY@-Wrs#"=s7_InN8sqg~>
+JcE^h!p>4JrWim0^&S,hPW9!\;RQ8rrs.Ca6JhaUKXKk?J,~>
+df0L%3?aXeN:dGX&5oXWrrLt"f*DC#V<Ipkmt;Mp&/\<Ys8Ur?3>`T2[J0Ru#MrWVhZ(9B[H%:;~>
+df0L%3?aXeN:dGX&5oXWrrLt"f*DC#V<Ip\n$RNAEsnMhs8VQ$N,s?9f(](A#Oe1In,LtHf&Qd\~>
+JcE[g%d0@/H]6PUs5$or#RH+?qYpfG8e</9s8ViQs*t~>
+e,KX/8dG\WelqbQ!Z70bci3u\eHc1![HRW#n!o&aN7S%/hI@]?(kgcBrs-hI(b)<]s7bOQJ,~>
+e,KX/8dG\WelqbQ!Z70bci3u\eHc1![HRW#n&DcC^$#Fqn"kAPF1(K5rs._OH[Ed4s7bOQJ,~>
+NrK+RZMt-tN$/H<;V(aF#Of'9#RDS`hV\?`~>
+eGfQp1&V@Y0e)l'!YAQ(ci4(@XVfOn!>q?ers%qN.1d=ohY[<Xn$R3J(b&tOhuA3~>
+eGfQp1&V@Y0e)l'!YAQ(ci4(@XVfOn!>q?ers&52HZOP(kPP8apXZHfF*jbPhuA3~>
+JcELb#3UX_#Vh"hqu6oXKII0D>,CE=s*t~>
+ec,[$3V!FW.@fkQrrVA1+jpVs+e7Zo#4IL"&2Ajpqu6oXN%l.m>,C]Es*t~>
+ec,[$3V!FW.@fkQrrVA1+jpVs+e7Zo#4K6PF,[Nqqu6oi[=iUJV8hu\s*t~>
+_uB`2JcG`L"f3%I6FH:[rs/"h64aDGN9C3?s6&A@J,~>
+f)Gd%9(E5h9%Na`rr_`'8eB>T!?nl5rroMJ&5'A!r;R#jX[3jA.?*`prrM<OiW"E~>
+f)Gd%9(E5h9%Na`rr_`'8eB>T!?nl5rrp\pF-P8Mr;R#rcBNZsHbJnIs8VQHs*t~>
+V>gPi[f6@%l2LnL=pSp4r;R#b```oZ+a`)DrrUbLhW"Qc~>
+fDbls3V*LW+f4/t"8D9QhYY:mC]733K`/mlHT;Y^#Qbj5pZ_\\k?8^<n,31jn&AiS(b'ggr;QiL
+;VpF5J,~>
+fDbls3V*LW+f4/t"8D9QhYY:mC]733K`/mlHT;Y^#Qbj5pZ_\\n!nI$p\b$rn(sR]F+gsir;Qi]
+SF>J;J,~>
+`r?&5JcGZJ"5Z?MK`(iThJ48?&5oq)qu6`K+f42uJ,~>
+f`)!/1%PYPA(LD7rsS:tPZh6N&-rOQ#S?h<!"d3W!?oJIrr_+M(khhe#MsMN&/\<Qn,*+deg[`\
+s*t~>
+f`)!/1%PYPA(LD7rsS:tPZh6N&-rOQ#S?h<!"d3W!?oJIrr__SF1(rG#OedAF*jG.p\XslkCh.?
+s*t~>
+WrE(nR/[9WF#i+Vrs.DN3=#mNXloT]"o"6A#ZBO>s*t~>
+g&D*(9(WAj+dD0Nrrr/)CH34C[Kln+n*9oTms@(Orr35[S2hDt3OS&Irrr.]3=o*Fj8XW~>
+g&D*(9(WAj+dD0Nrrr/)CH34C[Kln+n*9oTpU,tKrr35l`f+t[N6^nhrrr/1N,tNXj8XW~>
+JcELb$f9J's6$dn#RE/<hY[<XpWcAB#W\aUj8XW~>
+gA_3:9(`Gk(kh)5rrUJ]0sCoa9&Ak5$f9J's6m@*(`4udhY[<XpWcAJ(ce_mj8XW~>
+gA_3:9(`Gk(kh)5rrUJ]0sCoa9&Ak5$h*9Qs6nO/F*!;RkPP8apZIcfF,\E=j8XW~>
+g]%9JJcG]K!;GdY#do?2CEWs#A%ha=#1e,f#U*^7iW"E~>
+g]%?LKFmh_!BI:CrrVYR0s(]^C\R,o#do?2F"%YDA&eBF#1eH"&1M,GiW"E~>
+g]%?LKFmh_!BI:CrrVYR0s(]^C\R,o#hHEHXa>,9V:PMC#3WCYF*jbPiW"E~>
+JcEIa#Mqcr&-sGekPG2c[8I893OS>Us6%tos*t~>
+g]%;=)"n49F5H!X!mX[\X9\hDXm5okhF]L>(b)lUqYpo1;A]s*[I=.qn(-S"J,~>
+g]%;=)"n49F5H!X!mX[\X9\hDXm5okn!&KHF+i-5qYpoRS9&b1f(]4En)rd3J,~>
+JcEF`"IpVYSEKbK%G#SD#U,/qs5'l).72nQs*t~>
+h#@Dp+nl6C9#fok!PKq]#QYL^lMh!W.4LeMqYq#UHRTLTN:6f'Xa;chhW=cf~>
+h#@Dp+nl6C9#fok!PKq]#QYL^lMh",H\BE-qYq#fXa>,B^%_QqcF&=ikN2_o~>
+ci4">o`"pcJcG`L!o@F6qYq-$V+M")CUN$=N'\Zn#UuVEk5Tr~>
+h>[N43V`p`&2B.,p[nIdp[@_R!QI-t#Q[i[li.%C@se(P&GN;!(`7>%hStLH.1d%FV>'-PJ,~>
+h>[N43V`p`&2B.,p[nIdp[@_R!QI-t#Q[i[li.%TV7$1"&GOJ7F*k%?n(taBHZO7]`qSWqJ,~>
+JcF4!!;GgZ!OZG7rt4+@+UBfUesp5!&-rOrH]2b'k5Tr~>
+h>[J6q$7%"SC[92!oA:#o`"s;8u2doK_Og4!OZ_?rs@P@.2XduespM1rYPbmH^&=/k5Tr~>
+h>[J6q$7%"SC[92!oA:#o`"s;8u2doK_Og4!S4+Ert4_-KQE*ckJj?OHZO7e[Cr^2k5Tr~>
+JcE1Y'CVba#RF=<=pPBF+ZYLps8UrPhWFig~>
+hZ!W>+oV`M&0Y5AcLLo;kG8_=f(K%Dmo#qe!>)*hrtFk'8f/+;CL\1m(b%e1`rH(qV;CA7J,~>
+hZ!W>+oV`M&0Y5AcLLo;kG8_=f(K%Dmo#qe!>)*hrs/;DP]Lo9V5=04#_\/MhZ*WE`p`'iJ,~>
+fDbjFJcFa0!oA8IrWici&-s+>KXL";i;\<~>
+hZ!h>.8!L&Ph,TurrpDG(^MS9p&>'#&>KL33Srs!!oASZrX]>q(`4DgN4&-Ki;\<~>
+hZ!h>.8!L&Ph,TurrpDG(^MS9p&>'#&>KL33Srs!!q3ODrc8='HZOOu^"2Z0s*t~>
+[/U.#TDnocl2Lgm64j)$";!SH[GK^=J,~>
+hZ!\tf&#l_rs#k[&-rOjf(T+EpKF6r!JL43rr]Z$&/bBX";j.X[GK^=J,~>
+hZ!\tf&#l_rs#k[&-rOjf(T+EpKF6r!JL43rrL]8r,W!fN4mg2h#Dm~>
+aSu87JcGBB$La3&#RCtb3J>*/qu6oietlkS;PiR>s*t~>
+aSu>9XWdWK!@c=frrKeETa1Z9SEp1Vn!#:#&-OFBKZ<KXrs/#LX^b7,V<@%AJ,~>
+aSu>9XWdWK!@c=frrKeETa1Z9SEp1^pUtopF*i7m[GLBLrs/;]cD@&$`p`*jJ,~>
+JcE:\#*^8S6@6E7qYpZ\[=g:4#QSZ's*t~>
+aSu:C+oDTH+jTf]!+VW,!BJ`srs"]:.8#9,n,!%en$S*/)#Y!GF6ERR~>
+aSu:C+oDTH+jTf]!+VW,!BJ`srs$/`H^(qhp\Omln(+n*r,Vk?kPp&~>
+JcE:\"Qu#hhY6mH%,S*a+V4nj;HcBu.D=sFJ,~>
+ao;Cu+o2HEPkY1YeiB<-!.4&3"Qu#phY6mH"5^F`.K1.f;HcC(0uiGWJ,~>
+ao;Cu+o2HEPkY1YeiB<-!.4&3"Rj%\n+Z\Y%.DK3KQD3]S>DHkK\kqmJ,~>
+^]+<.JcGBB&GP@q;BZ;O+[U7is8V7K+gpP6J,~>
+b5VM2>58F)>5.gl!R;j[#QZ+"jSoeckI"2:(`4\gHcH*cmn,%:kl6/~>
+b5VM2>58F)>5.gl!R;j[#QZ+"jSoecn(+"^F*!#![GLr`n!&LVkl6/~>
+bPqS:JcG$8"R!1G66Z=6![3fbrVluN3?bfos*t~>
+bPqY<PSj3%!>+GhrrKeVSHo6okNDjJn$Rg@.K0k[.?r]frr^h4.CJC>J,~>
+bPqY<PSj3%!>+GhrrKeVSHo6okNDjJn(+n2HiA'fKY?jQrr_GCHe.E\J,~>
+[f6@%Jc>iP`a^1k#Rqqu+V:1<s8V888dIH.kl6/~>
+bPqV"1%tqRSGE0cpPbUJ!?nl7rtEC^.2WU-.=3K\V>(#imt=:M3S*EoJ,~>
+bPqV"1%tqRSGE0cpPbUJ!?nl7rrV&RK`6#qKWTTJ`r>uAn%Fs,N9BF)J,~>
+JcE.X'=AAW#XWUXs7]CsA'Uod+UAW&Pir's~>
+bPqQXp':Y_q#:>IRg9$ekN`'I[Jh!R6@7#XpJMQ<cE2.:(_A-\kPp&~>
+bPqQXp':Y_q#:>IRg9$ekN`'\epDIZPdTBJpRH<,kK^2VF*iSRkPp&~>
+[f6@%K)Z#23=n3(kPbDfPR&*T(^LC6CW>i+s*t~>
+bl7^W)#"::9'?$M!V^Z(#QV9urrq7G(d`o=rVm4p&0WbO&/[`T`p`*jJ,~>
+bl7^W)#"::9'?$M!V^Z(#QV9urrqkMH]5B$rVm5EF*iReF*!SJhY645J,~>
+c2Re<Jc>`Em/I0a+X+8jrs71!#RCu.N8F$bs*t~>
+c2Rh=HhRdH(p3Q4!Nd3.#Q[itm/I0a.4M\%rs71)&.f[NN8F$bs*t~>
+c2Rh=HhRdH(p3Q4!Nd3.#Q[itm/I1-H\BuIrs7e7F)u\m^$k^Ws*t~>
+JcE1Y#,N.c[HH`0rVm"I.;R5tir=N~>
+c2Rgi.JF)K>4;4c!QHRX#QYLEm/I9l+YgCnn)"$C"GALFcL9cmJ,~>
+c2Rgi.JF)K>4;4c!QHRX#QYLEm/I15H\BuLn,<7h[=k[FpYu4'~>
+JcE1Y#ObOr3GVMZf)G^LhV\?`~>
+c2Rd.pBUd2XnMbqk>I`S!D;hJrs/!j&41/19%O"As5)Z5J,~>
+c2Rd.pBUd2XnMbqk>I`S!D;hJrs/:gF,[5kPir&Gs6nkFJ,~>
+JcE.X!2]W"!>)Bes*t~>
+cMmq69(rSl;Xa;Y!/-dH!?nT3rrJr5r=At2gAc[~>
+cMmq69(rSl;Xa;Y!/-dH!?nT3rrC(;ErgX5gAc[~>
+JcE.X#5>N88n59lgAc[~>
+jSo7Fn*U,UehQn)!0$RM!T#8o#Q\H(mJdCb[;/BM[HH9DJ,~>
+jSo7Fn*U,UehQn)!0$RM!T#8o#Q\H(m/I7?V3J+5n(Rel~>
+JcCN*J,~>
+jo5DF3Tof0!OWL6#QZ+;oD\in&=Wq+.Fu96J,~>
+jo5DF3Tof0!OWL6#QZ+;oD\in&=Wq+.Fu96J,~>
+j8T,RiVroPJcEdjJ,~>
+jo5CiA,#Bj!0m3`!F#6hrrVY)&=Wq*N5,CC~>
+jo5CiA,#Bj!0m3`!F#6hrrVY)&=Wq*N5,CC~>
+j8T,RJcFs6!;F;/J,~>
+k5PPP;IfIgrr?j/#QThRrrVY1+e/f=9)$.$J,~>
+k5PPP;IfIgrr?j/#QThRrrVY1+e/f=9)$.$J,~>
+JcCN*J,~>
+k5PM..9c*<!$V+C!>riGrrVYk.@^YD[D;fm~>
+k5PM..9c*<!$V+C!>riGrrVYk.@^YD[D;fm~>
+JcEgk!;F>0J,~>
+k5PL0#[6Tp!$V+C!BK$)rrL,;SHo7;pVHl[~>
+k5PL0#[6Tp!$V+C!BK$)rrL,;SHo7;pVHl[~>
+kPkPVhZ!TMmJd1\JcFL)J,~>
+kPkYY3=&gTrr=5;#Q\H0mJd:_N%#=2#QZC*_>f#~>
+kPkYY3=&gTrr=5;#Q\H0mJd:_N%#=2#QZC*_>f#~>
+JcCN*J,~>
+kPkY(#RFW#rr=5<#QYdElMgqBPVJj;!>qZLs*t~>
+kPkY(#RFW#rr=5<#QYdElMgqBPVJj;!>qZLs*t~>
+JcEdj!;FA1J,~>
+kPkX*#RFW#rr=5<#QZ*gkl1_8N%q%4!H\"Ps*t~>
+kPkX*#RFW#rr=5<#QZ*gkl1_8N%q%4!H\"Ps*t~>
+`;]i3JcE^hJ,~>
+kl1e2+UA?Wm/I&/q$7!npZDJYkEI,,&>f^6.HeSJJ,~>
+kl1e2+UA?Wm/I&/q$7!npZDJYkEI,,&>f^6.HeSJJ,~>
+JcCN*J,~>
+kl1df+UA?Om/I&/q$6t9ir9+oN(Oqc#QZ*g_Z,,~>
+kl1df+UA?Om/I&/q$6t9ir9+oN(Oqc#QZ*g_Z,,~>
+l2LbX^&J*,Jc>cNkPVIKs*t~>
+l2LeYHi=9O+m87m!$V.D!4Cec"S_)m;CSRN!0#b6!q37nrjD+mJ,~>
+l2LeYHi=9O+m87m!$V.D!4Cec"S_)m;CSRN!0#b6!UnV<cKtR]~>
+U&P,eM#RYA[>[F4.Js_XK]he'J,~>
+l2LeI9)T"qkO&9L+o2HF3Ubi)"o$m!KK13X#QQ=5rrql!PX7Abr"oHfn*^4+~>
+l2LeI9)T"qkO&9L+o2HF3Ubi)"o$m!KK13X#QQ=5rrqlB]p+J/r-JIPn*^4+~>
+JcEai!;GdY"5^GU^&J$4c7/_urZMG38g+b)n*g:,~>
+l2Lasr!3;)mJd/@q?R(cg&D3D`d:<$YQt7@pZhb\hR/lnrr3#E1&_a`.K<!B.2\$4n,In~>
+l2Lasr!3;)mJd/@q?R(cg&D3D`d:<$YQt7@pZhb\n(,M8rr3#^K`6#uH\@':P^@bjp[A-4~>
+JcDqR"Q!<*#]'G>%GjDW;KJtR^"2%M#X[D:s*t~>
+l2La1r!3:4mJd3W)#OX?+jS[="6[[N9!JX%Xm>uihHD?FC]=>ChF\V_HaUl5hVN#b6Jh22J,~>
+l2La1r!3:4mJd3W)#OX?+jS[="6[[N9!JX%Xm>uin!n`GXoA>0n!%m`Xj5e[kO56gPje)@J,~>
+R/[0\Rf<QJ;@!gWF8c+@@gGuqrVm#pKEsp$n,In~>
+l2L`]r!3<HcL1];mt;hi#S:e7e,KRFn#^(CZj6Yrm/I7G;@jZoHi<sHCD]t4rVm#pKFgK,n,In~>
+l2L`]r!3<HcL1];mt;hi#S:e7e,KRFn#^(CZj6Yrm/I7PS9'%1Xo88%V/r0qr;Ql,F-Q.^s*t~>
+c2Re<rVlllJcGcM!;Gm\"f3@ZK\#>brsWBC;Wn)[kIm*H#ZBjSs*t~>
+lMgnJ&Gue7&>edo"o#,s3MlJqrrU2](q'\NA,#Bj"g'3sN7R1jrsWZ[;Wn)[kJi`Y(fKPcs*t~>
+lMgnJ&Gue7&>edo"o#,s3MlJqrrU2](q'\NA,#Bj"jVIA^$"k_rsY`FSF?LXn(u'KF.D^fs*t~>
+ao;A8bl7\;T`5/hHO)t$r;R6#PR'V=s8TJ]&-t"up[A-4~>
+lMgk0q?R(2li.%LhY57o!r%oj[g3!phX:CHpNm`Dn,31ppQQ4]kPtRq0c1`^[J0.iJ,~>
+lMgk0q?R(2li.%LhY57o!r%oj[g3!phX:CHpU,(,n,31ppUtX4n,NF=N,s'!f(\Y5J,~>
+JcDtS'q?F%[GKK2F)+r&#RIj<s7\5k.F.\Us*t~>
+lMgj2q?R*F`j>[Gmn1%p!AWHurtV%Q0t#lpX`JPe.2Wo0s8VgJ.5B-Bmf.e~>
+lMgj2q?R*F`j>[Gmn1%p!AWHurtWP#N7RI\cE44FHZO8Zs8VhPKS8O_mf.e~>
+JcDtS!T$0B#QPG6#QbPlf)G[NXkrg=s*t~>
+lMgj"q$6t1Zi:'>+h%^X&=i.f%GjD_&/Yrq&.fZi&2Dc8rrT=Zp[%p1~>
+lMgj"q$6t1Zi:'>+h%^X&=i.f!Ul9JErp]IkPkJ_cL:Mos*t~>
+JcDqR!OXre#R<@V8pdD:`qSWqJ,~>
+li."B3V`p](tQ+p!QHk%#QUC]rsZ:q&.f[F8kOc=Xj6\'s*t~>
+li."B3V`p](tQ+p!QHk%#QUC]rrL]0rc8='Pa&T$f&$/`s*t~>
+hu<]NJcF-t#Mukr^$"kQpYu4'~>
+li."2+nu<DF8*0D!T$GU#QU+Trs.Dg[Ctbln+YiAJ,~>
+li."2+nu<DF8*0D!T$GU#QU+TrrDNeec>1<pYu4'~>
+JcDAB"8D!Ap[/!2~>
+li.!f)#+@;&=g60!q36?[0Qe:n(n!GpZL`6mJh\~>
+li.!f)#+@;&=g60!q36?[0Qe:n(n!Gp[@SFmJh\~>
+JcDYJ%Hjj`V4=BPV0c*4F1(c2s*t~>
+li-s+p':[ZcF3`R]fEM,!D;P:rseG!S?8<`S>Cm:;L>hGn,In~>
+li-s+p':[ZcF3`R]fEM,!D;P:rseGJ`m2TL`l>EVS@-rBn,In~>
+h>[KLJcF0u#1e,M.5;tpq%3Q3!tZ;rp[J35~>
+li-s+o`tRQpU:)'kA(pE#QZsKli.":K`3\,.5CT7rt#5TK_P!9J,~>
+li-s+o`tRQpU:)'kA(pE#QZsKli.FW[=j3lKS4DnF*htTHi8!eHaWV;s*t~>
+m/I([JcE[g!QIb1#S/(5.60+30g]Yk@r"C:&A@T5J,~>
+m/I+\C\.l5K^ZAL!q367\Hi4.kNr3M`_%*I&-F@90ff4f#YJlRCMQNZ&A@T5J,~>
+m/I+\C\.l5K^ZAL!q367\Hi4.kNr3LhN[t[%ss7gN/WFKPc_'aXd!mRf'r]i~>
+O8f4SUAkJe@gG)AH\A6n`W=B9rVluF63sFWs*t~>
+m/I+C1%Y_Q&;9M\rrVr.9"G9/3Tof0"7L":3W=[:V8gg+`m2ldrVluF65Zios*t~>
+m/I+C1%Y_Q&;9M\rrVr.9"G9/3Tof0"8AX5N;g3b`r+]nkPbD_kEL&5nGe"~>
+gA_0IJcF@%"4d_`^&Id#s8VfqhEhLEnGe"~>
+m/I+;+nGs@&:=/ZrrVY!&A&2J[I*treeet3rqH0es7ZWP8f4]"s*t~>
+m/I+;+nGs@&:=/ZrrVY!&A&2J[I*ttkAt^qp\4C]s7ZWaP]P.>s*t~>
+g&D'H[Jp7$V>gYK&.#]ArrVZ7^&>qT]o7#J&.lPEs*t~>
+m/I+;+n5g=HhXrJ!r&f?]EeM>mJd:>(`9[YrseGB`l?<DcFo0`Eu5b6nGe"~>
+m/I+;+n5g=HhXrJ!r&f?]EeM>mJd:OHZRd9rrMlWr8%Y/]sXt`Hf"8lJ,~>
+MuNeOVZ.G#=pR-(CL_-q@js,]0ek+#&-rOQHggJ(J,~>
+m/I+;+n5g>(jk_ZrrVr.;S<>9XmQ,pmpcnhF),Q4CMWf%"t:B+&/]c_nGe"~>
+m/I+;+n5g>(jk_ZrrVr.;S<>9XmQ,jpRH;`r2g4#KT(SCN.cl`Erp]rp[J35~>
+f)GaEJcFI(!nKsTr<W62"sG]M0g_`"n,In~>
+m/I*V&F]r-&5(gR[Jp<k=qJFS!3PVf#1cB`(_@MqqA92]r\4IHXlo0QJ,~>
+m/I*V&F]r-&5(gR[Jp<k=qJFS!3PVf!p>epr,_mb$?LQ@F*ik!N0MWVn,In~>
+JcDkP%Gm%A8kN9OV59]YV4>Qis*t~>
+m/I'=m0Eb:Pjc!Z!NdN\#QV!mrs%>=;Gp+sSGo>eXehl6l2Q8~>
+m/I'=m0Eb:Pjc!Z!NdN\#QV!mrrqT!S<T87rPerb`l?m"s*t~>
+e,KFB[f6@%VuHbkrT=1Tir=N~>
+m/I'=lj*\19"ju-rrVr.9#1c5Xm5oipZM#.n+YiAJ,~>
+m/I'=lj*\19"ju-rrVr.9#1c5Xm5odp\jR>s*t~>
+JcDnQ!:TU\"8D!QpZqj0~>
+m/I'4l3IJ/>.*h-rrUbm&AnbRXmH&fn+H\_p[@kNli2J~>
+m/I'4l3IJ/>.*h-rrUbm&AnbRXmH&fp[nIdn+Z,IJ,~>
+JcDnQ!K=_crr]Z4>1W$>J,~>
+m/I'=kQh8%;Q\6QrrJr>`!?@Fm/I*F`qKE7[9@(kli2J~>
+m/I'=kQh8%;Q\6QrrJr>`!?@Fm/I+"hY-sOesrT"li2J~>
+bPqS:JcFm4!r$27pQPlPHOqX>p[@tQo`'F~>
+m/I'=jTku<N2>D*\c2]D9#V&9XmQ,ipLA"4S-=Q_0uitVqY0X^J,~>
+m/I'=jTku<N2>D*\c2]D9#V&9XmH)fV=qn3[<mS`s7uE]s*t~>
+WrE4rs7cQfMuNhP;YCY5(_?ra+Xnip+Yb,p+XpU.p\4]<~>
+m/I'4is5_u+YeZLPQTM*hQ?O:'".2skO7m&n*fH.n)s06s7cQfh>[N=9#_,:XmQ,ipJMRs(^)!!
+(_A.q0aK3_.5<8+>/p=2s*t~>
+m/I'4is5_u+YeZLPQTM*hQ?O:'".2skO7m&n*fH.n)s06s7cQfh>[N=9#_,:XmH&uS9'$uHZOOT
+HZOOTH[BgTre(Q9KT(SCKS5lHpA]X~>
+UAk5fNrK,X+o"&&0f^B_#UqJOq$7!M[J0]O~>
+m/I'=g^!ru+X-Ob!"efH!AT9+N!$c=f(\,&!p=&:a9VdJm/I)a.J>b*.2WmV0e)o0!AV"Vs*t~>
+m/I'=g^!ru+X-Ob!"efH!AT9+N!$c=f(\,&!p=&:a9VdJm/I*VK_C?.HZO7]N-kAA!K>V(s*t~>
+JcGcM!;Ef!'DH"$cGn/T`m2lLcGn.V&1OI$V>GoKHSGe0kP5(-~>
+m/I'=]*JTa.620jcL9cm!V^BN#QV!orri(3Pg7;Fc4\.BKGZG?cD?JYKT(kCKJ=$Jn+cp5~>
+m/I'=]*JTa.620jcL9cm!V^BN#QV!nruIrLkMGCbhWO(YkMGC0H\BE%`kB'n]tLh]N,tNXq#>j~>
+SGrT`PlCclf(T+TS.IF#s8Vinp](!fpOif4f(f8q~>
+m/I'4[Km!Q8pg%$jSo8;9$%>=XmH&g[GLWW&=aRlcN!q=s7cQfs7_H`3S+!*J,~>
+m/I'4[Km!Q8pg%$jSo8;9$%>=XmH&gf&uc,&B8dMkPtSVs7cQfs7a3JN9C!9J,~>
+JcDGD".UMh`qo`8pB,aJ3S+!*J,~>
+m/I'=ZNpXV>-6uLrrMR\b6S+lcJSX(S1-2<qZ$Ti"+(S>f(f8q~>
+m/I'=ZNpXV>-6uLrrMR\b6S+lcJSX(`d<[$qZ$Ti"1<3/kP5(-~>
+R/[0\MuNn1V6/qXrs$bY@j)+fn+cp5~>
+m/I'=Ym:FT8u;:ErrKeVbQn5AkMQ:AhPI@Cqu6lGCL\e1C[_&uJ,~>
+m/I'=Ym:FT8u;:ErrKeVbQn5AkMQ:AkJl*Aqu6l`V58idXnVVjJ,~>
+JcGZJ!;E&a"gnUA&37Gus*t~>
+m/I'4Y6Y4A;RPuWrrVqZ&BtI]3Tnrm"gnmQ(cfV1s*t~>
+m/I'4Y6Y4A;RPuWrrVqZ&BtI]3Tnrm!7q-j!K>V(s*t~>
+JcDkPrT=1TnG`X2;HfUApA]X~>
+m/I'=X9\l"XmbNS!Tu2^#Q[Q\li.+VkO7U.nG`X:;HfUApA]X~>
+m/I'=X9\l"XmbNS!Tu2^#Q[Q\li6qP!;H!_"Q#ZF`om'qJ,~>
+JcDnQ!T%ns;?2(BV#e:(p&>'Up[nK9~>
+m/I+"(p!uE&9H^mrrA;.#QZsKm/I+CF8f>IH_mj@XhFK%rrMT_o`'F~>
+m/I+"(p!uE&9H^mrrA;.#QZsKm/I+TXo=gp[DpM3cIVa_rrMT_o`'F~>
+OoGFUT`5&L;Z-k$&H3LJ&0We-3<`$>V6-T%rpL!an,K5lp]#a~>
+m/I+;+fYeL3N`&ArrM:Cc3OE/m/I.D=r@5M!#Y\Y!Z3@@r](!WPl@cb[JoUtp[A-a[J0]O~>
+m/I+;+fYeL3N`&ArrM:Cc3OE/m/I+TSGdO,HN8`tMuf0VrltMpr:^9mcIVaiJ,~>
+JcDtS$1DX80j8's>$<Z[.0(Od#lQac6B$TKp]#a~>
+m/I+;+fP_K&;9N<rrA;/#QUC^rr__*(btu!!*]=U!%IgW$Q'Ed(caTC3D,6hf(]2p~>
+m/I+;+fP_K&;9N<rrA;/#QUC^rri(uF,ZXgV#d*FrIjrerJUiC]tNV's*t~>
+O8f4SU]1GZP\[,orrMT6rk/<6rGr-X.2X3F)#OX?1"Q+!J,~>
+m/I+;+fGYJ&;9fErrL+_cj0X`V="9bkEL%irVloecMkf`Xo3STCG?t]+X%C.(_@65f(]2p~>
+m/I+;+fGYJ&;9fErrL+_cj0X`V="9bn%GjKrVlomkPj<FcF'd^Xf[8'H\?bDErh6_p]#a~>
+JcDqR!r(mPp](9^s7ZrjhVQi?[9=+Q@rjufp]#a~>
+m/I+L8uDpq&;9EM!U!)%#QZC2m/I.]n+ZSVs6p!^%.E'0f&!f<(`6b09%Nb:J,~>
+m/I+L8uDpq&;9EM!U!)%#QZC2m/I.]n+ZSVr:g6[$0Ud.S9oUZ[?TkKs*t~>
+JcD,;"e6`6s8V9Us*t~>
+li-s+V?d57HggD&!UjgN#QZsKec,fC.8p3Gn+Qd3~>
+li-s+V?d57HggD&!UjgN#QZsKec,fmH^t-9n+Qd3~>
+m/I([JcE^h!Ul9PEs%rXf(\e9!khKQoDa=~>
+m/I+\H_guK+gp_;!L+/C#Q[Qdm/I+TPl?"3SBf^[oD\m3;LA$8J,~>
+m/I+\H_guK+gp_;!L+/C#Q[Qdm/I+\^&G,9`olOZoD\mCS@.tgJ,~>
+JcDtS!Ul!G#RM%c3Eg4+hWOq5q#:BOkO\_(~>
+li.!^(o7K=1$A!)!Ls_K#QThMrt"RW(`3f$(b%ITF1'lfs7c<g!T*;:s*t~>
+li.!^(o7K=1$A!)!Ls_K#QThMrrMl-rGr9lKT)b0f'i)-p\=dgn+6R0~>
+JcDtS#c/[]@s^O/+V=SX#pEeoXhE<SkG>l\s*t~>
+li."2+f#ADN:-]Heeld?!4D1n$*>X"@s^O/.1d?q&.'dqF03I=n*d*mn,In~>
+li."2+f#ADN:-]Heeld?!4D1n#gRdDV6uPPH[G^4$%&MNf&#Tan&F5Qs*t~>
+JcEai!;Gm\%.A6C6Ke++hQ<Vq;F:<f"rJLM>'!$,n,In~>
+li.":0r,'U1$A!)!$Tbr!>tRurseF<&45j[kMEVCHW!HQrX]8W.8")k9!.R^J,~>
+li.":0r,'U1$A!)!$Tbr!>tRurs\Y0F-Q.fn)r!9[@EK[F8pRiPbkLHcL:d`~>
+JcE"T"SZ[;9)&8`#k-s5[C'1).1lIa!BJa"s*t~>
+lMgioUBgjQmf*81dKfh-m/I4_CD]\<r;R5pkMEVS@nJHe(_@NNf'iWh~>
+lMgioUBgjQmf*81dKfh-m/I4_X`Ka$r;R#rn*eiYV3HZ3Erh6_n,In~>
+JcDtS#c/[UCTY#$hXC=@#3W[Q;G(-Ln,In~>
+lMgjCUBgl\hXCIE+jpVrN9gKLXXP*.XgR$Bn,!%gn%FZX8m:*?s*t~>
+lMgjCUBgl\hXCIE+jpVrN9gKLc?jo?f%0<Yp\Omon(,1BPbmj;s*t~>
+JcE"T!r&2rrWi]>6<\/pV=46[!pA/'n,In~>
+lMgk@UBgl;Xmc8i+k$\t&?Y=!%/68/(_@5q6<\H,V=46[!q4_/n,In~>
+lMgk@UBgl;Xmc8i+k$\t&?Y=!!r']]rGr.,S?9fVp\Fgjn)sH6s*t~>
+M>mSMWrE7).1f*]+oVcI&-j@5>*Pl7p\3tQJ,~>
+lMgnR+eo;DK_P!9!$Tes!@cmlrt;Fg&5m!e(`3f$(b%1CS?:ZBpZhd/~>
+lMgnR+eo;DK_P!9!$Tes!@cmlrrp]$F-NMSrcA'c"cStkcKFrds*t~>
+JcE%U%/4fK6LXs2c@ft2.4P3$"<f3t[I<J^J,~>
+l2La!UBglDn+$DYmig-c!D;hJrtY9L(eX8shTh($;DBmC&.f[-0j;!Rm/MS~>
+l2La!UBglDn+$DYmig-c!D;hIrsPrMPkY4@kIn!fKS9;F"FGfuf(\P2J,~>
+JcE%U"8?jB>5S=-hT!6UHU8l!#RG57m/MS~>
+l2LakUBglDkOJQQXUrqe!0ljM"8?jJ>5S=-hT!Q^HU9/1&.iXGm/MS~>
+l2LakUBglDkOJQQXUrqe!0lgL!j-O6qu7&mhVPZJP_=C)F053's*t~>
+JcE%U#krBG+e8#qs7cHk#4LF"[=iUcli2J~>
+l2Le0&>TR4(uFf_!Ls_N#QZ*gm/I@cEtBdsn+ZkVr;QuihVPZ!F.DRrJ,~>
+l2Le0&>TR4(uFf_!Ls_N#QZ*gli.3lF*kq$p](!crs&5dkLR>K`p<YT~>
+l2LbXJcEpn!q0V1r<NU;H^rC4n*f?;J,~>
+l2LeY>,)?'K^o'CS.P;u";iRB0d5Zb!E/CQrseF4(`3eq(h85hcIVIYjSs`~>
+l2LeY>,)?'K^o'CS.P;u";iRB0d5Zb!E/CQrrVqkHi8!iV7">+kP+`3s*t~>
+l2LbXP5bOV]Di&c3HIeQ+oV`P&1KVLH_nFEkPp&~>
+l2LhZPRsVr!/0qC!V^C&#QbiH^&Hjic>t/m#QV9urrpt?F%SbJrX];O0fa#rXiBhms*t~>
+l2LhZPRsVr!/0qC!V^C&#QbiH^&Hjic>t/m#QV9urrqSE[?QVsrc8<kKT)b8cJJ<Ys*t~>
+JcFg2!;Fk?s-s>_hVPZ:F"nj:#R;1q;Hf%9hXBh2J,~>
+kl1\H0r,'TK_#-Dk=YFR![4E/r;Qim`ZaUQ!>t:ks8ST&n(up/V/n@?(_@5q+Ycl)N8EF[m/MS~>
+kl1\H0r,'TK_#-Dk=YFR![4E/r;Qim`ZaUQ!>t:ks8U(Dp[@S%`jLbPrGr3jKUemPn*g#;s*t~>
+JcD_L#M,`9;F2fL&H2q9&6eH#J,~>
+kPkNlU^-sRo)Aa(+nl6C;WmiT!0$1K!0#n:%+_PF;G&Ye(`3eq(g?;+J,~>
+kPkNlU^-sRo)Aa(+nl6C;WmiT!0$1K!0#n:#NsCGS<S\RHi8!cSF$9+~>
+JcE"T!RBQsrsAG_`heo'=qCs"m/MS~>
+kPkOiU^-sRo)A]lpBUdCcM.>>mo&KX!>*iHrrLF%q#:Zpn&D2g>$;aS3UHcr~>
+kPkOiU^-sRo)A]lpBUdCcM.>>mo&KX!>*iHrrM<Oq#:Zpn(u@'S=FqIN9pRp~>
+kPkPVM#RJLaSuLY;COUmN6^nerrr/[kK[Ram/MS~>
+kPkSW0r5-UN:[&MmooGk!N#ParrJr-m0E_jn*BuY`_nNO8rV'aq#:NlkNC-+K^A_h~>
+kPkSW0r5-UN:[&MmooGk!N#ParrJr-m0E_jn*BuYhOK7XPeH8Sq#:Nln*fG9[I!pD~>
+JcE+W$cY14&0V;b(cdhokP+uWV4?oPJ,~>
+k5PFXV?d2>cL_&:k:-03!Ft<crrL\2mK`h:[Hmi#c8cFQ.2WmF6BoLYp\t8rSF$9+~>
+k5PFXV?d2>cL_&:k:-03!Ft<crrL\2mK`h:[Hmi#hMcN&HZO7TN4n*:p\t9>`pE_U~>
+JcE+W%"nm0Pbi^]&-rOjCVBNC!Uo4<s*t~>
+k5PJ=3N!,`+m8Is!58.5!BK$/rrM:dmK`hcn*Bu^KFfT&V0ap6(_AE;`q]T6n*L()~>
+k5PJ=3N!,`+m8Is!58.5!BK$/rrM:dmK`hcn*Bu^[<$]7cF&UXF*!#:hY@*Op[@JKJ,~>
+JcE.X%duC`F8,_'eua!:#RF&Zir=N~>
+jo5@?&?#j8)!CMj!0$^Z!>)[0rr@`?#QV!mrsnKX&:=0On(t0n.1d=ghW"Qc~>
+jo5@?&?#j8)!CMj!0$^Z!>)[0rr@`?#QV!mrsnd^F05KBpZL,0HZO7mn)F@t~>
+M>mSMXoANW#[6*ZrVm5]N%#$cp]%(:V<@(BJ,~>
+jo5AE8uN!rF8,>,!TtX%#QS&urrA#H#QS&mrre8l>2K#PrsIVA0c5T<s/gXEkNMqr~>
+jo5AE8uN!rF8,>,!TtX%#QS&urrA#H#QS&mrrf`NV=40WrsJ5.KQFQqs3A$ln*'e%~>
+JcE.X#KBXI#XWmGf)G[VpNm04hY2's&6dBDs*t~>
+jSo4MW<`MAV=X]fV%EG.!1`TZ!0$CQ!>)[(rs-PA&.hH\[GLo_$MSla9&B;`(`6H%l2Q8~>
+jSo4MW<`MAV=X]fV%EG.!1`TZ!0$CQ!>)[(rs.DNF*!SRf'!#3$+4i=n+Wr*H^s9`s*t~>
+JcGZJ!;H!_!;Fe=(@PaK.1caj+[U8$kN?"SC[_#*3=#n3l2Q8~>
+jSo8L+fYeK+jT`[!V^+!#QUClrr`"lHggk3!JD$S#Q[Qdli.ahCND3I(_A,_He.ZS=qGK<pUrR(
+&9I+9J,~>
+jSo8L+fYeK+jT`[!V^+!#QUClrr`"lHggk3!JD$S#Q[Qdli.apV6,DtF)u\mXlo0AS9(h,pXY:E
+F04^,J,~>
+JcE1Y&)LLQs1O(X+V4nb.7+:GPl:UaKEqk?lMlA~>
+j8T+UWX&W'n+?V\c8#)"!3Q2!"f3pZ#V"@&rr@`B#QZC*lMh+G>4;L2KM!]m&-O^S(`8M9rr\2k
+(uFQXJ,~>
+j8T+UWX&W'n+?V\c8#)"!3Q2!"f3pZ#V"@&rr@`B#QZC*lMhC`SF?L7]p*kjF*!#!F*#A"rr]ZM
+F78DoJ,~>
+JcG]K!;GdY!;G"C!q2AMrVm#`[=hEhrWiQBKY@Bb"2+sGhWk,k~>
+j8T/C8ur:!&?YU)!r%?Zq$7!UhYmHTefjtt!K?dPrrM:dnH],AlMgqSS?;bi$KngM;A^5^&0Z_H
+rr3)6&/a9hs*t~>
+j8T/C8ur:!&?YU)!r%?Zq$7!UhYmHTefjtt!K?dPrrM:dnH],AlMgq[`m4P_"RjpLS9t6V!dh?+
+rr3)OF*$g8s*t~>
+j8T,RJcF=$!nL8Wqu73$hR-6)#RCtr>+E90#U/'is*t~>
+j8T2T[3=`>!>lBh#QZ+*o`"sT+nu<D1$AN8!MpA+#Q[Q\rr3#U3V!FV3To]-!o?h_qu73$hR-61
+&.f[5>,B5K&1QK$s*t~>
+j8T2T[3=`>!>lBh#QZ+*o`"sT+nu<D1$AN8!MpA+#Q[Q\rr3#U3V!FV3To]-!p?*)qu73$kLQ/M
+F)u\eSAsE^F*mB@s*t~>
+JcE4Z"f2JJK\#norrh2l8hh1]#QYcql2Q8~>
+ir9&JF6Nr4Hfq4KaTqm"oD\g(pBUdSkPbD]N"Gpn!@cn)rrK55o*>@6Xm,ihV&1Y7f(]%@"Q$gi
+0d6N-!Z3)6l2Q8~>
+ir9&JF6Nr4Hfq4KaTqm"oD\g(pBUdSkPbD]N"Gpn!@cn)rrK55o*>@6Xm,ih`cHg@kP+iQ"Rjp+
+N-kME!IM6=s*t~>
+JcFa0!;G.G#k)77#RDl+[HIAc#M,_T.1f[QkNW"s~>
+iVrr0+mTC:(tS`eKZXQ$+n,('!UiYT#QZ[CrVlo+)#OXBXoJFqF7KS:F6W]1mpd1O&2AjGn+ltg
+etlk2(g<Hul2Q8~>
+iVrr0+mTC:(tS`eKZXQ$+n,('!UiYT#QZ[CrVlo+)#OXBXoJFqF7KS:F6W]1pSE4XF+gsPn+ltg
+kJj?OH^r+El2Q8~>
+aSu87`r?&5Y5\gJ;RL9O#S8._Xn_nukLR?'kPp&~>
+i;We9lNdYCp](9M;ToCJ(o@!!rrKMEpBUdSkPbD]mihW8"W4rQs6hu>#QZ*ol2Lk*;RL<>(]l-i
+Xn_nukLRZ0kPp&~>
+i;We9lNdYCp](9M;ToCJ(o@!!rrKMEpBUdSkPbD]mihW8"W4rQs6hu>#QZ*ol2M(HSCXf`F*iS:
+cM7DAn)rQrkPp&~>
+i;WfOJcFI(%I`K[s5'84&-rP6[FY*/s*t~>
+i;WlQHP#QM!?pY*rrLt:bm4>Rn+?V\mo&ib!@cn'rrl"#+`h/$rr2tgnd#5Skl:\Os8N/WS3m2l
+"%ouPpYPq#~>
+i;WlQHP#QM!?pY*rrLt:bm4>Rn+?V\mo&ib!@cn'rrl"#+`h/$rr2tgnd#5Skl2+dn,NFV`ftgk
+F-P8=pYPq#~>
+`;]i3U&P,edJjO0PY)Jm(da2,n)44r~>
+hu<`69'cf`[Jp1-pU)0j#QZ*goD\if)"n49&?Ym1"19:$kPbD]pIb#_!BK#rrs@PP8f/Bg8rV'a
+i;\<~>
+hu<`69'cf`[Jp1-pU)0j#QZ*goD\if)"n49&?Ym1"19:$kPbD]pIb#_!BK#rrsA/6P]LnmPeH8S
+i;\<~>
+JcE"T$2<;@=pPBF3ICMZs*t~>
+hZ!W%+mfO8C]+25PShaQ!.4>;!UiYQ#QUClrrU31n,<7eXUt+1!>)*crsAGVS6?a@&35F<iW"E~>
+hZ!W%+mfO8C]+25PShaQ!.4>;!UiYQ#QUClrrU31n,<7eXUt+1!>)*crr`#a`hiZU!fXP]iW"E~>
+O8f4ST`5DFCEWrh+`"LKn"nn(s*t~>
+h>[M?&FKf)+jU#c!NdNn#Q]#@oD\j!&G-5/>4;1b!T$H?#QTh<rsR+n.2WUFCUNX"Xkr7@J,~>
+h>[M?&FKf)+jU#c!NdNn#Q]#@oD\j!&G-5/>4;1b!T$H?#QTh<rsS"lKQD3fXk)t8cL9rrJ,~>
+h>[KLVZ-YjXoAas]k]V6#U*Au>5.4[J,~>
+h>[QNKGa+_!/17L!NdNp#QZ[2oD\jc9(E5gF6E;t!Ls_n#Q\,cgA_NK]k]qO&1M+9>5.4[J,~>
+h>[QNKGa+_!/17L!NdNp#QZ[2oD\jc9(E5gF6E;t!Ls_n#Q\,cgA_NSeuamPF*jakSG24HJ,~>
+_#FE/Yl=^tcN!n#!:TU\#Nsrs.0q(hPii!r~>
+h#@ED9'urc9'?-P!r&N.ed):"cLUu9[1Mm7!YB/Aq>UK8.J*lH3ToT*rn[YDp&>9chLmTp.8$,m
+s*t~>
+h#@ED9'urc9'?-P!r&N.ed):"cLUu9[1Mm7!YB/Aq>UK8.J*lH3ToT*s6g!Op\"Rdmfg+PF+fdt
+k5Tr~>
+`W#r4r;QckJcGcM#Nq$p#S:1IkOecVXW\7Gjo9i~>
+g]%<21%#;JA,#p$!r&fGf*DAHo)AaR9(*#cV>C2m`[UNc!>r6.rs/"O0c1I*[I<bf"19QpSE9d$~>
+g]%<21%#;JA,#p$!r&fGf*DAHo)AaR9(*#cV>C2m`[UNc!>r6.rs/#+KQD42f'i82"3uRH`o[5N~>
+KDtrG]Dhnr&H)k9&:<"'rs%?Ks5$'RV<.`-~>
+gA_3)3U[4S+g(V@!PMC`#QUCdrrVqZ+n#[;+gq7J!jtW3o`tRAV<@jaPSb5K(_@O2f(f7LhXCL$
+8f4\ls*t~>
+gA_3)3U[4S+g(V@!PMC`#QUCdrrVqZ+n#[;+gq7J!jtW3o`tRAV<@jZ]mKZu!O_+crs%rds6l1n
+cK5(V~>
+JcG!7!;H!_!;G^W$e@WM9!sm<#S9"LhY[<XhJ5`kCChYsjo9i~>
+g&D)u3U[4S9(2WV!o@DugB[g'f(8nBhD+C'"t@7cs7`W=oEYL0V>'3R$e@W]9!t0D(`58dhY[<X
+hJ6#sEu6@6jo9i~>
+g&D)u3U[4S9(2WV!o@DugB[g'f(8nBhD+C'"t@7cs7`W=oEYL0V>'3R$g3aqPh*j5F*ikRn,*+i
+n#_i*Xa>EGjo9i~>
+]Dhm*bPqS:]Di>c.0udMs6#=q#RE/ukPbD][3>MT!Z5G1jo9i~>
+f`)!8.IRNC>2K,U!r&NGh$=#mN:[&MpIa`W";kpE8eCe(!"f&6!,L`s%F-[FV>pSYN%kk\0uiDT
+rs,q\&/Ys%A+/OZJ,~>
+f`)!8.IRNC>2K,U!r&NGh$=#mN:[&MpIa`W";kpE8eCe(!"f&6!,L`s%HiCccN!q5]o7#RN7RIr
+rrL\trc8-fV=3OGJ,~>
+PQ(XWo`"pc])Moa0aN-hrr3PC@jqZp>,C]fs5&uM+\J!^jSs`~>
+fDbm&9(*#d;XaG]!o@]9i!9B-N;)uE!r%ojhZs9<PS!g"!F"[Krrgn-(jkHFrt)kR0c1a2Xmc;i
+hOJ@18sJN"s*t~>
+fDbm&9(*#d;XaG]!o@]9i!9B-N;)uE!r%ojhZs9<PS!g"!F"[KrrhMDF1(K9rt*bXKQDL:cM.A=
+n&D2WPeHPHs*t~>
+PlCaXX8`@lKFf;1f)G[ZkDU5`#U+lXs8Vi^cJJ<Us*t~>
+f)Gd-Hg_4@A+06n"7ON5&E=#t.D>KIrrKeVhZsH9`pYnn#ZBO@rrqkM(b&YFrr3JsN$/`L.?*-`
+s7c!-hY6(1J,~>
+f)Gd-Hg_4@A+06n"7ON5&E=#t.D>KIrrKeVhZsH9`pYnn#ZBO@rrr/)H[DUPrr3Js]mFgAHbJnJ
+s7c9Nn+YlBJ,~>
+[f6@%M#RV7EtC@_rr3;M3=%r<&-s,;kMH5h~>
+eGfQ.+n,a<;V(XC"S_)L3>grc!YB.uo)AaA1#E6A1#Ds1S/>Guj8T8=Eu6pgrr3;M3>b(T(`4E\
+n)"(p~>
+eGfQ.+n,a<;V(XC"S_)L3>grc!YB.uo)AaA1#E6A1#Ds1S/>Guj8T8NXa?#irr3;fN,t5JHZOPI
+n)"(p~>
+eGfOCJcG!7!q2YmrVm7Y&.#u+KHUU<;SDh_s*t~>
+eGfUE[5m^^!\(8?p\t<O[41AH![3Nko)AaR9&BmT1!]du!oBI1iVruJSAtO-$]Go>`nl@t&0Xrk
+pYc(%~>
+eGfUE[5m^^!\(8?p\t<O[41AH![3Nko)AaR9&BmT1!]du!oBI1iVruR`n(+g$FP5%hXA.2F*jG.
+huA3~>
+R/[0\o)A^aYQ#$o3=&ggs7a3:&-tnbi;\<~>
+df0?nA+0a*+`$97rr>[W#Qd#op[\=cpOj+9#QZBoeGfsG3=oBos7a3:(`5m%i;\<~>
+df0?nA+0a*+`$97rr>[W#Qd#op[\=cpOj+9#QZBoeGfsGN,tNhs7b*@HZPG?i;\<~>
+dJj4@lMgkYj8T,RT)T8oHO'mD[I=.qpSB#=Hf4pS~>
+dJj:BV(qHF"<i-Cn+Z_Z!UiYJ#Qbirp[S7bmt;P9#QZ[2eGg!PHPd;\[I=.qpSB;UHf4pS~>
+dJj:BV(qHF"<i-Cn+Z_Z!UiYJ#Qbirp[S7bmt;P9#QZ[2e,KiaF*!Ssp](9f`e8E@i;\<~>
+MZ3\NXoAgC@h8nhHbKIZpFur#i;\<~>
+ci4'lCE`0Q$6`<+]tN;&f"H,9mK`hJ^$u%'pP][A#QZ[*df0`qCD[m;KZ=&lpG!M3i;\<~>
+ci4'lCE`0Q$6`<+]tN;&f"H,9mK`hJ^$u%'pP][A#QZ[*df0a4V0d9:[GLr`pPa1$i;\<~>
+cMmn=^]+<.X8`RjS3dJm.=9(S.0tmjs*t~>
+cMn"@]k\JR#lc%N0j6R\&FKf)CX2GL!r%Wji!9?<`mF_nkF>-](bp]``\A<hi;\<~>
+cMn"@]k\JR#lc%N0j6R\&FKf)CX2GL!r%Wji!9?<`mF_nn&CT5H\Af`hLos`i;\<~>
+bl7\;eGfOCQN%9[S1tQ\&.f+-f&6RY~>
+bl7e>c>+TU#Q];HnG`RYN#:IY!@cUErsA.a0b>0=&/[abi;\<~>
+bl7e>c>+TU#Q];HnG`RYN#:IY!@cUErsAG>N,s&eF*!<'i;\<~>
+NW0"QV>gb>CFKf3>.*8fJ,~>
+ao;I_CH36e#Q];@nG`RaKFm)J!Y@uLb5V[cF"nLT>.*8fJ,~>
+ao;I_CH36e#Q];@nG`RaKFm)J!Y@uLb5V\&Xb;%JV:OQ(J,~>
+aSu87aSu87U]1Jc`kB(KhZ&*~>
+aSuD;hR.,JhZs7(n*p>YpQQNQ#Q];8aSuD3`kB(KhZ&*~>
+aSuD;hR.,JhZs7(n*p>YpQQNQ#Q];8aSuD;hU^9HhZ&*~>
+`W#r4VuHbkTDsE~>
+`W$5<kK]Sq8g,#_jp2#CV=4!T!q1dZi!9@1pRhJ9~>
+`W$5<kK]Sq8g,#_jp2#CV=4!T!q1dZi!9@1pRhJ9~>
+_#FE/XoACqT)X<~>
+_#FZ6`kAKa@p2M'+mfO9&>f!u!p>LZi<TJrHhX-3J,~>
+_#FZ6`kAKa@p2M'+mfO9&>f!u!p>LZi<TJrHhX-3J,~>
+]`8$+NrK3pN/ZW4s*t~>
+]`8$+!WV?]`W28#CB.!$#QlMkK\#eq!nLNdi!9@)n(n!G]p+c<`W(G~>
+]`8$+!WV?]`W28#CB.!$#QlMkK\#eq!nLNdi!9@)n(n!Gf"Jcc`W(G~>
+Zi:.%s7cQmp\+Uep[nIcpY>cKpYPoThHCHr&/^)ha8^Y~>
+Zi:.%s7cQmpC$0QkO7U&kO7U&n+ZJS!r&3FhZs79pYPoNhHKmq![36ca8^Y~>
+Zi:.%s7cQmpC$0QkO7U&kO7U&n+ZJS!r&3FhZs79pYPoTn!n`GH[E0pa8^Y~>
+JcG0<!;G@M$28cP&5kLo(kgbes*t~>
+PlCgJN#:IY![36khZ!oVHPd;l3>`omhT5_I~>
+PlCgJN#:IY![36kh>[bgF*!k1F*k=`aT$b~>
+JcG3=!;G@M$hrL4#\2`)KErD]f#drB~>
+Q2^p*=r??,ruq@I!\(hWhZ!uXhDlE_hSt3c+\L>-s*t~>
+Q2^p*=r??,ruq@I!\(hWh>[iNKQF!YhR.EOPip0gJ,~>
+JcEso%I^,c&.!shs7_Hq#XZhZs*t~>
+Qi@-MPTf/p#S8/4KGXt#0ui&L%I^Ds(_DB#s7_I$&44[bs*t~>
+Qi@-MPTf/p#S8/4KGXt#0ui&L%JS/4HZQUps7a3RF-Pk1s*t~>
+JcEso%b=fn&-riDp]'uH(^NIJbQ!(~>
+R/[2`3T^SR&5o%LS/;M;CX1`8!nLObrYPpCp]'uP+W*PcbQ!(~>
+R/[2`3T^SR&5o%LS/;M;CX1`8%d0@YF)u]Rs8Vi,HZPG.bQ!(~>
+JcGQG!;G%D&EhX-V)\f1SH&WXN"?7TSG1;.J,~>
+Rf<H/F!9ZO#u\1opSB#=+f4Y^rt+YMkG:0M0qA:Dmu/)#6Cdeps*t~>
+Rf<H/F!9ZO#u\1opSB#=+f4Y^rt+Y^n&C<-KZ=&lpUtopN5kV:s*t~>
+Sc8]aiVruRs7b+E!r(mPrr3G@3=$e)p]'uq8dH8mn':r`~>
+Sc8fd`a^1T#RVD@[J0^qS08_A^"`Pgp[@kUrscY%&1OaUs7`on(a4k,cMrC~>
+Sc8fd`a^1T#RVD@[J0^qS08_A^"WJdn,<7qer4ZscM.A5es(6&^%]hPJ,~>
+JcG`L"8DiqpX]?Zer3ds`qTN5`\@`BSF?LXc:S?ZK_NgmJ,~>
+TDo#V]lP@[#R_JI[J0_$pRE[)V=31=("S=RPg9%'s3<>9.AcM5s3=LR+cQ0As*t~>
+TDo#V]lP@[#R_JI[J0_$pRE[)V=31="R!Ip`np^p%Gm%bHcGg[s6#VfHbK1"s*t~>
+U&P,eZ2Y$93=lH-0t%#\%CK(F+_0^8s4019&=i49s*t~>
+U&P5hS5LNo#Qu;KKY?jQrr_G;V;Br+#.6H.(_AF0rr3G8;A^iukPtS53=m$tn'M)b~>
+U&P5hS5LNo#Qu;KKY?jQrr_G;V;Br+!S35/Erh6Nrr3GYS9opkn,NFNN,s?cpX&qj~>
+V#LGhiW&rPqYpQig&D?78dI.T+UB7!rr3GrEsN%LhZ*W$@j)C]hU2@R~>
+V#LSlc=8"/lj*k.(cc*.hWOY-qYpQig&D?78f09m.2XMArr3GrHPdSthZ*W$CFL)uhU2@R~>
+V#LSlc=8"/lj*k.(cc*.hWOY-qYpQig&D?HP]Me[KQDLkrr3H%X`JQRn,NFNV0dQZkL'<[~>
+V>gPiY5]ER+X*]VXYC)1[J0_$kBdaGA(L\[mu/(hK_NppJ,~>
+V>gVkKH]^gruhMTHaV/^bPrL#.4M+f[4r4I[J0_$ms>lgA)@7cmu/D$K_NppJ,~>
+V>gVkKH]^gruhMTHaV/^bPrL;H[Ed,cAZgtf(]4En$RL`V<@mYpUtop[J/,LJ,~>
+JcF-t$G@T3^&Ri/+UBg9rr3DiEtAmd[K$9qHOq@?df4g~>
+V>gRL&Fg#1&/\#dPfC__rsHFg0tmV]XXP)A^&J$?kAqIO>.+D1mt;6$`mXm;~>
+V>gRL&Fg#1&/\#dPfC__rsI>1K\$1teqA+'f)G[Xn#^qXSC[`?pU,'qhU;FS~>
+VZ-YjmJm4\_uC+a0aLt>s8TJM#[6]rrsS:[0aJr)p]%W<&A?NlJ,~>
+VZ-\k;YCA&&/ZQ_H^*+Ep\2T*$cXn<>2K;Z[4)qrn,E=pn!#gD.CJpM[36C,df4g~>
+VZ-\k;YCA&&/ZQ_H^*+Ep\2T*$f6h`V=4HaeqA+7p\t1#pUuN,Hd;BcepDJpdf4g~>
+QN$sZ_Z'qf`npaqpREBM[Jp1/V(i6khYmH\[5eL9PeDDT1#C@YJ,~>
+V>h'b3AENK3AENKCP7A;kNDTVs8U@LhZ*WMS1,nprr3,'0c4]_rVm2364bT9`d8OWhU;FS~>
+V>h'b3AENK3AENKCP7A;kNDTVrrVB?n,E=h`d<Birr3,HN,u,arVm2TN,sZlhR.E`n'_5d~>
+V>gPiq>UHh^AeStKK1JJV>pSiPa(&(rrr.]&.iX6rVm,10aJpO&-udns*t~>
+V>gkrhU^Q7hU^Q7pV-Y8hLmmD8u;RfpQV3)rr3/rPSb6YhYmHZ[5edI0c1a;dJn^~>
+V>gkrhU^Q7hU^Q7pV-Y8n$S+-PfEb'pVt5Arr3/r]mG+.n,<7keqA*kKR7d:dJn^~>
+JcFF'$Kl11&.f*aV>(#ar;QfC6N.5kA*<gj#/)Gs#S:e.dJn^~>
+JcFF'!Ujh&(^)"Yp](!crs$b@(_@O"n,<7j`\A;A&8U.Ms*t~>
+JcFF'$Lb*<H[Bg\`qTN-r;Qf\Pl>_)V=4B_#2Y#[F*"JHdJn^~>
+JcG!7"8CBSf(K%K[0Rq?PX5X1cMRVIc8c.A64a]DhYmHXkAq1G>2I[,J,~>
+JcG!7"8CBShY$mS[1FdOS3e&IcMRVIc9`?b65U8LhYmHXmrK<_A)>W5J,~>
+JcG!7"8D!0kOni\eoQMX`ftP'kPP8bkDXJ/P]LoJn,<7in$R4XV=2h3J,~>
+JcG$8"n.C1+[W%!rs3BGA+0H26Bp[2rsI=L#T/6G@gEWUkPbDakA(>/A*;;?J,~>
+JcG$8"n.C1.8$H1rs3ZWA+0H;6Bps:rsI=T&0Z_XCD[n(n,<7ikAqIWA+.kGJ,~>
+JcG$8"o#]hH^)PDrs5`JV>(#HPeHP`rsIqRF*kU`V/q![n,<7in#^YPV=2k4J,~>
+JcG'9#krZ_&.f*jSG2s]$MVj7s.ouEf)Pd$qu7&eHOq?ZkPs^\&.ip\rs7e'&-uIbp](!=s*t~>
+JcG'9!r%?krYP\cV>'of$MVj7s.p8Uf)Pd,qu7&mHOqWbn,MQl&/]Kdrs8(/(`6H%p](!=s*t~>
+JcG'9!Va#$HNS>9`qTE2$MW`Xs2K,5kPtSFqu7&m[<m86n,MjYF*k%ers8(qF*"2@p](!=s*t~>
+JcG'9#gOS)N28iH.CK-S$.aH5hZ(kM#\2`drsR[e#XZ6)s6!l'+gq7J#Npap#U-%P^"346~>
+JcG'9#gOk9N29,X0tmPc$.acFhZ(kU(h;FtrsR[e&5'Y9s6j_?.CK*R#Od=#&1O`h`n(0?~>
+JcG'9#j6P]]uH:XN7Rt-$0S^mn,MR(F/A@#rsS:cF-P8Us6m(2K\$)$#Of'ZF+hiif%0kO~>
+JcG'9&"EnShZ'u<0t$cUkF=j^[Jp1.PR%PZrVlrn^#&bg$J%NL3R7[)ej9XXqYp`$+UB6$f%0kO~>
+JcG'9&"F1chZ'u<3OSV]n"i?"[Jp1.PSb7%rVlrn^#&bg$J%f\3R7[)ej:3hqYp`,.2XLLf%0kO~>
+JcG'9&&r[Dn,LstK\#ntn&CTFf)G[O]lS8.rVlrnf'iV<$KmXpN9C6@kEL%iqYp`EKQDgCkLTZ`~>
+JcG'9*h3KZ^&S,?hY7'EKMiWmC[_<'hJ3ZGV>(#QS0:5Mrr3=q+UC*As7_H`6I,H-"19QpV:GTr~>
+JcG'9*h4&r^&S,?hY7'EKMis1C[_<'hK'M_XnVkaS1-eUrr3>%.1ehcs7_Hh9$[;5"19j,V:GTr~>
+JcG'9*l`8Jf)Pd$n+ZkV[@DSbXnVkqn#^YacN!q5`d<s5rr3>FKQE+/s8TcRPiqoC"4i-P`mt*>~>
+JcG'9"5Z$D>5S=(pV#.B(_E5:rtsoc#VjWU=qCrF>4;LkpREB43OQ7T#\3?!rrTU)pXT:o~>
+JcG'9"5Z$LA,H91pV#.J+V:1Crtsoc(bs=e@i,ag>4;LkpREZL3OQ7](h<%1rrTU1pXT:o~>
+JcG'9"7M1iV>L8spX\NIHZR4+rtt3hF,];FV0d9)V>(#ipVql-N7QR=F/AX,rrL]reGk%~>
+JcG$8&;1T+^$isfHd;*[s6!8c6H9$)(:>S&;G%3+;@k"1p](9fV%<n].0pKeao?k~>
+JcG$8&;1l;`p^p#Hd;*[s6!8k9$[G9(:>k6>"TVC;A^jAp](9fV&1%(0b>2(ao?k~>
+JcG$8&@HS+hY5m7[HI;as6lJ!PhuE>(=n.[S<S)9S9oUrp](9f`d;c[KQDLcao?k~>
+JcG$8&^EBB@s]@)#U,H,s8So=#]oJ6rsF\r#RD8ohHC16^&J$9pQR*<&0[Rbs*t~>
+JcG$8&^E][@tZ9J(b(^Ds8T2M(j#0FrsF]%&/ZR;hI@*O^&J$9pRErT(b(urs*t~>
+JcG$8$0R7gV6tYkF+h7+rrgVoF1(cArrBb3Es@<*n"k)Yf)G[NpVqmcHN;(,s*t~>
+JcG!7!Nd4<#lcU\#U-VTrr[TR.CK0T$g2RB6H9'*ej9X/cMdbFpU-OBa8^Y~>
+JcG!7$*>?^&/[,V(b)llrr[oc0t%#\$g2jR6I,W2ek-cOcMdbFpU-OJa8^Y~>
+JcG!7!S2VsF8q1#F+i-Drr]ZMK\$/&$h(KMPhuH?kEL%PkPbD_pX[@Ia8^Y~>
+JcG*:']..(mofu&9$YFC#YO:[s5$'J6Ke@J!oAmUrVm#.&.!(?_#Jo~>
+JcG*:']..(mog869$YFK(eWuks5$?Z9(2cZ!oAmUrVm#.(_CKO_#Jo~>
+JcG*:'^t5ZpRH;GPipnfF-Q.ns6l1nPjeVO!q3hZrVm#OF*"JX_#Jo~>
+JcG0<&([7S>3Gq!#RHChs/chDPlC[cV'-Csp\t0mn,E=kp]']H&.kAIs*t~>
+JcG0<&([R\A*<m3(_DZ+s/chLSGrNkXXOg7p\t0mn,E=kp]']H(`8dYs*t~>
+JcG0<&*Ls&V=4H@F*#%ps4274`r>u?c@g8HrVlllrr32ss7a3RHcEl$J,~>
+JcG9?)t3h,@gGuqs8VOk#V"s:pK@h_kPtSVHOqp>p\b$rhOO'7hEhd#_#Jo~>
+JcG9?)t3h,CD]t<s8VOk(bt4RpKA+gkPtSVHPeKFp\b$rhOO'7hF\W3_#Jo~>
+JcG9?)u'C4V/r0qs8Vh`F+j#^pSDqin,NF^[<%;Xp\b$rn&G,%n!%n$_#Jo~>
+JcG?A#j7_Js8TbU&@MN;$)JIMPkY3[+V:1Crrh1=#YO:Yrs7e'+f4qQ0aN-As*t~>
+JcG?A#k+:Rs8U(f(q'AC$*>?fPkY3[.1i$Krrh1F(eX8qrs7e/.Acda0c58Qs*t~>
+JcG?A#k,dQs8Ur&He/2r$-mmE^&S,`H[Ed3rrheLF-Q.lrs8(qKZ<cCN,uDBs*t~>
+JcGEC)#&A;+YhjRk=Q"`n,NFV@gGEXs5$ob6Iu/9"/Q87F8c+EpK@h>;F1X+f"h<9~>
+JcGEC)#&\D.5B]Zmn+-pn,NFV@i.Phs5$or9%O"A"0ECOHi<sMpL>$`;G%cLf"h<9~>
+JcGEC)#(_&H]7.fn!%mip](9fV/qmis6lJ!Pir&G"3tt7[Jg+2pSDqXS<S)AkJ7+J~>
+JcGEC$g4po.1haDs-+'<cMmhM[36*Gp]%WE&=!1o"Qs8#+kHVl#/*#.#RDl<^]/f~>
+JcGEC$h(L*0c6G\s-sWLcMmhM[4)r_p]%WM(nCU*"Qs83.G"It!QI/!(]c(E^]/f~>
+JcGEC$h)ZlKR:`=s2K,,kPkJfepDb`p]&ftF2n4Z"Ri1.K]i=6#2Y;cF*!#J^]/f~>
+JcG?A([kN5>3Gq:3=(T<s8V8/#W^cAs)SH<hZ!NXc7'<?hYmHXer4s/[J.H9J,~>
+JcG?A([kiFA*<mC3>d_Ls8VP7(cgIQs*GSThZ!NXc7olOhYmHXer598[J.H9J,~>
+JcG?A(\abISF?L@N,u],s8VPqF,]Sfs/g@,kPkJakCdoYn,<7ikIn:2f(ZrZJ,~>
+JcG<@$(MPM[K#E*#W^K8rs@7*#b:qphB<GGrr3/rPSbR?p\b$ln+XNqJ,~>
+JcG<@$(Mh][K#]:(dcgQrs@72(nCX+hC0"Wrr3/rPT_KPp\b$ln+XNqJ,~>
+JcG<@$-%==f)P3@F,];]rs@kAF2n7[msBD`rr3/r]mG+Gp\b'kpV$TW~>
+JcG<@$/RuSK_PM[+X*]]rsJLR#T0uLs+Cq,`r>u@pK@hWcF3b'~>
+JcG<@$/S8kK_PMd.4MCursJLR(a6<es,7L<`r>u@pL>$pcF3b'~>
+JcG<@$1F+"[J0^XH\B]Crs?)SHe/5s[<%#Xrr3,qV/qUY[f:j~>
+JcG9?$$-A$f)PJ)#ZBjbrsI%3#]'27`]4<?n,E=jc7'#spYNF[J,~>
+JcG9?$%!4<f)PJ2&6eQ%rsI%3(i/mG`]4TOn,E=jc7p/6pYNF[J,~>
+JcG9?$+4i-kPt:8F.D^ursIqJF053:hMcNXp\t0rkCdoHp[>WlJ,~>
+JcG9?$-j(f[K$8k#Vjp0rsJ4J&2ClupN$Th^&@s7N!KtuCZi8.J,~>
+JcG9?$-j)![K$8k(bsV@rsJ4R&2D3)pNm`3^&@s7N#3C8F76[>J,~>
+JcG9?$0QANf)Pc`F,];]rsJM6F,\uUpU,'qf)>UP]lSOsXm`h#J,~>
+JcG9?$28KH6KeC30aMRnrsIU;#\3&tehIGGkPkJahGQ(Lf!ta1~>
+JcG9?$28c`6LXsC0bAF)rsIUC&8Ub7hD#jgn,E=ihGQ@\hRNT9~>
+JcG9?$2:iKPjeY@N,u-"rsJ4JF/A@*kDXJan,E=in!o'=kICPB~>
+JcG6>#dkKd`rGdK#V#]O$$uq$^&S+c#U.LlrrT%1n$i=I~>
+JcG6>#dkg!`rGdK&2F+_$%rj=^&S+c&1Pp'rrT=Bn$i=I~>
+JcG6>#hF?LhZ*>PF+jJk$+4i$f)PcXF+i`TrrUL&pUC0Q~>
+JcG6>$/SPcF8u9J.1i?Srs@OK#]'27c3O]hrVm#ps8UZi\c70~>
+JcG6>$/SPsF8u9J0c7%krs@OS(i/mGc57,+rVm#ps8UZq\c70~>
+JcG6>$0Rh"[K$9XKR;#CrsA.YF053:kAt^qrVm#ps8V9=\c70~>
+JcG3=$'Yu]cMua!#[6Eirs5GE#__'2#RJ-@rr]YX+hbJeJ,~>
+JcG3=$(MhmcMua!&7ao%rs5_U(kgbJ&/`+Xrr]Y`.D<=mJ,~>
+JcG3=$-%=NkPs_8F.D^trs6nsF1(J^F*#q0rr^i*He,e.J,~>
+JcG3=$-j\;SH&VZ&2D3'rs7dk#S9<G#X[DFrr[TR&?WPDJ,~>
+JcG3=$-jtKSH&VZ(bs>7rs7dk(`5jo(dd*Vrr[Tb&@K+LJ,~>
+JcG3=$0Qtg`rH(YH]6h[rs8(iF*j.)F-Q.jrr]ZMHd95&J,~>
+JcG0<$"F6=kPsC*#__sNrrJr>rWiNZ[JKn*c?"@$])R9~>
+JcG0<$#:AUkPsC2(khY^rs#SS(_@N=[JKn*c?"[-])R9~>
+JcG0<$)M^5n,Mj@F1(c@rrLDlrc8+!f)#CKkH2/d])R9~>
+JcG0<$,$lUV>pRK#W^c?rrq7G@rm"RY5a"~>
+JcG0<$-!f!XoJE[&457Prrq7GCNG0cY5a"~>
+JcG0<$.aHEcN!pXF,]SdrrqkUV6./oY5a"~>
+JcG0<$0OV\C\RkS#S=ECrr_GCF1nXSJ,~>
+JcG0<$0OnlC\RkS(`9[[rr__KF2k9\J,~>
+JcG0<$1F+"XnVkYF*#q3rr_`'Xk'QQJ,~>
+JcG-;%[75Bf(\#,#YNt)s8TdhWrIS~>
+JcG-;%\+@bhY5k<(eWZ9s8U*qWrIS~>
+JcG-;%`WRCkPt!lF-Q.Vs8UsEWrIS~>
+JcG-;$cXV$6?>-m3B:9FpS\%A~>
+JcG-;$dLI<6@1^03B:9NpS\%A~>
+JcG-;$f6PXPc]mcN/X:PpS\%A~>
+JcG-;!q2'ZrWiTTXhEnos*t~>
+JcG-;$1Efi(_@N=XiBP#s*t~>
+JcG-;!r'BTrc80pf&#kls*t~>
+JcG*:#5=s80ltY/U]5i~>
+JcG*:#5>6@0mh47U]5i~>
+JcG*:#5?EFN32:;U]5i~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+JcCN*J,~>
+%%EndData
+showpage
+%%Trailer
+end
+%%EOF
diff --git a/conf/lpr b/conf/lpr
new file mode 100644
index 0000000..fa1c313
--- /dev/null
+++ b/conf/lpr
@@ -0,0 +1 @@
+lpr -h
diff --git a/conf/maxsearchrecordsperpage b/conf/maxsearchrecordsperpage
new file mode 100644
index 0000000..29d6383
--- /dev/null
+++ b/conf/maxsearchrecordsperpage
@@ -0,0 +1 @@
+100
diff --git a/conf/report_template b/conf/report_template
new file mode 100644
index 0000000..9c6bb2b
--- /dev/null
+++ b/conf/report_template
@@ -0,0 +1,14 @@
+{ sprintf("%-19s", "Page $page of $total_pages"); } {
+ my $spacer = (40 - length($title) > 0) ? 40 - length($title) : 0;
+ $spacer = int($spacer / 2);
+ my $titlelen = 40 - $spacer;
+ sprintf("%*s%-*s", $spacer, " ", $titlelen, $title);
+ } { use Date::Format; time2str("%x %X", $date); }
+
+
+{
+ join("\n", map { $_ } report_lines(57));
+}
+
+
+
diff --git a/conf/shells b/conf/shells
new file mode 100644
index 0000000..a41fc62
--- /dev/null
+++ b/conf/shells
@@ -0,0 +1,5 @@
+
+/bin/sh
+/bin/csh
+/bin/bash
+/bin/false
diff --git a/conf/show-msgcat-codes b/conf/show-msgcat-codes
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/conf/show-msgcat-codes
diff --git a/conf/smtpmachine b/conf/smtpmachine
new file mode 100644
index 0000000..2fbb50c
--- /dev/null
+++ b/conf/smtpmachine
@@ -0,0 +1 @@
+localhost
diff --git a/conf/soadefaultttl b/conf/soadefaultttl
new file mode 100644
index 0000000..92f616f
--- /dev/null
+++ b/conf/soadefaultttl
@@ -0,0 +1 @@
+259200
diff --git a/conf/soaexpire b/conf/soaexpire
new file mode 100644
index 0000000..d235b91
--- /dev/null
+++ b/conf/soaexpire
@@ -0,0 +1 @@
+3600000
diff --git a/conf/soarefresh b/conf/soarefresh
new file mode 100644
index 0000000..9f35f8e
--- /dev/null
+++ b/conf/soarefresh
@@ -0,0 +1 @@
+10800
diff --git a/conf/soaretry b/conf/soaretry
new file mode 100644
index 0000000..bb08106
--- /dev/null
+++ b/conf/soaretry
@@ -0,0 +1 @@
+1800
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644
index 0000000..b51eee8
--- /dev/null
+++ b/debian/README.Debian
@@ -0,0 +1,6 @@
+freeside for Debian
+-------------------
+
+<possible notes regarding this package - if none, delete this file>
+
+ -- Ivan Kohler <ivan-debian@420.am>, Thu, 12 Apr 2001 15:49:17 -0700
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..d8283b5
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,9 @@
+freeside (1.4.1-1) unstable; urgency=low
+
+ * Initial Release.
+
+ -- Ivan Kohler <ivan-debian@420.am> Thu, 12 Apr 2001 15:49:17 -0700
+
+Local variables:
+mode: debian-changelog
+End:
diff --git a/debian/conffiles.ex b/debian/conffiles.ex
new file mode 100644
index 0000000..8686d2a
--- /dev/null
+++ b/debian/conffiles.ex
@@ -0,0 +1,7 @@
+#
+# If you want to use this conffile, remove all comments and put files that
+# you want dpkg to process here using their absolute pathnames.
+# See section 9.1 of the packaging manual.
+#
+# for example:
+# /etc/freeside/freeside.conf
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..d7873b2
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,59 @@
+Source: freeside
+Section: admin
+Priority: optional
+Maintainer: Ivan Kohler <ivan-debian@420.am>
+Build-Depends: debhelper (>> 3.0.0)
+Standards-Version: 3.5.2
+
+Package: freeside
+Architecture: any
+Depends: freeside-lib
+Recommends: freeside-doc, freeside-ui-web
+Suggests: freeside-selfservice-server
+Description: Billing and administration package for ISPs.
+ Freeside is a billing and account administration package for ISPs. It stores
+ customer information in an SQL database, and will update UNIX passwd and
+ shadow files, RADIUS users file and SQL databases, and configuration for
+ sendmail, qmail, BIND and/or Apache. It is also useful as a central database
+ of accounts/domains/web-space for a large number of machines.
+
+Package: freeside-doc
+Architecture: all
+Description: Documentation for freeside
+ This package provides the HTML documentation for Freeside, a billing and
+ account administration package for ISPs.
+
+Package: freeside-lib
+Architecture: all
+Depends: libmime-base64-perl, libdigest-md5-perl, liburi-perl, libhtml-tagset-perl, libhtml-parser-perl, libnet-perl, liblocale-codes-perl, libnet-whois-perl, libwww-perl, libbusiness-creditcard-perl, libmailtools-perl, libtimedate-perl, libdate-manip-perl, libfile-counterfile-perl, libfreezethaw-perl, libtext-template-perl, libdbd-pg-perl, libdbix-datasource-perl, libdbix-dbschema-perl, libnet-ssh-perl, libnet-scp-perl, libapache-asp-perl, libtie-ixhash-perl, libtime-duration-perl, libhtml-widgets-selectlayers-perl, libstorable-perl, libapache-dbi-perl
+Description: Freeside libraries and extension API
+ This package contains the libraries which implement the business logic and
+ backend functions of Freeside, a billing and account administration package
+ for ISPs. This package also contains the manual pages for the library API.
+ (? like a libmodule-perl package)
+
+Package: freeside-ui-web
+Architecture: all
+Depends: libhtml-mason-perl, libstring-approx-perl, freeside-lib, libapache-mod-perl|apache-perl
+Suggests: libapache-mod-ssl|apache-ssl
+Description: Easy-to-use web interface for Freeside
+ This package contains the web interface for Freeside, a billing and account
+ administration package for ISPs. This is what sales or support folks will
+ typically use to add new accounts, edit exiting accounts and so on.
+
+Package: freeside-selfservice-server
+Architecture: all
+Depends: freeside-lib, libnet-ssh-perl, ssh
+Description:
+ This package contains the server side of the customer self-service interface.
+ It is installed on a private backend machine, and opens an outgoing ssh
+ connection to one or more public web server(s).
+
+Package: freeside-selfservice-client
+Architecture: all
+Depends: libstorable-perl, libhttp-browserdetect-perl, libbusiness-creditcard-perl, ssh
+Description:
+ This package contains the client side of the customer self-service interface.
+ It is typically installed on a public webserver and interfaces with
+ freeside-selfservice-server installed on a private backend machine.
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..e148fce
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,10 @@
+This package was debianized by Ivan Kohler <ivan-debian@420.am> on
+Thu, 12 Apr 2001 15:49:17 -0700.
+
+It was downloaded from <fill in ftp site>
+
+Upstream Author(s): <put author(s) name and email here>
+
+Copyright:
+
+<Must follow here>
diff --git a/debian/cron.d.ex b/debian/cron.d.ex
new file mode 100644
index 0000000..61c074d
--- /dev/null
+++ b/debian/cron.d.ex
@@ -0,0 +1,4 @@
+#
+# Regular cron jobs for the freeside package
+#
+0 4 * * * root freeside_maintenance
diff --git a/debian/dirs b/debian/dirs
new file mode 100644
index 0000000..ca882bb
--- /dev/null
+++ b/debian/dirs
@@ -0,0 +1,2 @@
+usr/bin
+usr/sbin
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..16636bd
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,3 @@
+INSTALL
+README
+TODO
diff --git a/debian/ex.doc-base.package b/debian/ex.doc-base.package
new file mode 100644
index 0000000..2a055d1
--- /dev/null
+++ b/debian/ex.doc-base.package
@@ -0,0 +1,22 @@
+Document: freeside
+Title: Debian freeside Manual
+Author: <insert document author here>
+Abstract: This manual describes what freeside is
+ and how it can be used to
+ manage online manuals on Debian systems.
+Section: unknown
+
+Format: debiandoc-sgml
+Files: /usr/share/doc/freeside/freeside.sgml.gz
+
+Format: postscript
+Files: /usr/share/doc/freeside/freeside.ps.gz
+
+Format: text
+Files: /usr/share/doc/freeside/freeside.text.gz
+
+Format: HTML
+Index: /usr/share/doc/freeside/html/index.html
+Files: /usr/share/doc/freeside/html/*.html
+
+
diff --git a/debian/freeside-doc.docs b/debian/freeside-doc.docs
new file mode 100644
index 0000000..299950c
--- /dev/null
+++ b/debian/freeside-doc.docs
@@ -0,0 +1,2 @@
+#DOCS#
+
diff --git a/debian/freeside-doc.files b/debian/freeside-doc.files
new file mode 100644
index 0000000..299950c
--- /dev/null
+++ b/debian/freeside-doc.files
@@ -0,0 +1,2 @@
+#DOCS#
+
diff --git a/debian/init.d.ex b/debian/init.d.ex
new file mode 100644
index 0000000..5791049
--- /dev/null
+++ b/debian/init.d.ex
@@ -0,0 +1,70 @@
+#! /bin/sh
+#
+# skeleton example file to build /etc/init.d/ scripts.
+# This file should be used to construct scripts for /etc/init.d.
+#
+# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
+# Modified for Debian GNU/Linux
+# by Ian Murdock <imurdock@gnu.ai.mit.edu>.
+#
+# Version: @(#)skeleton 1.8 03-Mar-1998 miquels@cistron.nl
+#
+# This file was automatically customized by dh-make on Thu, 12 Apr 2001 15:49:17 -0700
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/freeside
+NAME=freeside
+DESC=freeside
+
+test -f $DAEMON || exit 0
+
+set -e
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC: "
+ start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
+ --exec $DAEMON
+ echo "$NAME."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \
+ --exec $DAEMON
+ echo "$NAME."
+ ;;
+ #reload)
+ #
+ # If the daemon can reload its config files on the fly
+ # for example by sending it SIGHUP, do it here.
+ #
+ # If the daemon responds to changes in its config file
+ # directly anyway, make this a do-nothing entry.
+ #
+ # echo "Reloading $DESC configuration files."
+ # start-stop-daemon --stop --signal 1 --quiet --pidfile \
+ # /var/run/$NAME.pid --exec $DAEMON
+ #;;
+ restart|force-reload)
+ #
+ # If the "reload" option is implemented, move the "force-reload"
+ # option to the "reload" entry above. If not, "force-reload" is
+ # just the same as "restart".
+ #
+ echo -n "Restarting $DESC: "
+ start-stop-daemon --stop --quiet --pidfile \
+ /var/run/$NAME.pid --exec $DAEMON
+ sleep 1
+ start-stop-daemon --start --quiet --pidfile \
+ /var/run/$NAME.pid --exec $DAEMON
+ echo "$NAME."
+ ;;
+ *)
+ N=/etc/init.d/$NAME
+ # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
+ echo "Usage: $N {start|stop|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/debian/manpage.1.ex b/debian/manpage.1.ex
new file mode 100644
index 0000000..ec542bb
--- /dev/null
+++ b/debian/manpage.1.ex
@@ -0,0 +1,60 @@
+.\" Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH FREESIDE SECTION "April 12, 2001"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh disable hyphenation
+.\" .hy enable hyphenation
+.\" .ad l left justify
+.\" .ad b justify to both left and right margins
+.\" .nf disable filling
+.\" .fi enable filling
+.\" .br insert line break
+.\" .sp <n> insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+freeside \- program to do something
+.SH SYNOPSIS
+.B freeside
+.RI [ options ] " files" ...
+.br
+.B bar
+.RI [ options ] " files" ...
+.SH DESCRIPTION
+This manual page documents briefly the
+.B freeside
+and
+.B bar
+commands.
+This manual page was written for the Debian GNU/Linux distribution
+because the original program does not have a manual page.
+Instead, it has documentation in the GNU Info format; see below.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" respectively.
+\fBfreeside\fP is a program that...
+.SH OPTIONS
+These programs follow the usual GNU command line syntax, with long
+options starting with two dashes (`-').
+A summary of options is included below.
+For a complete description, see the Info files.
+.TP
+.B \-h, \-\-help
+Show summary of options.
+.TP
+.B \-v, \-\-version
+Show version of program.
+.SH SEE ALSO
+.BR bar (1),
+.BR baz (1).
+.br
+The programs are documented fully by
+.IR "The Rise and Fall of a Fooish Bar" ,
+available via the Info system.
+.SH AUTHOR
+This manual page was written by Ivan Kohler <ivan-debian@420.am>,
+for the Debian GNU/Linux system (but may be used by others).
diff --git a/debian/manpage.sgml.ex b/debian/manpage.sgml.ex
new file mode 100644
index 0000000..9bc3a86
--- /dev/null
+++ b/debian/manpage.sgml.ex
@@ -0,0 +1,143 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+
+<!-- Process this file with docbook-to-man to generate an nroff manual
+ page: `docbook-to-man manpage.sgml > manpage.1'. You may view
+ the manual page with: `docbook-to-man manpage.sgml | nroff -man |
+ less'. A typical entry in a Makefile or Makefile.am is:
+
+manpage.1: manpage.sgml
+ docbook-to-man $< > $@
+ -->
+
+ <!-- Fill in your name for FIRSTNAME and SURNAME. -->
+ <!ENTITY dhfirstname "<firstname>FIRSTNAME</firstname>">
+ <!ENTITY dhsurname "<surname>SURNAME</surname>">
+ <!-- Please adjust the date whenever revising the manpage. -->
+ <!ENTITY dhdate "<date>April 12, 2001</date>">
+ <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
+ allowed: see man(7), man(1). -->
+ <!ENTITY dhsection "<manvolnum>SECTION</manvolnum>">
+ <!ENTITY dhemail "<email>ivan-debian@420.am</email>">
+ <!ENTITY dhusername "Ivan Kohler">
+ <!ENTITY dhucpackage "<refentrytitle>FREESIDE</refentrytitle>">
+ <!ENTITY dhpackage "freeside">
+
+ <!ENTITY debian "<productname>Debian GNU/Linux</productname>">
+ <!ENTITY gnu "<acronym>GNU</acronym>">
+]>
+
+<refentry>
+ <refentryinfo>
+ <address>
+ &dhemail;
+ </address>
+ <author>
+ &dhfirstname;
+ &dhsurname;
+ </author>
+ <copyright>
+ <year>2001</year>
+ <holder>&dhusername;</holder>
+ </copyright>
+ &dhdate;
+ </refentryinfo>
+ <refmeta>
+ &dhucpackage;
+
+ &dhsection;
+ </refmeta>
+ <refnamediv>
+ <refname>&dhpackage;</refname>
+
+ <refpurpose>program to do something</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>&dhpackage;</command>
+
+ <arg><option>-e <replaceable>this</replaceable></option></arg>
+
+ <arg><option>--example <replaceable>that</replaceable></option></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This manual page documents briefly the
+ <command>&dhpackage;</command> and <command>bar</command>
+ commands.</para>
+
+ <para>This manual page was written for the &debian; distribution
+ because the original program does not have a manual page.
+ Instead, it has documentation in the &gnu;
+ <application>Info</application> format; see below.</para>
+
+ <para><command>&dhpackage;</command> is a program that...</para>
+
+ </refsect1>
+ <refsect1>
+ <title>OPTIONS</title>
+
+ <para>These programs follow the usual GNU command line syntax,
+ with long options starting with two dashes (`-'). A summary of
+ options is included below. For a complete description, see the
+ <application>Info</application> files.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>-h</option>
+ <option>--help</option>
+ </term>
+ <listitem>
+ <para>Show summary of options.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-v</option>
+ <option>--version</option>
+ </term>
+ <listitem>
+ <para>Show version of program.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>SEE ALSO</title>
+
+ <para>bar (1), baz (1).</para>
+
+ <para>The programs are documented fully by <citetitle>The Rise and
+ Fall of a Fooish Bar</citetitle> available via the
+ <application>Info</application> system.</para>
+ </refsect1>
+ <refsect1>
+ <title>AUTHOR</title>
+
+ <para>This manual page was written by &dhusername; &dhemail; for
+ the &debian; system (but may be used by others). Permission is
+ granted to copy, distribute and/or modify this document under
+ the terms of the <acronym>GNU</acronym> Free Documentation
+ License, Version 1.1 or any later version published by the Free
+ Software Foundation; with no Invariant Sections, no Front-Cover
+ Texts and no Back-Cover Texts.</para>
+
+ </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/debian/menu.ex b/debian/menu.ex
new file mode 100644
index 0000000..ddc947e
--- /dev/null
+++ b/debian/menu.ex
@@ -0,0 +1,2 @@
+?package(freeside):needs=X11|text|vc|wm section=Apps/see-menu-manual\
+ title="freeside" command="/usr/bin/freeside"
diff --git a/debian/postinst.ex b/debian/postinst.ex
new file mode 100644
index 0000000..c4d4bfb
--- /dev/null
+++ b/debian/postinst.ex
@@ -0,0 +1,47 @@
+#! /bin/sh
+# postinst script for freeside
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see /usr/share/doc/packaging-manual/
+#
+# quoting from the policy:
+# Any necessary prompting should almost always be confined to the
+# post-installation script, and should be protected with a conditional
+# so that unnecessary prompting doesn't happen if a package's
+# installation fails and the `postinst' is called with `abort-upgrade',
+# `abort-remove' or `abort-deconfigure'.
+
+case "$1" in
+ configure)
+
+ ;;
+
+ abort-upgrade|abort-remove|abort-deconfigure)
+
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 0
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
+
diff --git a/debian/postrm.ex b/debian/postrm.ex
new file mode 100644
index 0000000..bed8abd
--- /dev/null
+++ b/debian/postrm.ex
@@ -0,0 +1,36 @@
+#! /bin/sh
+# postrm script for freeside
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postrm> `remove'
+# * <postrm> `purge'
+# * <old-postrm> `upgrade' <new-version>
+# * <new-postrm> `failed-upgrade' <old-version>
+# * <new-postrm> `abort-install'
+# * <new-postrm> `abort-install' <old-version>
+# * <new-postrm> `abort-upgrade' <old-version>
+# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
+# for details, see /usr/share/doc/packaging-manual/
+
+case "$1" in
+ purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+
+
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 0
+
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+
diff --git a/debian/preinst.ex b/debian/preinst.ex
new file mode 100644
index 0000000..0b42bb2
--- /dev/null
+++ b/debian/preinst.ex
@@ -0,0 +1,42 @@
+#! /bin/sh
+# preinst script for freeside
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <new-preinst> `install'
+# * <new-preinst> `install' <old-version>
+# * <new-preinst> `upgrade' <old-version>
+# * <old-preinst> `abort-upgrade' <new-version>
+#
+# For details see /usr/share/doc/packaging-manual/
+
+case "$1" in
+ install|upgrade)
+# if [ "$1" = "upgrade" ]
+# then
+# start-stop-daemon --stop --quiet --oknodo \
+# --pidfile /var/run/freeside.pid \
+# --exec /usr/sbin/freeside 2>/dev/null || true
+# fi
+ ;;
+
+ abort-upgrade)
+ ;;
+
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 0
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
+
diff --git a/debian/prerm.ex b/debian/prerm.ex
new file mode 100644
index 0000000..ebb87c5
--- /dev/null
+++ b/debian/prerm.ex
@@ -0,0 +1,37 @@
+#! /bin/sh
+# prerm script for freeside
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <prerm> `remove'
+# * <old-prerm> `upgrade' <new-version>
+# * <new-prerm> `failed-upgrade' <old-version>
+# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
+# * <deconfigured's-prerm> `deconfigure' `in-favour'
+# <package-being-installed> <version> `removing'
+# <conflicting-package> <version>
+# for details, see /usr/share/doc/packaging-manual/
+
+case "$1" in
+ remove|upgrade|deconfigure)
+# install-info --quiet --remove /usr/info/freeside.info.gz
+ ;;
+ failed-upgrade)
+ ;;
+ *)
+ echo "prerm called with unknown argument \`$1'" >&2
+ exit 0
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
+
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..71016c4
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,113 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 by Joey Hess.
+#
+# This version is for a hypothetical package that builds an
+# architecture-dependant package, as well as an architecture-independent
+# package.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatability version to use.
+export DH_COMPAT=3
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+ # Add here commands to configure the package.
+
+
+ touch configure-stamp
+
+build: configure-stamp build-stamp
+build-stamp:
+ dh_testdir
+
+ # Add here commands to compile the package.
+ $(MAKE)
+
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp configure-stamp
+
+ # Add here commands to clean up after the build process.
+ -$(MAKE) clean
+
+ dh_clean
+
+install: DH_OPTIONS=
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # Add here commands to install the package into debian/freeside.
+ $(MAKE) install DESTDIR=$(CURDIR)/debian/freeside
+
+ dh_movefiles
+
+# Build architecture-independent files here.
+# Pass -i to all debhelper commands in this target to reduce clutter.
+binary-indep: build install
+ dh_testdir -i
+ dh_testroot -i
+# dh_installdebconf -i
+ dh_installdocs -i
+ dh_installexamples -i
+ dh_installmenu -i
+# dh_installlogrotate -i
+# dh_installemacsen -i
+# dh_installpam -i
+# dh_installmime -i
+# dh_installinit -i
+ dh_installcron -i
+# dh_installman -i
+ dh_installinfo -i
+# dh_undocumented -i
+ dh_installchangelogs -i
+ dh_link -i
+ dh_compress -i
+ dh_fixperms -i
+ dh_installdeb -i
+# dh_perl -i
+ dh_gencontrol -i
+ dh_md5sums -i
+ dh_builddeb -i
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir -a
+ dh_testroot -a
+# dh_installdebconf -a
+ dh_installdocs -a
+ dh_installexamples -a
+ dh_installmenu -a
+# dh_installlogrotate -a
+# dh_installemacsen -a
+# dh_installpam -a
+# dh_installmime -a
+# dh_installinit -a
+ dh_installcron -a
+# dh_installman -a
+ dh_installinfo -a
+# dh_undocumented -a
+ dh_installchangelogs -a
+ dh_strip -a
+ dh_link -a
+ dh_compress -a
+ dh_fixperms -a
+# dh_makeshlibs -a
+ dh_installdeb -a
+# dh_perl -a
+ dh_shlibdeps -a
+ dh_gencontrol -a
+ dh_md5sums -a
+ dh_builddeb -a
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/debian/watch.ex b/debian/watch.ex
new file mode 100644
index 0000000..3f57ae0
--- /dev/null
+++ b/debian/watch.ex
@@ -0,0 +1,5 @@
+# Example watch control file for uscan
+# Rename this file to "watch" and then you can run the "uscan" command
+# to check for upstream updates and more.
+# Site Directory Pattern Version Script
+sunsite.unc.edu /pub/Linux/Incoming freeside-(.*)\.tar\.gz debian uupdate
diff --git a/eg/TEMPLATE_cust_main.import b/eg/TEMPLATE_cust_main.import
new file mode 100755
index 0000000..e91a2f1
--- /dev/null
+++ b/eg/TEMPLATE_cust_main.import
@@ -0,0 +1,198 @@
+#!/usr/bin/perl -w
+#
+# Template for importing legacy customer data
+#
+# $Id: TEMPLATE_cust_main.import,v 1.4 2001-08-21 02:44:47 ivan Exp $
+
+use strict;
+use Date::Parse;
+use FS::UID qw(adminsuidsetup datasrc);
+use FS::Record qw(fields qsearch qsearchs);
+use FS::cust_main;
+use FS::cust_pkg;
+use FS::cust_svc;
+use FS::svc_acct;
+use FS::pkg_svc;
+
+my $user = shift or die &usage;
+adminsuidsetup $user;
+
+# use these for the imported cust_main records (unless you have these in legacy
+# data)
+my($agentnum)=4;
+my($refnum)=5;
+
+# map from legacy billing data to pkgpart, maps imported field
+# LegacyBillingData to pkgpart. your names and pkgparts will be different
+my(%pkgpart)=(
+ 'Employee' => 10,
+ 'Business' => 11,
+ 'Individual' => 12,
+ 'Basic PPP' => 13,
+ 'Slave' => 14,
+ 'Co-Located Server' => 15,
+ 'Virtual Web' => 16,
+ 'Perk Mail' => 17,
+ 'Credit Hold' => 18,
+);
+
+my($file)="legacy_file";
+
+open(CLIENT,$file)
+ or die "Can't open $file: $!";
+
+# put a tab-separated header atop the file, or define @fields
+# (use these names or change them below)
+#
+# for cust_main
+# custnum - unique
+# last - (name)
+# first - (name)
+# company
+# address1
+# address2
+# city
+# state
+# zip
+# country
+# daytime - (phone)
+# night - (phone)
+# fax
+# payby - CARD, BILL or COMP
+# payinfo - Credit card #, P.O. # or COMP authorization
+# paydate - Expiration
+# tax - 'Y' for tax exempt
+# for cust_pkg
+# LegacyBillingData - maps via %pkgpart above to a pkgpart
+# for svc_acct
+# username
+
+my($header);
+$header=<CLIENT>;
+chop $header;
+my(@fields)=map { /^\s*(.*[^\s]+)\s*$/; $1 } split(/\t/,$header);
+#print join("\n",@fields);
+
+my($error);
+my($link,$line)=(0,0);
+while (<CLIENT>) {
+ chop;
+ next if /^[\s\t]*$/; #skip any blank lines
+
+ #define %svc hash for this record
+ my(@record)=split(/\t/);
+ my(%svc);
+ foreach (@fields) {
+ $svc{$_}=shift @record;
+ }
+
+ # might need to massage some data like this
+ $svc{'payby'} =~ s/^Credit Card$/CARD/io;
+ $svc{'payby'} =~ s/^Check$/BILL/io;
+ $svc{'payby'} =~ s/^Cash$/BILL/io;
+ $svc{'payby'} =~ s/^$/BILL/o;
+ $svc{'First'} =~ s/&/and/go;
+ $svc{'Zip'} =~ s/\s+$//go;
+
+ my($cust_main) = new FS::cust_main ( {
+ 'custnum' => $svc{'custnum'},
+ 'agentnum' => $agentnum,
+ 'last' => $svc{'last'},
+ 'first' => $svc{'first'},
+ 'company' => $svc{'company'},
+ 'address1' => $svc{'address1'},
+ 'address2' => $svc{'address2'},
+ 'city' => $svc{'city'},
+ 'state' => $svc{'state'},
+ 'zip' => $svc{'zip'},
+ 'country' => $svc{'country'},
+ 'daytime' => $svc{'daytime'},
+ 'night' => $svc{'night'},
+ 'fax' => $svc{'fax'},
+ 'payby' => $svc{'payby'},
+ 'payinfo' => $svc{'payinfo'},
+ 'paydate' => $svc{'paydate'},
+ 'payname' => $svc{'payname'},
+ 'tax' => $svc{'tax'},
+ 'refnum' => $refnum,
+ } );
+
+ $error=$cust_main->insert;
+
+ if ( $error ) {
+ warn $cust_main->_dump;
+ warn map "$_: ". $svc{$_}. "|\n", keys %svc;
+ die $error;
+ }
+
+ my($cust_pkg)=new FS::cust_pkg ( {
+ 'custnum' => $svc{'custnum'},
+ 'pkgpart' => $pkgpart{$svc{'LegacyBillingData'}},
+ 'setup' => '',
+ 'bill' => '',
+ 'susp' => '',
+ 'expire' => '',
+ 'cancel' => '',
+ } );
+
+ $error=$cust_pkg->insert;
+ if ( $error ) {
+ warn $svc{'LegacyBillingData'};
+ die $error;
+ }
+
+ unless ( $svc{'username'} ) {
+ warn "Empty login";
+ } else {
+ #find svc_acct record (imported with bin/svc_acct.import) for this username
+ my($svc_acct)=qsearchs('svc_acct',{'username'=>$svc{'username'}});
+ unless ( $svc_acct ) {
+ warn "username ", $svc{'username'}, " not found\n";
+ } else {
+ #link to the cust_pkg record we created above
+
+ #find cust_svc record for this svc_acct record
+ my($o_cust_svc)=qsearchs('cust_svc',{
+ 'svcnum' => $svc_acct->svcnum,
+ 'pkgnum' => '',
+ } );
+ unless ( $o_cust_svc ) {
+ warn "No unlinked cust_svc for svcnum ", $svc_acct->svcnum;
+ } else {
+
+ #make sure this svcpart is in pkgpart
+ my($pkg_svc)=qsearchs('pkg_svc',{
+ 'pkgpart' => $pkgpart{$svc{'LegacyBillingData'}},
+ 'svcpart' => $o_cust_svc->svcpart,
+ 'quantity' => 1,
+ });
+ unless ( $pkg_svc ) {
+ warn "login ", $svc{'username'}, ": No svcpart ", $o_cust_svc->svcpart,
+ " for pkgpart ", $pkgpart{$svc{'Acct. Type'}}, "\n" ;
+ } else {
+
+ #create new cust_svc record linked to cust_pkg record
+ my($n_cust_svc) = new FS::cust_svc ({
+ 'svcnum' => $o_cust_svc->svcnum,
+ 'pkgnum' => $cust_pkg->pkgnum,
+ 'svcpart' => $pkg_svc->svcpart,
+ });
+ my($error) = $n_cust_svc->replace($o_cust_svc);
+ die $error if $error;
+ $link++;
+ }
+ }
+ }
+ }
+
+ $line++;
+
+}
+
+warn "\n$link of $line lines linked\n";
+
+# ---
+
+sub usage {
+ die "Usage:\n\n cust_main.import user\n";
+}
diff --git a/eg/export_template.pm b/eg/export_template.pm
new file mode 100644
index 0000000..2c199db
--- /dev/null
+++ b/eg/export_template.pm
@@ -0,0 +1,81 @@
+package FS::part_export::myexport;
+
+use vars qw(@ISA %info);
+use Tie::IxHash;
+use FS::part_export;
+
+@ISA = qw(FS::part_export);
+
+tie my %options, 'Tie::IxHash',
+ 'regular_option' => { label => 'Option description', default => 'value' },
+ 'select_option' => { label => 'Select option description',
+ type => 'select', options=>[qw(chocolate vanilla)],
+ default => 'vanilla',
+ },
+ 'textarea_option' => { label => 'Textarea option description',
+ type => 'textarea',
+ default => 'Default text.',
+ },
+ 'checkbox_option' => { label => 'Checkbox label', type => 'checkbox' },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ #'svc' => [qw( svc_acct svc_forward )],
+ 'desc' =>
+ 'Export short description',
+ 'options' => \%options,
+ 'nodomain' => 'Y',
+ 'notes' => <<'END'
+HTML notes about this export.
+END
+
+sub rebless { shift; }
+
+sub _export_insert {
+ my($self, $svc_something) = (shift, shift);
+ $err_or_queue = $self->myexport_queue( $svc_something->svcnum, 'insert',
+ $svc_something->username, $svc_something->_password );
+ ref($err_or_queue) ? '' : $err_or_queue;
+}
+
+sub _export_replace {
+ my( $self, $new, $old ) = (shift, shift, shift);
+ #return "can't change username with myexport"
+ # if $old->username ne $new->username;
+ #return '' unless $old->_password ne $new->_password;
+ $err_or_queue = $self->myexport_queue( $new->svcnum,
+ 'replace', $new->username, $new->_password );
+ ref($err_or_queue) ? '' : $err_or_queue;
+}
+
+sub _export_delete {
+ my( $self, $svc_something ) = (shift, shift);
+ $err_or_queue = $self->myexport_queue( $svc_something->svcnum,
+ 'delete', $svc_something->username );
+ ref($err_or_queue) ? '' : $err_or_queue;
+}
+
+#a good idea to queue anything that could fail or take any time
+sub myexport_queue {
+ my( $self, $svcnum, $method ) = (shift, shift, shift);
+ my $queue = new FS::queue {
+ 'svcnum' => $svcnum,
+ 'job' => "FS::part_export::myexport::myexport_$method",
+ };
+ $queue->insert( @_ ) or $queue;
+}
+
+sub myexport_insert { #subroutine, not method
+ my( $username, $password ) = @_;
+ #do things with $username and $password
+}
+
+sub myexport_replace { #subroutine, not method
+}
+
+sub myexport_delete { #subroutine, not method
+ my( $username ) = @_;
+ #do things with $username
+}
+
diff --git a/eg/table_template-svc.pm b/eg/table_template-svc.pm
new file mode 100644
index 0000000..7f7ef4b
--- /dev/null
+++ b/eg/table_template-svc.pm
@@ -0,0 +1,161 @@
+package FS::svc_table;
+
+use strict;
+use vars qw(@ISA);
+#use FS::Record qw( qsearch qsearchs );
+use FS::svc_Common;
+use FS::cust_svc;
+
+@ISA = qw(FS::svc_Common);
+
+=head1 NAME
+
+FS::table_name - Object methods for table_name records
+
+=head1 SYNOPSIS
+
+ use FS::table_name;
+
+ $record = new FS::table_name \%hash;
+ $record = new FS::table_name { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $error = $record->cancel;
+
+=head1 DESCRIPTION
+
+An FS::table_name object represents an example. FS::table_name inherits from
+FS::svc_Common. The following fields are currently supported:
+
+=over 4
+
+=item field - description
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'table_name'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my $error;
+
+ $error = $self->SUPER::insert;
+ return $error if $error;
+
+ '';
+}
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+sub delete {
+ my $self = shift;
+ my $error;
+
+ $error = $self->SUPER::delete;
+ return $error if $error;
+
+ '';
+}
+
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+ my $error;
+
+ $error = $new->SUPER::replace($old);
+ return $error if $error;
+
+ '';
+}
+
+=item suspend
+
+Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item unsuspend
+
+Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item cancel
+
+Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item check
+
+Checks all fields to make sure this is a valid example. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and repalce methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $x = $self->setfixed;
+ return $x unless ref($x);
+ my $part_svc = $x;
+
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::svc_Common>, L<FS::Record>, L<FS::cust_svc>, L<FS::part_svc>,
+L<FS::cust_pkg>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/eg/table_template.pm b/eg/table_template.pm
new file mode 100644
index 0000000..d609bd5
--- /dev/null
+++ b/eg/table_template.pm
@@ -0,0 +1,112 @@
+package FS::table_name;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::table_name - Object methods for table_name records
+
+=head1 SYNOPSIS
+
+ use FS::table_name;
+
+ $record = new FS::table_name \%hash;
+ $record = new FS::table_name { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::table_name object represents an example. FS::table_name inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item field - description
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new example. To add the example to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'table_name'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid example. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ ''; #no error
+}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/etc/abbr_state.txt b/etc/abbr_state.txt
new file mode 100644
index 0000000..7e4f57f
--- /dev/null
+++ b/etc/abbr_state.txt
@@ -0,0 +1,72 @@
+State/Possession Abbreviation
+
+ALABAMA AL
+ALASKA AK
+AMERICAN SAMOA AS
+ARIZONA AZ
+ARKANSAS AR
+CALIFORNIA CA
+COLORADO CO
+CONNECTICUT CT
+DELAWARE DE
+DISTRICT OF COLUMBIA DC
+FEDERATED STATES OF MICRONESIA FM
+FLORIDA FL
+GEORGIA GA
+GUAM GU
+HAWAII HI
+IDAHO ID
+ILLINOIS IL
+INDIANA IN
+IOWA IA
+KANSAS KS
+KENTUCKY KY
+LOUISIANA LA
+MAINE ME
+MARSHALL ISLANDS MH
+MARYLAND MD
+MASSACHUSETTS MA
+MICHIGAN MI
+MINNESOTA MN
+MISSISSIPPI MS
+MISSOURI MO
+MONTANA MT
+NEBRASKA NE
+NEVADA NV
+NEW HAMPSHIRE NH
+NEW JERSEY NJ
+NEW MEXICO NM
+NEW YORK NY
+NORTH CAROLINA NC
+NORTH DAKOTA ND
+NORTHERN MARIANA ISLANDS MP
+OHIO OH
+OKLAHOMA OK
+OREGON OR
+PALAU PW
+PENNSYLVANIA PA
+PUERTO RICO PR
+RHODE ISLAND RI
+SOUTH CAROLINA SC
+SOUTH DAKOTA SD
+TENNESSEE TN
+TEXAS TX
+UTAH UT
+VERMONT VT
+VIRGIN ISLANDS VI
+VIRGINIA VA
+WASHINGTON WA
+WEST VIRGINIA WV
+WISCONSIN WI
+WYOMING WY
+
+
+Military "State" Abbreviation
+
+Armed Forces Africa AE
+Armed Forces Americas AA
+(except Canada)
+Armed Forces Canada AE
+Armed Forces Europe AE
+Armed Forces Middle East AE
+Armed Forces Pacific AP
diff --git a/etc/countries.txt b/etc/countries.txt
new file mode 100644
index 0000000..73c3975
--- /dev/null
+++ b/etc/countries.txt
@@ -0,0 +1,239 @@
+AFGHANISTAN AF AFG 004
+ALBANIA AL ALB 008
+ALGERIA DZ DZA 012
+AMERICAN SAMOA AS ASM 016
+ANDORRA AD AND 020
+ANGOLA AO AGO 024
+ANGUILLA AI AIA 660
+ANTARCTICA AQ ATA 010
+ANTIGUA AND BARBUDA AG ATG 028
+ARGENTINA AR ARG 032
+ARMENIA AM ARM 051
+ARUBA AW ABW 533
+AUSTRALIA AU AUS 036
+AUSTRIA AT AUT 040
+AZERBAIJAN AZ AZE 031
+BAHAMAS BS BHS 044
+BAHRAIN BH BHR 048
+BANGLADESH BD BGD 050
+BARBADOS BB BRB 052
+BELARUS BY BLR 112
+BELGIUM BE BEL 056
+BELIZE BZ BLZ 084
+BENIN BJ BEN 204
+BERMUDA BM BMU 060
+BHUTAN BT BTN 064
+BOLIVIA BO BOL 068
+BOSNIA AND HERZEGOWINA BA BIH 070
+BOTSWANA BW BWA 072
+BOUVET ISLAND BV BVT 074
+BRAZIL BR BRA 076
+BRITISH INDIAN OCEAN TERRITORY IO IOT 086
+BRUNEI DARUSSALAM BN BRN 096
+BULGARIA BG BGR 100
+BURKINA FASO BF BFA 854
+BURUNDI BI BDI 108
+CAMBODIA KH KHM 116
+CAMEROON CM CMR 120
+CANADA CA CAN 124
+CAPE VERDE CV CPV 132
+CAYMAN ISLANDS KY CYM 136
+CENTRAL AFRICAN REPUBLIC CF CAF 140
+CHAD TD TCD 148
+CHILE CL CHL 152
+CHINA CN CHN 156
+CHRISTMAS ISLAND CX CXR 162
+COCOS (KEELING) ISLANDS CC CCK 166
+COLOMBIA CO COL 170
+COMOROS KM COM 174
+CONGO CG COG 178
+COOK ISLANDS CK COK 184
+COSTA RICA CR CRI 188
+COTE D'IVOIRE CI CIV 384
+CROATIA (local name: Hrvatska) HR HRV 191
+CUBA CU CUB 192
+CYPRUS CY CYP 196
+CZECH REPUBLIC CZ CZE 203
+DENMARK DK DNK 208
+DJIBOUTI DJ DJI 262
+DOMINICA DM DMA 212
+DOMINICAN REPUBLIC DO DOM 214
+EAST TIMOR TP TMP 626
+ECUADOR EC ECU 218
+EGYPT EG EGY 818
+EL SALVADOR SV SLV 222
+EQUATORIAL GUINEA GQ GNQ 226
+ERITREA ER ERI 232
+ESTONIA EE EST 233
+ETHIOPIA ET ETH 231
+FALKLAND ISLANDS (MALVINAS) FK FLK 238
+FAROE ISLANDS FO FRO 234
+FIJI FJ FJI 242
+FINLAND FI FIN 246
+FRANCE FR FRA 250
+FRANCE, METROPOLITAN FX FXX 249
+FRENCH GUIANA GF GUF 254
+FRENCH POLYNESIA PF PYF 258
+FRENCH SOUTHERN TERRITORIES TF ATF 260
+GABON GA GAB 266
+GAMBIA GM GMB 270
+GEORGIA GE GEO 268
+GERMANY DE DEU 276
+GHANA GH GHA 288
+GIBRALTAR GI GIB 292
+GREECE GR GRC 300
+GREENLAND GL GRL 304
+GRENADA GD GRD 308
+GUADELOUPE GP GLP 312
+GUAM GU GUM 316
+GUATEMALA GT GTM 320
+GUINEA GN GIN 324
+GUINEA-BISSAU GW GNB 624
+GUYANA GY GUY 328
+HAITI HT HTI 332
+HEARD AND MC DONALD ISLANDS HM HMD 334
+HONDURAS HN HND 340
+HONG KONG HK HKG 344
+HUNGARY HU HUN 348
+ICELAND IS ISL 352
+INDIA IN IND 356
+INDONESIA ID IDN 360
+IRAN (ISLAMIC REPUBLIC OF) IR IRN 364
+IRAQ IQ IRQ 368
+IRELAND IE IRL 372
+ISRAEL IL ISR 376
+ITALY IT ITA 380
+JAMAICA JM JAM 388
+JAPAN JP JPN 392
+JORDAN JO JOR 400
+KAZAKHSTAN KZ KAZ 398
+KENYA KE KEN 404
+KIRIBATI KI KIR 296
+KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF KP PRK 408
+KOREA, REPUBLIC OF KR KOR 410
+KUWAIT KW KWT 414
+KYRGYZSTAN KG KGZ 417
+LAO PEOPLE'S DEMOCRATIC REPUBLIC LA LAO 418
+LATVIA LV LVA 428
+LEBANON LB LBN 422
+LESOTHO LS LSO 426
+LIBERIA LR LBR 430
+LIBYAN ARAB JAMAHIRIYA LY LBY 434
+LIECHTENSTEIN LI LIE 438
+LITHUANIA LT LTU 440
+LUXEMBOURG LU LUX 442
+MACAU MO MAC 446
+MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF MK MKD 807
+MADAGASCAR MG MDG 450
+MALAWI MW MWI 454
+MALAYSIA MY MYS 458
+MALDIVES MV MDV 462
+MALI ML MLI 466
+MALTA MT MLT 470
+MARSHALL ISLANDS MH MHL 584
+MARTINIQUE MQ MTQ 474
+MAURITANIA MR MRT 478
+MAURITIUS MU MUS 480
+MAYOTTE YT MYT 175
+MEXICO MX MEX 484
+MICRONESIA, FEDERATED STATES OF FM FSM 583
+MOLDOVA, REPUBLIC OF MD MDA 498
+MONACO MC MCO 492
+MONGOLIA MN MNG 496
+MONTSERRAT MS MSR 500
+MOROCCO MA MAR 504
+MOZAMBIQUE MZ MOZ 508
+MYANMAR MM MMR 104
+NAMIBIA NA NAM 516
+NAURU NR NRU 520
+NEPAL NP NPL 524
+NETHERLANDS NL NLD 528
+NETHERLANDS ANTILLES AN ANT 530
+NEW CALEDONIA NC NCL 540
+NEW ZEALAND NZ NZL 554
+NICARAGUA NI NIC 558
+NIGER NE NER 562
+NIGERIA NG NGA 566
+NIUE NU NIU 570
+NORFOLK ISLAND NF NFK 574
+NORTHERN MARIANA ISLANDS MP MNP 580
+NORWAY NO NOR 578
+OMAN OM OMN 512
+PAKISTAN PK PAK 586
+PALAU PW PLW 585
+PANAMA PA PAN 591
+PAPUA NEW GUINEA PG PNG 598
+PARAGUAY PY PRY 600
+PERU PE PER 604
+PHILIPPINES PH PHL 608
+PITCAIRN PN PCN 612
+POLAND PL POL 616
+PORTUGAL PT PRT 620
+PUERTO RICO PR PRI 630
+QATAR QA QAT 634
+REUNION RE REU 638
+ROMANIA RO ROM 642
+RUSSIAN FEDERATION RU RUS 643
+RWANDA RW RWA 646
+SAINT KITTS AND NEVIS KN KNA 659
+SAINT LUCIA LC LCA 662
+SAINT VINCENT AND THE GRENADINES VC VCT 670
+SAMOA WS WSM 882
+SAN MARINO SM SMR 674
+SAO TOME AND PRINCIPE ST STP 678
+SAUDI ARABIA SA SAU 682
+SENEGAL SN SEN 686
+SEYCHELLES SC SYC 690
+SIERRA LEONE SL SLE 694
+SINGAPORE SG SGP 702
+SLOVAKIA (Slovak Republic) SK SVK 703
+SLOVENIA SI SVN 705
+SOLOMON ISLANDS SB SLB 090
+SOMALIA SO SOM 706
+SOUTH AFRICA ZA ZAF 710
+SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS GS SGS 239
+SPAIN ES ESP 724
+SRI LANKA LK LKA 144
+ST. HELENA SH SHN 654
+ST. PIERRE AND MIQUELON PM SPM 666
+SUDAN SD SDN 736
+SURINAME SR SUR 740
+SVALBARD AND JAN MAYEN ISLANDS SJ SJM 744
+SWAZILAND SZ SWZ 748
+SWEDEN SE SWE 752
+SWITZERLAND CH CHE 756
+SYRIAN ARAB REPUBLIC SY SYR 760
+TAIWAN, PROVINCE OF CHINA TW TWN 158
+TAJIKISTAN TJ TJK 762
+TANZANIA, UNITED REPUBLIC OF TZ TZA 834
+THAILAND TH THA 764
+TOGO TG TGO 768
+TOKELAU TK TKL 772
+TONGA TO TON 776
+TRINIDAD AND TOBAGO TT TTO 780
+TUNISIA TN TUN 788
+TURKEY TR TUR 792
+TURKMENISTAN TM TKM 795
+TURKS AND CAICOS ISLANDS TC TCA 796
+TUVALU TV TUV 798
+UGANDA UG UGA 800
+UKRAINE UA UKR 804
+UNITED ARAB EMIRATES AE ARE 784
+UNITED KINGDOM GB GBR 826
+UNITED STATES US USA 840
+UNITED STATES MINOR OUTLYING ISLANDS UM UMI 581
+URUGUAY UY URY 858
+UZBEKISTAN UZ UZB 860
+VANUATU VU VUT 548
+VATICAN CITY STATE (HOLY SEE) VA VAT 336
+VENEZUELA VE VEN 862
+VIET NAM VN VNM 704
+VIRGIN ISLANDS (BRITISH) VG VGB 092
+VIRGIN ISLANDS (U.S.) VI VIR 850
+WALLIS AND FUTUNA ISLANDS WF WLF 876
+WESTERN SAHARA EH ESH 732
+YEMEN YE YEM 887
+YUGOSLAVIA YU YUG 891
+ZAIRE ZR ZAR 180
+ZAMBIA ZM ZMB 894
+ZIMBABWE ZW ZWE 716
diff --git a/etc/domain-template.txt b/etc/domain-template.txt
new file mode 100644
index 0000000..8e4983c
--- /dev/null
+++ b/etc/domain-template.txt
@@ -0,0 +1,231 @@
+[ URL ftp://rs.internic.net/templates/domain-template.txt ] [ 03/98 ]
+
+******* Please DO NOT REMOVE Version Number or Sections A-Q ********
+
+Domain Version Number: 4.0
+
+******* Email completed agreement to hostmaster@internic.net *******
+
+ NETWORK SOLUTIONS, INC.
+
+ DOMAIN NAME REGISTRATION AGREEMENT
+
+
+A. Introduction. This domain name registration agreement
+("Registration Agreement") is submitted to NETWORK SOLUTIONS, INC.
+("NSI") for the purpose of applying for and registering a domain name
+on the Internet. If this Registration Agreement is accepted by NSI,
+and a domain name is registered in NSI's domain name database and
+assigned to the Registrant, Registrant ("Registrant") agrees to be
+bound by the terms of this Registration Agreement and the terms of
+NSI's Domain Name Dispute Policy ("Dispute Policy") which is
+incorporated herein by reference and made a part of this Registration
+Agreement. This Registration Agreement shall be accepted at the
+offices of NSI.
+
+B. Fees and Payments.
+
+1) Registration or renewal (re-registration) date through March 31, 1998:
+Registrant agrees to pay a registration fee of One Hundred United States
+Dollars (US$100) as consideration for the registration of each new domain
+name or Fifty United States Dollars (US$50) to renew (re-register) an
+existing registration.
+2) Registration or renewal date on and after April 1, 1998: Registrant
+agrees to pay a registration fee of Seventy United States Dollars (US$70)
+as consideration for the registration of each new domain name or the
+applicable renewal (re-registration) fee (currently Thirty-Five United
+States Dollars (US$35)) at the time of renewal (re-registration).
+3) Period of Service: The non-refundable fee covers a period of two (2)
+years for each new registration, and one (1) year for each renewal,
+and includes any permitted modification(s) to the domain name record
+during the covered period.
+4) Payment: Payment is due to Network Solutions within thirty (30)
+days from the date of the invoice.
+
+C. Dispute Policy. Registrant agrees, as a condition to
+submitting this Registration Agreement, and if the Registration
+Agreement is accepted by NSI, that the Registrant shall be bound by
+NSI's current Dispute Policy. The current version of the Dispute
+Policy may be found at the InterNIC Registration Services web site:
+"http://www.netsol.com/rs/dispute-policy.html".
+
+D. Dispute Policy Changes or Modifications. Registrant agrees
+that NSI, in its sole discretion, may change or modify the Dispute
+Policy, incorporated by reference herein, at any time. Registrant
+agrees that Registrant's maintaining the registration of a domain name
+after changes or modifications to the Dispute Policy become effective
+constitutes Registrant's continued acceptance of these changes or
+modifications. Registrant agrees that if Registrant considers any such
+changes or modifications to be unacceptable, Registrant may request
+that the domain name be deleted from the domain name database.
+
+E. Disputes. Registrant agrees that, if the registration of its
+domain name is challenged by any third party, the Registrant will be
+subject to the provisions specified in the Dispute Policy.
+
+F. Agents. Registrant agrees that if this Registration Agreement
+is completed by an agent for the Registrant, such as an ISP or
+Administrative Contact/Agent, the Registrant is nonetheless bound as a
+principal by all terms and conditions herein, including the Dispute
+Policy.
+
+G. Limitation of Liability. Registrant agrees that NSI shall have
+no liability to the Registrant for any loss Registrant may incur in
+connection with NSI's processing of this Registration Agreement, in
+connection with NSI's processing of any authorized modification to the
+domain name's record during the covered period, as a result of the
+Registrant's ISP's failure to pay either the initial registration fee
+or renewal fee, or as a result of the application of the provisions of
+the Dispute Policy. Registrant agrees that in no event shall the
+maximum liability of NSI under this Agreement for any matter exceed
+Five Hundred United States Dollars (US$500).
+
+H. Indemnity. Registrant agrees, in the event the Registration
+Agreement is accepted by NSI and a subsequent dispute arises with any
+third party, to indemnify and hold NSI harmless pursuant to the terms
+and conditions contained in the Dispute Policy.
+
+I. Breach. Registrant agrees that failure to abide by any
+provision of this Registration Agreement or the Dispute Policy may be
+considered by NSI to be a material breach and that NSI may provide a
+written notice, describing the breach, to the Registrant. If, within
+thirty (30) days of the date of mailing such notice, the Registrant
+fails to provide evidence, which is reasonably satisfactory to NSI,
+that it has not breached its obligations, then NSI may delete
+Registrant's registration of the domain name. Any such breach by a
+Registrant shall not be deemed to be excused simply because NSI did
+not act earlier in response to that, or any other, breach by the
+Registrant.
+
+J. No Guaranty. Registrant agrees that, by registration of a
+domain name, such registration does not confer immunity from objection
+to either the registration or use of the domain name.
+
+K. Warranty. Registrant warrants by submitting this Registration
+Agreement that, to the best of Registrant's knowledge and belief, the
+information submitted herein is true and correct, and that any future
+changes to this information will be provided to NSI in a timely manner
+according to the domain name modification procedures in place at that
+time. Breach of this warranty will constitute a material breach.
+
+L. Revocation. Registrant agrees that NSI may delete a
+Registrant's domain name if this Registration Agreement, or subsequent
+modification(s) thereto, contains false or misleading information, or
+conceals or omits any information NSI would likely consider material
+to its decision to approve this Registration Agreement.
+
+M. Right of Refusal. NSI, in its sole discretion, reserves the
+right to refuse to approve the Registration Agreement for any
+Registrant. Registrant agrees that the submission of this Registration
+Agreement does not obligate NSI to accept this Registration Agreement.
+Registrant agrees that NSI shall not be liable for loss or damages
+that may result from NSI's refusal to accept this Registration
+Agreement.
+
+N. Severability. Registrant agrees that the terms of this
+Registration Agreement are severable. If any term or provision is
+declared invalid, it shall not affect the remaining terms or
+provisions which shall continue to be binding.
+
+O. Entirety. Registrant agrees that this Registration Agreement
+and the Dispute Policy is the complete and exclusive agreement between
+Registrant and NSI regarding the registration of Registrant's domain
+name. This Registration Agreement and the Dispute Policy supersede all
+prior agreements and understandings, whether established by custom,
+practice, policy, or precedent.
+
+P. Governing Law. Registrant agrees that this Registration
+Agreement shall be governed in all respects by and construed in
+accordance with the laws of the Commonwealth of Virginia, United
+States of America. By submitting this Registration Agreement,
+Registrant consents to the exclusive jurisdiction and venue of the
+United States District Court for the Eastern District of Virginia,
+Alexandria Division. If there is no jurisdiction in the United States
+District Court for the Eastern District of Virginia, Alexandria
+Division, then jurisdiction shall be in the Circuit Court of Fairfax
+County, Fairfax, Virginia.
+
+Q. This is Domain Name Registration Agreement Version
+Number 4.0. This Registration Agreement is only for registrations
+under top-level domains: COM, ORG, NET, and EDU. By completing
+and submitting this Registration Agreement for consideration and
+acceptance by NSI, the Registrant agrees that he/she has read and
+agrees to be bound by A through P above.
+
+
+Authorization
+0a. (N)ew (M)odify (D)elete....:###action###
+0b. Auth Scheme................:
+0c. Auth Info..................:
+
+1. Comments...................:###purpose###
+
+2. Complete Domain Name.......:###domain###
+
+Organization Using Domain Name
+
+3a. Organization Name..........:###company###
+###LOOP###
+3b. Street Address.............:###address###
+###ENDLOOP###
+3c. City.......................:###city###
+3d. State......................:###state###
+3e. Postal Code................:###zip###
+3f. Country....................:###country###
+
+Administrative Contact
+4a. NIC Handle (if known)......:
+4b. (I)ndividual (R)ole........:I
+4c. Name (Last, First).........:###last###, ###first###
+4d. Organization Name..........:###company###
+###LOOP###
+4e. Street Address.............:###address###
+###ENDLOOP###
+4f. City.......................:###city###
+4g. State......................:###state###
+4h. Postal Code................:###zip###
+4i. Country....................:###country###
+4j. Phone Number...............:###daytime###
+4k. Fax Number.................:###fax###
+4l. E-Mailbox..................:###email###
+
+Technical Contact
+5a. NIC Handle (if known)......:###tech_contact###
+5b. (I)ndividual (R)ole........:
+5c. Name (Last, First).........:
+5d. Organization Name..........:
+5e. Street Address.............:
+5f. City.......................:
+5g. State......................:
+5h. Postal Code................:
+5i. Country....................:
+5j. Phone Number...............:
+5k. Fax Number.................:
+5l. E-Mailbox..................:
+
+Billing Contact
+6a. NIC Handle (if known)......:
+6b. (I)ndividual (R)ole........:
+6c. Name (Last, First).........:
+6d. Organization Name..........:
+6e. Street Address.............:
+6f. City.......................:
+6g. State......................:
+6h. Postal Code................:
+6i. Country....................:
+6j. Phone Number...............:
+6k. Fax Number.................:
+6l. E-Mailbox..................:
+
+Prime Name Server
+7a. Primary Server Hostname....:###primary###
+7b. Primary Server Netaddress..:###primary_ip###
+
+Secondary Name Server(s)
+###LOOP###
+8a. Secondary Server Hostname..:###secondary###
+8b. Secondary Server Netaddress:###secondary_ip###
+###ENDLOOP###
+
+END OF AGREEMENT
+
diff --git a/etc/megapop.pl b/etc/megapop.pl
new file mode 100755
index 0000000..b250bcd
--- /dev/null
+++ b/etc/megapop.pl
@@ -0,0 +1,116 @@
+#!/usr/bin/perl -Tw
+#
+# $Id: megapop.pl,v 1.1 1999-04-19 10:32:44 ivan Exp $
+#
+# this will break when megapop changes the URL or format of their listing page.
+# that's stupid. perhaps they can provide a machine-readable listing?
+
+use strict;
+use LWP::UserAgent;
+use FS::UID qw(adminsuidsetup);
+use FS::svc_acct_pop;
+
+my $url = "http://www.megapop.com/location.htm";
+
+my $user = shift or die &usage;
+adminsuidsetup($user);
+
+my %state2usps = &state2usps;
+$state2usps{'WASHINGTON STATE'} = 'WA'; #megapop's on crack
+$state2usps{'CANADA'} = 'CANADA'; #freeside's on crack
+
+my $ua = new LWP::UserAgent;
+my $request = new HTTP::Request('GET', $url);
+my $response = $ua->request($request);
+die $response->error_as_HTML unless $response->is_success;
+my $line;
+my $usps = '';
+foreach $line ( split("\n", $response->content) ) {
+ if ( $line =~ /\W(\w[\w\s]*\w)\s+LOCATIONS/i ) {
+ $usps = $state2usps{uc($1)}
+ or warn "warning: unknown state $1\n";
+ } elsif ( $line =~ /(\d{3})\-(\d{3})\-(\d{4})\s+(\w[\w\s]*\w)/ ) {
+ print "$1 $2 $3 $4 $usps\n";
+ my $svc_acct_pop = new FS::svc_acct_pop ( {
+ 'city' => $4,
+ 'state' => $usps,
+ 'ac' => $1,
+ 'exch' => $2,
+ } );
+ my $error = $svc_acct_pop->insert;
+ die $error if $error;
+ }
+}
+
+sub usage {
+ die "Usage:\n $0 user\n";
+}
+
+sub state2usps{ (
+ 'ALABAMA' => 'AL',
+ 'ALASKA' => 'AK',
+ 'AMERICAN SAMOA' => 'AS',
+ 'ARIZONA' => 'AZ',
+ 'ARKANSAS' => 'AR',
+ 'CALIFORNIA' => 'CA',
+ 'COLORADO' => 'CO',
+ 'CONNECTICUT' => 'CT',
+ 'DELAWARE' => 'DE',
+ 'DISTRICT OF COLUMBIA' => 'DC',
+ 'FEDERATED STATES OF MICRONESIA' => 'FM',
+ 'FLORIDA' => 'FL',
+ 'GEORGIA' => 'GA',
+ 'GUAM' => 'GU',
+ 'HAWAII' => 'HI',
+ 'IDAHO' => 'ID',
+ 'ILLINOIS' => 'IL',
+ 'INDIANA' => 'IN',
+ 'IOWA' => 'IA',
+ 'KANSAS' => 'KS',
+ 'KENTUCKY' => 'KY',
+ 'LOUISIANA' => 'LA',
+ 'MAINE' => 'ME',
+ 'MARSHALL ISLANDS' => 'MH',
+ 'MARYLAND' => 'MD',
+ 'MASSACHUSETTS' => 'MA',
+ 'MICHIGAN' => 'MI',
+ 'MINNESOTA' => 'MN',
+ 'MISSISSIPPI' => 'MS',
+ 'MISSOURI' => 'MO',
+ 'MONTANA' => 'MT',
+ 'NEBRASKA' => 'NE',
+ 'NEVADA' => 'NV',
+ 'NEW HAMPSHIRE' => 'NH',
+ 'NEW JERSEY' => 'NJ',
+ 'NEW MEXICO' => 'NM',
+ 'NEW YORK' => 'NY',
+ 'NORTH CAROLINA' => 'NC',
+ 'NORTH DAKOTA' => 'ND',
+ 'NORTHERN MARIANA ISLANDS' => 'MP',
+ 'OHIO' => 'OH',
+ 'OKLAHOMA' => 'OK',
+ 'OREGON' => 'OR',
+ 'PALAU' => 'PW',
+ 'PENNSYLVANIA' => 'PA',
+ 'PUERTO RICO' => 'PR',
+ 'RHODE ISLAND' => 'RI',
+ 'SOUTH CAROLINA' => 'SC',
+ 'SOUTH DAKOTA' => 'SD',
+ 'TENNESSEE' => 'TN',
+ 'TEXAS' => 'TX',
+ 'UTAH' => 'UT',
+ 'VERMONT' => 'VT',
+ 'VIRGIN ISLANDS' => 'VI',
+ 'VIRGINIA' => 'VA',
+ 'WASHINGTON' => 'WA',
+ 'WEST VIRGINIA' => 'WV',
+ 'WISCONSIN' => 'WI',
+ 'WYOMING' => 'WY',
+ 'ARMED FORCES AFRICA' => 'AE',
+ 'ARMED FORCES AMERICAS' => 'AA',
+ 'ARMED FORCES CANADA' => 'AE',
+ 'ARMED FORCES EUROPE' => 'AE',
+ 'ARMED FORCES MIDDLE EAST' => 'AE',
+ 'ARMED FORCES PACIFIC' => 'AP',
+) }
+
diff --git a/etc/sql-reserved-words.txt b/etc/sql-reserved-words.txt
new file mode 100644
index 0000000..dc507ce
--- /dev/null
+++ b/etc/sql-reserved-words.txt
@@ -0,0 +1,103 @@
+From http://epoch.cs.berkeley.edu:8000/sequoia/dba/montage/FAQ/SQL.html
+ by Jean Anderson (jta@postgres.berkeley.edu)
+
+What are the SQL reserved words?
+
+I grep'd the following list out of the sql docs available via anonymous ftp to speckle.ncsl.nist.gov:/isowg3.
+SQL3 words are not set in stone, but you'd do well to avoid them.
+
+ From sql1992.txt:
+
+ AFTER, ALIAS, ASYNC, BEFORE, BOOLEAN, BREADTH,
+ COMPLETION, CALL, CYCLE, DATA, DEPTH, DICTIONARY, EACH, ELSEIF,
+ EQUALS, GENERAL, IF, IGNORE, LEAVE, LESS, LIMIT, LOOP, MODIFY,
+ NEW, NONE, OBJECT, OFF, OID, OLD, OPERATION, OPERATORS, OTHERS,
+ PARAMETERS, PENDANT, PREORDER, PRIVATE, PROTECTED, RECURSIVE, REF,
+ REFERENCING, REPLACE, RESIGNAL, RETURN, RETURNS, ROLE, ROUTINE,
+ ROW, SAVEPOINT, SEARCH, SENSITIVE, SEQUENCE, SIGNAL, SIMILAR,
+ SQLEXCEPTION, SQLWARNING, STRUCTURE, TEST, THERE, TRIGGER, TYPE,
+ UNDER, VARIABLE, VIRTUAL, VISIBLE, WAIT, WHILE, WITHOUT
+
+ From sql1992.txt (Annex E):
+
+ ABSOLUTE, ACTION, ADD, ALLOCATE, ALTER, ARE, ASSERTION, AT, BETWEEN,
+ BIT, BIT
+
+What are the SQL reserved words?
+
+I grep'd the following list out of the sql docs available via anonymous ftp to speckle.ncsl.nist.gov:/isowg3.
+SQL3 words are not set in stone, but you'd do well to avoid them.
+
+ From sql1992.txt:
+
+ AFTER, ALIAS, ASYNC, BEFORE, BOOLEAN, BREADTH,
+ COMPLETION, CALL, CYCLE, DATA, DEPTH, DICTIONARY, EACH, ELSEIF,
+ EQUALS, GENERAL, IF, IGNORE, LEAVE, LESS, LIMIT, LOOP, MODIFY,
+ NEW, NONE, OBJECT, OFF, OID, OLD, OPERATION, OPERATORS, OTHERS,
+ PARAMETERS, PENDANT, PREORDER, PRIVATE, PROTECTED, RECURSIVE, REF,
+ REFERENCING, REPLACE, RESIGNAL, RETURN, RETURNS, ROLE, ROUTINE,
+ ROW, SAVEPOINT, SEARCH, SENSITIVE, SEQUENCE, SIGNAL, SIMILAR,
+ SQLEXCEPTION, SQLWARNING, STRUCTURE, TEST, THERE, TRIGGER, TYPE,
+ UNDER, VARIABLE, VIRTUAL, VISIBLE, WAIT, WHILE, WITHOUT
+
+ From sql1992.txt (Annex E):
+
+ ABSOLUTE, ACTION, ADD, ALLOCATE, ALTER, ARE, ASSERTION, AT, BETWEEN,
+ BIT, BIT
+
+What are the SQL reserved words?
+
+I grep'd the following list out of the sql docs available via anonymous ftp to speckle.ncsl.nist.gov:/isowg3.
+SQL3 words are not set in stone, but you'd do well to avoid them.
+
+ From sql1992.txt:
+
+ AFTER, ALIAS, ASYNC, BEFORE, BOOLEAN, BREADTH,
+ COMPLETION, CALL, CYCLE, DATA, DEPTH, DICTIONARY, EACH, ELSEIF,
+ EQUALS, GENERAL, IF, IGNORE, LEAVE, LESS, LIMIT, LOOP, MODIFY,
+ NEW, NONE, OBJECT, OFF, OID, OLD, OPERATION, OPERATORS, OTHERS,
+ PARAMETERS, PENDANT, PREORDER, PRIVATE, PROTECTED, RECURSIVE, REF,
+ REFERENCING, REPLACE, RESIGNAL, RETURN, RETURNS, ROLE, ROUTINE,
+ ROW, SAVEPOINT, SEARCH, SENSITIVE, SEQUENCE, SIGNAL, SIMILAR,
+ SQLEXCEPTION, SQLWARNING, STRUCTURE, TEST, THERE, TRIGGER, TYPE,
+ UNDER, VARIABLE, VIRTUAL, VISIBLE, WAIT, WHILE, WITHOUT
+
+ From sql1992.txt (Annex E):
+
+ ABSOLUTE, ACTION, ADD, ALLOCATE, ALTER, ARE, ASSERTION, AT, BETWEEN,
+ BIT, BIT_LENGTH, BOTH, CASCADE, CASCADED, CASE, CAST, CATALOG,
+ CHAR_LENGTH, CHARACTER_LENGTH, COALESCE, COLLATE, COLLATION, COLUMN,
+ CONNECT, CONNECTION, CONSTRAINT, CONSTRAINTS, CONVERT, CORRESPONDING,
+ CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER,
+ DATE, DAY, DEALLOCATE, DEFERRABLE, DEFERRED, DESCRIBE, DESCRIPTOR,
+ DIAGNOSTICS, DISCONNECT, DOMAIN, DROP, ELSE, END-EXEC, EXCEPT,
+ EXCEPTION, EXECUTE, EXTERNAL, EXTRACT, FALSE, FIRST, FULL, GET,
+ GLOBAL, HOUR, IDENTITY, IMMEDIATE, INITIALLY, INNER, INPUT,
+ INSENSITIVE, INTERSECT, INTERVAL, ISOLATION, JOIN, LAST, LEADING,
+ LEFT, LEVEL, LOCAL, LOWER, MATCH, MINUTE, MONTH, NAMES, NATIONAL,
+ NATURAL, NCHAR, NEXT, NO, NULLIF, OCTET_LENGTH, ONLY, OUTER, OUTPUT,
+ OVERLAPS, PAD, PARTIAL, POSITION, PREPARE, PRESERVE, PRIOR, READ,
+ RELATIVE, RESTRICT, REVOKE, RIGHT, ROWS, SCROLL, SECOND, SESSION,
+ SESSION_USER, SIZE, SPACE, SQLSTATE, SUBSTRING, SYSTEM_USER,
+ TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE,
+ TRAILING, TRANSACTION, TRANSLATE, TRANSLATION, TRIM, TRUE, UNKNOWN,
+ UPPER, USAGE, USING, VALUE, VARCHAR, VARYING, WHEN, WRITE, YEAR, ZONE
+
+ From sql3part2.txt (Annex E)
+
+ ACTION, ACTOR, AFTER, ALIAS, ASYNC, ATTRIBUTES, BEFORE, BOOLEAN,
+ BREADTH, COMPLETION, CURRENT_PATH, CYCLE, DATA, DEPTH, DESTROY,
+ DICTIONARY, EACH, ELEMENT, ELSEIF, EQUALS, FACTOR, GENERAL, HOLD,
+ IGNORE, INSTEAD, LESS, LIMIT, LIST, MODIFY, NEW, NEW_TABLE, NO,
+ NONE, OFF, OID, OLD, OLD_TABLE, OPERATION, OPERATOR, OPERATORS,
+ PARAMETERS, PATH, PENDANT, POSTFIX, PREFIX, PREORDER, PRIVATE,
+ PROTECTED, RECURSIVE, REFERENCING, REPLACE, ROLE, ROUTINE, ROW,
+ SAVEPOINT, SEARCH, SENSITIVE, SEQUENCE, SESSION, SIMILAR, SPACE,
+ SQLEXCEPTION, SQLWARNING, START, STATE, STRUCTURE, SYMBOL, TERM,
+ TEST, THERE, TRIGGER, TYPE, UNDER, VARIABLE, VIRTUAL, VISIBLE,
+ WAIT, WITHOUT
+
+ sql3part4.txt (ANNEX E):
+
+ CALL, DO, ELSEIF, EXCEPTION, IF, LEAVE, LOOP, OTHERS, RESIGNAL,
+ RETURN, RETURNS, SIGNAL, TUPLE, WHILE
diff --git a/fs_passwd/fs_passwd b/fs_passwd/fs_passwd
new file mode 100755
index 0000000..feddb46
--- /dev/null
+++ b/fs_passwd/fs_passwd
@@ -0,0 +1,131 @@
+#!/usr/bin/perl -Tw
+#
+# fs_passwd
+#
+# portions of this script are copied from the `passwd' script in the original
+# (perl 4) camel book, now archived at
+# http://www.perl.com/CPAN/scripts/nutshell/ch6/passwd
+#
+# ivan@sisd.com 98-mar-8
+#
+# password lengths 0,255 instead of 6,8 - we'll let the server process
+# check the data ivan@sisd.com 98-jul-17
+#
+# updated for the exciting new world of self-service 2004-mar-10
+
+use strict;
+use Getopt::Std;
+use FS::SelfService qw(passwd);
+use vars qw($opt_f $opt_s);
+
+my($freeside_uid)=scalar(getpwnam('freeside'));
+
+$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+$SIG{__DIE__}= sub { system '/bin/stty', 'echo'; };
+
+die "passwd program isn't running setuid to freeside\n" if $> != $freeside_uid;
+
+unshift @ARGV, "-f" if $0 =~ /chfn$/;
+unshift @ARGV, "-s" if $0 =~ /chsh$/;
+
+getopts('fs');
+
+my($me)='';
+if ( $_ = shift(@ARGV) ) {
+ /^(\w{2,8})$/;
+ $me = $1;
+}
+die "You can't change the password for $me." if $me && $<;
+$me = (getpwuid($<))[0] unless $me;
+
+my($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell)=
+ getpwnam $me;
+
+my($old_password,$new_password,$new_gecos,$new_shell);
+
+if ( $opt_f || $opt_s ) {
+ system '/bin/stty', '-echo';
+ print "Password:";
+ $old_password=<STDIN>;
+ system '/bin/stty', 'echo';
+ chop($old_password);
+ #$old_password =~ /^(.{6,8})$/ or die "\nIllegal password.\n";
+ $old_password =~ /^(.{0,255})$/ or die "\nIllegal password.\n";
+ $old_password = $1;
+
+ $new_password = '';
+
+ if ( $opt_f ) {
+ print "\nChanging gecos for $me.\n";
+ print "Gecos [", $gcos, "]: ";
+ $new_gecos=<STDIN>;
+ chop($new_gecos);
+ $new_gecos ||= $gcos;
+ $new_gecos =~ /^(.{0,255})$/ or die "\nIllegal gecos.\n";
+ } else {
+ $new_gecos = '';
+ }
+
+ if ( $opt_s ) {
+ print "\nChanging shell for $me.\n";
+ print "Shell [", $shell, "]: ";
+ $new_shell=<STDIN>;
+ chop($new_shell);
+ $new_shell ||= $shell;
+ $new_shell =~ /^(.{0,255})$/ or die "\nIllegal shell.\n";
+ } else {
+ $new_shell = '';
+ }
+
+} else {
+
+ print "Changing password for $me.\n";
+ print "Old password:";
+ system '/bin/stty', '-echo';
+ $old_password=<STDIN>;
+ chop $old_password;
+ #$old_password =~ /^(.{6,8})$/ or die "\nIllegal password.\n";
+ $old_password =~ /^(.{0,255})$/ or die "\nIllegal password.\n";
+ $old_password = $1;
+ print "\nEnter the new password (minimum of 6, maximum of 8 characters)\n";
+ print "Please use a combination of upper and lowercase letters and numbers.\n";
+ print "New password:";
+ $new_password=<STDIN>;
+ chop($new_password);
+ #$new_password =~ /^(.{6,8})$/ or die "\nIllegal password.\n";
+ $new_password =~ /^(.{0,255})$/ or die "\nIllegal password.\n";
+ $new_password = $1;
+ print "\nRe-enter new password:";
+ my($check_new_password);
+ $check_new_password=<STDIN>;
+ chop($check_new_password);
+ die "\nThey don't match; try again.\n" unless $check_new_password eq $new_password;
+
+ $new_gecos='';
+ $new_shell='';
+}
+print "\n";
+
+system '/bin/stty', 'echo';
+
+my $rv = passwd(
+ 'username' => $me,
+ 'old_password' => $old_password,
+ 'new_password' => $new_password,
+ 'new_gecos' => $new_gecos,
+ 'new_shell' => $new_shell,
+);
+
+my $error = $rv->{error};
+
+if ($error) {
+ print "\nUpdate error: $error\n";
+} else {
+ print "\nUpdate sucessful.\n";
+}
diff --git a/fs_radlog/fs_radlogd b/fs_radlog/fs_radlogd
new file mode 100755
index 0000000..74c2af3
--- /dev/null
+++ b/fs_radlog/fs_radlogd
@@ -0,0 +1,51 @@
+#!/usr/bin/perl -Tw
+#
+# ivan@sisd.com 98-mar-23
+
+use strict;
+use Date::Parse; #but hopefully not
+
+$|=1;
+
+my($file,$pos)=@_;
+open(FILE,"<$file") or die "Can't open $file: $!";
+seek(FILE,$pos,0) or die "Can't seek: $!";
+
+my($datestr);
+my(%param);
+
+$SIG{'HUP'} = sub { print "EOF\n"; exit; };
+
+while (1) {
+
+ while (<FILE>) {
+ next if /^$/;
+ if ( /^\S/ ) {
+ chop($datestr=$_);
+ undef %param;
+ } else {
+ warn "Unexpected line: $_";
+ }
+ while (<FILE>) {
+ if ( /^$/ ) {
+ #if ( $param{'Acct-Status-Type'} eq 'Stop' ) {
+ print join("\t",
+ tell FILE,
+ %param,
+ ),"\n";
+ #}
+ last;
+ } elsif ( /^\s+([\w\-]+)\s\=\s\"?([\w\.\-]+)\"?\s*$/ ) {
+ $param{$1}=$2;
+ } else {
+ warn "Unexpected line: $_";
+ }
+
+ }
+
+ }
+ sleep 1;
+ seek(FILE,0,1);
+}
+
+
diff --git a/fs_selfadmin/FS-MailAdminServer/MailAdminClient.pm b/fs_selfadmin/FS-MailAdminServer/MailAdminClient.pm
new file mode 100755
index 0000000..46cde4c
--- /dev/null
+++ b/fs_selfadmin/FS-MailAdminServer/MailAdminClient.pm
@@ -0,0 +1,541 @@
+package FS::MailAdminClient;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT_OK $fs_mailadmind_socket);
+use Exporter;
+use Socket;
+use FileHandle;
+use IO::Handle;
+
+$VERSION = '0.01';
+
+@ISA = qw( Exporter );
+@EXPORT_OK = qw( signup_info authenticate list_packages list_mailboxes delete_mailbox password_mailbox add_mailbox list_forwards list_pkg_forwards delete_forward add_forward new_customer );
+
+$fs_mailadmind_socket = "/usr/local/freeside/fs_mailadmind_socket";
+
+$ENV{'PATH'} ='/usr/bin:/usr/ucb:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+my $freeside_uid = scalar(getpwnam('freeside'));
+die "not running as the freeside user\n" if $> != $freeside_uid;
+
+=head1 NAME
+
+FS::MailAdminClient - Freeside mail administration client API
+
+=head1 SYNOPSIS
+
+ use FS::MailAdminClient qw( signup_info list_mailboxes new_customer );
+
+ ( $locales, $packages, $pops ) = signup_info;
+
+ ( $accounts ) = list_mailboxes;
+
+ $error = new_customer ( {
+ 'first' => $first,
+ 'last' => $last,
+ 'ss' => $ss,
+ 'comapny' => $company,
+ 'address1' => $address1,
+ 'address2' => $address2,
+ 'city' => $city,
+ 'county' => $county,
+ 'state' => $state,
+ 'zip' => $zip,
+ 'country' => $country,
+ 'daytime' => $daytime,
+ 'night' => $night,
+ 'fax' => $fax,
+ 'payby' => $payby,
+ 'payinfo' => $payinfo,
+ 'paydate' => $paydate,
+ 'payname' => $payname,
+ 'invoicing_list' => $invoicing_list,
+ 'pkgpart' => $pkgpart,
+ 'username' => $username,
+ '_password' => $password,
+ 'popnum' => $popnum,
+ } );
+
+=head1 DESCRIPTION
+
+This module provides an API for a remote mail administration server.
+
+It needs to be run as the freeside user. Because of this, the program which
+calls these subroutines should be written very carefully.
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item signup_info
+
+Returns three array references of hash references.
+
+The first set of hash references is of allowable locales. Each hash reference
+has the following keys:
+ taxnum
+ state
+ county
+ country
+
+The second set of hash references is of allowable packages. Each hash
+reference has the following keys:
+ pkgpart
+ pkg
+
+The third set of hash references is of allowable POPs (Points Of Presence).
+Each hash reference has the following keys:
+ popnum
+ city
+ state
+ ac
+ exch
+
+=cut
+
+sub signup_info {
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "signup_info\n";
+ SOCK->flush;
+
+ chop ( my $n_cust_main_county = <SOCK> );
+ my @cust_main_county = map {
+ chop ( my $taxnum = <SOCK> );
+ chop ( my $state = <SOCK> );
+ chop ( my $county = <SOCK> );
+ chop ( my $country = <SOCK> );
+ {
+ 'taxnum' => $taxnum,
+ 'state' => $state,
+ 'county' => $county,
+ 'country' => $country,
+ };
+ } 1 .. $n_cust_main_county;
+
+ chop ( my $n_part_pkg = <SOCK> );
+ my @part_pkg = map {
+ chop ( my $pkgpart = <SOCK> );
+ chop ( my $pkg = <SOCK> );
+ {
+ 'pkgpart' => $pkgpart,
+ 'pkg' => $pkg,
+ };
+ } 1 .. $n_part_pkg;
+
+ chop ( my $n_svc_acct_pop = <SOCK> );
+ my @svc_acct_pop = map {
+ chop ( my $popnum = <SOCK> );
+ chop ( my $city = <SOCK> );
+ chop ( my $state = <SOCK> );
+ chop ( my $ac = <SOCK> );
+ chop ( my $exch = <SOCK> );
+ chop ( my $loc = <SOCK> );
+ {
+ 'popnum' => $popnum,
+ 'city' => $city,
+ 'state' => $state,
+ 'ac' => $ac,
+ 'exch' => $exch,
+ 'loc' => $loc,
+ };
+ } 1 .. $n_svc_acct_pop;
+
+ close SOCK;
+
+ \@cust_main_county, \@part_pkg, \@svc_acct_pop;
+}
+
+=item authenticate
+
+Authentictes against a service on the remote Freeside system. Requires a hash
+reference as a parameter with the following keys:
+ authuser
+ _password
+
+Returns a scalar error message of the form "authuser OK|FAILED" or an error
+message.
+
+=cut
+
+sub authenticate {
+ my $hashref = shift;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "authenticate", "\n";
+ SOCK->flush;
+
+ print SOCK join("\n", map { $hashref->{$_} } qw(
+ authuser _password
+ ) ), "\n";
+ SOCK->flush;
+
+ chop( my $error = <SOCK> );
+ close SOCK;
+
+ $error;
+}
+
+=item list_packages
+
+Returns one array reference of hash references.
+
+The set of hash references is of existing packages. Each hash reference
+has the following keys:
+ pkgnum
+ domain
+ account
+
+=cut
+
+sub list_packages {
+ my $user = shift;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "list_packages\n", $user, "\n";
+ SOCK->flush;
+
+ chop ( my $n_packages = <SOCK> );
+ my @packages = map {
+ chop ( my $pkgnum = <SOCK> );
+ chop ( my $domain = <SOCK> );
+ chop ( my $account = <SOCK> );
+ {
+ 'pkgnum' => $pkgnum,
+ 'domain' => $domain,
+ 'account' => $account,
+ };
+ } 1 .. $n_packages;
+
+ close SOCK;
+
+ \@packages;
+}
+
+=item list_mailboxes
+
+Returns one array references of hash references.
+
+The set of hash references is of existing accounts. Each hash reference
+has the following keys:
+ svcnum
+ username
+ _password
+
+=cut
+
+sub list_mailboxes {
+ my ($user, $package) = @_;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "list_mailboxes\n", $user, "\n", $package, "\n";
+ SOCK->flush;
+
+ chop ( my $n_svc_acct = <SOCK> );
+ my @svc_acct = map {
+ chop ( my $svcnum = <SOCK> );
+ chop ( my $username = <SOCK> );
+ chop ( my $_password = <SOCK> );
+ {
+ 'svcnum' => $svcnum,
+ 'username' => $username,
+ '_password' => $_password,
+ };
+ } 1 .. $n_svc_acct;
+
+ close SOCK;
+
+ \@svc_acct;
+}
+
+=item delete_mailbox
+
+Deletes a mailbox service from the remote Freeside system. Requires a hash
+reference as a paramater with the following keys:
+ authuser
+ account
+
+Returns a scalar error message, or the empty string for success.
+
+=cut
+
+sub delete_mailbox {
+ my $hashref = shift;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "delete_mailbox", "\n";
+ SOCK->flush;
+
+ print SOCK join("\n", map { $hashref->{$_} } qw(
+ authuser account
+ ) ), "\n";
+ SOCK->flush;
+
+ chop( my $error = <SOCK> );
+ close SOCK;
+
+ $error;
+}
+
+=item password_mailbox
+
+Changes the password for a mailbox service on the remote Freeside system.
+ Requires a hash reference as a paramater with the following keys:
+ authuser
+ account
+ _password
+
+Returns a scalar error message, or the empty string for success.
+
+=cut
+
+sub password_mailbox {
+ my $hashref = shift;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "password_mailbox", "\n";
+ SOCK->flush;
+
+ print SOCK join("\n", map { $hashref->{$_} } qw(
+ authuser account _password
+ ) ), "\n";
+ SOCK->flush;
+
+ chop( my $error = <SOCK> );
+ close SOCK;
+
+ $error;
+}
+
+=item add_mailbox
+
+Creates a mailbox service on the remote Freeside system. Requires a hash
+reference as a parameter with the following keys:
+ authuser
+ package
+ account
+ _password
+
+Returns a scalar error message, or the empty string for success.
+
+=cut
+
+sub add_mailbox {
+ my $hashref = shift;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "add_mailbox", "\n";
+ SOCK->flush;
+
+ print SOCK join("\n", map { $hashref->{$_} } qw(
+ authuser package account _password
+ ) ), "\n";
+ SOCK->flush;
+
+ chop( my $error = <SOCK> );
+ close SOCK;
+
+ $error;
+}
+
+=item list_forwards
+
+Returns one array references of hash references.
+
+The set of hash references is of existing forwards. Each hash reference
+has the following keys:
+ svcnum
+ dest
+
+=cut
+
+sub list_forwards {
+ my ($user, $service) = @_;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "list_forwards\n", $user, "\n", $service, "\n";
+ SOCK->flush;
+
+ chop ( my $n_svc_forward = <SOCK> );
+ my @svc_forward = map {
+ chop ( my $svcnum = <SOCK> );
+ chop ( my $dest = <SOCK> );
+ {
+ 'svcnum' => $svcnum,
+ 'dest' => $dest,
+ };
+ } 1 .. $n_svc_forward;
+
+ close SOCK;
+
+ \@svc_forward;
+}
+
+=item list_pkg_forwards
+
+Returns one array references of hash references.
+
+The set of hash references is of existing forwards. Each hash reference
+has the following keys:
+ svcnum
+ srcsvc
+ dest
+
+=cut
+
+sub list_pkg_forwards {
+ my ($user, $package) = @_;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "list_pkg_forwards\n", $user, "\n", $package, "\n";
+ SOCK->flush;
+
+ chop ( my $n_svc_forward = <SOCK> );
+ my @svc_forward = map {
+ chop ( my $svcnum = <SOCK> );
+ chop ( my $srcsvc = <SOCK> );
+ chop ( my $dest = <SOCK> );
+ {
+ 'svcnum' => $svcnum,
+ 'srcsvc' => $srcsvc,
+ 'dest' => $dest,
+ };
+ } 1 .. $n_svc_forward;
+
+ close SOCK;
+
+ \@svc_forward;
+}
+
+=item delete_forward
+
+Deletes a forward service from the remote Freeside system. Requires a hash
+reference as a paramater with the following keys:
+ authuser
+ svcnum
+
+Returns a scalar error message, or the empty string for success.
+
+=cut
+
+sub delete_forward {
+ my $hashref = shift;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "delete_forward", "\n";
+ SOCK->flush;
+
+ print SOCK join("\n", map { $hashref->{$_} } qw(
+ authuser svcnum
+ ) ), "\n";
+ SOCK->flush;
+
+ chop( my $error = <SOCK> );
+ close SOCK;
+
+ $error;
+}
+
+=item add_forward
+
+Creates a forward service on the remote Freeside system. Requires a hash
+reference as a parameter with the following keys:
+ authuser
+ package
+ source
+ dest
+
+Returns a scalar error message, or the empty string for success.
+
+=cut
+
+sub add_forward {
+ my $hashref = shift;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "add_forward", "\n";
+ SOCK->flush;
+
+ print SOCK join("\n", map { $hashref->{$_} } qw(
+ authuser package source dest
+ ) ), "\n";
+ SOCK->flush;
+
+ chop( my $error = <SOCK> );
+ close SOCK;
+
+ $error;
+}
+
+=item new_customer HASHREF
+
+Adds a customer to the remote Freeside system. Requires a hash reference as
+a paramater with the following keys:
+ first
+ last
+ ss
+ comapny
+ address1
+ address2
+ city
+ county
+ state
+ zip
+ country
+ daytime
+ night
+ fax
+ payby
+ payinfo
+ paydate
+ payname
+ invoicing_list
+ pkgpart
+ username
+ _password
+ popnum
+
+Returns a scalar error message, or the empty string for success.
+
+=cut
+
+sub new_customer {
+ my $hashref = shift;
+
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_mailadmind_socket)) or die "connect: $!";
+ print SOCK "new_customer\n";
+
+ print SOCK join("\n", map { $hashref->{$_} } qw(
+ first last ss company address1 address2 city county state zip country
+ daytime night fax payby payinfo paydate payname invoicing_list
+ pkgpart username _password popnum
+ ) ), "\n";
+ SOCK->flush;
+
+ chop( my $error = <SOCK> );
+ $error;
+}
+
+=back
+
+=head1 VERSION
+
+$Id: MailAdminClient.pm,v 1.1 2001-10-18 15:04:54 jeff Exp $
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<fs_signupd>, L<FS::SignupServer>, L<FS::cust_main>
+
+=cut
+
+1;
+
diff --git a/fs_selfadmin/FS-MailAdminServer/cgi/mailadmin.cgi b/fs_selfadmin/FS-MailAdminServer/cgi/mailadmin.cgi
new file mode 100755
index 0000000..c26c3dc
--- /dev/null
+++ b/fs_selfadmin/FS-MailAdminServer/cgi/mailadmin.cgi
@@ -0,0 +1,698 @@
+#!/usr/bin/perl
+########################################################################
+# #
+# mailadmin.cgi NCI2000 #
+# Jeff Finucane <jeff@nci2000.net> #
+# 26 April 2001 #
+# #
+########################################################################
+
+use DBI;
+use strict;
+use CGI;
+use FS::MailAdminClient qw(authenticate list_packages list_mailboxes delete_mailbox password_mailbox add_mailbox list_forwards list_pkg_forwards delete_forward add_forward);
+
+my $sessionfile = '/usr/local/apache/htdocs/mailadmin/adminsess'; # session file
+my $tmpdir = '/usr/local/apache/htdocs/mailadmin/tmp'; # Location to store temp files
+my $cookiedomain = ".your.dom"; # domain if THIS server, should prepend with a '.'
+my $cookieexpire = '+12h'; # expire the cookie session after this much idle time
+my $sessexpire = 43200; # expire session after this long of no use (in seconds)
+
+my $body = "<body bgcolor=dddddd>";
+
+#### Should not have to change anything under this line ####
+my $printmainpage = 1;
+my $i = 0;
+my $printheader = 1;
+my $query = new CGI;
+my $cgi = $query->url();
+my $now = getdatetime();
+my $current_package = 0;
+my $current_account = 0;
+my $current_domname = "";
+
+# if they are trying to login we wont check the session yet
+if ($query->param('login') eq '' && $query->param('action') ne 'login') {
+ checksession();
+ printheader();
+}
+
+if ($query->param('login') ne '') {
+
+ my $username = $query->param('username');
+ my $password = $query->param('password');
+
+ if (!checkuserpass($username, $password)) {
+ printheader();
+ error('not_admin');
+ }
+
+ my @alpha = ('A'..'Z', 'a'..'z', 0..9);
+ my $sessid = '';
+ for (my $i = 0; $i < 10; $i++) {
+ $sessid .= @alpha[rand(@alpha)];
+ }
+
+ my $cookie1 = $query->cookie(-name=>'username',
+ -value=>$username,
+ -expires=>$cookieexpire,
+ -domain=>$cookiedomain);
+
+ my $cookie2 = $query->cookie(-name=>'ma_sessionid',
+ -value=>$sessid,
+ -expires=>$cookieexpire,
+ -domain=>$cookiedomain);
+
+ my $now = time();
+ open(NEWSESS, ">>$sessionfile") || error('open');
+ print NEWSESS "$username $sessid $now 0 0\n";
+ close(NEWSESS);
+
+ print $query->header(-COOKIE=>[$cookie1, $cookie2]);
+
+ $printmainpage = 1;
+
+} elsif ($query->param('action') eq 'blankframe') {
+
+ print "<html>$body</body></html>\n";
+ $printmainpage = 0;
+
+} elsif ($query->param('action') eq 'list_packages') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ my $list = list_packages($username);
+ print "<html>$body\n";
+ print "<center><table border=0>\n";
+ print "<tr><td></td><td><p>Package Number</td><td><p>Description</td></tr>\n";
+ foreach my $package ( @{$list} ) {
+ print "<tr>";
+ print "<td></td><td><p>$package->{'pkgnum'}</td><td><p>$package->{'domain'}</td>\n";
+ print "<td></td><td><a href=\"$cgi\?action=select&package=$package->{'pkgnum'}&account=$package->{'account'}&domname=$package->{'domain'}\" target=\"rightmainframe\">select</td>\n";
+ print "</tr>";
+ }
+ print "</table>\n";
+ print "</body></html>\n";
+ $printmainpage=0;
+
+} elsif ($query->param('action') eq 'list_mailboxes') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $list = list_mailboxes($username, $current_package);
+ my $forwardlist = list_pkg_forwards($username, $current_package);
+ print "<html>$body\n";
+ print "<center><table border=0>\n";
+ print "<tr><td></td><td><p>Username</td><td><p>Password</td></tr>\n";
+ foreach my $account ( @{$list} ) {
+ print "<tr>";
+ print "<td></td><td><p>$account->{'username'}</td><td><p>$account->{'_password'}</td>\n";
+ print "<td></td><td><a href=\"$cgi\?action=change&account=$account->{'svcnum'}&mailbox=$account->{'username'}\" target=\"rightmainframe\">change</td>\n";
+ print "</tr>";
+
+# my $forwardlist = list_forwards($username, $account->{'svcnum'});
+# foreach my $forward ( @{$forwardlist} ) {
+# my $label = qq!=> ! . $forward->{'dest'};
+# print "<tr><td></td><td></td><td><p>$label</td></tr>\n";
+# }
+ foreach my $forward ( @{$forwardlist} ) {
+ if ($forward->{'srcsvc'} == $account->{'svcnum'}) {
+ my $label = qq!=> ! . $forward->{'dest'};
+ print "<tr><td></td><td></td><td><p>$label</td></tr>\n";
+ }
+ }
+
+ }
+ print "</table>\n";
+ print "</body></html>\n";
+ $printmainpage=0;
+
+} elsif ($query->param('action') eq 'select') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ $current_package = $query->param('package');
+ $current_account = $query->param('account');
+ $current_domname = $query->param('domname');
+ set_package();
+ print "<html>$body\n";
+ print "<form name=form1 action=\"$cgi\" method=post target=\"rightmainframe\">\n";
+ print "<center>\n";
+ print "<p>Selected package $current_package\n";
+ print "</center>\n";
+ print "</form>\n";
+ print "</body></html>\n";
+ $printmainpage=0;
+
+} elsif ($query->param('action') eq 'change') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $account = $query->param('account');
+ my $mailbox = $query->param('mailbox');
+ my $list = list_forwards($username, $account);
+ print "<html>$body\n";
+ print "<form name=form1 action=\"$cgi\" method=post target=\"rightmainframe\">\n";
+ print "<center><table border=0>\n";
+ print "<tr><td></td><td><p>Username</td><td><p>$mailbox</td></tr>\n";
+ print "<input type=hidden name=\"account\" value=\"$account\">\n";
+ print "<input type=hidden name=\"mailbox\" value=\"$mailbox\">\n";
+ foreach my $forward ( @{$list} ) {
+ my $label = qq!=> ! . $forward->{'dest'};
+# print "<tr><td></td><td></td><td><p>$label</td></tr>\n";
+ print "<tr><td></td><td></td><td><p>$label</td><td><a href=\"$cgi\?action=deleteforward&service=$forward->{'svcnum'}&mailbox=$mailbox&dest=$forward->{'dest'}\" target=\"rightmainframe\">remove</td></tr>\n";
+ }
+ print "<tr><td></td><td><p>Password</td><td><input type=text name=\"_password\" value=\"\"></td></tr>\n";
+ print "</table>\n";
+ print "<input type=submit name=\"deleteaccount\" value=\"Delete This User\">\n";
+ print "<input type=submit name=\"changepassword\" value=\"Change The Password\">\n";
+ print "<input type=submit name=\"addforward\" value=\"Add Forwarding\">\n";
+ print "</center>\n";
+ print "</form>\n";
+ print "<br>\n";
+ print "<p> You may delete this user and all mailforwarding by pressing <B>Delete This User</B>.\n";
+ print "<p> To set or change the password for this user, type the new password in the box next to <B>Password</B> and press <B>Change The Password</B>.\n";
+ print "<p> If you would like to have mail destined for this user forwarded to another email address then press the <B>Add Forwarding</B> button.\n";
+ print "</body></html>\n";
+ $printmainpage=0;
+
+} elsif ($query->param('deleteaccount') ne '') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $account = $query->param('account');
+ my $mailbox = $query->param('mailbox');
+ print "<html>$body\n";
+ print "<form name=form1 action=\"$cgi\" method=post target=\"rightmainframe\">\n";
+ print "<p>Are you certain you want to delete user $mailbox?\n";
+ print "<p><input type=hidden name=\"account\" value=\"$account\">\n";
+ print "<input type=submit name=\"deleteaccounty\" value=\"Confirm\">\n";
+ print "</body></html>\n";
+ $printmainpage=0;
+
+} elsif ($query->param('deleteaccounty') ne '') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $account = $query->param('account');
+
+ if ( my $error = delete_mailbox ( {
+ 'authuser' => $username,
+ 'account' => $account,
+ } ) ) {
+ print "<html>$body\n";
+ print "<p>$error\n";
+ print "</body></html>\n";
+
+ } else {
+ print "<html>$body\n";
+ print "<p>Deleted\n";
+ print "</body></html>\n";
+ }
+
+ $printmainpage=0;
+
+} elsif ($query->param('changepassword') ne '') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $account = $query->param('account');
+ my $_password = $query->param('_password');
+
+ if ( my $error = password_mailbox ( {
+ 'authuser' => $username,
+ 'account' => $account,
+ '_password' => $_password,
+ } ) ) {
+ print "<html>$body\n";
+ print "<p>$error\n";
+ print "</body></html>\n";
+
+ } else {
+ print "<html>$body\n";
+ print "<p>Changed\n";
+ print "</body></html>\n";
+ }
+
+ $printmainpage=0;
+
+} elsif ($query->param('action') eq 'newmailbox') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ print "<html>$body\n";
+ print "<form name=form1 action=\"$cgi\" method=post target=\"rightmainframe\">\n";
+ print "<center><table border=0>\n";
+ print "<tr><td></td><td><p>Username </td><td><input type=text name=\"account\" value=\"\"></td><td>@ " . $current_domname . "</td></tr>\n";
+ print "<tr><td></td><td><p>Password</td><td><input type=text name=\"_password\" value=\"\"></td></tr>\n";
+ print "</table>\n";
+ print "<input type=submit name=\"addmailbox\" value=\"Add This User\">\n";
+ print "</center>\n";
+ print "</form>\n";
+ print "<br>\n";
+ print "<p>Use this screen to add a new mailbox user. If the domain name of the email address (the part after the <B>@</B> sign) is not what you expect then you may need to use <B>List Packages</B> to select the package with the correct domain.\n";
+ print "<p>Enter the first portion of the email address in the box adjacent to <B>Username</B> and enter the password for that user in the space next to <B>Password</B>. Then press the button labeled <B>Add The User</B>.\n";
+ print "<p>If you do not want to add a new user at this time then select a choice from the menu at the left, such as <B>List Mailboxes</B>.\n";
+ print "</body></html>\n";
+ $printmainpage=0;
+
+} elsif ($query->param('addmailbox') ne '') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $account = $query->param('account');
+ my $_password = $query->param('_password');
+
+ if ( my $error = add_mailbox ( {
+ 'authuser' => $username,
+ 'package' => $current_package,
+ 'account' => $account,
+ '_password' => $_password,
+ } ) ) {
+ print "<html>$body\n";
+ print "<p>$error\n";
+ print "</body></html>\n";
+
+ } else {
+ print "<html>$body\n";
+ print "<p>Created\n";
+ print "</body></html>\n";
+ }
+
+ $printmainpage=0;
+
+} elsif ($query->param('action') eq 'deleteforward') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $svcnum = $query->param('service');
+ my $mailbox = $query->param('mailbox');
+ my $dest = $query->param('dest');
+ print "<html>$body\n";
+ print "<form name=form1 action=\"$cgi\" method=post target=\"rightmainframe\">\n";
+ print "<p>Are you certain you want to remove the forwarding from $mailbox to $dest?\n";
+ print "<p><input type=hidden name=\"service\" value=\"$svcnum\">\n";
+ print "<input type=submit name=\"deleteforwardy\" value=\"Confirm\">\n";
+ print "</body></html>\n";
+ $printmainpage=0;
+
+} elsif ($query->param('deleteforwardy') ne '') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $service = $query->param('service');
+
+ if ( my $error = delete_forward ( {
+ 'authuser' => $username,
+ 'svcnum' => $service,
+ } ) ) {
+ print "<html>$body\n";
+ print "<p>$error\n";
+ print "</body></html>\n";
+
+ } else {
+ print "<html>$body\n";
+ print "<p>Forwarding Removed\n";
+ print "</body></html>\n";
+ }
+
+ $printmainpage=0;
+
+} elsif ($query->param('addforward') ne '') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $account = $query->param('account');
+ my $mailbox = $query->param('mailbox');
+
+ print "<html>$body\n";
+ print "<form name=form1 action=\"$cgi\" method=post target=\"rightmainframe\">\n";
+ print "<center><table border=0>\n";
+ print "<input type=hidden name=\"account\" value=\"$account\">\n";
+ print "<input type=hidden name=\"mailbox\" value=\"$mailbox\">\n";
+ print "<tr><td>Forward mail from </td><td><p>$mailbox:</td><td> to </td></tr>\n";
+ print "<tr><td></td><td><p>Destination:</td><td><input type=text name=\"dest\" value=\"\"></td></tr>\n";
+ print "</table>\n";
+ print "<input type=submit name=\"addforwarddst\" value=\"Add the Forwarding\">\n";
+ print "</center>\n";
+ print "</form>\n";
+ print "<br>\n";
+ print "<p> If you would like mail originally destined for the above address to be forwarded to a different email address then type that email address in the box next to <B>Destination:</B> and press the <B>Add the Forwarding</B> button.\n";
+ print "<p> If you do not want to add mail forwarding then select a choice from the menu at the left, such as <B>List Accounts</B>.\n";
+
+ $printmainpage=0;
+
+} elsif ($query->param('addforwarddst') ne '') {
+
+ my $username = $query->cookie(-name=>'username'); # session checked
+ select_package($username) unless $current_package;
+ my $account = $query->param('account');
+ my $dest = $query->param('dest');
+
+ if ( my $error = add_forward ( {
+ 'authuser' => $username,
+ 'package' => $current_package,
+ 'source' => $account,
+ 'dest' => $dest,
+ } ) ) {
+ print "<html>$body\n";
+ print "<p>$error\n";
+ print "</body></html>\n";
+
+ } else {
+ print "<html>$body\n";
+ print "<p>Forwarding Created\n";
+ print "</body></html>\n";
+ }
+
+ $printmainpage=0;
+
+} elsif ($query->param('action') eq 'navframe') {
+
+ print "<html><body bgcolor=bbbbbb>\n";
+ print "<center><h2>NCI2000 MAIL ADMIN Web Interface</h2></center>\n";
+
+ print "<br><center>Choose Action:</center><br>\n";
+ print "<center><table border=0>\n";
+ print "<ul>\n";
+ print "<tr><td><li><a href=\"$cgi\?action=logout\" target=\"_top\">Log Off</a></td><tr>\n";
+ print "<tr><td><li><a href=\"$cgi\?action=list_packages\" target=\"rightmainframe\">List Packages</a></td><tr>\n";
+ print "<tr><td><li><a href=\"$cgi\?action=list_mailboxes\" target=\"rightmainframe\">List Accounts</a></td><tr>\n";
+ print "<tr><td><li><a href=\"$cgi\?action=newmailbox\" target=\"rightmainframe\">Add Account</a></td><tr>\n";
+ print "</ul>\n";
+ print "</table></center>\n";
+
+ print "<br><br><br>\n";
+ print "</body></html>\n";
+
+ $printmainpage = 0;
+
+} elsif ($query->param('action') eq 'rightmainframe') {
+
+ print "<html>$body\n";
+ print "<br><br><br>\n";
+ print "<font size=4><----- Please choose function on the left menu</font>\n";
+ print "<br><br>\n";
+ print "<p> Choose <B>Log Off</B> when you are finished. This helps prevent unauthorized access to your accounts.\n";
+ print "<p> Use <B>List Packages</B> when you administer multiple packages. When you have multiple domains at NCI2000 you are likely to have multiple packages. Use of <B>List Packages</B> is not necessary if administer only one package.\n";
+ print "<p> Use <B>List Accounts</B> to view your current arrangement of mailboxes. From this list you my choose to make changes to existing mailboxes or delete mailboxes. If you would like to modify the forwarding associated with a mailbox then choose it from this list.\n";
+ print "<p> Use <B>Add Account</B> when you would like an additional mailbox. After you have added the mailbox you may choose to make additional changes from the list provided by <B>List Accounts<B>.\n";
+ print "</body></html>\n";
+
+ $printmainpage = 0;
+
+}
+
+
+if ($query->param('action') eq 'login') {
+
+ printheader();
+ printlogin();
+
+} elsif ($query->param('action') eq 'logout') {
+
+ destroysession();
+ printheader();
+ printlogin();
+
+} elsif ($printmainpage) {
+
+
+ print "<html><head><title>NCI2000 MAIL ADMIN Web Interface</title></head>\n";
+ print "<FRAMESET cols=\"160,*\" BORDER=\"3\">\n";
+ print "<FRAME NAME=\"navframe\" src=\"$cgi?action=navframe\">\n";
+ print "<FRAME NAME=\"rightmainframe\" src=\"$cgi?action=rightmainframe\">\n";
+ print "</FRAMESET>\n";
+ print "</html>\n";
+
+
+}
+
+sub getdatetime {
+ my $today = localtime(time());
+ my ($day,$mon,$dayofmon,$time,$year) = split(/\s+/,$today);
+ my @datemonths = ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
+
+ my $numidx = "01";
+ my ($nummon);
+ foreach my $mons (@datemonths) {
+ if ($mon eq $mons) {
+ $nummon = $numidx;
+ }
+ $numidx++;
+ }
+
+ return "$year-$nummon-$dayofmon $time";
+
+}
+
+sub error {
+
+ my $error = shift;
+ my $arg1 = shift;
+
+ printheader();
+
+ if ($error eq 'not_admin') {
+ print "<html><head><title>Error!</title></head>\n";
+ print "$body\n";
+ print "<center><h1><font face=arial>Error!</font></h1></center>\n";
+ print "<font face=arial>Unauthorized attempt to access mail administration.</font>\n";
+ print "<br><font face=arial>Please login again if you think this is an error.</font>\n";
+ print "<form><input type=button value=\"<<Back\" OnClick=\"history.back()\"></form>\n";
+ print "</body></html>\n";
+ } elsif ($error eq 'exists') {
+ print "<html><head><title>Error!</title></head>\n";
+ print "$body\n";
+ print "<center><h1><font face=arial>Error!</font></h1></center>\n";
+ print "<font face=arial>The user you are trying to enter already exists. Please go back and enter a different username</font>\n";
+ print "</font></body></html>\n";
+ } elsif ($error eq 'ingroup') {
+ print "<html><head><title>Error!</title></head>\n";
+ print "$body\n";
+ print "<center><h1><font face=arial>Error!</font></h1></center>\n";
+ print "<font face=arial>This user is already in the group <i>$arg1</i>. Please go back and deselect group <i>$arg1</i> from the list.</font>\n";
+ print "<form><input type=button value=\"<<Back\" OnClick=\"history.back()\"></form>\n";
+ print "</font></body></html>\n";
+ } elsif ($error eq 'sess_expired') {
+ print "<html>$body\n";
+ print "<center><font size=4>Your session has expired.</font></center>\n";
+ print "<br><br><center>Please login again <a href=\"$cgi\?action=login\" target=\"_top\"> HERE</a></center>\n";
+ print "</body></html>\n";
+ } elsif ($error eq 'open') {
+ print "<html>$body\n";
+ print "<center><font size=4>Unable to open or rename file.</font></center>\n";
+ print "<br><br><center>If this continues, please contact your administrator</center>\n";
+ print "</body></html>\n";
+ }
+
+
+ exit;
+
+}
+
+
+#print a html header if not printed yet
+sub printheader {
+
+ if ($printheader) {
+ print "Content-Type: text/html\n\n";
+ $printheader = 0;
+ }
+
+}
+
+
+#verify user can access administration
+sub checksession {
+
+ my $username = $query->cookie(-name=>'username');
+ my $sessionid = $query->cookie(-name=>'ma_sessionid');
+
+ if ($sessionid eq '') {
+ printheader();
+ if ($query->param()) {
+ error('sess_expired');
+ } else {
+ printlogin();
+ exit;
+ }
+ }
+
+ my $now = time();
+ my $founduser = 0;
+ open(SESSFILE, "$sessionfile") || error('open');
+ error('open') if -l "$tmpdir/adminsess.$$";
+ open(NEWSESS, ">$tmpdir/adminsess.$$") || error('open');
+ while (<SESSFILE>) {
+ chomp();
+ my ($user, $sess, $time, $pkgnum, $svcdomain, $domname) = split(/\s+/);
+ next if $now - $sessexpire > $time;
+ if ($username eq $user && !$founduser) {
+ if ($sess eq $sessionid) {
+ $founduser = 1;
+ print NEWSESS "$user $sess $now $pkgnum $svcdomain $domname\n";
+ $current_package=$pkgnum;
+ $current_account=$svcdomain;
+ $current_domname=$domname;
+ next;
+ }
+ }
+ print NEWSESS "$user $sess $time $pkgnum $svcdomain $domname\n";
+ }
+ close(SESSFILE);
+ close(NEWSESS);
+ system("mv $tmpdir/adminsess.$$ $sessionfile");
+ error('sess_expired') unless $founduser;
+
+ my $cookie1 = $query->cookie(-name=>'username',
+ -value=>$username,
+ -expires=>$cookieexpire,
+ -domain=>$cookiedomain);
+
+ my $cookie2 = $query->cookie(-name=>'ma_sessionid',
+ -value=>$sessionid,
+ -expires=>$cookieexpire,
+ -domain=>$cookiedomain);
+
+ print $query->header(-COOKIE=>[$cookie1, $cookie2]);
+
+ $printheader = 0;
+
+ return 0;
+
+}
+
+sub destroysession {
+
+ my $username = $query->cookie(-name=>'username');
+ my $sessionid = $query->cookie(-name=>'ma_sessionid');
+
+ if ($sessionid eq '') {
+ printheader();
+ if ($query->param()) {
+ error('sess_expired');
+ } else {
+ printlogin();
+ exit;
+ }
+ }
+
+ my $now = time();
+ my $founduser = 0;
+ open(SESSFILE, "$sessionfile") || error('open');
+ error('open') if -l "$tmpdir/adminsess.$$";
+ open(NEWSESS, ">$tmpdir/adminsess.$$") || error('open');
+ while (<SESSFILE>) {
+ chomp();
+ my ($user, $sess, $time, $pkgnum, $svcdomain, $domname) = split(/\s+/);
+ next if $now - $sessexpire > $time;
+ if ($username eq $user && !$founduser) {
+ if ($sess eq $sessionid) {
+ $founduser = 1;
+ next;
+ }
+ }
+ print NEWSESS "$user $sess $time $pkgnum $svcdomain $domname\n";
+ }
+ close(SESSFILE);
+ close(NEWSESS);
+ system("mv $tmpdir/adminsess.$$ $sessionfile");
+ error('sess_expired') unless $founduser;
+
+ $printheader = 0;
+
+ return 0;
+
+}
+
+# checks the username and pass against the database
+sub checkuserpass {
+
+ my $username = shift;
+ my $password = shift;
+
+ my $error = authenticate ( {
+ 'authuser' => $username,
+ '_password' => $password,
+ } );
+
+ if ($error eq "$username OK") {
+ return 1;
+ }else{
+ return 0;
+ }
+
+}
+
+#printlogin prints a login page
+sub printlogin {
+
+ print "<html>$body\n";
+ print "<center><font size=4>Please login to access MAIL ADMIN</font></center>\n";
+ print "<form action=\"$cgi\" method=post>\n";
+ print "<center>Email Address: &nbsp; <input type=text name=\"username\">\n";
+ print "<br>Email Password: <input type=password name=\"password\">\n";
+ print "<br><input type=submit name=\"login\" value=\"Login\">\n";
+ print "</form></center>\n";
+ print "</body></html>\n";
+}
+
+
+#select_package chooses a administrable package if more than one exists
+sub select_package {
+ my $user = shift;
+ my $packages = list_packages($user);
+ if (scalar(@{$packages}) eq 1) {
+ $current_package = @{$packages}[0]->{'pkgnum'};
+ set_package();
+ }
+ if (scalar(@{$packages}) > 1) {
+# print $query->redirect("$cgi\?action=list_packages");
+ print "<p>No package selected. You must first <a href=\"$cgi\?action=list_packages\" target=\"rightmainframe\">select a package</a>.\n";
+ exit;
+ }
+}
+
+sub set_package {
+
+ my $username = $query->cookie(-name=>'username');
+ my $sessionid = $query->cookie(-name=>'ma_sessionid');
+
+ if ($sessionid eq '') {
+ printheader();
+ if ($query->param()) {
+ error('sess_expired');
+ } else {
+ printlogin();
+ exit;
+ }
+ }
+
+ my $now = time();
+ my $founduser = 0;
+ open(SESSFILE, "$sessionfile") || error('open');
+ error('open') if -l "$tmpdir/adminsess.$$";
+ open(NEWSESS, ">$tmpdir/adminsess.$$") || error('open');
+ while (<SESSFILE>) {
+ chomp();
+ my ($user, $sess, $time, $pkgnum, $svcdomain, $domname) = split(/\s+/);
+ next if $now - $sessexpire > $time;
+ if ($username eq $user && !$founduser) {
+ if ($sess eq $sessionid) {
+ $founduser = 1;
+ print NEWSESS "$user $sess $time $current_package $current_account $current_domname\n";
+ next;
+ }
+ }
+ print NEWSESS "$user $sess $time $pkgnum $svcdomain $domname\n";
+ }
+ close(SESSFILE);
+ close(NEWSESS);
+ system("mv $tmpdir/adminsess.$$ $sessionfile");
+ error('sess_expired') unless $founduser;
+
+ $printheader = 0;
+
+ return 0;
+
+}
+
diff --git a/fs_selfadmin/FS-MailAdminServer/fs_mailadmind b/fs_selfadmin/FS-MailAdminServer/fs_mailadmind
new file mode 100755
index 0000000..746d782
--- /dev/null
+++ b/fs_selfadmin/FS-MailAdminServer/fs_mailadmind
@@ -0,0 +1,366 @@
+#!/usr/bin/perl -Tw
+
+eval 'exec /usr/bin/perl -Tw -S $0 ${1+"$@"}'
+ if 0; # not running under some shell
+#
+# fs_mailadmind
+#
+# This is run REMOTELY over ssh by fs_mailadmin_server.
+#
+
+use strict;
+use Socket;
+
+use vars qw( $Debug );
+
+$Debug = 0;
+
+my($fs_mailadmind_socket)="/usr/local/freeside/fs_mailadmind_socket";
+
+$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+$|=1;
+
+warn "[fs_mailadmind] Reading locales...\n" if $Debug;
+chomp( my $n_cust_main_county = <STDIN> );
+my @cust_main_county = map {
+ chomp( my $taxnum = <STDIN> );
+ chomp( my $state = <STDIN> );
+ chomp( my $county = <STDIN> );
+ chomp( my $country = <STDIN> );
+ {
+ 'taxnum' => $taxnum,
+ 'state' => $state,
+ 'county' => $county,
+ 'country' => $country,
+ };
+} ( 1 .. $n_cust_main_county );
+
+warn "[fs_mailadmind] Reading package definitions...\n" if $Debug;
+chomp( my $n_part_pkg = <STDIN> );
+my @part_pkg = map {
+ chomp( my $pkgpart = <STDIN> );
+ chomp( my $pkg = <STDIN> );
+ {
+ 'pkgpart' => $pkgpart,
+ 'pkg' => $pkg,
+ };
+} ( 1 .. $n_part_pkg );
+
+warn "[fs_mailadmind] Reading POPs...\n" if $Debug;
+chomp( my $n_svc_acct_pop = <STDIN> );
+my @svc_acct_pop = map {
+ chomp( my $popnum = <STDIN> );
+ chomp( my $city = <STDIN> );
+ chomp( my $state = <STDIN> );
+ chomp( my $ac = <STDIN> );
+ chomp( my $exch = <STDIN> );
+ chomp( my $loc = <STDIN> );
+ {
+ 'popnum' => $popnum,
+ 'city' => $city,
+ 'state' => $state,
+ 'ac' => $ac,
+ 'exch' => $exch,
+ 'loc' => $loc,
+ };
+} ( 1 .. $n_svc_acct_pop );
+
+warn "[fs_mailadmind] Creating $fs_mailadmind_socket\n" if $Debug;
+my $uaddr = sockaddr_un($fs_mailadmind_socket);
+my $proto = getprotobyname('tcp');
+socket(Server,PF_UNIX,SOCK_STREAM,0) or die "socket: $!";
+unlink($fs_mailadmind_socket);
+bind(Server, $uaddr) or die "bind: $!";
+listen(Server,SOMAXCONN) or die "listen: $!";
+
+warn "[fs_mailadmind] Entering main loop...\n" if $Debug;
+my $paddr;
+for ( ; $paddr = accept(Client,Server); close Client) {
+
+ chop( my $command = <Client> );
+
+ if ( $command eq "signup_info" ) {
+ warn "[fs_mailadmind] sending signup info...\n" if $Debug;
+ print Client join("\n", $n_cust_main_county,
+ map {
+ $_->{taxnum},
+ $_->{state},
+ $_->{county},
+ $_->{country},
+ } @cust_main_county
+ ), "\n";
+
+ print Client join("\n", $n_part_pkg,
+ map {
+ $_->{pkgpart},
+ $_->{pkg},
+ } @part_pkg
+ ), "\n";
+
+ print Client join("\n", $n_svc_acct_pop,
+ map {
+ $_->{popnum},
+ $_->{city},
+ $_->{state},
+ $_->{ac},
+ $_->{exch},
+ $_->{loc},
+ } @svc_acct_pop
+ ), "\n";
+
+ } elsif ( $command eq "new_customer" ) {
+ warn "[fs_mailadmind] reading customer signup...\n" if $Debug;
+ my(
+ $first, $last, $ss, $company, $address1, $address2, $city, $county,
+ $state, $zip, $country, $daytime, $night, $fax, $payby, $payinfo,
+ $paydate, $payname, $invoicing_list, $pkgpart, $username, $password,
+ $popnum,
+ ) = map { scalar(<Client>) } ( 1 .. 23 );
+
+ warn "[fs_mailadmind] sending customer data to remote server...\n" if $Debug;
+ print
+ $first, $last, $ss, $company, $address1, $address2, $city, $county,
+ $state, $zip, $country, $daytime, $night, $fax, $payby, $payinfo,
+ $paydate, $payname, $invoicing_list, $pkgpart, $username, $password,
+ $popnum,
+ ;
+
+ warn "[fs_mailadmind] reading error from remote server...\n" if $Debug;
+ my $error = <STDIN>;
+
+ warn "[fs_mailadmind] sending error to local client...\n" if $Debug;
+ print Client $error;
+
+ } elsif ( $command eq "authenticate" ) {
+ warn "[fs_mailadmind] reading user information to auth...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] reading authentication material...\n" if $Debug;
+ chop( my $password = <Client> );
+ warn "[fs_mailadmind] sending information to remote server...\n" if $Debug;
+ print "authenticate\n", $user, "\n", $password, "\n";
+
+ warn "[fs_mailadmind] reading error from remote server...\n" if $Debug;
+ my $error = <STDIN>;
+
+ warn "[fs_mailadmind] sending error to local client...\n" if $Debug;
+ print Client $error;
+
+ } elsif ( $command eq "list_packages" ) {
+ warn "[fs_mailadmind] reading user information to list_packages...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] sending user information to remote server...\n" if $Debug;
+ print "list_packages\n", $user, "\n";
+
+ warn "[fs_mailadmind] reading data from remote server...\n" if $Debug;
+ chomp( my $n_packages = <STDIN> );
+ my @packages = map {
+ chomp( my $pkgnum = <STDIN> );
+ chomp( my $domain = <STDIN> );
+ chomp( my $account = <STDIN> );
+ {
+ 'pkgnum' => $pkgnum,
+ 'domain' => $domain,
+ 'account' => $account,
+ };
+ } ( 1 .. $n_packages );
+
+ warn "[fs_mailadmind] sending data to local client...\n" if $Debug;
+
+ print Client join("\n", $n_packages,
+ map {
+ $_->{pkgnum},
+ $_->{domain},
+ $_->{account},
+ } @packages
+ ), "\n";
+
+ } elsif ( $command eq "list_mailboxes" ) {
+ warn "[fs_mailadmind] reading user information to list_mailboxes...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] reading package number to list_mailboxes...\n" if $Debug;
+ chop( my $package = <Client> );
+ warn "[fs_mailadmind] sending user information to remote server...\n" if $Debug;
+ print "list_mailboxes\n", $user, "\n", $package, "\n";
+
+ warn "[fs_mailadmind] reading data from remote server...\n" if $Debug;
+ chomp( my $n_svc_acct = <STDIN> );
+ my @svc_acct = map {
+ chomp( my $svcnum = <STDIN> );
+ chomp( my $username = <STDIN> );
+ chomp( my $_password = <STDIN> );
+ {
+ 'svcnum' => $svcnum,
+ 'username' => $username,
+ '_password' => $_password,
+ };
+ } ( 1 .. $n_svc_acct );
+
+ warn "[fs_mailadmind] sending data to local client...\n" if $Debug;
+
+ print Client join("\n", $n_svc_acct,
+ map {
+ $_->{svcnum},
+ $_->{username},
+ $_->{_password},
+ } @svc_acct
+ ), "\n";
+
+ } elsif ( $command eq "delete_mailbox" ) {
+ warn "[fs_mailadmind] reading user information to auth...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] reading account information to delete...\n" if $Debug;
+ chop( my $account = <Client> );
+ warn "[fs_mailadmind] sending information to remote server...\n" if $Debug;
+ print "delete_mailbox\n", $user, "\n", $account, "\n";
+
+ warn "[fs_mailadmind] reading error from remote server...\n" if $Debug;
+ my $error = <STDIN>;
+
+ warn "[fs_mailadmind] sending error to local client...\n" if $Debug;
+ print Client $error;
+
+ } elsif ( $command eq "password_mailbox" ) {
+ warn "[fs_mailadmind] reading user information to auth...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] reading account information to password...\n" if $Debug;
+ my(
+ $account, $_password,
+ ) = map { scalar(<Client>) } ( 1 .. 2 );
+
+ warn "[fs_mailadmind] sending password data to remote server...\n" if $Debug;
+ print "password_mailbox", "\n";
+ print
+ $user, "\n", $account, $_password,
+ ;
+
+ warn "[fs_mailadmind] reading error from remote server...\n" if $Debug;
+ my $error = <STDIN>;
+
+ warn "[fs_mailadmind] sending error to local client...\n" if $Debug;
+ print Client $error;
+
+ } elsif ( $command eq "add_mailbox" ) {
+ warn "[fs_mailadmind] reading user information to auth...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] reading account information to create...\n" if $Debug;
+ my(
+ $package, $account, $_password,
+ ) = map { scalar(<Client>) } ( 1 .. 3 );
+
+ warn "[fs_mailadmind] sending service data to remote server...\n" if $Debug;
+ print "add_mailbox", "\n";
+ print
+ $user, "\n", $package, $account, $_password,
+ ;
+
+ warn "[fs_mailadmind] reading error from remote server...\n" if $Debug;
+ my $error = <STDIN>;
+
+ warn "[fs_mailadmind] sending error to local client...\n" if $Debug;
+ print Client $error;
+
+ } elsif ( $command eq "add_forward" ) {
+ warn "[fs_mailadmind] reading user information to auth...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] reading forward information to create...\n" if $Debug;
+ my(
+ $package, $source, $dest,
+ ) = map { scalar(<Client>) } ( 1 .. 3 );
+
+ warn "[fs_mailadmind] sending service data to remote server...\n" if $Debug;
+ print "add_forward", "\n";
+ print
+ $user, "\n", $package, $source, $dest,
+ ;
+
+ warn "[fs_mailadmind] reading error from remote server...\n" if $Debug;
+ my $error = <STDIN>;
+
+ warn "[fs_mailadmind] sending error to local client...\n" if $Debug;
+ print Client $error;
+
+ } elsif ( $command eq "delete_forward" ) {
+ warn "[fs_mailadmind] reading user information to auth...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] reading forward information to delete...\n" if $Debug;
+ chop( my $service = <Client> );
+ warn "[fs_mailadmind] sending information to remote server...\n" if $Debug;
+ print "delete_forward\n", $user, "\n", $service, "\n";
+
+ warn "[fs_mailadmind] reading error from remote server...\n" if $Debug;
+ my $error = <STDIN>;
+
+ warn "[fs_mailadmind] sending error to local client...\n" if $Debug;
+ print Client $error;
+
+ } elsif ( $command eq "list_forwards" ) {
+ warn "[fs_mailadmind] reading user information to list_forwards...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] reading service number to list_forwards...\n" if $Debug;
+ chop( my $service = <Client> );
+ warn "[fs_mailadmind] sending user information to remote server...\n" if $Debug;
+ print "list_forwards\n", $user, "\n", $service, "\n";
+
+ warn "[fs_mailadmind] reading data from remote server...\n" if $Debug;
+ chomp( my $n_svc_forward = <STDIN> );
+ my @svc_forward = map {
+ chomp( my $svcnum = <STDIN> );
+ chomp( my $dest = <STDIN> );
+ {
+ 'svcnum' => $svcnum,
+ 'dest' => $dest,
+ };
+ } ( 1 .. $n_svc_forward );
+
+ warn "[fs_mailadmind] sending data to local client...\n" if $Debug;
+
+ print Client join("\n", $n_svc_forward,
+ map {
+ $_->{svcnum},
+ $_->{dest},
+ } @svc_forward
+ ), "\n";
+
+ } elsif ( $command eq "list_pkg_forwards" ) {
+ warn "[fs_mailadmind] reading user information to list_pkg_forwards...\n" if $Debug;
+ chop( my $user = <Client> );
+ warn "[fs_mailadmind] reading service number to list_forwards...\n" if $Debug;
+ chop( my $package = <Client> );
+ warn "[fs_mailadmind] sending user information to remote server...\n" if $Debug;
+ print "list_pkg_forwards\n", $user, "\n", $package, "\n";
+
+ warn "[fs_mailadmind] reading data from remote server...\n" if $Debug;
+ chomp( my $n_svc_forward = <STDIN> );
+ my @svc_forward = map {
+ chomp( my $svcnum = <STDIN> );
+ chomp( my $srcsvc = <STDIN> );
+ chomp( my $dest = <STDIN> );
+ {
+ 'svcnum' => $svcnum,
+ 'srcsvc' => $srcsvc,
+ 'dest' => $dest,
+ };
+ } ( 1 .. $n_svc_forward );
+
+ warn "[fs_mailadmind] sending data to local client...\n" if $Debug;
+
+ print Client join("\n", $n_svc_forward,
+ map {
+ $_->{svcnum},
+ $_->{srcsvc},
+ $_->{dest},
+ } @svc_forward
+ ), "\n";
+
+ } else {
+ die "unexpected command from client: $command";
+ }
+
+}
+
diff --git a/fs_selfadmin/README b/fs_selfadmin/README
new file mode 100644
index 0000000..d9857f0
--- /dev/null
+++ b/fs_selfadmin/README
@@ -0,0 +1,27 @@
+
+This collection of files implements a 'self-administered mail service.'
+Configuration is similar to fs_signupd
+
+Additionally you will need to modify the database:
+
+CREATE TABLE svc_acct_admin (
+ svcnum int primary key,
+ adminsvc int not null
+);
+
+creating both as keys might be good
+
+(and perform the dbdef-create)
+
+
+As it exists now, a package containing one svc_domain, at least one
+svc_acct_admin, and other services can have its svc_acct's and svc_forward's
+manipulated by the svc_acct referenced by a svc_acct_admin in the package.
+
+One svc_acct may be referenced as svc_acct_admin for multiple packages.
+
+fs_mailadmin_server contains hard coded references to service numbers which
+will require editing for your system.
+
+It's not a lot, but it might provide inspiration.
+
diff --git a/fs_selfadmin/fs_mailadmin_server b/fs_selfadmin/fs_mailadmin_server
new file mode 100755
index 0000000..ef47885
--- /dev/null
+++ b/fs_selfadmin/fs_mailadmin_server
@@ -0,0 +1,642 @@
+#!/usr/bin/perl -Tw
+#
+# fs_mailadmin_server
+#
+
+use strict;
+use IO::Handle;
+use FS::SSH qw(sshopen2);
+use FS::UID qw(adminsuidsetup);
+use FS::Conf;
+use FS::Record qw( qsearch qsearchs );
+use FS::cust_main_county;
+use FS::cust_main;
+use FS::svc_acct_admin;
+
+use vars qw( $opt $Debug $conf $default_domain );
+
+$Debug = 1;
+
+#my @payby = qw(CARD PREPAY);
+
+my $user = shift or die &usage;
+&adminsuidsetup( $user );
+
+$conf = new FS::Conf;
+$default_domain = $conf->config('domain');
+
+my $machine = shift or die &usage;
+
+my $agentnum = shift or die &usage;
+my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } ) or die &usage;
+my $pkgpart = $agent->pkgpart_hashref;
+
+my $refnum = shift or die &usage;
+
+#causing trouble for some folks
+#$SIG{CHLD} = sub { wait() };
+
+my($fs_mailadmind)=$conf->config('fs_mailadmind');
+
+while (1) {
+ my($reader,$writer)=(new IO::Handle, new IO::Handle);
+ $writer->autoflush(1);
+ warn "[fs_mailadmin_server] Connecting to $machine...\n" if $Debug;
+ sshopen2($machine,$reader,$writer,$fs_mailadmind);
+
+ my $data;
+
+ warn "[fs_mailadmin_server] Sending locales...\n" if $Debug;
+ my @cust_main_county = qsearch('cust_main_county', {} );
+ print $writer $data = join("\n",
+ ( scalar(@cust_main_county) || die "no tax rates (cust_main_county records)" ),
+ map {
+ $_->taxnum,
+ $_->state,
+ $_->county,
+ $_->country,
+ } @cust_main_county
+ ),"\n";
+ warn "[fs_mailadmin_server] $data\n" if $Debug > 2;
+
+ warn "[fs_mailadmin_server] Sending package definitions...\n" if $Debug;
+ my @part_pkg = grep { $_->svcpart('svc_acct') && $pkgpart->{ $_->pkgpart } }
+ qsearch( 'part_pkg', {} );
+ print $writer $data = join("\n",
+ ( scalar(@part_pkg) || die "no usable package definitions, agent $agentnum" ),
+ map {
+ $_->pkgpart,
+ $_->pkg,
+ } @part_pkg
+ ), "\n";
+ warn "[fs_mailadmin_server] $data\n" if $Debug > 2;
+
+ warn "[fs_mailadmin_server] Sending POPs...\n" if $Debug;
+ my @svc_acct_pop = qsearch ('svc_acct_pop',{} );
+ print $writer $data = join("\n",
+ ( scalar(@svc_acct_pop) || die "No points of presence (svc_acct_pop records)" ),
+ map {
+ $_->popnum,
+ $_->city,
+ $_->state,
+ $_->ac,
+ $_->exch,
+ $_->loc,
+ } @svc_acct_pop
+ ), "\n";
+ warn "[fs_mailadmin_server] $data\n" if $Debug > 2;
+
+ warn "[fs_mailadmin_server] Entering main loop...\n" if $Debug;
+COMMAND: while (1) {
+ warn "[fs_mailadmin_server] Reading (waiting for) command...\n" if $Debug;
+ chop( my($command, $user) = map { scalar(<$reader>) } ( 1 .. 2 ) );
+ my $domain = $default_domain;
+ $user =~ /^([\w\.\-]+)\@(([\w\-]+\.)+\w+)$/;
+ ($user, $domain) = ($1, $2);
+
+ if ($command eq 'authenticate'){
+ warn "[fs_mailadmin_server] Processing authenticate command for $user \n" if $Debug;
+ chop( my($password) = map { scalar(<$reader>) } ( 1 .. 1 ) );
+
+ my $error = '';
+
+ my @svc_domain = qsearchs('svc_domain', { 'domain' => $domain });
+
+ if (scalar(@svc_domain) != 1) {
+ warn "Nonexistant or duplicate service account for \"$domain\"";
+ next COMMAND;
+ }
+
+ my @svc_acct = qsearchs('svc_acct', { 'username' => $user,
+ 'domsvc' => $svc_domain[0]->svcnum });
+ if (scalar(@svc_acct) != 1) {
+ die "Nonexistant or duplicate service account for \"$user\"";
+ next COMMAND;
+ }
+
+ if ($svc_acct[0]->_password eq $password) {
+ $error = "$user\@$domain OK";
+ }else{
+ $error = "$user\@$domain FAILED";
+ }
+ warn "[fs_mailadmin_server] Sending results...\n" if $Debug;
+ print $writer $error, "\n";
+ }
+ elsif ($command eq 'list_packages'){
+ warn "[fs_mailadmin_server] Processing list_packages command for $user \n" if $Debug;
+
+ my $error = '';
+
+ my @packages = eval {find_administrable_packages( $user, $domain )};
+ warn "$@" if $@;
+
+ my %packages;
+ my %accounts;
+
+ foreach my $package (@packages) {
+ $packages{my $pkgnum = $package->getfield('pkgnum')} = $default_domain;
+ $accounts{$pkgnum} = 0;
+ my @services = qsearch('cust_svc', { 'pkgnum' => $pkgnum });
+ foreach my $service (@services) {
+ if ($service->getfield('svcpart') eq '4'){
+ my $account=qsearchs('svc_domain', { 'svcnum' => $service->getfield('svcnum') });
+ $packages{$pkgnum}=$account->getfield('domain');
+ $accounts{$pkgnum}=$account->getfield('svcnum');
+ }
+ }
+ }
+
+ print $writer $data = join("\n",
+ ( scalar(keys(%packages)) ),
+ map {
+ $_,
+ $packages{$_},
+ $accounts{$_},
+ } keys(%packages)
+ ), "\n";
+ warn "[fs_mailadmin_server] $data\n" if $Debug > 2;
+
+ }elsif ($command eq 'list_mailboxes'){
+
+ warn "[fs_mailadmin_server] Processing list_mailboxes command for $user" if $Debug;
+ chop( my($pkgnum) = map { scalar(<$reader>) } ( 1 .. 1 ) );
+ warn "package $pkgnum \n" if $Debug;
+
+ my $error = '';
+
+ my @packages = eval {find_administrable_packages( $user, $domain )};
+ warn "$@" if $@;
+
+ my @accounts;
+
+ foreach my $package (@packages) {
+ next unless ($pkgnum eq $package->getfield('pkgnum'));
+ my @services = qsearch('cust_svc', { 'pkgnum' => $package->getfield('pkgnum') });
+ foreach my $service (@services) {
+ if ($service->getfield('svcpart') eq '2'){
+ my $account=qsearchs('svc_acct', { 'svcnum' => $service->getfield('svcnum') });
+# $accounts[$#accounts+1]=$account->getfield('username');
+ $accounts[$#accounts+1]=$account;
+ }
+ }
+ }
+
+ print $writer $data = join("\n",
+# ( scalar(@accounts) || die "No accounts (svc_acct records)" ),
+ ( scalar(@accounts) ),
+ map {
+ $_->svcnum,
+# $_->username,
+ $_->email,
+# $_->_password,
+ '*****',
+ } @accounts
+ ), "\n";
+ warn "[fs_mailadmin_server] $data\n" if $Debug > 2;
+
+
+ } elsif ($command eq 'delete_mailbox'){
+ warn "[fs_mailadmin_server] Processing delete_mailbox command for $user " if $Debug;
+ chop( my($account) = map { scalar(<$reader>) } ( 1 .. 1 ) );
+ warn "account $account \n" if $Debug;
+
+ my $error = '';
+
+ my @packages = eval { find_administrable_packages($user, $domain) };
+ warn "$@" if $@;
+ $error ||= "$@" if $@;
+
+ my @svc_acct = qsearchs('svc_acct', { 'svcnum' => $account }) unless $error;
+ if (scalar(@svc_acct) != 1) { $error ||= 'Nonexistant or duplicate service account for user.' };
+ if (! $error && check_administrator(\@packages, $svc_acct[0])){
+# not sure about the next three lines... do we delete? or return error
+ foreach my $svc_forward (qsearch('svc_forward', { 'dstsvc' => $svc_acct[0]->getfield('svcnum') })) {
+ $error ||= $svc_forward->delete;
+ }
+ foreach my $svc_forward (qsearch('svc_forward', { 'srcsvc' => $svc_acct[0]->getfield('svcnum') })) {
+ $error ||= $svc_forward->delete;
+ }
+ $error ||= $svc_acct[0]->delete;
+ } else {
+ $error ||= "Illegal attempt to remove service";
+ }
+
+
+ warn "[fs_mailadmin_server] Sending results...\n" if $Debug;
+ print $writer $error, "\n";
+
+ } elsif ($command eq 'password_mailbox'){
+ warn "[fs_mailadmin_server] Processing password_mailbox command for $user " if $Debug;
+ chop( my($account, $_password) = map { scalar(<$reader>) } ( 1 .. 2 ) );
+ warn "account $account with password $_password \n" if $Debug;
+
+ my $error = '';
+
+ my @packages = eval { find_administrable_packages($user, $domain) };
+ warn "$@" if $@;
+ $error ||= "$@" if $@;
+
+ my @svc_acct = qsearchs('svc_acct', { 'svcnum' => $account }) unless $error;
+ if (scalar(@svc_acct) != 1) { $error ||= 'Nonexistant or duplicate service account.' };
+
+ if (! $error && check_administrator(\@packages, $svc_acct[0])){
+ my $new = new FS::svc_acct ({$svc_acct[0]->hash});
+ $new->setfield('_password' => $_password);
+ $error ||= $new->replace($svc_acct[0]);
+ } else {
+ $error ||= "Illegal attempt to change password";
+ }
+
+
+ warn "[fs_mailadmin_server] Sending results...\n" if $Debug;
+ print $writer $error, "\n";
+
+ } elsif ($command eq 'add_mailbox'){
+ warn "[fs_mailadmin_server] Processing add_mailbox command for $user " if $Debug;
+ chop( my($target_package, $account, $_password) = map { scalar(<$reader>) } ( 1 .. 3 ) );
+ warn "in package $target_package account $account with password $_password \n" if $Debug;
+
+ my $found_package;
+ my $domainsvc=0;
+ my $svcpart=2; # this is 'email box'
+ my $svcpartsm=3; # this is 'domain alias'
+ my $error = '';
+ my $found = 0;
+
+ my @packages = eval { find_administrable_packages($user, $domain) };
+ warn "$@" if $@;
+ $error ||= "$@" if $@;
+
+ foreach my $package (@packages) {
+ if ($package->getfield('pkgnum') eq $target_package) {
+ $found = 1;
+ $found_package=$package;
+ my @services = qsearch('cust_svc', { 'pkgnum' => $target_package });
+ foreach my $service (@services) {
+ if ($service->getfield('svcpart') eq '4'){
+ my @svc_domain=qsearchs('svc_domain', { 'svcnum' => $service->getfield('svcnum') });
+ if (scalar(@svc_domain) eq 1) {
+ $domainsvc=$svc_domain[0]->getfield('svcnum');
+ }
+ }
+ }
+ last;
+ }
+ }
+ warn "User $user does not have administration rights to package $target_package\n" unless $found;
+ $error ||= "User $user does not have administration rights to package $target_package\n" unless $found;
+
+ my $part_pkg = qsearchs('part_pkg',{'pkgpart'=>$found_package->getfield('pkgpart')});
+
+ #list of services this pkgpart includes (although at the moment we only care
+ # about $svcpart
+ my $pkg_svc;
+ my %pkg_svc = ();
+ foreach $pkg_svc ( qsearch('pkg_svc',{'pkgpart'=> $found_package->pkgpart }) ) {
+ $pkg_svc{$pkg_svc->svcpart} = $pkg_svc->quantity if $pkg_svc->quantity;
+ }
+
+ my @services = qsearch('cust_svc', {'pkgnum' => $found_package->getfield('pkgnum'),
+ 'svcpart' => $svcpart,
+ });
+
+ if (scalar(@services) >= $pkg_svc{$svcpart}) {
+ $error="Maximum allowed already reached.";
+ }
+
+ my $svc_acct = new FS::svc_acct ( {
+ 'pkgnum' => $found_package->pkgnum,
+ 'svcpart' => $svcpart,
+ 'username' => $account,
+ 'domsvc' => $domainsvc,
+ '_password' => $_password,
+ } );
+
+ my $y = $svc_acct->setdefault; # arguably should be in new method
+ $error ||= $y unless ref($y);
+ #and just in case you were silly
+ $svc_acct->pkgnum($found_package->pkgnum);
+ $svc_acct->svcpart($svcpart);
+ $svc_acct->username($account);
+ $svc_acct->domsvc($domainsvc);
+ $svc_acct->_password($_password);
+
+ $error ||= $svc_acct->check;
+
+ if ( ! $error ) { #in this case, $cust_pkg should always
+ #be definied, but....
+ $error ||= $svc_acct->insert;
+ warn "WARNING: $error on pre-checked svc_acct record!" if $error;
+ }
+
+ warn "[fs_mailadmin_server] Sending results...\n" if $Debug;
+ print $writer $error, "\n";
+
+ }elsif ($command eq 'list_forwards'){
+
+ warn "[fs_mailadmin_server] Processing list_forwards command for $user" if $Debug;
+ chop( my($svcnum) = map { scalar(<$reader>) } ( 1 .. 1 ) );
+ warn "service $svcnum \n" if $Debug;
+
+ my $error = '';
+
+ my @packages = eval {find_administrable_packages( $user, $domain )};
+ warn "$@" if $@;
+
+ my @forwards;
+
+ foreach my $package (@packages) {
+# next unless ($pkgnum eq $package->getfield('pkgnum'));
+ my @services = qsearch('cust_svc', { 'pkgnum' => $package->getfield('pkgnum') });
+ foreach my $service (@services) {
+ if ($service->getfield('svcpart') eq '10'){
+ my $forward=qsearchs('svc_forward', { 'svcnum' => $service->getfield('svcnum') });
+ $forwards[$#forwards+1]=$forward if ($forward->getfield('srcsvc') == $svcnum);
+ }
+ }
+ }
+
+ print $writer $data = join("\n",
+ ( scalar(@forwards) ),
+ map {
+ $_->svcnum,
+ ($_->dstsvc ? qsearchs('svc_acct', {'svcnum' => $_->dstsvc})->email : $_->dst),
+ } @forwards
+ ), "\n";
+ warn "[fs_mailadmin_server] $data\n" if $Debug > 2;
+
+
+ }elsif ($command eq 'list_pkg_forwards'){
+
+ warn "[fs_mailadmin_server] Processing list_pkg_forwards command for $user" if $Debug;
+ chop( my($pkgnum) = map { scalar(<$reader>) } ( 1 .. 1 ) );
+ warn "package $pkgnum \n" if $Debug;
+
+ my $error = '';
+
+ my @packages = eval {find_administrable_packages( $user, $domain )};
+ warn "$@" if $@;
+
+ my @forwards;
+
+ foreach my $package (@packages) {
+ next unless ($pkgnum eq $package->getfield('pkgnum'));
+ my @services = qsearch('cust_svc', { 'pkgnum' => $package->getfield('pkgnum') });
+ foreach my $service (@services) {
+ if ($service->getfield('svcpart') eq '10'){
+ my $forward=qsearchs('svc_forward', { 'svcnum' => $service->getfield('svcnum') });
+ $forwards[$#forwards+1]=$forward;
+ }
+ }
+ }
+
+ print $writer $data = join("\n",
+ ( scalar(@forwards) ),
+ map {
+ $_->svcnum,
+ $_->srcsvc,
+ ($_->dstsvc ? qsearchs('svc_acct', {'svcnum' => $_->dstsvc})->email : $_->dst),
+ } @forwards
+ ), "\n";
+ warn "[fs_mailadmin_server] $data\n" if $Debug > 2;
+
+
+ } elsif ($command eq 'delete_forward'){
+ warn "[fs_mailadmin_server] Processing delete_forward command for $user " if $Debug;
+ chop( my($forward) = map { scalar(<$reader>) } ( 1 .. 1 ) );
+ warn "forward $forward \n" if $Debug;
+
+ my $error = '';
+
+ my @packages = eval { find_administrable_packages($user, $domain) };
+ warn "$@" if $@;
+ $error ||= "$@" if $@;
+
+ my @svc_forward = qsearchs('svc_forward', { 'svcnum' => $forward }) unless $error;
+ if (scalar(@svc_forward) != 1) { $error ||= 'Nonexistant or duplicate service account for user.' };
+ if (! $error && check_administrator(\@packages, $svc_forward[0])){
+# not sure about the next three lines... do we delete? or return error
+ $error ||= $svc_forward[0]->delete;
+ } else {
+ $error ||= "Illegal attempt to remove service";
+ }
+
+
+ warn "[fs_mailadmin_server] Sending results...\n" if $Debug;
+ print $writer $error, "\n";
+
+ } elsif ($command eq 'add_forward'){
+ warn "[fs_mailadmin_server] Processing add_forward command for $user " if $Debug;
+ chop( my($target_package, $source, $dest) = map { scalar(<$reader>) } ( 1 .. 3 ) );
+ warn "in package $target_package source $source with destination $dest \n" if $Debug;
+
+ my $found_package;
+ my $domainsvc=0;
+ my $svcpart=10; # this is 'forward service'
+ my $error = '';
+ my $found = 0;
+
+ my @packages = eval { find_administrable_packages($user, $domain) };
+ warn "$@" if $@;
+ $error ||= "$@" if $@;
+
+ foreach my $package (@packages) {
+ if ($package->getfield('pkgnum') eq $target_package) {
+ $found = 1;
+ $found_package=$package;
+ last;
+ }
+ }
+ warn "User $user does not have administration rights to package $target_package\n" unless $found;
+ $error ||= "User $user does not have administration rights to package $target_package\n" unless $found;
+
+ my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $source });
+ warn "Forwarding source $source does not exist.\n" unless $svc_acct;
+ $error ||= "Forwarding source $source does not exist.\n" unless $svc_acct;
+
+ my $cust_svc = qsearchs('cust_svc', { 'svcnum' => $source });
+ warn "Forwarding source $source not attached to any account.\n" unless $cust_svc;
+ $error ||= "Forwarding source $source not attached to any account.\n" unless $cust_svc;
+
+ if ( ! $error ) {
+ warn "Forwarding source $source is not in package $target_package\n"
+ unless ($cust_svc->getfield('pkgnum') == $target_package);
+ $error ||= "Forwarding source $source is not in package $target_package\n"
+ unless ($cust_svc->getfield('pkgnum') == $target_package);
+ }
+
+ my $part_pkg = qsearchs('part_pkg',{'pkgpart'=>$found_package->getfield('pkgpart')});
+
+ #list of services this pkgpart includes (although at the moment we only care
+ # about $svcpart
+ my $pkg_svc;
+ my %pkg_svc = ();
+ foreach $pkg_svc ( qsearch('pkg_svc',{'pkgpart'=> $found_package->pkgpart }) ) {
+ $pkg_svc{$pkg_svc->svcpart} = $pkg_svc->quantity if $pkg_svc->quantity;
+ }
+
+ my @services = qsearch('cust_svc', {'pkgnum' => $found_package->getfield('pkgnum'),
+ 'svcpart' => $svcpart,
+ });
+
+ if (scalar(@services) >= $pkg_svc{$svcpart}) {
+ $error="Maximum allowed already reached.";
+ }
+
+ my $svc_forward = new FS::svc_forward ( {
+ 'pkgnum' => $found_package->pkgnum,
+ 'svcpart' => $svcpart,
+ 'srcsvc' => $source,
+ 'dstsvc' => 0,
+ 'dst' => $dest,
+ } );
+
+ my $y = $svc_forward->setdefault; # arguably should be in new method
+ $error ||= $y unless ref($y);
+ #and just in case you were silly
+ $svc_forward->pkgnum($found_package->pkgnum);
+ $svc_forward->svcpart($svcpart);
+ $svc_forward->srcsvc($source);
+ $svc_forward->dstsvc(0);
+ $svc_forward->dst($dest);
+
+ $error ||= $svc_forward->check;
+
+ if ( ! $error ) { #in this case, $cust_pkg should always
+ #be definied, but....
+ $error ||= $svc_forward->insert;
+ warn "WARNING: $error on pre-checked svc_forward record!" if $error;
+ }
+
+ warn "[fs_mailadmin_server] Sending results...\n" if $Debug;
+ print $writer $error, "\n";
+
+ } else {
+ warn "[fs_mailadmin_server] Bad command: $command \n" if $Debug;
+ print $writer "Bad command \n";
+ }
+ }
+ close $writer;
+ close $reader;
+ warn "connection to $machine lost! waiting 60 seconds...\n";
+ sleep 60;
+ warn "reconnecting...\n";
+}
+
+sub usage {
+ die "Usage:\n\n fs_mailadmin_server user machine agentnum refnum\n";
+}
+
+#sub find_administrable_packages {
+# my $user = shift;
+#
+# my $error = '';
+#
+# my @svc_acct = qsearchs('svc_acct', { 'username' => $user });
+# if (scalar(@svc_acct) != 1) {
+# die "Nonexistant or duplicate service account for \"$user\"";
+# }
+#
+# my @cust_svc = qsearchs('cust_svc', { 'svcnum' => $svc_acct[0]->getfield('svcnum') });
+# if (scalar(@cust_svc) != 1 ) {
+# die "Nonexistant or duplicate customer service for \"$user\"";
+# }
+#
+# my @cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_svc[0]->getfield('pkgnum') });
+# if (scalar(@cust_pkg) != 1) {
+# die "Nonexistant or duplicate customer package for \"$user\"";
+# }
+#
+# my @cust_main = qsearchs('cust_main', { 'custnum' => $cust_pkg[0]->getfield('custnum') });
+# if (scalar(@cust_main) != 1 ) {
+# die "Nonexistant or duplicate customer for \"$user\"";
+# }
+#
+# my @packages = $cust_main[0]->ncancelled_pkgs;
+#}
+
+sub find_administrable_packages {
+ my $user = shift;
+ my $domain = shift;
+
+ my @packages;
+ my $error = '';
+
+ my @svc_domain = qsearchs('svc_domain', { 'domain' => $domain });
+
+ if (scalar(@svc_domain) != 1) {
+ die "Nonexistant or duplicate service account for \"$domain\"";
+ }
+
+ my @svc_acct = qsearchs('svc_acct', { 'username' => $user,
+ 'domsvc' => $svc_domain[0]->svcnum });
+ if (scalar(@svc_acct) != 1) {
+ die "Nonexistant or duplicate service account for \"$user\"";
+ }
+
+ my @svc_acct_admin = qsearch('svc_acct_admin', {'adminsvc' => $svc_acct[0]->getfield('svcnum') });
+ die "Nonexistant or duplicate customer service for \"$user\"" unless scalar(@svc_acct_admin);
+
+ foreach my $svc_acct_admin (@svc_acct_admin) {
+ my @cust_svc = qsearchs('cust_svc', { 'svcnum' => $svc_acct_admin->getfield('svcnum') });
+ if (scalar(@cust_svc) != 1 ) {
+ die "Nonexistant or duplicate customer service for admin \"$svc_acct_admin->getfield('svcnum')\"";
+ }
+
+ my @cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_svc[0]->getfield('pkgnum') });
+ if (scalar(@cust_pkg) != 1) {
+ die "Nonexistant or duplicate customer package for admin \"$user\"";
+ }
+
+ push @packages, $cust_pkg[0] unless $cust_pkg[0]->getfield('cancel');
+
+ }
+ (@packages);
+}
+
+sub check_administrator {
+ my ($allowed_packages_aref, $svc_acct_ref) = @_;
+
+ my $error = '';
+ my $found = 0;
+
+ {
+ my @cust_svc = qsearchs('cust_svc', { 'svcnum' => $svc_acct_ref->getfield('svcnum') });
+ if (scalar(@cust_svc) != 1 ) {
+ warn "Nonexistant or duplicate customer service for \"$svc_acct_ref->getfield('username')\"";
+ last;
+ }
+
+ my @cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_svc[0]->getfield('pkgnum') });
+ if (scalar(@cust_pkg) != 1) {
+ warn "Nonexistant or duplicate customer package for \"$svc_acct_ref->getfield('username')\"";
+ last;
+ }
+
+ foreach my $package (@$allowed_packages_aref) {
+ if ($package->getfield('pkgnum') eq $cust_pkg[0]->getfield('pkgnum')) {
+ $found = 1;
+ last;
+ }
+ }
+ }
+
+ $found;
+}
+
+sub check_add {
+ my ($allowed_packages_aref, $target_package) = @_;
+
+ my $error = '';
+ my $found = 0;
+
+ foreach my $package (@$allowed_packages_aref) {
+ if ($package->getfield('pkgnum') eq $target_package) {
+ $found = 1;
+ last;
+ }
+ }
+
+ $found;
+}
+
diff --git a/fs_selfservice/DEPLOY b/fs_selfservice/DEPLOY
new file mode 100755
index 0000000..7420df7
--- /dev/null
+++ b/fs_selfservice/DEPLOY
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+kill `cat /var/run/freeside-selfservice-server.fs_selfservice.pid`
+
+( cd ..; make deploy; cd fs_selfservice )
+
+cd FS-SelfService
+perl Makefile.PL && make && make install
+
+cp /home/ivan/freeside/fs_selfservice/FS-SelfService/cgi/* /var/www/MyAccount
+chown freeside /var/www/MyAccount/selfservice.cgi /var/www/MyAccount/agent.cgi
+chmod 755 /var/www/MyAccount/selfservice.cgi /var/www/MyAccount/agent.cgi
+ln -s /var/www/MyAccount/selfservice.cgi /var/www/MyAccount/index.cgi || true
+
+cp /home/ivan/freeside/fs_signup/FS-SignupClient/cgi/* /var/www/signup/
+#mv /var/www/signup/signup-snarf.html /var/www/signup/signup.html #!!!!!
+chown freeside /var/www/signup/signup.cgi
+chmod 755 /var/www/signup/signup.cgi
+ln -s /var/www/signup/signup.cgi /var/www/signup/index.cgi || true
+
diff --git a/fs_selfservice/FS-SelfService/Changes b/fs_selfservice/FS-SelfService/Changes
new file mode 100644
index 0000000..b9e26b7
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension FS::SelfService.
+
+0.01 Tue May 28 16:49:41 2002
+ - original version; created by h2xs 1.21 with options
+ -A -X -n FS::SelfService
+
diff --git a/fs_selfservice/FS-SelfService/MANIFEST b/fs_selfservice/FS-SelfService/MANIFEST
new file mode 100644
index 0000000..ebd0d3b
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/MANIFEST
@@ -0,0 +1,6 @@
+Changes
+Makefile.PL
+MANIFEST
+SelfService.pm
+test.pl
+freeside-selfservice-clientd
diff --git a/fs_selfservice/FS-SelfService/Makefile.PL b/fs_selfservice/FS-SelfService/Makefile.PL
new file mode 100644
index 0000000..0b7fc46
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/Makefile.PL
@@ -0,0 +1,19 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'FS::SelfService',
+ 'VERSION_FROM' => 'SelfService.pm', # finds $VERSION
+ 'EXE_FILES' => [ 'freeside-selfservice-clientd',
+ #'freeside-selfservice-xmlrpc-server',
+ ],
+ 'INSTALLSCRIPT' => '/usr/local/sbin',
+ 'INSTALLSITEBIN' => '/usr/local/sbin',
+ 'PERM_RWX' => '750',
+ 'PREREQ_PM' => {
+ 'Storable' => 2.09,
+ }, # e.g., Module::Name => 1.1
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'SelfService.pm', # retrieve abstract from module
+ AUTHOR => 'Ivan Kohler <ivan-freeside-selfservice@420.am>') : ()),
+);
diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm
new file mode 100644
index 0000000..2cda9fe
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/SelfService.pm
@@ -0,0 +1,1057 @@
+package FS::SelfService;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT_OK $socket %autoload $tag);
+use Exporter;
+use Socket;
+use FileHandle;
+#use IO::Handle;
+use IO::Select;
+use Storable 2.09 qw(nstore_fd fd_retrieve);
+
+$VERSION = '0.03';
+
+@ISA = qw( Exporter );
+
+$socket = "/usr/local/freeside/selfservice_socket";
+$socket .= '.'.$tag if defined $tag && length($tag);
+
+#maybe should ask ClientAPI for this list
+%autoload = (
+ 'passwd' => 'passwd/passwd',
+ 'chfn' => 'passwd/passwd',
+ 'chsh' => 'passwd/passwd',
+ 'login' => 'MyAccount/login',
+ 'customer_info' => 'MyAccount/customer_info',
+ 'edit_info' => 'MyAccount/edit_info',
+ 'invoice' => 'MyAccount/invoice',
+ 'list_invoices' => 'MyAccount/list_invoices',
+ 'cancel' => 'MyAccount/cancel',
+ 'payment_info' => 'MyAccount/payment_info',
+ 'process_payment' => 'MyAccount/process_payment',
+ 'list_pkgs' => 'MyAccount/list_pkgs',
+ 'order_pkg' => 'MyAccount/order_pkg',
+ 'cancel_pkg' => 'MyAccount/cancel_pkg',
+ 'charge' => 'MyAccount/charge',
+ 'signup_info' => 'Signup/signup_info',
+ 'new_customer' => 'Signup/new_customer',
+ 'agent_login' => 'Agent/agent_login',
+ 'agent_info' => 'Agent/agent_info',
+ 'agent_list_customers' => 'Agent/agent_list_customers',
+);
+@EXPORT_OK = ( keys(%autoload), qw( regionselector expselect popselector ) );
+
+$ENV{'PATH'} ='/usr/bin:/usr/ucb:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+my $freeside_uid = scalar(getpwnam('freeside'));
+die "not running as the freeside user\n" if $> != $freeside_uid;
+
+foreach my $autoload ( keys %autoload ) {
+
+ my $eval =
+ "sub $autoload { ". '
+ my $param;
+ if ( ref($_[0]) ) {
+ $param = shift;
+ } else {
+ $param = { @_ };
+ }
+
+ $param->{_packet} = \''. $autoload{$autoload}. '\';
+
+ simple_packet($param);
+ }';
+
+ eval $eval;
+ die $@ if $@;
+
+}
+
+sub simple_packet {
+ my $packet = shift;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($socket)) or die "connect: $!";
+ nstore_fd($packet, \*SOCK) or die "can't send packet: $!";
+ SOCK->flush;
+
+ #shoudl trap: Magic number checking on storable file failed at blib/lib/Storable.pm (autosplit into blib/lib/auto/Storable/fd_retrieve.al) line 337, at /usr/local/share/perl/5.6.1/FS/SelfService.pm line 71
+
+ #block until there is a message on socket
+# my $w = new IO::Select;
+# $w->add(\*SOCK);
+# my @wait = $w->can_read;
+ my $return = fd_retrieve(\*SOCK) or die "error reading result: $!";
+ die $return->{'_error'} if defined $return->{_error} && $return->{_error};
+
+ $return;
+}
+
+=head1 NAME
+
+FS::SelfService - Freeside self-service API
+
+=head1 SYNOPSIS
+
+ # password and shell account changes
+ use FS::SelfService qw(passwd chfn chsh);
+
+ # "my account" functionality
+ use FS::SelfService qw( login customer_info invoice cancel payment_info process_payment );
+
+ my $rv = login( { 'username' => $username,
+ 'domain' => $domain,
+ 'password' => $password,
+ }
+ );
+
+ if ( $rv->{'error'} ) {
+ #handle login error...
+ } else {
+ #successful login
+ my $session_id = $rv->{'session_id'};
+ }
+
+ my $customer_info = customer_info( { 'session_id' => $session_id } );
+
+ #payment_info and process_payment are available in 1.5+ only
+ my $payment_info = payment_info( { 'session_id' => $session_id } );
+
+ #!!! process_payment example
+
+ #!!! list_pkgs example
+
+ #!!! order_pkg example
+
+ #!!! cancel_pkg example
+
+ # signup functionality
+ use FS::SelfService qw( signup_info new_customer );
+
+ my $signup_info = signup_info;
+
+ $rv = new_customer( {
+ 'first' => $first,
+ 'last' => $last,
+ 'company' => $company,
+ 'address1' => $address1,
+ 'address2' => $address2,
+ 'city' => $city,
+ 'state' => $state,
+ 'zip' => $zip,
+ 'country' => $country,
+ 'daytime' => $daytime,
+ 'night' => $night,
+ 'fax' => $fax,
+ 'payby' => $payby,
+ 'payinfo' => $payinfo,
+ 'paycvv' => $paycvv,
+ 'paydate' => $paydate,
+ 'payname' => $payname,
+ 'invoicing_list' => $invoicing_list,
+ 'referral_custnum' => $referral_custnum,
+ 'pkgpart' => $pkgpart,
+ 'username' => $username,
+ '_password' => $password,
+ 'popnum' => $popnum,
+ 'agentnum' => $agentnum,
+ }
+ );
+
+ my $error = $rv->{'error'};
+ if ( $error eq '_decline' ) {
+ print_decline();
+ } elsif ( $error ) {
+ reprint_signup();
+ } else {
+ print_success();
+ }
+
+=head1 DESCRIPTION
+
+Use this API to implement your own client "self-service" module.
+
+If you just want to customize the look of the existing "self-service" module,
+see XXXX instead.
+
+=head1 PASSWORD, GECOS, SHELL CHANGING FUNCTIONS
+
+=over 4
+
+=item passwd
+
+=item chfn
+
+=item chsh
+
+=back
+
+=head1 "MY ACCOUNT" FUNCTIONS
+
+=over 4
+
+=item login HASHREF
+
+Creates a user session. Takes a hash reference as parameter with the
+following keys:
+
+=over 4
+
+=item username
+
+=item domain
+
+=item password
+
+=back
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors.
+
+=item session_id
+
+Session identifier for successful logins
+
+=back
+
+=item customer_info HASHREF
+
+Returns general customer information.
+
+Takes a hash reference as parameter with a single key: B<session_id>
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item name
+
+Customer name
+
+=item balance
+
+Balance owed
+
+=item open
+
+Array reference of hash references of open inoices. Each hash reference has
+the following keys: invnum, date, owed
+
+=item small_custview
+
+An HTML fragment containing shipping and billing addresses.
+
+=item The following fields are also returned: first last company address1 address2 city county state zip country daytime night fax ship_first ship_last ship_company ship_address1 ship_address2 ship_city ship_state ship_zip ship_country ship_daytime ship_night ship_fax payby payinfo payname month year invoicing_list postal_invoicing
+
+=back
+
+=item edit_info HASHREF
+
+Takes a hash reference as parameter with any of the following keys:
+
+first last company address1 address2 city county state zip country daytime night fax ship_first ship_last ship_company ship_address1 ship_address2 ship_city ship_state ship_zip ship_country ship_daytime ship_night ship_fax payby payinfo paycvv payname month year invoicing_list postal_invoicing
+
+If a field exists, the customer record is updated with the new value of that
+field. If a field does not exist, that field is not changed on the customer
+record.
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors
+
+=item invoice HASHREF
+
+Returns an invoice. Takes a hash reference as parameter with two keys:
+session_id and invnum
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors
+
+=item invnum
+
+Invoice number
+
+=item invoice_text
+
+Invoice text
+
+=back
+
+=item list_invoices HASHREF
+
+Returns a list of all customer invoices. Takes a hash references with a single
+key, session_id.
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors
+
+=item invoices
+
+Reference to array of hash references with the following keys:
+
+=over 4
+
+=item invnum
+
+Invoice ID
+
+=item _date
+
+Invoice date, in UNIX epoch time
+
+=back
+
+=back
+
+=item cancel HASHREF
+
+Cancels this customer.
+
+Takes a hash reference as parameter with a single key: B<session_id>
+
+Returns a hash reference with a single key, B<error>, which is empty on
+success or an error message on errors.
+
+=item payment_info HASHREF
+
+Returns information that may be useful in displaying a payment page.
+
+Takes a hash reference as parameter with a single key: B<session_id>.
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors
+
+=item balance
+
+Balance owed
+
+=item payname
+
+Exact name on credit card (CARD/DCRD)
+
+=item address1
+
+=item address2
+
+=item city
+
+=item state
+
+=item zip
+
+=item payby
+
+Customer's current default payment type.
+
+=item card_type
+
+For CARD/DCRD payment types, the card type (Visa card, MasterCard, Discover card, American Express card, etc.)
+
+=item payinfo
+
+For CARD/DCRD payment types, the card number
+
+=item month
+
+For CARD/DCRD payment types, expiration month
+
+=item year
+
+For CARD/DCRD payment types, expiration year
+
+=item cust_main_county
+
+County/state/country data - array reference of hash references, each of which has the fields of a cust_main_county record (see L<FS::cust_main_county>). Note these are not FS::cust_main_county objects, but hash references of columns and values.
+
+=item states
+
+Array reference of all states in the current default country.
+
+=item card_types
+
+Hash reference of card types; keys are card types, values are the exact strings
+passed to the process_payment function
+
+=item paybatch
+
+Unique transaction identifier (prevents multiple charges), passed to the
+process_payment function
+
+=back
+
+=item process_payment HASHREF
+
+Processes a payment and possible change of address or payment type. Takes a
+hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+=item save
+
+If true, address and card information entered will be saved for subsequent
+transactions.
+
+=item auto
+
+If true, future credit card payments will be done automatically (sets payby to
+CARD). If false, future credit card payments will be done on-demand (sets
+payby to DCRD). This option only has meaning if B<save> is set true.
+
+=item payname
+
+=item address1
+
+=item address2
+
+=item city
+
+=item state
+
+=item zip
+
+=item payinfo
+
+Card number
+
+=item month
+
+Card expiration month
+
+=item year
+
+Card expiration year
+
+=item paybatch
+
+Unique transaction identifier, returned from the payment_info function.
+Prevents multiple charges.
+
+=back
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors
+
+=item list_pkgs
+
+Returns package information for this customer.
+
+Takes a hash reference as parameter with a single key: B<session_id>
+
+Returns a hash reference containing customer package information. The hash reference contains the following keys:
+
+=over 4
+
+=item cust_pkg HASHREF
+
+Array reference of hash references, each of which has the fields of a cust_pkg record (see L<FS::cust_pkg>). Note these are not FS::cust_pkg objects, but hash references of columns and values.
+
+=back
+
+=item order_pkg
+
+Orders a package for this customer.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+=item pkgpart
+
+=item svcpart
+
+optional svcpart, required only if the package definition does not contain
+one svc_acct service definition with quantity 1 (it may contain others with
+quantity >1)
+
+=item username
+
+=item _password
+
+=item sec_phrase
+
+=item popnum
+
+=back
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors. The special error '_decline' is returned for
+declined transactions.
+
+=item cancel_pkg
+
+Cancels a package for this customer.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+=item pkgpart
+
+=back
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
+=back
+
+=head1 SIGNUP FUNCTIONS
+
+=over 4
+
+=item signup_info HASHREF
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id - Optional agent/reseller interface session
+
+=back
+
+Returns a hash reference containing information that may be useful in
+displaying a signup page. The hash reference contains the following keys:
+
+=over 4
+
+=item cust_main_county
+
+County/state/country data - array reference of hash references, each of which has the fields of a cust_main_county record (see L<FS::cust_main_county>). Note these are not FS::cust_main_county objects, but hash references of columns and values.
+
+=item part_pkg
+
+Available packages - array reference of hash references, each of which has the fields of a part_pkg record (see L<FS::part_pkg>). Each hash reference also has an additional 'payby' field containing an array reference of acceptable payment types specific to this package (see below and L<FS::part_pkg/payby>). Note these are not FS::part_pkg objects, but hash references of columns and values. Requires the 'signup_server-default_agentnum' configuration value to be set, or
+an agentnum specified explicitly via reseller interface session_id in the
+options.
+
+=item agent
+
+Array reference of hash references, each of which has the fields of an agent record (see L<FS::agent>). Note these are not FS::agent objects, but hash references of columns and values.
+
+=item agentnum2part_pkg
+
+Hash reference; keys are agentnums, values are array references of available packages for that agent, in the same format as the part_pkg arrayref above.
+
+=item svc_acct_pop
+
+Access numbers - array reference of hash references, each of which has the fields of an svc_acct_pop record (see L<FS::svc_acct_pop>). Note these are not FS::svc_acct_pop objects, but hash references of columns and values.
+
+=item security_phrase
+
+True if the "security_phrase" feature is enabled
+
+=item payby
+
+Array reference of acceptable payment types for signup
+
+=over 4
+
+=item CARD (credit card - automatic)
+
+=item DCRD (credit card - on-demand - version 1.5+ only)
+
+=item CHEK (electronic check - automatic)
+
+=item DCHK (electronic check - on-demand - version 1.5+ only)
+
+=item LECB (Phone bill billing)
+
+=item BILL (billing, not recommended for signups)
+
+=item COMP (free, definately not recommended for signups)
+
+=item PREPAY (special billing type: applies a credit (see FS::prepay_credit) and sets billing type to BILL)
+
+=back
+
+=item cvv_enabled
+
+True if CVV features are available (1.5+ or 1.4.2 with CVV schema patch)
+
+=item msgcat
+
+Hash reference of message catalog values, to support error message customization. Currently available keys are: passwords_dont_match, invalid_card, unknown_card_type, and not_a (as in "Not a Discover card"). Values are configured in the web interface under "View/Edit message catalog".
+
+=item statedefault
+
+Default state
+
+=item countrydefault
+
+Default country
+
+=back
+
+=item new_customer HASHREF
+
+Creates a new customer. Takes a hash reference as parameter with the
+following keys:
+
+=over 4
+
+=item first - first name (required)
+
+=item last - last name (required)
+
+=item ss (not typically collected; mostly used for ACH transactions)
+
+=item company
+
+=item address1 (required)
+
+=item address2
+
+=item city (required)
+
+=item county
+
+=item state (required)
+
+=item zip (required)
+
+=item daytime - phone
+
+=item night - phone
+
+=item fax - phone
+
+=item payby - CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY (see L</signup_info> (required)
+
+=item payinfo - Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL
+
+=item paycvv - Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch)
+
+=item paydate - Expiration date for CARD/DCRD
+
+=item payname - Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK
+
+=item invoicing_list - comma-separated list of email addresses for email invoices. The special value 'POST' is used to designate postal invoicing (it may be specified alone or in addition to email addresses),
+
+=item referral_custnum - referring customer number
+
+=item pkgpart - pkgpart of initial package
+
+=item username
+
+=item _password
+
+=item sec_phrase - security phrase
+
+=item popnum - access number (index, not the literal number)
+
+=item agentnum - agent number
+
+=back
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error Empty on success, or an error message on errors. The special error '_decline' is returned for declined transactions; other error messages should be suitable for display to the user (and are customizable in under Sysadmin | View/Edit message catalog)
+
+=back
+
+=item regionselector HASHREF | LIST
+
+Takes as input a hashref or list of key/value pairs with the following keys:
+
+=over 4
+
+=item selected_county
+
+=item selected_state
+
+=item selected_country
+
+=item prefix - Specify a unique prefix string if you intend to use the HTML output multiple time son one page.
+
+=item onchange - Specify a javascript subroutine to call on changes
+
+=item default_state
+
+=item default_country
+
+=item locales - An arrayref of hash references specifying regions. Normally you can just pass the value of the I<cust_main_county> field returned by B<signup_info>.
+
+=back
+
+Returns a list consisting of three HTML fragments for county selection,
+state selection and country selection, respectively.
+
+=cut
+
+#false laziness w/FS::cust_main_county (this is currently the "newest" version)
+sub regionselector {
+ my $param;
+ if ( ref($_[0]) ) {
+ $param = shift;
+ } else {
+ $param = { @_ };
+ }
+ $param->{'selected_country'} ||= $param->{'default_country'};
+ $param->{'selected_state'} ||= $param->{'default_state'};
+
+ my $prefix = exists($param->{'prefix'}) ? $param->{'prefix'} : '';
+
+ my $countyflag = 0;
+
+ my %cust_main_county;
+
+# unless ( @cust_main_county ) { #cache
+ #@cust_main_county = qsearch('cust_main_county', {} );
+ #foreach my $c ( @cust_main_county ) {
+ foreach my $c ( @{ $param->{'locales'} } ) {
+ #$countyflag=1 if $c->county;
+ $countyflag=1 if $c->{county};
+ #push @{$cust_main_county{$c->country}{$c->state}}, $c->county;
+ #$cust_main_county{$c->country}{$c->state}{$c->county} = 1;
+ $cust_main_county{$c->{country}}{$c->{state}}{$c->{county}} = 1;
+ }
+# }
+ $countyflag=1 if $param->{selected_county};
+
+ my $script_html = <<END;
+ <SCRIPT>
+ function opt(what,value,text) {
+ var optionName = new Option(text, value, false, false);
+ var length = what.length;
+ what.options[length] = optionName;
+ }
+ function ${prefix}country_changed(what) {
+ country = what.options[what.selectedIndex].text;
+ for ( var i = what.form.${prefix}state.length; i >= 0; i-- )
+ what.form.${prefix}state.options[i] = null;
+END
+ #what.form.${prefix}state.options[0] = new Option('', '', false, true);
+
+ foreach my $country ( sort keys %cust_main_county ) {
+ $script_html .= "\nif ( country == \"$country\" ) {\n";
+ foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
+ my $text = $state || '(n/a)';
+ $script_html .= qq!opt(what.form.${prefix}state, "$state", "$text");\n!;
+ }
+ $script_html .= "}\n";
+ }
+
+ $script_html .= <<END;
+ }
+ function ${prefix}state_changed(what) {
+END
+
+ if ( $countyflag ) {
+ $script_html .= <<END;
+ state = what.options[what.selectedIndex].text;
+ country = what.form.${prefix}country.options[what.form.${prefix}country.selectedIndex].text;
+ for ( var i = what.form.${prefix}county.length; i >= 0; i-- )
+ what.form.${prefix}county.options[i] = null;
+END
+
+ foreach my $country ( sort keys %cust_main_county ) {
+ $script_html .= "\nif ( country == \"$country\" ) {\n";
+ foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
+ $script_html .= "\nif ( state == \"$state\" ) {\n";
+ #foreach my $county ( sort @{$cust_main_county{$country}{$state}} ) {
+ foreach my $county ( sort keys %{$cust_main_county{$country}{$state}} ) {
+ my $text = $county || '(n/a)';
+ $script_html .=
+ qq!opt(what.form.${prefix}county, "$county", "$text");\n!;
+ }
+ $script_html .= "}\n";
+ }
+ $script_html .= "}\n";
+ }
+ }
+
+ $script_html .= <<END;
+ }
+ </SCRIPT>
+END
+
+ my $county_html = $script_html;
+ if ( $countyflag ) {
+ $county_html .= qq!<SELECT NAME="${prefix}county" onChange="$param->{'onchange'}">!;
+ $county_html .= '</SELECT>';
+ } else {
+ $county_html .=
+ qq!<INPUT TYPE="hidden" NAME="${prefix}county" VALUE="$param->{'selected_county'}">!;
+ }
+
+ my $state_html = qq!<SELECT NAME="${prefix}state" !.
+ qq!onChange="${prefix}state_changed(this); $param->{'onchange'}">!;
+ foreach my $state ( sort keys %{ $cust_main_county{$param->{'selected_country'}} } ) {
+ my $text = $state || '(n/a)';
+ my $selected = $state eq $param->{'selected_state'} ? 'SELECTED' : '';
+ $state_html .= "\n<OPTION $selected VALUE=$state>$text</OPTION>"
+ }
+ $state_html .= '</SELECT>';
+
+ $state_html .= '</SELECT>';
+
+ my $country_html = qq!<SELECT NAME="${prefix}country" !.
+ qq!onChange="${prefix}country_changed(this); $param->{'onchange'}">!;
+ my $countrydefault = $param->{default_country} || 'US';
+ foreach my $country (
+ sort { ($b eq $countrydefault) <=> ($a eq $countrydefault) or $a cmp $b }
+ keys %cust_main_county
+ ) {
+ my $selected = $country eq $param->{'selected_country'} ? ' SELECTED' : '';
+ $country_html .= "\n<OPTION$selected>$country</OPTION>"
+ }
+ $country_html .= '</SELECT>';
+
+ ($county_html, $state_html, $country_html);
+
+}
+
+#=item expselect HASHREF | LIST
+#
+#Takes as input a hashref or list of key/value pairs with the following keys:
+#
+#=over 4
+#
+#=item prefix - Specify a unique prefix string if you intend to use the HTML output multiple time son one page.
+#
+#=item date - current date, in yyyy-mm-dd or m-d-yyyy format
+#
+#=back
+
+=item expselect PREFIX [ DATE ]
+
+Takes as input a unique prefix string and the current expiration date, in
+yyyy-mm-dd or m-d-yyyy format
+
+Returns an HTML fragments for expiration date selection.
+
+=cut
+
+sub expselect {
+ #my $param;
+ #if ( ref($_[0]) ) {
+ # $param = shift;
+ #} else {
+ # $param = { @_ };
+ #my $prefix = $param->{'prefix'};
+ #my $prefix = exists($param->{'prefix'}) ? $param->{'prefix'} : '';
+ #my $date = exists($param->{'date'}) ? $param->{'date'} : '';
+ my $prefix = shift;
+ my $date = scalar(@_) ? shift : '';
+
+ my( $m, $y ) = ( 0, 0 );
+ if ( $date =~ /^(\d{4})-(\d{2})-\d{2}$/ ) { #PostgreSQL date format
+ ( $m, $y ) = ( $2, $1 );
+ } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) {
+ ( $m, $y ) = ( $1, $3 );
+ }
+ my $return = qq!<SELECT NAME="$prefix!. qq!_month" SIZE="1">!;
+ for ( 1 .. 12 ) {
+ $return .= "<OPTION";
+ $return .= " SELECTED" if $_ == $m;
+ $return .= ">$_";
+ }
+ $return .= qq!</SELECT>/<SELECT NAME="$prefix!. qq!_year" SIZE="1">!;
+ my @t = localtime;
+ my $thisYear = $t[5] + 1900;
+ for ( ($thisYear > $y && $y > 0 ? $y : $thisYear) .. 2037 ) {
+ $return .= "<OPTION";
+ $return .= " SELECTED" if $_ == $y;
+ $return .= ">$_";
+ }
+ $return .= "</SELECT>";
+
+ $return;
+}
+
+=item popselector HASHREF | LIST
+
+Takes as input a hashref or list of key/value pairs with the following keys:
+
+=over 4
+
+=item popnum
+
+=item pops - An arrayref of hash references specifying access numbers. Normally you can just pass the value of the I<svc_acct_pop> field returned by B<signup_info>.
+
+=back
+
+Returns an HTML fragment for access number selection.
+
+=cut
+
+#horrible false laziness with FS/FS/svc_acct_pop.pm::popselector
+sub popselector {
+ my $param;
+ if ( ref($_[0]) ) {
+ $param = shift;
+ } else {
+ $param = { @_ };
+ }
+ my $popnum = $param->{'popnum'};
+ my $pops = $param->{'pops'};
+
+ return '<INPUT TYPE="hidden" NAME="popnum" VALUE="">' unless @$pops;
+ return $pops->[0]{city}. ', '. $pops->[0]{state}.
+ ' ('. $pops->[0]{ac}. ')/'. $pops->[0]{exch}. '-'. $pops->[0]{loc}.
+ '<INPUT TYPE="hidden" NAME="popnum" VALUE="'. $pops->[0]{popnum}. '">'
+ if scalar(@$pops) == 1;
+
+ my %pop = ();
+ my %popnum2pop = ();
+ foreach (@$pops) {
+ push @{ $pop{ $_->{state} }->{ $_->{ac} } }, $_;
+ $popnum2pop{$_->{popnum}} = $_;
+ }
+
+ my $text = <<END;
+ <SCRIPT>
+ function opt(what,href,text) {
+ var optionName = new Option(text, href, false, false)
+ var length = what.length;
+ what.options[length] = optionName;
+ }
+END
+
+ my $init_popstate = $param->{'init_popstate'};
+ if ( $init_popstate ) {
+ $text .= '<INPUT TYPE="hidden" NAME="init_popstate" VALUE="'.
+ $init_popstate. '">';
+ } else {
+ $text .= <<END;
+ function acstate_changed(what) {
+ state = what.options[what.selectedIndex].text;
+ what.form.popac.options.length = 0
+ what.form.popac.options[0] = new Option("Area code", "-1", false, true);
+END
+ }
+
+ my @states = $init_popstate ? ( $init_popstate ) : keys %pop;
+ foreach my $state ( sort { $a cmp $b } @states ) {
+ $text .= "\nif ( state == \"$state\" ) {\n" unless $init_popstate;
+
+ foreach my $ac ( sort { $a cmp $b } keys %{ $pop{$state} }) {
+ $text .= "opt(what.form.popac, \"$ac\", \"$ac\");\n";
+ if ($ac eq $param->{'popac'}) {
+ $text .= "what.form.popac.options[what.form.popac.length-1].selected = true;\n";
+ }
+ }
+ $text .= "}\n" unless $init_popstate;
+ }
+ $text .= "popac_changed(what.form.popac)}\n";
+
+ $text .= <<END;
+ function popac_changed(what) {
+ ac = what.options[what.selectedIndex].text;
+ what.form.popnum.options.length = 0;
+ what.form.popnum.options[0] = new Option("City", "-1", false, true);
+
+END
+
+ foreach my $state ( @states ) {
+ foreach my $popac ( keys %{ $pop{$state} } ) {
+ $text .= "\nif ( ac == \"$popac\" ) {\n";
+
+ foreach my $pop ( @{$pop{$state}->{$popac}}) {
+ my $o_popnum = $pop->{popnum};
+ my $poptext = $pop->{city}. ', '. $pop->{state}.
+ ' ('. $pop->{ac}. ')/'. $pop->{exch}. '-'. $pop->{loc};
+
+ $text .= "opt(what.form.popnum, \"$o_popnum\", \"$poptext\");\n";
+ if ($popnum == $o_popnum) {
+ $text .= "what.form.popnum.options[what.form.popnum.length-1].selected = true;\n";
+ }
+ }
+ $text .= "}\n";
+ }
+ }
+
+
+ $text .= "}\n</SCRIPT>\n";
+
+ $text .=
+ qq!<TABLE CELLPADDING="0"><TR><TD><SELECT NAME="acstate"! .
+ qq!SIZE=1 onChange="acstate_changed(this)"><OPTION VALUE=-1>State!;
+ $text .= "<OPTION" . ($_ eq $param->{'acstate'} ? " SELECTED" : "") .
+ ">$_" foreach sort { $a cmp $b } @states;
+ $text .= '</SELECT>'; #callback? return 3 html pieces? #'</TD>';
+
+ $text .=
+ qq!<SELECT NAME="popac" SIZE=1 onChange="popac_changed(this)">!.
+ qq!<OPTION>Area code</SELECT></TR><TR VALIGN="top">!;
+
+ $text .= qq!<TR><TD><SELECT NAME="popnum" SIZE=1 STYLE="width: 20em"><OPTION>City!;
+
+
+ #comment this block to disable initial list polulation
+ my @initial_select = ();
+ if ( scalar( @$pops ) > 100 ) {
+ push @initial_select, $popnum2pop{$popnum} if $popnum2pop{$popnum};
+ } else {
+ @initial_select = @$pops;
+ }
+ foreach my $pop ( sort { $a->{state} cmp $b->{state} } @initial_select ) {
+ $text .= qq!<OPTION VALUE="!. $pop->{popnum}. '"'.
+ ( ( $popnum && $pop->{popnum} == $popnum ) ? ' SELECTED' : '' ). ">".
+ $pop->{city}. ', '. $pop->{state}.
+ ' ('. $pop->{ac}. ')/'. $pop->{exch}. '-'. $pop->{loc};
+ }
+
+ $text .= qq!</SELECT></TD></TR></TABLE>!;
+
+ $text;
+
+}
+
+=back
+
+=head1 RESELLER FUNCTIONS
+
+Note: Resellers can also use the B<signup_info> and B<new_customer> functions
+with their active session.
+
+=over 4
+
+=item agent_login
+
+=item agent_info
+
+=item agent_list_customers
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<freeside-selfservice-clientd>, L<freeside-selfservice-server>
+
+=cut
+
+1;
+
diff --git a/fs_selfservice/FS-SelfService/cgi/agent.cgi b/fs_selfservice/FS-SelfService/cgi/agent.cgi
new file mode 100644
index 0000000..9b07ee1
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent.cgi
@@ -0,0 +1,265 @@
+#!/usr/bin/perl -Tw
+
+#some false laziness w/selfservice.cgi
+
+use strict;
+use vars qw($cgi $session_id $form_max $template_dir);
+use subs qw(do_template);
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use Business::CreditCard;
+use Text::Template;
+use FS::SelfService qw( agent_login agent_info
+ agent_list_customers
+ signup_info new_customer
+ customer_info order_pkg
+ );
+
+$template_dir = '.';
+
+$form_max = 255;
+
+$cgi = new CGI;
+
+unless ( defined $cgi->param('session') ) {
+ do_template('agent_login',{});
+ exit;
+}
+
+if ( $cgi->param('session') eq 'login' ) {
+
+ $cgi->param('username') =~ /^\s*([a-z0-9_\-\.\&]{0,$form_max})\s*$/i
+ or die "illegal username";
+ my $username = $1;
+
+ $cgi->param('password') =~ /^(.{0,$form_max})$/
+ or die "illegal password";
+ my $password = $1;
+
+ my $rv = agent_login(
+ 'username' => $username,
+ 'password' => $password,
+ );
+ if ( $rv->{error} ) {
+ do_template('agent_login', {
+ 'error' => $rv->{error},
+ 'username' => $username,
+ } );
+ exit;
+ } else {
+ $cgi->param('session' => $rv->{session_id} );
+ $cgi->param('action' => 'agent_main' );
+ }
+}
+
+$session_id = $cgi->param('session');
+
+$cgi->param('action') =~
+ /^(agent_main|signup|process_signup|list_customers|view_customer|process_order_pkg)$/
+ or die "unknown action ". $cgi->param('action');
+my $action = $1;
+
+warn "running $action\n";
+my $result = eval "&$action();";
+die $@ if $@;
+
+if ( $result->{error} eq "Can't resume session" ) { #ick
+ do_template('agent_login',{});
+ exit;
+}
+
+warn "processing template $action\n";
+do_template($action, {
+ 'session_id' => $session_id,
+ %{$result}
+});
+
+#--
+
+sub agent_main { agent_info( 'session_id' => $session_id ); }
+
+sub signup { signup_info( 'session_id' => $session_id ); }
+
+sub process_signup {
+
+ my $init_data = signup_info( 'session_id' => $session_id );
+ if ( $init_data->{'error'} ) {
+ if ( $init_data->{'error'} eq "Can't resume session" ) { #ick
+ do_template('agent_login',{});
+ exit;
+ } else { #?
+ die $init_data->{'error'};
+ }
+ }
+
+ my $error = '';
+
+ #some false laziness w/signup.cgi
+ my $payby = $cgi->param('payby');
+ if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) {
+ #$payinfo = join('@', map { $cgi->param( $payby. "_payinfo$_" ) } (1,2) );
+ $cgi->param('payinfo' => $cgi->param($payby. '_payinfo1'). '@'.
+ $cgi->param($payby. '_payinfo2')
+ );
+ } else {
+ $cgi->param('payinfo' => $cgi->param( $payby. '_payinfo' ) );
+ }
+ $cgi->param('paydate' => $cgi->param( $payby. '_month' ). '-'.
+ $cgi->param( $payby. '_year' )
+ );
+ $cgi->param('payname' => $cgi->param( $payby. '_payname' ) );
+ $cgi->param('paycvv' => defined $cgi->param( $payby. '_paycvv' )
+ ? $cgi->param( $payby. '_paycvv' )
+ : ''
+ );
+
+ if ( $cgi->param('invoicing_list') ) {
+ $cgi->param('invoicing_list' => $cgi->param('invoicing_list'). ', POST')
+ if $cgi->param('invoicing_list_POST');
+ } else {
+ $cgi->param('invoicing_list' => 'POST' );
+ }
+
+ if ( $cgi->param('_password') ne $cgi->param('_password2') ) {
+ $error = $init_data->{msgcat}{passwords_dont_match}; #msgcat
+ $cgi->param('_password', '');
+ $cgi->param('_password2', '');
+ }
+
+ if ( $payby =~ /^(CARD|DCRD)$/ && $cgi->param('CARD_type') ) {
+ my $payinfo = $cgi->param('payinfo');
+ $payinfo =~ s/\D//g;
+
+ $payinfo =~ /^(\d{13,16})$/
+ or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ $payinfo = $1;
+ validate($payinfo)
+ or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ cardtype($payinfo) eq $cgi->param('CARD_type')
+ or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
+ }
+
+ unless ( $error ) {
+ my $rv = new_customer ( {
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) }
+ qw( last first ss company
+ address1 address2 city county state zip country
+ daytime night fax
+ payby payinfo paycvv paydate payname invoicing_list
+ pkgpart username sec_phrase _password popnum refnum
+ ),
+ grep { /^snarf_/ } $cgi->param
+ } );
+ $error = $rv->{'error'};
+ }
+
+ if ( $error ) {
+ $action = 'signup';
+ my $r = {
+ $cgi->Vars,
+ %{$init_data},
+ 'error' => $error,
+ };
+ #warn join('\n', map "$_ => $r->{$_}", keys %$r )."\n";
+ $r;
+ } else {
+ $action = 'agent_main';
+ my $agent_info = agent_info( 'session_id' => $session_id );
+ $agent_info->{'message'} = 'Signup sucessful';
+ $agent_info;
+ }
+
+}
+
+sub list_customers {
+ agent_list_customers( 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) }
+ grep defined($cgi->param($_)),
+ qw(prospect active susp cancel)
+ );
+}
+
+sub view_customer {
+
+ my $init_data = signup_info( 'session_id' => $session_id );
+ if ( $init_data->{'error'} ) {
+ if ( $init_data->{'error'} eq "Can't resume session" ) { #ick
+ do_template('agent_login',{});
+ exit;
+ } else { #?
+ die $init_data->{'error'};
+ }
+ }
+
+ my $customer_info = customer_info (
+ 'agent_session_id' => $session_id,
+ 'custnum' => $cgi->param('custnum')
+ );
+
+
+ return {
+ ( map { $_ => $init_data->{$_} }
+ qw( part_pkg security_phrase svc_acct_pop ),
+ ),
+ %$customer_info,
+ };
+}
+
+sub process_order_pkg {
+
+ my $results = '';
+
+ if ( $cgi->param('_password') ne $cgi->param('_password2') ) {
+ my $init_data = signup_info( 'session_id' => $session_id );
+ $results = { error => $init_data->{msgcat}{passwords_dont_match} };
+ $cgi->param('_password', '');
+ $cgi->param('_password2', '');
+ }
+
+ $results ||= order_pkg (
+ 'agent_session_id' => $session_id,
+ map { $_ => $cgi->param($_) }
+ qw( custnum pkgpart username _password _password2 sec_phrase popnum )
+ );
+
+ $action = 'view_customer';
+ $cgi->delete( grep { $_ ne 'custnum' } $cgi->param )
+ unless $results->{'error'};
+
+ return {
+ $cgi->Vars,
+ %{view_customer()},
+ 'message' => $results->{'error'}
+ ? '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>'
+ : 'Package order sucessful.'
+ };
+
+}
+
+#--
+
+sub do_template {
+ my $name = shift;
+ my $fill_in = shift;
+ #warn join(' / ', map { "$_=>".$fill_in->{$_} } keys %$fill_in). "\n";
+
+ $cgi->delete_all();
+ $fill_in->{'selfurl'} = $cgi->self_url;
+ $fill_in->{'cgi'} = \$cgi;
+
+ my $template = new Text::Template( TYPE => 'FILE',
+ SOURCE => "$template_dir/$name.html",
+ DELIMITERS => [ '<%=', '%>' ],
+ UNTAINT => 1, )
+ or die $Text::Template::ERROR;
+
+ print $cgi->header( '-expires' => 'now' ),
+ $template->fill_in( PACKAGE => 'FS::SelfService::_agentcgi',
+ HASH => $fill_in
+ );
+}
+
+package FS::SelfService::_agentcgi;
+use FS::SelfService qw(regionselector expselect popselector);
+
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_login.html b/fs_selfservice/FS-SelfService/cgi/agent_login.html
new file mode 100644
index 0000000..4b0778e
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_login.html
@@ -0,0 +1,22 @@
+<HTML><HEAD><TITLE>Reseller Login</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=5>Reseller Login</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM ACTION="<%= $self_url %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="login">
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=2 CELLPADDING=0>
+<TR>
+ <TH ALIGN="right">Username </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="username" VALUE="<%= $username %>">
+ </TD>
+</TR>
+<TR>
+ <TH ALIGN="right">Password </TH>
+ <TD>
+ <INPUT TYPE="password" NAME="password">
+ </TD>
+</TR>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" VALUE="Login">
+</FORM></BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_main.html b/fs_selfservice/FS-SelfService/cgi/agent_main.html
new file mode 100644
index 0000000..89a1b33
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_main.html
@@ -0,0 +1,40 @@
+<HTML><HEAD><TITLE>Reseller Main</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>Reseller Main</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+<A HREF="<%= $url %>agent_main">Reseller Main</A><BR>
+<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
+</TD><TD VALIGN="top">
+
+<%= $message
+ ? "<FONT SIZE=\"+2\"><B>$message</B></FONT>"
+ : "Hello $agent!"
+%><BR><BR>
+
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">
+<TR><TH BGCOLOR="#cccccc">Customer summary</TH></TR>
+<TR><TD BGCOLOR="#dddddd">
+
+ <B><%= $num_prospect %></B>
+ <A HREF="<%= $url %>list_customers&prospect=1">prospects</A>
+
+ <BR><FONT COLOR="#00CC00"><B><%= $num_active %></B></FONT>
+ <A HREF="<%= $url %>list_customers&active=1">active</A>
+
+ <BR><FONT COLOR="#FF9900"><B><%= $num_susp %></B></FONT>
+ <A HREF="<%= $url %>list_customers&susp=1">suspended</A>
+
+ <BR><FONT COLOR="#FF0000"><B><%= $num_cancel %></B></FONT>
+ <A HREF="<%= $url %>list_customers&cancel=1">cancelled</A>
+
+</TD></TR></TABLE>
+
+<BR><A HREF="<%= $url %>signup">New customer<!--/prospect--></A>
+
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
+
+
diff --git a/fs_selfservice/FS-SelfService/cgi/cvv2.html b/fs_selfservice/FS-SelfService/cgi/cvv2.html
new file mode 100644
index 0000000..b178c85
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/cvv2.html
@@ -0,0 +1,25 @@
+<HTML>
+ <HEAD>
+ <TITLE>
+ CVV2 information
+ </TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ The CVV2 number (also called CVC2 or CID) is a three- or four-digit
+ security code used to reduce credit card fraud.<BR><BR>
+ <TABLE BORDER=0 CELLSPACING=4>
+ <TR>
+ <TH>Visa / MasterCard / Discover</TH>
+ <TH>American Express</TH>
+ </TR>
+ <TR>
+ <TD>
+ <IMG BORDER=0 ALT="Visa/MasterCard/Discover" SRC="cvv2.png">
+ </TD>
+ <TD>
+ <IMG BORDER=0 ALT="American Express" SRC="cvv2_amex.png">
+ </TD>
+ </TABLE>
+ <CENTER><A HREF="javascript:close()">(close window)</A></CENTER>
+ </BODY>
+</HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/cvv2.png b/fs_selfservice/FS-SelfService/cgi/cvv2.png
new file mode 100644
index 0000000..4610dcb
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/cvv2.png
Binary files differ
diff --git a/fs_selfservice/FS-SelfService/cgi/cvv2_amex.png b/fs_selfservice/FS-SelfService/cgi/cvv2_amex.png
new file mode 100644
index 0000000..21c36a0
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/cvv2_amex.png
Binary files differ
diff --git a/fs_selfservice/FS-SelfService/cgi/list_customers.html b/fs_selfservice/FS-SelfService/cgi/list_customers.html
new file mode 100644
index 0000000..6d4ba56
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/list_customers.html
@@ -0,0 +1,41 @@
+<HTML><HEAD><TITLE>Reseller Main</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>Reseller Main</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+<A HREF="<%= $url %>agent_main">Reseller Main</A><BR>
+<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
+</TD><TD VALIGN="top">
+
+<%=
+ if ( @customers ) {
+ $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
+ '<TR><TH BGCOLOR="#cccccc" COLSPAN=3>Customers</TH><TD>';
+ my $col1 = "ffffff";
+ my $col2 = "dddddd";
+ my $col = $col1;
+
+ foreach my $customer ( @customers ) {
+ my $td = qq!<TD BGCOLOR="#$col">!;
+ my $a = qq!<A HREF="${url}view_customer;custnum=!.
+ $customer->{'custnum'}. '">';
+ $OUT .=
+ '<TR>'.
+ "$td<FONT COLOR=\"". $customer->{'statuscolor'}. '">'.
+ ucfirst($customer->{'status'}). "</TD>". "$td</TD>".
+ "$td$a". $customer->{'name'}. "</A></TD>".
+ '</TR>';
+ #"$td</TD>".
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+ $OUT .= '</TABLE>';
+ } else {
+ $OUT .= 'No customers.<BR><BR>';
+ }
+%>
+
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
+
diff --git a/fs_selfservice/FS-SelfService/cgi/login.html b/fs_selfservice/FS-SelfService/cgi/login.html
new file mode 100644
index 0000000..5607de7
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/login.html
@@ -0,0 +1,29 @@
+<HTML><HEAD><TITLE>Login</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=5>Login</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM ACTION="<%= $self_url %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="login">
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=2 CELLPADDING=0>
+<TR>
+ <TH ALIGN="right">Username </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="username" VALUE="<%= $username %>">
+ </TD>
+</TR>
+<TR>
+ <TH ALIGN="right">Domain </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="domain" VALUE="<%= $domain %>">
+ </TD>
+</TR>
+<!--<INPUT TYPE="hidden" NAME="domain" VALUE="myisp.com">-->
+<TR>
+ <TH ALIGN="right">Password </TH>
+ <TD>
+ <INPUT TYPE="password" NAME="password">
+ </TD>
+</TR>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" VALUE="Login">
+</FORM></BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/make_payment.html b/fs_selfservice/FS-SelfService/cgi/make_payment.html
new file mode 100644
index 0000000..40cd83c
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/make_payment.html
@@ -0,0 +1,120 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+<A HREF="<%= $url %>myaccount">MyAccount</A><BR>
+<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
+</TD><TD VALIGN="top">
+<FONT SIZE=4>Make a payment</FONT><BR><BR>
+<FORM NAME="OneTrueForm" METHOD="POST" ACTION="<%=$selfurl%>" onSubmit="document.OneTrueForm.process.disabled=true">
+<INPUT TYPE="hidden" NAME="session" VALUE="<%=$session_id%>">
+<INPUT TYPE="hidden" NAME="action" VALUE="payment_results">
+<TABLE BGCOLOR="#cccccc">
+<TR>
+ <TD ALIGN="right">Amount&nbsp;Due</TD>
+ <TD>
+ <TABLE><TR><TD BGCOLOR="#ffffff">
+ $<%=sprintf("%.2f",$balance)%>
+ </TD></TR></TABLE>
+ </TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Payment&nbsp;amount</TD>
+ <TD>
+ <TABLE><TR><TD BGCOLOR="#ffffff">
+ $<INPUT TYPE="text" NAME="amount" SIZE=8 VALUE="<%=sprintf("%.2f",$balance)%>">
+ </TD></TR></TABLE>
+ </TD>
+</TR><TR>
+ <TD ALIGN="right">Card&nbsp;type</TD>
+ <TD>
+ <SELECT NAME="card_type"><OPTION></OPTION>
+ <%= foreach ( keys %card_types ) {
+ $selected = $card_type eq $card_types{$_} ? ' SELECTED' : '';
+ $OUT .= qq(<OPTION$selected VALUE="). $card_types{$_}. qq(">$_\n);
+ } %>
+ </SELECT>
+ </TD>
+</TD><TR>
+ <TD ALIGN="right">Card&nbsp;number</TD>
+ <TD>
+ <TABLE>
+ <TR>
+ <TD>
+ <INPUT TYPE="text" NAME="payinfo" SIZE=20 MAXLENGTH=19 VALUE="<%=$payinfo%>"> </TD>
+ <TD>Exp.</TD>
+ <TD>
+ <SELECT NAME="month">
+ <%= for ( ( map "0$_", 1 .. 9 ), 11, 12 ) {
+ $OUT .= '<OPTION'. ($_ eq $month ? ' SELECTED' : ''). ">$_\n";
+ } %>
+ </SELECT>
+ </TD>
+ <TD> / </TD>
+ <TD>
+ <SELECT NAME="year">
+ <%= my @a = localtime; for ( $a[5]+1900 .. $a[5]+1915 ) {
+ $OUT .= '<OPTION'. ($_ eq $year ? ' SELECTED' : ''). ">$_\n";
+ } %>
+ </SELECT>
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+</TR><TR>
+ <TD ALIGN="right">Exact&nbsp;name&nbsp;on&nbsp;card</TD>
+ <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%=$payname%>"></TD>
+</TR><TR>
+ <TD ALIGN="right">Card&nbsp;billing&nbsp;address</TD>
+ <TD>
+ <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address1" VALUE="<%=$address1%>">
+ </TD>
+</TR><TR>
+ <TD ALIGN="right">Address&nbsp;line&nbsp;2</TD>
+ <TD>
+ <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address2" VALUE="<%=$address2%>">
+ </TD>
+</TR><TR>
+ <TD ALIGN="right">City</TD>
+ <TD>
+ <TABLE>
+ <TR>
+ <TD>
+ <INPUT TYPE="text" NAME="city" SIZE="12" MAXLENGTH=80 VALUE="<%=$city%>">
+ </TD>
+ <TD>State</TD>
+ <TD>
+ <SELECT NAME="state">
+ <%= for ( @states ) {
+ $OUT .= '<OPTION'. ($_ eq $state ? ' SELECTED' : '' ). ">$_\n";
+ } %>
+ </SELECT>
+ </TD>
+ <TD>Zip</TD>
+ <TD>
+ <INPUT TYPE="text" NAME="zip" SIZE=11 MAXLENGTH=10 VALUE="<%=$zip%>">
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+</TR><TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox" CHECKED NAME="save" VALUE="1">
+ Remember this information
+ </TD>
+</TR><TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox"<%= $payby eq 'CARD' ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }">
+ Charge future payments to this card automatically
+ </TD>
+</TR>
+</TABLE>
+<BR>
+<INPUT TYPE="hidden" NAME="paybatch" VALUE="<%=$paybatch%>">
+<INPUT TYPE="submit" NAME="process" VALUE="Process payment"> <!-- onClick="this.disabled=true"> -->
+</FORM>
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount.html b/fs_selfservice/FS-SelfService/cgi/myaccount.html
new file mode 100644
index 0000000..f48fded
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/myaccount.html
@@ -0,0 +1,47 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+<A HREF="<%= $url %>myaccount">MyAccount</A><BR>
+<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
+</TD><TD VALIGN="top">
+
+Hello <%= $name %>!<BR><BR>
+<%= $small_custview %>
+<BR>
+<%= if ( $balance > 0 ) {
+ $OUT .= qq! <B><A HREF="${url}make_payment">Make a payment</A></B><BR><BR>!;
+} %>
+<%=
+ if ( @open_invoices ) {
+ $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
+ '<TR><TH BGCOLOR="#ff3333" COLSPAN=5>Open Invoices</TH><TD>';
+ my $link = qq!<A HREF="<%= $url %>myaccount!;
+ my $col1 = "ffffff";
+ my $col2 = "dddddd";
+ my $col = $col1;
+
+ foreach my $invoice ( @open_invoices ) {
+ my $td = qq!<TD BGCOLOR="#$col">!;
+ my $a=qq!<A HREF="${url}view_invoice;invnum=!. $invoice->{'invnum'}. '">';
+ $OUT .=
+ "<TR>$td${a}Invoice #". $invoice->{'invnum'}. "</A></TD>$td</TD>".
+ "$td$a". $invoice->{'date'}. "</A></TD>$td</TD>".
+ qq!<TD BGCOLOR="#$col" ALIGN="right">$a\$!. $invoice->{'owed'}.
+ '</A></TD>'.
+ '</TR>';
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+ $OUT .= '</TABLE>';
+ } else {
+ $OUT .= 'You have no outstanding invoices.<BR><BR>';
+ }
+%>
+
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
+
+
diff --git a/fs_selfservice/FS-SelfService/cgi/passwd.cgi b/fs_selfservice/FS-SelfService/cgi/passwd.cgi
new file mode 100755
index 0000000..38b70d0
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/passwd.cgi
@@ -0,0 +1,60 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use Getopt::Std;
+use FS::SelfService qw(passwd);
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+
+my $freeside_uid = scalar(getpwnam('freeside'));
+
+$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+die "fs_passwd.cgi isn't running as freeside user\n" if $> != $freeside_uid;
+
+my $cgi = new CGI;
+
+$cgi->param('username') =~ /^([^\n]{0,255}$)/ or die "Illegal username";
+my $me = $1;
+
+$cgi->param('domain') =~ /^([^\n]{0,255}$)/ or die "Illegal domain";
+my $domain = $1;
+
+$cgi->param('old_password') =~ /^([^\n]{0,255}$)/ or die "Illegal old_password";
+my $old_password = $1;
+
+$cgi->param('new_password') =~ /^([^\n]{0,255}$)/ or die "Illegal new_password";
+my $new_password = $1;
+
+die "New passwords don't match"
+ unless $new_password eq $cgi->param('new_password2');
+
+my $rv = passwd(
+ 'username' => $me,
+ 'domain' => $domain,
+ 'old_password' => $old_password,
+ 'new_password' => $new_password,
+);
+
+my $error = $rv->{error};
+
+if ($error) {
+ die $error;
+} else {
+ print $cgi->header(), <<END;
+<html>
+ <head>
+ <title>Password changed</title>
+ </head>
+ <body bgcolor="#e8e8e8">
+ <h3>Password changed</h3>
+<br>Your password has been changed.
+ </body>
+</html>
+END
+}
diff --git a/fs_selfservice/FS-SelfService/cgi/passwd.html b/fs_selfservice/FS-SelfService/cgi/passwd.html
new file mode 100644
index 0000000..7e06ecf
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/passwd.html
@@ -0,0 +1,28 @@
+<html>
+ <head>
+ <title>Change password</title>
+ </head>
+ <body bgcolor="#e8e8e8">
+ <h3>Change password</h3>
+ <form action="/cgi-bin/fs_passwd.cgi" method="post">
+ <table bgcolor="#cccccc" border=0 cellspacing=2>
+ <tr><th align="right">Username</th>
+ <td><input type="text" name="username" size="18"></td>
+ </tr>
+ <tr><th align="right">Domain</th>
+ <td><input type="text" name="domain" size="18"></td>
+ </tr>
+ <tr><th align="right">Current password</th>
+ <td><input type="password" name="old_password" size="18"></td>
+ </tr>
+ <tr><th align="right">New password</th>
+ <td><input type="password" name="new_password" size="18"></td>
+ </tr>
+ <tr><th align="right">Re-enter new password</th>
+ <td><input type="password" name="new_password2" size="18"></td>
+ </tr>
+ </table>
+ <br><input type="submit" value="Change password">
+ </body>
+</html>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/payment_results.html b/fs_selfservice/FS-SelfService/cgi/payment_results.html
new file mode 100644
index 0000000..92c8cf5
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/payment_results.html
@@ -0,0 +1,18 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+<A HREF="<%= $url %>myaccount">MyAccount</A><BR>
+<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
+</TD><TD VALIGN="top">
+<FONT SIZE=4>Payment results</FONT><BR><BR>
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error processing your payment: $error</FONT>!;
+} else {
+ $OUT .= 'Your payment was processed sucessfully. Thank you.';
+} %>
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
new file mode 100644
index 0000000..6d6716d
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
@@ -0,0 +1,188 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use vars qw($cgi $session_id $form_max $template_dir);
+use subs qw(do_template);
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use Text::Template;
+use FS::SelfService qw( login customer_info invoice payment_info
+ process_payment );
+
+$template_dir = '.';
+
+$form_max = 255;
+
+$cgi = new CGI;
+
+unless ( defined $cgi->param('session') ) {
+ do_template('login',{});
+ exit;
+}
+
+if ( $cgi->param('session') eq 'login' ) {
+
+ $cgi->param('username') =~ /^\s*([a-z0-9_\-\.\&]{0,$form_max})\s*$/i
+ or die "illegal username";
+ my $username = $1;
+
+ $cgi->param('domain') =~ /^\s*([\w\-\.]{0,$form_max})\s*$/
+ or die "illegal domain";
+ my $domain = $1;
+
+ $cgi->param('password') =~ /^(.{0,$form_max})$/
+ or die "illegal password";
+ my $password = $1;
+
+ my $rv = login(
+ 'username' => $username,
+ 'domain' => $domain,
+ 'password' => $password,
+ );
+ if ( $rv->{error} ) {
+ do_template('login', {
+ 'error' => $rv->{error},
+ 'username' => $username,
+ 'domain' => $domain,
+ } );
+ exit;
+ } else {
+ $cgi->param('session' => $rv->{session_id} );
+ $cgi->param('action' => 'myaccount' );
+ }
+}
+
+$session_id = $cgi->param('session');
+
+$cgi->param('action') =~
+ /^(myaccount|view_invoice|make_payment|payment_results)$/
+ or die "unknown action ". $cgi->param('action');
+my $action = $1;
+
+my $result = eval "&$action();";
+die $@ if $@;
+
+if ( $result->{error} eq "Can't resume session" ) { #ick
+ do_template('login',{});
+ exit;
+}
+
+#warn $result->{'open_invoices'};
+#warn scalar(@{$result->{'open_invoices'}});
+
+warn "processing template $action\n";
+do_template($action, {
+ 'session_id' => $session_id,
+ %{$result}
+});
+
+#--
+
+sub myaccount { customer_info( 'session_id' => $session_id ); }
+
+sub view_invoice {
+
+ $cgi->param('invnum') =~ /^(\d+)$/ or die "illegal invnum";
+ my $invnum = $1;
+
+ invoice( 'session_id' => $session_id,
+ 'invnum' => $invnum,
+ );
+
+}
+
+sub make_payment {
+ payment_info( 'session_id' => $session_id );
+}
+
+sub payment_results {
+
+ use Business::CreditCard;
+
+ $cgi->param('amount') =~ /^\s*(\d+(\.\d{2})?)\s*$/
+ or die "illegal amount"; #!!!
+ my $amount = $1;
+
+ my $payinfo = $cgi->param('payinfo');
+ $payinfo =~ s/\D//g;
+ $payinfo =~ /^(\d{13,16})$/
+ #or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ or die "illegal card"; #!!!
+ $payinfo = $1;
+ validate($payinfo)
+ #or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ or die "invalid card"; #!!!
+ cardtype($payinfo) eq $cgi->param('card_type')
+ #or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
+ or die "not a ". $cgi->param('card_type');
+
+ $cgi->param('month') =~ /^(\d{2})$/ or die "illegal month";
+ my $month = $1;
+ $cgi->param('year') =~ /^(\d{4})$/ or die "illegal year";
+ my $year = $1;
+
+ $cgi->param('payname') =~ /^(.{0,80})$/ or die "illegal payname";
+ my $payname = $1;
+
+ $cgi->param('address1') =~ /^(.{0,80})$/ or die "illegal address1";
+ my $address1 = $1;
+
+ $cgi->param('address2') =~ /^(.{0,80})$/ or die "illegal address2";
+ my $address2 = $1;
+
+ $cgi->param('city') =~ /^(.{0,80})$/ or die "illegal city";
+ my $city = $1;
+
+ $cgi->param('state') =~ /^(.{2})$/ or die "illegal state";
+ my $state = $1;
+
+ $cgi->param('zip') =~ /^(.{0,10})$/ or die "illegal zip";
+ my $zip = $1;
+
+ my $save = 0;
+ $save = 1 if $cgi->param('save');
+
+ my $auto = 0;
+ $auto = 1 if $cgi->param('auto');
+
+ $cgi->param('paybatch') =~ /^([\w\-\.]+)$/ or die "illegal paybatch";
+ my $paybatch = $1;
+
+ process_payment(
+ 'session_id' => $session_id,
+ 'amount' => $amount,
+ 'payinfo' => $payinfo,
+ 'month' => $month,
+ 'year' => $year,
+ 'payname' => $payname,
+ 'address1' => $address1,
+ 'address2' => $address2,
+ 'city' => $city,
+ 'state' => $state,
+ 'zip' => $zip,
+ 'save' => $save,
+ 'auto' => $auto,
+ 'paybatch' => $paybatch,
+ );
+
+}
+
+#--
+
+sub do_template {
+ my $name = shift;
+ my $fill_in = shift;
+
+ $cgi->delete_all();
+ $fill_in->{'selfurl'} = $cgi->self_url;
+
+ my $template = new Text::Template( TYPE => 'FILE',
+ SOURCE => "$template_dir/$name.html",
+ DELIMITERS => [ '<%=', '%>' ],
+ UNTAINT => 1, )
+ or die $Text::Template::ERROR;
+
+ print $cgi->header( '-expires' => 'now' ),
+ $template->fill_in( HASH => $fill_in );
+}
+
diff --git a/fs_selfservice/FS-SelfService/cgi/signup.html b/fs_selfservice/FS-SelfService/cgi/signup.html
new file mode 100755
index 0000000..9730351
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/signup.html
@@ -0,0 +1,233 @@
+<HTML><HEAD><TITLE><%= $agent || 'ISP' %> Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8" onUnload="myclose()">
+<script language="JavaScript"><!--
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+//--></script>
+<FONT SIZE=7><%= $agent || 'ISP' %> Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM ACTION="<%= $selfurl %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_signup">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+Where did you hear about our service? <SELECT NAME="refnum">
+<%=
+ $OUT .= '<OPTION VALUE="">' unless $refnum;
+ foreach my $part_referral ( @part_referral ) {
+ $OUT .= '<OPTION VALUE="'. $part_referral->{'refnum'}. '"';
+ $OUT .= ' SELECTED' if $part_referral->{'refnum'} eq $refnum;
+ $OUT .= '>'. $part_referral->{'referral'};
+ }
+%>
+</SELECT><BR><BR>
+Contact Information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ regionselector( {
+ selected_county => $county,
+ selected_state => $state,
+ selected_country => $country,
+ default_state => $statedefault,
+ default_country => $countrydefault,
+ locales => \@cust_main_county,
+ } );
+
+ "$county_html $state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+<BR>Billing information<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR><TD>
+
+ <%=
+ $OUT .= '<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $OUT .= ' CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+ $OUT .= '>';
+ %>
+
+ Postal mail invoice
+</TD></TR>
+<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ) %>">
+</TD></TR>
+<%= scalar(@payby) > 1 ? '<TR><TD>Billing type</TD></TR>' : '' %>
+</TABLE>
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>
+
+ <%=
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected = $CARD_type eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .= qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ my %payby = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", "12-2037"). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+ );
+
+ if ( $cvv_enabled ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $payby{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ my( $account, $aba ) = split('@', $payinfo);
+ my %paybychecked = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", $paydate). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+ );
+
+ if ( $cvv_enabled ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $paybychecked{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ for (@payby) {
+ if ( scalar(@payby) == 1) {
+ $OUT .= '<TD VALIGN=TOP>'.
+ qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$_">!.
+ "$paybychecked{$_}</TD>";
+ } else {
+ $OUT .= qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($payby eq $_) {
+ $OUT .= qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ $OUT .= qq!> $payby{$_}</TD>!;
+ }
+
+ }
+ }
+ %>
+
+</TR></TABLE><font color="#ff0000">*</font> required fields for each billing type
+<BR><BR>First package
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart"><OPTION VALUE="">(none)
+
+ <%=
+ foreach my $part_pkg ( @part_pkg ) {
+ $OUT .= '<OPTION VALUE="'. $part_pkg->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $part_pkg->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $part_pkg->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $_password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $_password2 %>"></TD>
+</TR>
+<%=
+ if ( $security_phrase ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( @svc_acct_pop ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector( 'popnum' => $popnum,
+ 'pops' => \@svc_acct_pop,
+ 'init_popstate' => $init_popstate,
+ 'popac' => $popac,
+ 'acstate' => $acstate,
+ ).
+ '</TD></TR>';
+ } else {
+ $OUT .= popselector(popnum=>$popnum, pops=>\@svc_acct_pop);
+ }
+%>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" VALUE="Signup">
+</FORM></BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/view_customer.html b/fs_selfservice/FS-SelfService/cgi/view_customer.html
new file mode 100644
index 0000000..e4e9be2
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/view_customer.html
@@ -0,0 +1,84 @@
+<HTML><HEAD><TITLE>View Customer</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>View Customer</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+<A HREF="<%= $url %>agent_main">Reseller Main</A><BR>
+<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
+</TD><TD VALIGN="top">
+
+<%= $message
+ ? "<FONT SIZE=\"+2\"><B>$message</B></FONT><BR><BR>"
+ : ''
+%>
+
+<%= $small_custview %>
+
+<BR>Purchase additional package
+<FORM ACTION="<%= $selfurl %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_order_pkg">
+<INPUT TYPE="hidden" NAME="custnum" VALUE="<%= $custnum %>">
+<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0>
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart"><OPTION VALUE="">
+
+ <%=
+ foreach my $part_pkg ( @part_pkg ) {
+ $OUT .= '<OPTION VALUE="'. $part_pkg->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $part_pkg->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $part_pkg->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $_password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $_password2 %>"></TD>
+</TR>
+<%=
+ if ( $security_phrase ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( @svc_acct_pop ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector( 'popnum' => $popnum,
+ 'pops' => \@svc_acct_pop,
+ 'init_popstate' => $init_popstate,
+ 'popac' => $popac,
+ 'acstate' => $acstate,
+ ).
+ '</TD></TR>';
+ } else {
+ $OUT .= popselector(popnum=>$popnum, pops=>\@svc_acct_pop);
+ }
+%>
+</TABLE>
+<INPUT TYPE="submit" VALUE="Purchase">
+</FORM>
+
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
+
+
diff --git a/fs_selfservice/FS-SelfService/cgi/view_invoice.html b/fs_selfservice/FS-SelfService/cgi/view_invoice.html
new file mode 100644
index 0000000..d2b012b
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/view_invoice.html
@@ -0,0 +1,21 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR><TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+<A HREF="<%= $url %>myaccount">MyAccount</A><BR>
+<!-- <A HREF="<%= $url %>other">SomethingElse</A><BR> -->
+</TD><TD VALIGN="top">
+
+<A HREF="<%= $url %>myaccount"><-- back to MyAccount</A><BR><BR>
+
+<FONT SIZE="-1"><PRE>
+<%= $invoice_text %>
+</FONT></PRE>
+
+</TD></TR></TABLE>
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT>
+</BODY></HTML>
+
+
+
diff --git a/fs_selfservice/FS-SelfService/freeside-selfservice-clientd b/fs_selfservice/FS-SelfService/freeside-selfservice-clientd
new file mode 100644
index 0000000..ce9e14d
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/freeside-selfservice-clientd
@@ -0,0 +1,256 @@
+#!/usr/bin/perl -w
+#
+# freeside-selfservice-clientd
+#
+# This is run REMOTELY over ssh by freeside-selfservice-server
+
+use strict;
+use subs qw(spawn logmsg lock_write unlock_write);
+use Fcntl qw(:flock);
+use POSIX qw(:sys_wait_h);
+use Socket;
+use Storable 2.09 qw(nstore_fd fd_retrieve);
+use IO::Handle qw(_IONBF);
+use IO::Select;
+use IO::File;
+
+#STDOUT->setbuf('');
+
+my $tag = scalar(@ARGV) ? '.'.shift : '';
+
+use vars qw( $Debug );
+$Debug = 2; #2 will turn on child logging, 3 will log packet contents,
+ #including potentially compromising information
+
+my $socket = "/usr/local/freeside/selfservice_socket$tag";
+my $pid_file = "$socket.pid";
+
+my $log_file = "/usr/local/freeside/selfservice$tag.log";
+
+my $lock_file = "/usr/local/freeside/selfservice$tag.writelock";
+
+#my $me = '[client]';
+
+$|=1;
+
+$SIG{__WARN__} = \&_logmsg;
+
+#read data to be cached or something
+#warn "$me Reading init data\n" if $Debug;
+#my $signup_init =
+
+warn "Creating $lock_file\n" if $Debug;
+open(LOCKFILE,">$lock_file") or die "can't open $lock_file: $!";
+
+warn "Creating $socket\n" if $Debug;
+my $uaddr = sockaddr_un($socket);
+my $proto = getprotobyname('tcp');
+socket(Server,PF_UNIX,SOCK_STREAM,0) or die "socket: $!";
+unlink($socket);
+bind(Server, $uaddr) or die "bind: $!";
+listen(Server,SOMAXCONN) or die "listen: $!";
+
+if ( -e $pid_file ) {
+ open(PIDFILE,"<$pid_file");
+ my $old_pid = <PIDFILE>;
+ close PIDFILE;
+ $old_pid =~ /^(\d+)$/;
+ kill 'TERM', $1;
+}
+open(PIDFILE,">$pid_file");
+print PIDFILE "$$\n";
+close PIDFILE;
+
+#my $waitedpid;
+#sub REAPER { $waitedpid = wait; $SIG{CHLD} = \&REAPER; }
+#$SIG{CHLD} = \&REAPER;
+
+warn "entering main loop\n" if $Debug;
+
+my %kids;
+
+my $s = new IO::Select;
+$s->add(\*STDIN);
+$s->add(\*Server);
+
+#for ( $waitedpid = 0;
+# accept(Client,Server) || $waitedpid;
+# $waitedpid = 0, close Client)
+#{
+# next if $waitedpid;
+
+#$SIG{PIPE} = sub { warn "SIGPIPE received" };
+#$SIG{CHLD} = sub { warn "SIGCHLD received" };
+
+#sub REAPER { warn "SIGCHLD received"; my $pid = wait; $SIG{CHLD} = \&REAPER; }
+#sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; }
+#sub REAPER { my $pid = wait; delete $kids{$pid}; $SIG{CHLD} = \&REAPER; }
+#$SIG{CHLD} = \&REAPER;
+
+my $undisp = 0;
+while (1) {
+
+ &reap_kids;
+
+ warn "waiting for connection\n" if $Debug && !$undisp;
+
+ #my @handles = $s->can_read();
+ my @handles = $s->can_read(5);
+ $undisp = !scalar(@handles);
+ foreach my $handle ( @handles ) {
+
+ if ( $handle == \*STDIN ) {
+
+ warn "receiving packet from server\n" if $Debug;
+
+ my $packet = fd_retrieve(\*STDIN);
+ my $token = $packet->{'_token'};
+ warn "received packet from server with token $token\n".
+ ( $Debug > 2
+ ? join('', map { " $_=>$packet->{$_}\n" } keys %$packet )
+ : '' )
+ if $Debug;
+
+ if ( exists($kids{$token}) ) {
+ warn "sending return packet to $token via $kids{$token}\n"
+ if $Debug;
+ nstore_fd($packet, $kids{$token});
+ warn "flushing to $token\n" if $Debug;
+ until ( $kids{$token}->flush ) {
+ warn "WARNING: error flushing: $!";
+ sleep 1;
+ }
+ #no close or delete here - will block waiting for child
+ warn "done with $token\n" if $Debug;
+ } else {
+ warn "WARNING: unknown token $token, discarding message";
+ }
+
+ } elsif ( $handle == \*Server ) {
+
+ until ( accept(Client, Server) ) {
+ warn "WARNING: accept failed: $!";
+ next;
+ }
+
+ warn "received local connection; forking\n" if $Debug;
+
+ spawn sub { #child
+ warn "[child-$$] reading packet from local client" if $Debug > 1;
+ my $packet = fd_retrieve(\*Client);
+ warn "[child-$$] packet received:\n".
+ join('', map { " $_=>$packet->{$_}\n" } keys %$packet )
+ if $Debug > 2;
+ my $command = $packet->{'command'};
+ #handle some commands weirdly?
+ $packet->{_token}=$$;
+
+ warn "[child-$$] locking write stream\n" if $Debug > 1;
+ lock_write;
+
+ warn "[child-$$] sending packet to remote server\n" if $Debug > 1;
+ nstore_fd($packet, \*STDOUT) or die "FATAL: can't send response: $!";
+
+ warn "[child-$$] flushing write stream\n" if $Debug > 1;
+ STDOUT->flush or die "FATAL: can't flush: $!";
+
+ warn "[child-$$] releasing write lock\n" if $Debug > 1;
+ unlock_write;
+
+ warn "[child-$$] closing write stream\n" if $Debug > 1;
+ close STDOUT or die "FATAL: can't close write stream: $!"; #??!
+
+ warn "[child-$$] waiting for response from parent\n" if $Debug > 1;
+ my $w = new IO::Select;
+ $w->add(\*STDIN);
+ until ( $w->can_read ) {
+ warn "[child-$$] WARNING: interrupted select: $!\n";
+ }
+ my $rv = fd_retrieve(\*STDIN);
+
+ #close STDIN;
+
+ warn "[child-$$] sending response to local client" if $Debug > 1;
+ nstore_fd($rv, \*Client);
+ Client->flush or die "FATAL: can't flush to local client: $!";
+ close Client or die "FATAL: can't close connection to local client: $!";
+
+ warn "[child-$$] child exiting" if $Debug > 1;
+ exit;
+
+ }; #eo child
+
+ #close Client;
+
+ } else {
+ die "wtf? $handle";
+ }
+
+ }
+
+}
+
+sub reap_kids {
+ #warn "reaping kids\n";
+ foreach my $pid ( keys %kids ) {
+ my $kid = waitpid($pid, WNOHANG);
+ if ( $kid > 0 ) {
+ close $kids{$kid};
+ delete $kids{$kid};
+ }
+ }
+ #warn "done reaping\n";
+}
+
+sub spawn {
+ my $coderef = shift;
+
+ unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
+ use Carp;
+ confess "usage: spawn CODEREF";
+ }
+
+ my $pid;
+ #if (!defined($pid = fork)) {
+ my $kid = new IO::Handle;
+ if (!defined($pid = open($kid, '|-'))) {
+ warn "WARNING: cannot fork: $!";
+ return;
+ } elsif ($pid) {
+ warn "begat $pid" if $Debug;
+ $kids{$pid} = $kid;
+ #$kids{$pid}->autoflush;
+ return; # I'm the parent
+ }
+ # else I'm the child -- go spawn
+
+# open(STDIN, "<&Client") || die "can't dup client to stdin";
+# open(STDOUT, ">&Client") || die "can't dup client to stdout";
+# open(STDERR, ">&STDOUT") || die "can't dup stdout to stderr";
+ exit &$coderef();
+}
+
+sub _logmsg {
+ chomp( my $msg = shift );
+ my $log = new IO::File ">>$log_file";
+ die "can't open $log_file: $!" unless defined($log);
+ flock($log, LOCK_EX);
+ seek($log, 0, 2);
+ print $log "[client] [". scalar(localtime). "] [$$] $msg\n";
+ flock($log, LOCK_UN);
+ close $log;
+}
+
+sub lock_write {
+ #broken on freebsd?
+ #flock(STDOUT, LOCK_EX) or die "FATAL: can't lock write stream: $!";
+
+ flock(LOCKFILE, LOCK_EX) or die "FATAL: can't lock $lock_file: $!";
+}
+
+sub unlock_write {
+ #broken on freebsd?
+ #flock(STDOUT, LOCK_UN) or die "FATAL: can't release write lock: $!";
+
+ flock(LOCKFILE, LOCK_UN) or die "FATAL: can't unlock $lock_file: $!";
+}
diff --git a/fs_selfservice/FS-SelfService/test.pl b/fs_selfservice/FS-SelfService/test.pl
new file mode 100644
index 0000000..7468ea4
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/test.pl
@@ -0,0 +1,17 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test;
+BEGIN { plan tests => 1 };
+use FS::SelfService;
+ok(1); # If we made it this far, we're ok.
+
+#########################
+
+# Insert your test code below, the Test module is use()ed here so read
+# its man page ( perldoc Test ) for help writing this test script.
+
diff --git a/fs_selfservice/fs_passwd_test b/fs_selfservice/fs_passwd_test
new file mode 100755
index 0000000..4f8b8a8
--- /dev/null
+++ b/fs_selfservice/fs_passwd_test
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -w
+
+use strict;
+use FS::SelfService qw(passwd);
+
+my $rv = passwd(
+ 'username' => 'ivan',
+ 'old_password' => 'heyhoo',
+ 'new_password' => 'haloo',
+);
+my $error = $rv->{error};
+
+if ( $error eq 'Incorrect password.' ) {
+ exit;
+} else {
+ die $error if $error;
+ die "no error";
+}
+
diff --git a/fs_sesmon/FS-SessionClient/Changes b/fs_sesmon/FS-SessionClient/Changes
new file mode 100644
index 0000000..390a7b9
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/Changes
@@ -0,0 +1,5 @@
+Revision history for Perl extension FS::SessionClient
+
+0.01 Wed Oct 18 16:34:36 1999
+ - original version; created by ivan 1.0
+
diff --git a/fs_sesmon/FS-SessionClient/MANIFEST b/fs_sesmon/FS-SessionClient/MANIFEST
new file mode 100644
index 0000000..162d4e4
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/MANIFEST
@@ -0,0 +1,11 @@
+Changes
+MANIFEST
+MANIFEST.SKIP
+Makefile.PL
+SessionClient.pm
+test.pl
+fs_sessiond
+cgi/login.cgi
+cgi/logout.cgi
+bin/freeside-login
+bin/freeside-logout
diff --git a/fs_sesmon/FS-SessionClient/MANIFEST.SKIP b/fs_sesmon/FS-SessionClient/MANIFEST.SKIP
new file mode 100644
index 0000000..ae335e7
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/MANIFEST.SKIP
@@ -0,0 +1 @@
+CVS/
diff --git a/fs_sesmon/FS-SessionClient/Makefile.PL b/fs_sesmon/FS-SessionClient/Makefile.PL
new file mode 100644
index 0000000..137b6b8
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/Makefile.PL
@@ -0,0 +1,10 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'FS::SessionClient',
+ 'VERSION_FROM' => 'SessionClient.pm', # finds $VERSION
+ 'EXE_FILES' => [ qw(fs_sessiond bin/freeside-login bin/freeside-logout) ],
+ 'INSTALLSCRIPT' => '/usr/local/sbin',
+ 'PERM_RWX' => '750',
+);
diff --git a/fs_sesmon/FS-SessionClient/SessionClient.pm b/fs_sesmon/FS-SessionClient/SessionClient.pm
new file mode 100644
index 0000000..8a0ff70
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/SessionClient.pm
@@ -0,0 +1,122 @@
+package FS::SessionClient;
+
+use strict;
+use vars qw($AUTOLOAD $VERSION @ISA @EXPORT_OK $fs_sessiond_socket);
+use Exporter;
+use Socket;
+use FileHandle;
+use IO::Handle;
+
+$VERSION = '0.01';
+
+@ISA = qw( Exporter );
+@EXPORT_OK = qw( login logout portnum );
+
+$fs_sessiond_socket = "/usr/local/freeside/fs_sessiond_socket";
+
+$ENV{'PATH'} ='/usr/bin:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+my $freeside_uid = scalar(getpwnam('freeside'));
+die "not running as the freeside user\n" if $> != $freeside_uid;
+
+=head1 NAME
+
+FS::SessionClient - Freeside session client API
+
+=head1 SYNOPSIS
+
+ use FS::SessionClient qw( login portnum logout );
+
+ $error = login ( {
+ 'username' => $username,
+ 'password' => $password,
+ 'login' => $timestamp,
+ 'portnum' => $portnum,
+ } );
+
+ $portnum = portnum( { 'ip' => $ip } ) or die "unknown ip!"
+ $portnum = portnum( { 'nasnum' => $nasnum, 'nasport' => $nasport } )
+ or die "unknown nasnum/nasport";
+
+ $error = logout ( {
+ 'username' => $username,
+ 'password' => $password,
+ 'logout' => $timestamp,
+ 'portnum' => $portnum,
+ } );
+
+=head1 DESCRIPTION
+
+This modules provides an API for a remote session application.
+
+It needs to be run as the freeside user. Because of this, the program which
+calls these subroutines should be written very carefully.
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item login HASHREF
+
+HASHREF should have the following keys: username, password, login and portnum.
+login is a UNIX timestamp; if not specified, will default to the current time.
+Starts a new session for the specified user and portnum. The password is
+optional, but must be correct if specified.
+
+Returns a scalar error message, or the empty string for success.
+
+=item portnum
+
+HASHREF should contain a single key: ip, or the two keys: nasnum and nasport.
+Returns a portnum suitable for the login and logout subroutines, or false
+on error.
+
+=item logout HASHREF
+
+HASHREF should have the following keys: usrename, password, logout and portnum.
+logout is a UNIX timestamp; if not specified, will default to the current time.
+Starts a new session for the specified user and portnum. The password is
+optional, but must be correct if specified.
+
+Returns a scalar error message, or the empty string for success.
+
+=cut
+
+sub AUTOLOAD {
+ my $hashref = shift;
+ my $method = $AUTOLOAD;
+ $method =~ s/^.*:://;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($fs_sessiond_socket)) or die "connect: $!";
+ print SOCK "$method\n";
+
+ print SOCK join("\n", %{$hashref}, 'END' ), "\n";
+ SOCK->flush;
+
+ chomp( my $r = <SOCK> );
+ $r;
+}
+
+=back
+
+=head1 VERSION
+
+$Id: SessionClient.pm,v 1.3 2000-12-03 20:25:20 ivan Exp $
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<fs_sessiond>
+
+=cut
+
+1;
+
+
+
diff --git a/fs_sesmon/FS-SessionClient/bin/freeside-login b/fs_sesmon/FS-SessionClient/bin/freeside-login
new file mode 100644
index 0000000..a6d4751
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/bin/freeside-login
@@ -0,0 +1,36 @@
+#!/usr/bin/perl -Tw
+
+#false-laziness hack w freeside-logout
+
+use strict;
+use FS::SessionClient qw( login portnum );
+
+my $username = shift;
+
+my $portnum;
+if ( scalar(@ARGV) == 1 ) {
+ my $arg = shift;
+ if ( $arg =~ /^(\d+)$/ ) {
+ $portnum = $1;
+ } elsif ( $arg =~ /^([\d\.]+)$/ ) {
+ $portnum = portnum( { 'ip' => $1 } ) or die "unknown ip!"
+ } else {
+ &usage;
+ }
+} elsif ( scalar(@ARGV) == 2 ) {
+ $portnum = portnum( { 'nasnum' => shift, 'nasport' => shift } )
+ or die "unknown nasnum/nasport";
+} else {
+ &usage;
+}
+
+my $error = login ( {
+ 'username' => $username,
+ 'portnum' => $portnum,
+} );
+
+warn $error if $error;
+
+sub usage {
+ die "Usage:\n\n freeside-login username ( portnum | ip | nasnum nasport )";
+}
diff --git a/fs_sesmon/FS-SessionClient/bin/freeside-logout b/fs_sesmon/FS-SessionClient/bin/freeside-logout
new file mode 100644
index 0000000..9b4ecfe
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/bin/freeside-logout
@@ -0,0 +1,36 @@
+#!/usr/bin/perl -Tw
+
+#false-laziness hack w freeside-login
+
+use strict;
+use FS::SessionClient qw( logout portnum );
+
+my $username = shift;
+
+my $portnum;
+if ( scalar(@ARGV) == 1 ) {
+ my $arg = shift;
+ if ( $arg =~ /^(\d+)$/ ) {
+ $portnum = $1;
+ } elsif ( $arg =~ /^([\d\.]+)$/ ) {
+ $portnum = portnum( { 'ip' => $1 } ) or die "unknown ip!"
+ } else {
+ &usage;
+ }
+} elsif ( scalar(@ARGV) == 2 ) {
+ $portnum = portnum( { 'nasnum' => shift, 'nasport' => shift } )
+ or die "unknown nasnum/nasport";
+} else {
+ &usage;
+}
+
+my $error = logout ( {
+ 'username' => $username,
+ 'portnum' => $portnum,
+} );
+
+warn $error if $error;
+
+sub usage {
+ die "Usage:\n\n freeside-logout username ( portnum | ip | nasnum nasport )";
+}
diff --git a/fs_sesmon/FS-SessionClient/cgi/login.cgi b/fs_sesmon/FS-SessionClient/cgi/login.cgi
new file mode 100644
index 0000000..0307c5a
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/cgi/login.cgi
@@ -0,0 +1,108 @@
+#!/usr/bin/perl -Tw
+
+#false-laziness hack w logout.cgi
+
+use strict;
+use vars qw( $cgi $username $password $error $ip $portnum );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use FS::SessionClient qw( login portnum );
+
+$cgi = new CGI;
+
+if ( defined $cgi->param('magic') ) {
+ $cgi->param('username') =~ /^\s*(\w{1,255})\s*$/ or do {
+ $error = "Illegal username";
+ &print_form;
+ exit;
+ };
+ $username = $1;
+ $cgi->param('password') =~ /^([^\n]{0,255})$/ or die "guru meditation #420";
+ $password = $1;
+ #$ip = $cgi->remote_host;
+ $ip = $ENV{REMOTE_ADDR};
+ $ip =~ /^([\d\.]+)$/ or die "illegal ip: $ip";
+ $ip = $1;
+ $portnum = portnum( { 'ip' => $1 } ) or do {
+ $error = "You appear to be coming from an unknown IP address. Verify ".
+ "that your computer is set to obtain an IP address automatically ".
+ "via DHCP.";
+ &print_form;
+ exit;
+ };
+
+ ( $error = login ( {
+ 'username' => $username,
+ 'portnum' => $portnum,
+ 'password' => $password,
+ } ) )
+ ? &print_form()
+ : &print_okay();
+
+} else {
+ $username = '';
+ $password = '';
+ $error = '';
+ &print_form;
+}
+
+sub print_form {
+ my $self_url = $cgi->self_url;
+
+ print $cgi->header( '-expires' => 'now' ), <<END;
+<HTML><HEAD><TITLE>login</TITLE></HEAD>
+<BODY BGCOLOR="#FFFFFF">
+END
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT>! if $error;
+
+print <<END;
+<FORM ACTION="$self_url" METHOD="POST">
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="4" ALIGN="center">
+<TR>
+ <TD ALIGN="center" COLSPAN="2">
+ <STRONG>Welcome</STRONG>
+ </TD>
+</TR>
+<TR>
+ <TD ALIGN="right">
+ Username
+ </TD>
+ <TD ALIGN="left">
+ <INPUT TYPE="text" NAME="username" VALUE="$username">
+ </TD>
+</TR>
+<TR>
+ <TD ALIGN="right">
+ Password
+ </TD>
+ <TD ALIGN="left">
+ <INPUT TYPE="password" NAME="password">
+ </TD>
+</TR>
+<TR>
+ <TD ALIGN="center" COLSPAN="2">
+ <INPUT TYPE="submit" VALUE=" Login ">
+ </TD>
+</TR>
+</TABLE>
+</FORM>
+</BODY>
+</HTML>
+END
+
+}
+
+sub print_okay {
+ print $cgi->header( '-expires' => 'now' ), <<END;
+<HTML><HEAD><TITLE>login sucessful</TITLE></HEAD>
+<BODY>login successful, etc.
+</BODY>
+</HTML>
+END
+}
+
+sub usage {
+ die "Usage:\n\n freeside-login username ( portnum | ip | nasnum nasport )";
+}
diff --git a/fs_sesmon/FS-SessionClient/cgi/logout.cgi b/fs_sesmon/FS-SessionClient/cgi/logout.cgi
new file mode 100644
index 0000000..95cef98
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/cgi/logout.cgi
@@ -0,0 +1,83 @@
+#!/usr/bin/perl -Tw
+
+#false-laziness hack w login.cgi
+
+use strict;
+use vars qw( $cgi $username $password $error $ip $portnum );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use FS::SessionClient qw( logout portnum );
+
+$cgi = new CGI;
+
+if ( defined $cgi->param('magic') ) {
+ $cgi->param('username') =~ /^\s*(\w{1,255})\s*$/ or do {
+ $error = "Illegal username";
+ &print_form;
+ exit;
+ };
+ $username = $1;
+ $cgi->param('password') =~ /^([^\n]{0,255})$/ or die "guru meditation #420";
+ $password = $1;
+ #$ip = $cgi->remote_host;
+ $ip = $ENV{REMOTE_ADDR};
+ $ip =~ /^([\d\.]+)$/ or die "illegal ip: $ip";
+ $ip = $1;
+ $portnum = portnum( { 'ip' => $1 } ) or do {
+ $error = "You appear to be coming from an unknown IP address. Verify ".
+ "that your computer is set to obtain an IP address automatically ".
+ "via DHCP.";
+ &print_form;
+ exit;
+ };
+
+ ( $error = logout ( {
+ 'username' => $username,
+ 'portnum' => $portnum,
+ 'password' => $password,
+ } ) )
+ ? &print_form()
+ : &print_okay();
+
+} else {
+ $username = '';
+ $password = '';
+ $error = '';
+ &print_form;
+}
+
+sub print_form {
+ my $self_url = $cgi->self_url;
+
+ print $cgi->header( '-expires' => 'now' ), <<END;
+<HTML><HEAD><TITLE>logout</TITLE></HEAD>
+<BODY>
+END
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT>! if $error;
+
+print <<END;
+<FORM ACTION="$self_url" METHOD=POST>
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+Username <INPUT TYPE="text" NAME="username" VALUE="$username"><BR>
+Password <INPUT TYPE="password" NAME="password"><BR>
+<INPUT TYPE="submit">
+</FORM>
+</BODY>
+</HTML>
+END
+
+}
+
+sub print_okay {
+ print $cgi->header( '-expires' => 'now' ), <<END;
+<HTML><HEAD><TITLE>logout sucessful</TITLE></HEAD>
+<BODY>logout successful, etc.
+</BODY>
+</HTML>
+END
+}
+
+sub usage {
+ die "Usage:\n\n freeside-logout username ( portnum | ip | nasnum nasport )";
+}
diff --git a/fs_sesmon/FS-SessionClient/fs_sessiond b/fs_sesmon/FS-SessionClient/fs_sessiond
new file mode 100644
index 0000000..bfdb20a
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/fs_sessiond
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -Tw
+#
+# fs_sessiond
+#
+# This is run REMOTELY over ssh by fs_session_server
+#
+
+use strict;
+use Socket;
+
+use vars qw( $Debug );
+
+$Debug = 1;
+
+my $fs_sessiond_socket = "/usr/local/freeside/fs_sessiond_socket";
+
+$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+$|=1;
+
+my $me = "[fs_sessiond]";
+
+warn "$me starting\n" if $Debug;
+#nothing to read from server
+
+warn "$me creating $fs_sessiond_socket\n" if $Debug;
+my $uaddr = sockaddr_un($fs_sessiond_socket);
+my $proto = getprotobyname('tcp');
+socket(Server,PF_UNIX,SOCK_STREAM,0) or die "socket: $!";
+unlink($fs_sessiond_socket);
+bind(Server, $uaddr) or die "bind: $!";
+listen(Server,SOMAXCONN) or die "listen: $!";
+
+warn "$me entering main loop\n" if $Debug;
+my $paddr;
+for ( ; $paddr = accept(Client,Server); close Client) {
+
+ chomp( my $command = <Client> );
+
+ if ( $command eq 'login' || $command eq 'logout' || $command eq 'portnum' ) {
+ warn "$me reading data from local client\n" if $Debug;
+ my @data;
+ my $dos = 0;
+ push @data, scalar(<Client>) until $dos++ == 99 || $data[$#data] eq "END\n";
+ if ( $dos == 99 ) {
+ warn "$me WARNING: DoS attempt!"
+ } else {
+ warn "$me sending data to remote server\n" if $Debug;
+ print "$command\n", @data;
+ warn "$me reading result from remote server\n" if $Debug;
+ my $error = <STDIN>;
+ warn "$me sending error to local client\n" if $Debug;
+ print Client $error;
+ }
+ } else {
+ warn "$me WARNING: unexpected command from client: $command";
+ }
+
+}
+
diff --git a/fs_sesmon/FS-SessionClient/test.pl b/fs_sesmon/FS-SessionClient/test.pl
new file mode 100644
index 0000000..4b9ae17
--- /dev/null
+++ b/fs_sesmon/FS-SessionClient/test.pl
@@ -0,0 +1,21 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+######################### We start with some black magic to print on failure.
+
+# Change 1..1 below to 1..last_test_to_print .
+# (It may become useful if the test is moved to ./t subdirectory.)
+
+BEGIN { $| = 1; print "1..1\n"; }
+END {print "not ok 1\n" unless $loaded;}
+#use FS::SessionClient;
+#sigh, "not running as the freeside user"
+$loaded = 1;
+print "ok 1\n";
+
+######################### End of black magic.
+
+# Insert your test code below (better if it prints "ok 13"
+# (correspondingly "not ok 13") depending on the success of chunk 13
+# of the test code):
+
diff --git a/fs_sesmon/fs_session_server b/fs_sesmon/fs_session_server
new file mode 100644
index 0000000..00229f8
--- /dev/null
+++ b/fs_sesmon/fs_session_server
@@ -0,0 +1,140 @@
+#!/usr/bin/perl -Tw
+#
+# fs_session_server
+#
+
+use strict;
+use vars qw( $opt $Debug );
+use IO::Handle;
+use Net::SSH qw(sshopen2);
+use FS::UID qw(adminsuidsetup dbh);
+use FS::Record qw( qsearchs ); #qsearch );
+#use FS::cust_main_county;
+#use FS::cust_main;
+use FS::session;
+use FS::port;
+use FS::svc_acct;
+
+#require "configfile";
+$Debug = 1;
+
+my $user = shift or die &usage;
+&adminsuidsetup( $user );
+
+my $machine = shift or die &usage;
+
+my $fs_sessiond = "/usr/local/sbin/fs_sessiond";
+
+my $me = "[fs_session_server]";
+
+while (1) {
+ my($reader, $writer) = (new IO::Handle, new IO::Handle);
+ $writer->autoflush(1);
+ warn "$me Connecting to $machine\n" if $Debug;
+ sshopen2($machine,$reader,$writer,$fs_sessiond);
+
+ warn "$me Entering main loop\n" if $Debug;
+ while (1) {
+ warn "$me Reading (waiting for) data\n" if $Debug;
+ my $command = scalar(<$reader>);
+ chomp $command;
+ #DoS protection here too, to protect against a compromised client? *sigh*
+ my %hash;
+ while ( ( my $key = scalar(<$reader>) ) ne "END\n" ) {
+ chomp $key;
+ chomp( $hash{$key} = scalar(<$reader>) );
+ }
+
+ if ( $command eq 'login' ) {
+ my $error = &login(\%hash);
+ print $writer "$error\n";
+ } elsif ( $command eq 'logout' ) {
+ my $error = &logout(\%hash);
+ print $writer "$error\n";
+ } elsif ( $command eq 'portnum' ) {
+ my $port;
+ if ( exists $hash{'ip'} ) {
+ $hash{'ip'} =~ /^([\d\.]+)$/ or $1='nomatch';
+ $port = qsearchs('port', { 'ip' => $1 } );
+ } else {
+ $hash{'nasnum'} =~ /^(\d+)$/ and my $nasnum = $1;
+ $hash{'nasport'} =~ /^(\d+)$/ and my $nasport = $1;
+ $port = qsearchs('port', { 'nasnum'=>$nasnum, 'nasport'=>$nasport } );
+ }
+ print $writer ( $port ? $port->portnum : '' ), "\n";
+ } else {
+ warn "$me WARNING: unrecognized command: $command";
+ }
+ }
+ #won't ever reach without code above to throw out of loop, but...
+ close $writer;
+ close $reader;
+ warn "connection to $machine lost!\n";
+ sleep 5;
+ warn "reconnecting...\n";
+}
+
+sub login {
+ my $href = shift;
+ $href->{'username'} =~ /^([a-z0-9_\-\.]+)$/ or return "Illegal username";
+ my $username = $1;
+ my $svc_acct = qsearchs('svc_acct', { 'username' => $username } )
+ or return "Unknown user";
+ return "Incorrect password"
+ if exists($href->{'password'})
+ && $href->{'password'} ne $svc_acct->_password;
+ return "Time limit exceeded" unless $svc_acct->seconds;
+ my $session = new FS::session {
+ 'portnum' => $href->{'portnum'},
+ 'svcnum' => $svc_acct->svcnum,
+ 'login' => $href->{'login'},
+ };
+ $session->insert;
+}
+
+sub logout {
+ my $href = shift;
+ $href->{'username'} =~ /^([a-z0-9_\-\.]+)$/ or return "Illegal username";
+ my $username = $1;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+ my $svc_acct =
+ qsearchs('svc_acct', { 'username' => $username }, '', 'FOR UPDATE' )
+ or return "Unknown user";
+ return "Incorrect password"
+ if exists($href->{'password'})
+ && $href->{'password'} ne $svc_acct->_password;
+ my $session = qsearchs( 'session', {
+ 'portnum' => $href->{'portnum'},
+ 'svcnum' => $svc_acct->svcnum,
+ 'logout' => '',
+ },
+ '', 'FOR UPDATE'
+ );
+ unless ( $session ) {
+ $dbh->rollback;
+ return "No currently open sessions found for that user/port!";
+ }
+ my $nsession = new FS::session ( { $session->hash } );
+ warn "$nsession replacing $session";
+ my $error = $nsession->replace($session);
+ if ( $error ) {
+ $dbh->rollback;
+ return "can't logout: $error";
+ }
+ my $time = $nsession->logout - $nsession->login;
+ my $new_svc_acct = new FS::svc_acct ( { $svc_acct->hash } );
+ my $seconds = $new_svc_acct->seconds;
+ $seconds -= $time;
+ $seconds = 0 if $seconds < 0;
+ $new_svc_acct->seconds( $seconds );
+ $error = $new_svc_acct->replace( $svc_acct );
+ warn "can't debit time: $error\n"; #don't want to rollback, though
+ $dbh->commit or die $dbh->errstr;
+ ''
+}
+
+sub usage {
+ die "Usage:\n\n fs_session_server user machine\n";
+}
+
diff --git a/fs_signup/FS-SignupClient/Changes b/fs_signup/FS-SignupClient/Changes
new file mode 100644
index 0000000..e750a82
--- /dev/null
+++ b/fs_signup/FS-SignupClient/Changes
@@ -0,0 +1,5 @@
+Revision history for Perl extension FS::SignupClient.
+
+0.01 Mon Aug 23 01:12:46 1999
+ - original version; created by h2xs 1.19
+
diff --git a/fs_signup/FS-SignupClient/MANIFEST b/fs_signup/FS-SignupClient/MANIFEST
new file mode 100644
index 0000000..365ae66
--- /dev/null
+++ b/fs_signup/FS-SignupClient/MANIFEST
@@ -0,0 +1,7 @@
+Changes
+MANIFEST
+MANIFEST.SKIP
+Makefile.PL
+SignupClient.pm
+test.pl
+cgi/signup.cgi
diff --git a/fs_signup/FS-SignupClient/MANIFEST.SKIP b/fs_signup/FS-SignupClient/MANIFEST.SKIP
new file mode 100644
index 0000000..ae335e7
--- /dev/null
+++ b/fs_signup/FS-SignupClient/MANIFEST.SKIP
@@ -0,0 +1 @@
+CVS/
diff --git a/fs_signup/FS-SignupClient/Makefile.PL b/fs_signup/FS-SignupClient/Makefile.PL
new file mode 100644
index 0000000..9850c87
--- /dev/null
+++ b/fs_signup/FS-SignupClient/Makefile.PL
@@ -0,0 +1,17 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'FS::SignupClient',
+ 'VERSION_FROM' => 'SignupClient.pm', # finds $VERSION
+# 'EXE_FILES' => [ 'fs_signupd' ],
+# 'INSTALLSCRIPT' => '/usr/local/sbin',
+# 'INSTALLSITEBIN' => '/usr/local/sbin',
+ 'PERM_RWX' => '750',
+ 'PREREQ_PM' => {
+ 'Business::CreditCard' => 0,
+ 'HTTP::BrowserDetect' => 0,
+ 'Text::Template' => 0,
+ 'FS::SelfService' => 0,
+ },
+);
diff --git a/fs_signup/FS-SignupClient/SignupClient.pm b/fs_signup/FS-SignupClient/SignupClient.pm
new file mode 100644
index 0000000..284fddd
--- /dev/null
+++ b/fs_signup/FS-SignupClient/SignupClient.pm
@@ -0,0 +1,208 @@
+package FS::SignupClient;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT_OK $init_data); # $fs_signupd_socket);
+use Exporter;
+#use Socket;
+#use FileHandle;
+#use IO::Handle;
+#use Storable qw(nstore_fd fd_retrieve);
+use FS::SelfService; # qw( new_customer signup_info );
+
+$VERSION = '0.04';
+
+@ISA = qw( Exporter );
+@EXPORT_OK = qw( signup_info new_customer regionselector expselect popselector);
+
+=head1 NAME
+
+FS::SignupClient - Freeside signup client API
+
+=head1 SYNOPSIS
+
+ use FS::SignupClient qw( signup_info new_customer );
+
+ #this is the backwards-compatibility bit
+ ( $locales, $packages, $pops, $real_signup_info ) = signup_info;
+
+ #this is compatible with FS::SelfService::new_customer
+ $error = new_customer ( {
+ 'first' => $first,
+ 'last' => $last,
+ 'ss' => $ss,
+ 'comapny' => $company,
+ 'address1' => $address1,
+ 'address2' => $address2,
+ 'city' => $city,
+ 'county' => $county,
+ 'state' => $state,
+ 'zip' => $zip,
+ 'country' => $country,
+ 'daytime' => $daytime,
+ 'night' => $night,
+ 'fax' => $fax,
+ 'payby' => $payby,
+ 'payinfo' => $payinfo,
+ 'paycvv' => $paycvv,
+ 'paydate' => $paydate,
+ 'payname' => $payname,
+ 'invoicing_list' => $invoicing_list,
+ 'referral_custnum' => $referral_custnum,
+ 'comments' => $comments,
+ 'pkgpart' => $pkgpart,
+ 'username' => $username,
+ '_password' => $password,
+ 'sec_phrase' => $sec_phrase,
+ 'popnum' => $popnum,
+ 'agentnum' => $agentnum, #optional
+ } );
+
+=head1 DESCRIPTION
+
+This module provides an API for a remote signup server.
+
+It needs to be run as the freeside user. Because of this, the program which
+calls these subroutines should be written very carefully.
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item signup_info
+
+Returns three array references of hash references.
+
+The first set of hash references is of allowable locales. Each hash reference
+has the following keys:
+ taxnum
+ state
+ county
+ country
+
+The second set of hash references is of allowable packages. Each hash
+reference has the following keys:
+ pkgpart
+ pkg
+
+The third set of hash references is of allowable POPs (Points Of Presence).
+Each hash reference has the following keys:
+ popnum
+ city
+ state
+ ac
+ exch
+
+(Future expansion: fourth argument is the $init_data hash reference)
+
+=cut
+
+#compatibility bit
+sub signup_info {
+
+ $init_data = FS::SelfService::signup_info();
+
+ (map { $init_data->{$_} } qw( cust_main_county part_pkg svc_acct_pop ) ),
+ $init_data;
+
+}
+
+=item new_customer HASHREF
+
+Adds a customer to the remote Freeside system. Requires a hash reference as
+a paramater with the following keys:
+ first
+ last
+ ss
+ comapny
+ address1
+ address2
+ city
+ county
+ state
+ zip
+ country
+ daytime
+ night
+ fax
+ payby
+ payinfo
+ paycvv
+ paydate
+ payname
+ invoicing_list
+ referral_custnum
+ comments
+ pkgpart
+ username
+ _password
+ sec_phrase
+ popnum
+
+Returns a scalar error message, or the empty string for success.
+
+=cut
+
+#compatibility bit
+sub new_customer {
+ my $hash = FS::SelfService::new_customer(@_);
+ $hash->{'error'};
+}
+
+=item regionselector SELECTED_COUNTY, SELECTED_STATE, SELECTED_COUNTRY, PREFIX, ONCHANGE
+
+=cut
+
+sub regionselector {
+ my ( $selected_county, $selected_state, $selected_country,
+ $prefix, $onchange ) = @_;
+ signup_info() unless $init_data;
+ FS::SelfService::regionselector({
+ selected_county => $selected_county,
+ selected_state => $selected_state,
+ selected_country => $selected_country,
+ prefix => $prefix,
+ onchange => $onchange,
+ default_country => $init_data->{countrydefault},
+ locales => $init_data->{cust_main_county},
+ });
+ #default_state => $init_data->{statedefault},
+}
+
+=item expselect PREFIX, DATE
+
+=cut
+
+sub expselect {
+ FS::SelfService::expselect(@_);
+}
+
+=item popselector
+
+=cut
+
+sub popselector {
+ my( $popnum ) = @_;
+ signup_info() unless $init_data;
+ FS::SelfService::popselector({
+ popnum => $popnum,
+ pops => $init_data->{svc_acct_pop},
+ });
+ #popac =>
+ #acstate =>
+}
+
+=back
+
+=head1 BUGS
+
+This is just a wrapper around FS::SelfService functions for backwards
+compatibility and will probably be deprecated soon.
+
+=head1 SEE ALSO
+
+L<fs_signupd>, L<FS::cust_main>
+
+=cut
+
+1;
+
diff --git a/fs_signup/FS-SignupClient/cgi/cvv2.html b/fs_signup/FS-SignupClient/cgi/cvv2.html
new file mode 100644
index 0000000..b178c85
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/cvv2.html
@@ -0,0 +1,25 @@
+<HTML>
+ <HEAD>
+ <TITLE>
+ CVV2 information
+ </TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ The CVV2 number (also called CVC2 or CID) is a three- or four-digit
+ security code used to reduce credit card fraud.<BR><BR>
+ <TABLE BORDER=0 CELLSPACING=4>
+ <TR>
+ <TH>Visa / MasterCard / Discover</TH>
+ <TH>American Express</TH>
+ </TR>
+ <TR>
+ <TD>
+ <IMG BORDER=0 ALT="Visa/MasterCard/Discover" SRC="cvv2.png">
+ </TD>
+ <TD>
+ <IMG BORDER=0 ALT="American Express" SRC="cvv2_amex.png">
+ </TD>
+ </TABLE>
+ <CENTER><A HREF="javascript:close()">(close window)</A></CENTER>
+ </BODY>
+</HTML>
diff --git a/fs_signup/FS-SignupClient/cgi/cvv2.png b/fs_signup/FS-SignupClient/cgi/cvv2.png
new file mode 100644
index 0000000..4610dcb
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/cvv2.png
Binary files differ
diff --git a/fs_signup/FS-SignupClient/cgi/cvv2_amex.png b/fs_signup/FS-SignupClient/cgi/cvv2_amex.png
new file mode 100644
index 0000000..21c36a0
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/cvv2_amex.png
Binary files differ
diff --git a/fs_signup/FS-SignupClient/cgi/decline.html b/fs_signup/FS-SignupClient/cgi/decline.html
new file mode 100644
index 0000000..a37ba3a
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/decline.html
@@ -0,0 +1,5 @@
+<HTML><HEAD><TITLE>Processing error</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>Processing error</FONT><BR><BR>
+There has been an error processing your account. Please contact customer
+support.
+</BODY></HTML>
diff --git a/fs_signup/FS-SignupClient/cgi/map.gif b/fs_signup/FS-SignupClient/cgi/map.gif
new file mode 100644
index 0000000..ef884d8
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/map.gif
Binary files differ
diff --git a/fs_signup/FS-SignupClient/cgi/signup-agentselect.html b/fs_signup/FS-SignupClient/cgi/signup-agentselect.html
new file mode 100755
index 0000000..2451361
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/signup-agentselect.html
@@ -0,0 +1,195 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM ACTION="<%= $self_url %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+Agent <SELECT NAME="agentnum">
+<%=
+ warn $init_data;
+ warn $init_data->{'agent'};
+ foreach my $agent ( @{$init_data->{'agent'}} ) {
+ $OUT .= '<OPTION VALUE="'. $agent->{'agentnum'}. '"';
+ $OUT .= ' SELECTED' if $agent->{'agentnum'} eq $agentnum;
+ $OUT .= '>'. $agent->{'agent'};
+ }
+%>
+</SELECT><BR><BR>
+Contact Information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ regionselector( $county, $state, $country );
+
+ "$county_html $state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+<BR>Billing information<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR><TD>
+
+ <%=
+ $OUT .= '<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $OUT .= ' CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+ $OUT .= '>';
+ %>
+
+ Postal mail invoice
+</TD></TR>
+<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ) %>">
+</TD></TR>
+<%= scalar(@payby) > 1 ? '<TR><TD>Billing type</TD></TR>' : '' %>
+</TABLE>
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>
+
+ <%=
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected = $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .= qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ my %payby = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", "12-2037"). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+ );
+
+ my( $account, $aba ) = split('@', $payinfo);
+ my %paybychecked = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", $paydate). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+ );
+
+ for (@payby) {
+ if ( scalar(@payby) == 1) {
+ $OUT .= '<TD VALIGN=TOP>'.
+ qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$_">!.
+ "$paybychecked{$_}</TD>";
+ } else {
+ $OUT .= qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($payby eq $_) {
+ $OUT .= qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ $OUT .= qq!> $payby{$_}</TD>!;
+ }
+
+ }
+ }
+ %>
+
+</TR></TABLE><font color="#ff0000">*</font> required fields for each billing type
+<BR><BR>First package
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart"><OPTION VALUE="">(none)
+
+ <%=
+ foreach my $package ( @{$packages} ) {
+ $OUT .= '<OPTION VALUE="'. $package->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $package->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $package->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+<%=
+ if ( $init_data->{'security_phrase'} ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( scalar(@$pops) ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector($popnum). '</TD></TR>';
+ } else {
+ $OUT .= popselector($popnum);
+ }
+%>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" VALUE="Signup">
+</FORM></BODY></HTML>
diff --git a/fs_signup/FS-SignupClient/cgi/signup-alternate.html b/fs_signup/FS-SignupClient/cgi/signup-alternate.html
new file mode 100755
index 0000000..490cefa
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/signup-alternate.html
@@ -0,0 +1,218 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM NAME="dummy">
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+<INPUT TYPE="hidden" NAME="agentnum" VALUE="3">
+Contact Information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD><SELECT NAME="state" SIZE="1">
+
+ <%=
+ foreach ( @{$locales} ) {
+ my $value = $_->{'state'};
+ $value .= ' ('. $_->{'county'}. ')' if $_->{'county'};
+ $value .= ' / '. $_->{'country'};
+
+ $OUT .= qq(<OPTION VALUE="$value");
+ $OUT .= ' SELECTED' if ( $state eq $_->{'state'}
+ && $county eq $_->{'county'}
+ && $country eq $_->{'country'}
+ );
+ $OUT .= ">$value</OPTION>";
+ }
+ %>
+
+ </SELECT></TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+
+<BR><BR>
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Username</TH>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Password</TH>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Re-enter Password</TH>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+
+<%= if ( $init_data->{'security_phrase'} ) {
+ <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+
+<%= if ( scalar(@$pops) ) {
+ '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector($popnum). '</TD></TR>';
+ } else {
+ popselector($popnum);
+ }
+%>
+
+</TABLE><font color="#ff0000">*</font> required fields
+
+<BR><BR>First package
+
+ <%= use Tie::IxHash;
+ my %pkgpart2payby = map { $_->{pkgpart} => $_->{payby}[0] } @{$packages};
+ tie my %options, 'Tie::IxHash',
+ '' => '(none)',
+ map { $_->{pkgpart} => $_->{pkg} }
+ sort { $a->{recur} <=> $b->{recur} }
+ @{$packages}
+ ;
+
+ use HTML::Widgets::SelectLayers 0.02;
+ my @form_text = qw( magic ref ss agentnum
+ last first company address1 address2
+ city zip daytime night fax
+ username _password _password2 sec_phrase );
+ my @form_select = qw( state ); #county country
+ if ( scalar(@$pops) == 0 or scalar(@$pops) == 1 ) {
+ push @form_text, 'popnum',
+ } else {
+ push @form_select, 'popnum',
+ }
+ my $widget = new HTML::Widgets::SelectLayers(
+ options => \%options,
+ selected_layer => $pkgpart,
+ form_name => 'dummy',
+ form_action => $self_url,
+ form_text => \@form_text,
+ form_select => \@form_select,
+ layer_callback => sub {
+ my $layer = shift;
+ my $html = qq( <INPUT TYPE="hidden" NAME="pkgpart" VALUE="$layer">);
+
+ if ( $pkgpart2payby{$layer} eq 'BILL' ) {
+ $html .= <<ENDOUT;
+<INPUT TYPE="hidden" NAME="payby" VALUE="BILL">
+<INPUT TYPE="hidden" NAME="invoicing_list_POST" VALUE="">
+<INPUT TYPE="hidden" NAME="BILL_payinfo" VALUE="">
+<INPUT TYPE="hidden" NAME="BILL_month" VALUE="12">
+<INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">
+<INPUT TYPE="hidden" NAME="BILL_payname" VALUE="">
+<BR><BR><INPUT TYPE="submit" VALUE="Signup">
+ENDOUT
+ } elsif ( $pkgpart2payby{$layer} eq 'CARD' ) {
+ my $postal_checked = '';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $postal_checked = 'CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+
+ $invoicing_list= join(', ', grep { $_ ne 'POST' } @invoicing_list );
+
+ my $expselect = expselect("CARD", $paydate);
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected =
+ $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .=
+ qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ $html .= <<ENDOUT;
+<INPUT TYPE="hidden" NAME="payby" VALUE="CARD">
+<BR><BR>Billing information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0>
+<INPUT TYPE="hidden" NAME="invoicing_list_POST" VALUE="">
+<TR>
+ <TD ALIGN="right">Email statement to </TD>
+ <TD><INPUT TYPE="text" NAME="invoicing_list" VALUE="$invoicing_list"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Credit card type</TH>
+ <TD>$cardselect</TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Card number</TH>
+ <TD><INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>*</font>Exp</TH>
+ <TD>$expselect</TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Name on card</TH>
+ <TD><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname"></TD>
+</TR>
+</TABLE>
+<font color="#ff0000">*</font> required fields
+<BR><BR><INPUT TYPE="submit" VALUE="Signup">
+ENDOUT
+ } else {
+ $html = <<ENDOUT;
+<BR>Please select a package.<BR>
+ENDOUT
+
+ }
+
+ $html;
+
+ },
+ );
+
+ $widget->html;
+
+
+ %>
+</BODY></HTML>
diff --git a/fs_signup/FS-SignupClient/cgi/signup-snarf.html b/fs_signup/FS-SignupClient/cgi/signup-snarf.html
new file mode 100755
index 0000000..d167efb
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/signup-snarf.html
@@ -0,0 +1,228 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8" onUnload="myclose()">
+<script language="JavaScript"><!--
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+//--></script>
+<FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM ACTION="<%= $self_url %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+Contact Information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ regionselector( $county, $state, $country );
+
+ "$county_html $state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+<BR>Billing information<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR><TD>
+
+ <%=
+ $OUT .= '<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $OUT .= ' CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+ $OUT .= '>';
+ %>
+
+ Postal mail invoice
+</TD></TR>
+<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ) %>">
+</TD></TR>
+<%= scalar(@payby) > 1 ? '<TR><TD>Billing type</TD></TR>' : '' %>
+</TABLE>
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>
+
+ <%=
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected = $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .= qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ my %payby = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", "12-2037"). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $payby{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ my( $account, $aba ) = split('@', $payinfo);
+ my %paybychecked = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", $paydate). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $paybychecked{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ for (@payby) {
+ if ( scalar(@payby) == 1) {
+ $OUT .= '<TD VALIGN=TOP>'.
+ qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$_">!.
+ "$paybychecked{$_}</TD>";
+ } else {
+ $OUT .= qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($payby eq $_) {
+ $OUT .= qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ $OUT .= qq!> $payby{$_}</TD>!;
+ }
+
+ }
+ }
+ %>
+
+</TR></TABLE><font color="#ff0000">*</font> required fields for each billing type
+<BR><BR>First package
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart"><OPTION VALUE="">(none)
+
+ <%=
+ foreach my $package ( @{$packages} ) {
+ $OUT .= '<OPTION VALUE="'. $package->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $package->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $package->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+<%=
+ if ( $init_data->{'security_phrase'} ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( scalar(@$pops) ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector($popnum). '</TD></TR>';
+ } else {
+ $OUT .= popselector($popnum);
+ }
+%>
+</TABLE>
+<BR><BR>Enter up to ten external accounts from which to retrieve email
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="left">Mail server</TH>
+ <TH ALIGN="left">Username</TH>
+ <TH ALIGN="left">Password</TH>
+</TR>
+<%=
+ for my $num ( 1..10 ) {
+ no strict 'vars';
+ $OUT .= qq!<TR><TD><INPUT TYPE="text" NAME="snarf_machine$num" VALUE="${"snarf_machine$num"}"></TD>!.
+ qq!<INPUT TYPE="hidden" NAME="snarf_protocol$num" VALUE="pop3">!.
+ qq!<TD><INPUT TYPE="text" NAME="snarf_username$num" VALUE="${"snarf_username$num"}"></TD>!.
+ qq!<TD><INPUT TYPE="password" NAME="snarf_password$num" VALUE="${"snarf_password$num"}"></TD>!.
+ qq!</TR>!;
+ }
+%>
+</TABLE>
+
+<BR><BR><INPUT TYPE="submit" VALUE="Signup">
+</FORM></BODY></HTML>
diff --git a/fs_signup/FS-SignupClient/cgi/signup.cgi b/fs_signup/FS-SignupClient/cgi/signup.cgi
new file mode 100755
index 0000000..00a7aa6
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/signup.cgi
@@ -0,0 +1,388 @@
+#!/usr/bin/perl -Tw
+#
+# $Id: signup.cgi,v 1.51 2004-06-10 12:31:32 ivan Exp $
+
+use strict;
+use vars qw( @payby $cgi $locales $packages
+ $pops %pop %popnum2pop
+ $init_data $error
+ $last $first $ss $company $address1 $address2 $city $state $county
+ $country $zip $daytime $night $fax $invoicing_list $payby $payinfo
+ $paycvv $paydate $payname $referral_custnum $init_popstate
+ $pkgpart $username $password $password2 $sec_phrase $popnum
+ $agentnum $refnum
+ $ieak_file $ieak_template
+ $signup_html $signup_template
+ $success_html $success_template
+ $decline_html $decline_template
+ $ac $exch $loc
+ $email_name $pkg
+ $self_url
+ );
+use subs qw( print_form print_okay print_decline
+ success_default decline_default );
+use CGI;
+#use CGI::Carp qw(fatalsToBrowser);
+use Text::Template;
+use Business::CreditCard;
+use HTTP::BrowserDetect;
+use FS::SignupClient 0.03 qw( signup_info new_customer
+ regionselector expselect popselector);
+
+#acceptable payment methods
+#
+#@payby = qw( CARD BILL COMP );
+#@payby = qw( CARD BILL );
+#@payby = qw( CARD );
+@payby = qw( CARD PREPAY );
+
+$ieak_file = '/usr/local/freeside/ieak.template';
+$signup_html = -e 'signup.html'
+ ? 'signup.html'
+ : '/usr/local/freeside/signup.html';
+$success_html = -e 'success.html'
+ ? 'success.html'
+ : '/usr/local/freeside/success.html';
+$decline_html = -e 'decline.html'
+ ? 'decline.html'
+ : '/usr/local/freeside/decline.html';
+
+
+if ( -e $ieak_file ) {
+ my $ieak_txt = Text::Template::_load_text($ieak_file)
+ or die $Text::Template::ERROR;
+ $ieak_txt =~ /^(.*)$/s; #untaint the template source - it's trusted
+ $ieak_txt = $1;
+ $ieak_txt =~ s/\r//g; # don't double \r on old templates
+ $ieak_txt =~ s/\n/\r\n/g;
+ $ieak_template = new Text::Template ( TYPE => 'STRING', SOURCE => $ieak_txt )
+ or die $Text::Template::ERROR;
+} else {
+ $ieak_template = '';
+}
+
+$agentnum = '';
+if ( -e $signup_html ) {
+ my $signup_txt = Text::Template::_load_text($signup_html)
+ or die $Text::Template::ERROR;
+ $signup_txt =~ /^(.*)$/s; #untaint the template source - it's trusted
+ $signup_txt = $1;
+ $signup_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => $signup_txt,
+ DELIMITERS => [ '<%=', '%>' ]
+ )
+ or die $Text::Template::ERROR;
+ if ( $signup_txt =~
+ /<\s*INPUT TYPE="?hidden"?\s+NAME="?agentnum"?\s+VALUE="?(\d+)"?\s*>/si
+ ) {
+ $agentnum = $1;
+ }
+} else {
+ #too much maintenance hassle to keep in this file
+ die "can't find ./signup.html or /usr/local/freeside/signup.html";
+ #$signup_template = new Text::Template ( TYPE => 'STRING',
+ # SOURCE => &signup_default,
+ # DELIMITERS => [ '<%=', '%>' ]
+ # )
+ # or die $Text::Template::ERROR;
+}
+
+if ( -e $success_html ) {
+ my $success_txt = Text::Template::_load_text($success_html)
+ or die $Text::Template::ERROR;
+ $success_txt =~ /^(.*)$/s; #untaint the template source - it's trusted
+ $success_txt = $1;
+ $success_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => $success_txt,
+ DELIMITERS => [ '<%=', '%>' ],
+ )
+ or die $Text::Template::ERROR;
+} else {
+ $success_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => &success_default,
+ DELIMITERS => [ '<%=', '%>' ],
+ )
+ or die $Text::Template::ERROR;
+}
+
+if ( -e $decline_html ) {
+ my $decline_txt = Text::Template::_load_text($decline_html)
+ or die $Text::Template::ERROR;
+ $decline_txt =~ /^(.*)$/s; #untaint the template source - it's trusted
+ $decline_txt = $1;
+ $decline_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => $decline_txt,
+ DELIMITERS => [ '<%=', '%>' ],
+ )
+ or die $Text::Template::ERROR;
+} else {
+ $decline_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => &decline_default,
+ DELIMITERS => [ '<%=', '%>' ],
+ )
+ or die $Text::Template::ERROR;
+}
+
+
+( $locales, $packages, $pops, $init_data ) = signup_info();
+@payby = @{$init_data->{'payby'}} if @{$init_data->{'payby'}};
+$packages = $init_data->{agentnum2part_pkg}{$agentnum} if $agentnum;
+%pop = ();
+%popnum2pop = ();
+foreach (@$pops) {
+ push @{ $pop{ $_->{state} }->{ $_->{ac} } }, $_;
+ $popnum2pop{$_->{popnum}} = $_;
+}
+
+$cgi = new CGI;
+
+if ( defined $cgi->param('magic') ) {
+ if ( $cgi->param('magic') eq 'process' ) {
+
+ if ( $cgi->param('state') =~ /^(\w*)( \(([\w ]+)\))? ?\/ ?(\w+)$/ ) {
+ $state = $1;
+ $county = $3 || '';
+ $country = $4;
+ } elsif ( $cgi->param('state') =~ /^(\w*)$/ ) {
+ $state = $1;
+ $cgi->param('county') =~ /^([\w ]*)$/
+ or die "illegal county: ". $cgi->param('county');
+ $county = $1;
+ $cgi->param('country') =~ /^(\w+)$/
+ or die "illegal country: ". $cgi->param('country');
+ $country = $1;
+ } else {
+ die "illegal state: ". $cgi->param('state');
+ }
+
+ $payby = $cgi->param('payby');
+ if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) {
+ #$payinfo = join('@', map { $cgi->param( $payby. "_payinfo$_" ) } (1,2) );
+ $payinfo = $cgi->param($payby. '_payinfo1'). '@'.
+ $cgi->param($payby. '_payinfo2');
+ } else {
+ $payinfo = $cgi->param( $payby. '_payinfo' );
+ }
+ $paydate =
+ $cgi->param( $payby. '_month' ). '-'. $cgi->param( $payby. '_year' );
+ $payname = $cgi->param( $payby. '_payname' );
+ $paycvv = defined $cgi->param( $payby. '_paycvv' )
+ ? $cgi->param( $payby. '_paycvv' )
+ : '';
+
+ if ( $invoicing_list = $cgi->param('invoicing_list') ) {
+ $invoicing_list .= ', POST' if $cgi->param('invoicing_list_POST');
+ } else {
+ $invoicing_list = 'POST';
+ }
+
+ $error = '';
+
+ $last = $cgi->param('last');
+ $first = $cgi->param('first');
+ $ss = $cgi->param('ss');
+ $company = $cgi->param('company');
+ $address1 = $cgi->param('address1');
+ $address2 = $cgi->param('address2');
+ $city = $cgi->param('city');
+ #$county,
+ #$state,
+ $zip = $cgi->param('zip');
+ #$country,
+ $daytime = $cgi->param('daytime');
+ $night = $cgi->param('night');
+ $fax = $cgi->param('fax');
+ #$payby,
+ #$payinfo,
+ #$paydate,
+ #$payname,
+ #$invoicing_list,
+ $referral_custnum = $cgi->param('ref');
+ $pkgpart = $cgi->param('pkgpart');
+ $username = $cgi->param('username');
+ $sec_phrase = $cgi->param('sec_phrase');
+ $password = $cgi->param('_password');
+ $popnum = $cgi->param('popnum');
+ #$agentnum, # = $cgi->param('agentnum'),
+ $agentnum ||= $cgi->param('agentnum');
+ $init_popstate = $cgi->param('init_popstate');
+ $refnum = $cgi->param('refnum');
+
+ if ( $cgi->param('_password') ne $cgi->param('_password2') ) {
+ $error = $init_data->{msgcat}{passwords_dont_match}; #msgcat
+ $password = '';
+ $password2 = '';
+ } else {
+ $password2 = $cgi->param('_password2');
+
+ if ( $payby =~ /^(CARD|DCRD)$/ && $cgi->param('CARD_type') ) {
+ $payinfo =~ s/\D//g;
+
+ $payinfo =~ /^(\d{13,16})$/
+ or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ $payinfo = $1;
+ validate($payinfo)
+ or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ cardtype($payinfo) eq $cgi->param('CARD_type')
+ or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
+ }
+
+ $error ||= new_customer ( {
+ 'last' => $last,
+ 'first' => $first,
+ 'ss' => $ss,
+ 'company' => $company,
+ 'address1' => $address1,
+ 'address2' => $address2,
+ 'city' => $city,
+ 'county' => $county,
+ 'state' => $state,
+ 'zip' => $zip,
+ 'country' => $country,
+ 'daytime' => $daytime,
+ 'night' => $night,
+ 'fax' => $fax,
+ 'payby' => $payby,
+ 'payinfo' => $payinfo,
+ 'paycvv' => $paycvv,
+ 'paydate' => $paydate,
+ 'payname' => $payname,
+ 'invoicing_list' => $invoicing_list,
+ 'referral_custnum' => $referral_custnum,
+ 'pkgpart' => $pkgpart,
+ 'username' => $username,
+ 'sec_phrase' => $sec_phrase,
+ '_password' => $password,
+ 'popnum' => $popnum,
+ 'agentnum' => $agentnum,
+ 'refnum' => $refnum,
+ map { $_ => $cgi->param($_) } grep { /^snarf_/ } $cgi->param
+ } );
+
+ }
+
+ if ( $error eq '_decline' ) {
+ print_decline();
+ } elsif ( $error ) {
+ #fudge the snarf info
+ no strict 'refs';
+ ${$_} = $cgi->param($_) foreach grep { /^snarf_/ } $cgi->param;
+ print_form();
+ } else {
+ print_okay();
+ }
+
+ } else {
+ die "unrecognized magic: ". $cgi->param('magic');
+ }
+} else {
+ $error = '';
+ $last = '';
+ $first = '';
+ $ss = '';
+ $company = '';
+ $address1 = '';
+ $address2 = '';
+ $city = '';
+ $state = $init_data->{statedefault};
+ $county = '';
+ $country = $init_data->{countrydefault};
+ $zip = '';
+ $daytime = '';
+ $night = '';
+ $fax = '';
+ $invoicing_list = '';
+ $payby = '';
+ $payinfo = '';
+ $paydate = '';
+ $payname = '';
+ $pkgpart = '';
+ $username = '';
+ $password = '';
+ $password2 = '';
+ $sec_phrase = '';
+ $popnum = '';
+ $referral_custnum = $cgi->param('ref') || '';
+ $init_popstate = $cgi->param('init_popstate') || '';
+ $refnum = $init_data->{'refnum'};
+ print_form;
+}
+
+sub print_form {
+
+ $cgi->delete('ref');
+ $cgi->delete('init_popstate');
+ $self_url = $cgi->self_url;
+
+ $error = "Error: $error" if $error;
+
+ print $cgi->header( '-expires' => 'now' ),
+ $signup_template->fill_in();
+
+}
+
+sub print_decline {
+ print $cgi->header( '-expires' => 'now' ),
+ $decline_template->fill_in();
+}
+
+sub print_okay {
+ my $user_agent = new HTTP::BrowserDetect $ENV{HTTP_USER_AGENT};
+
+ $cgi->param('username') =~ /^(.+)$/
+ or die "fatal: invalid username got past FS::SignupClient::new_customer";
+ my $username = $1;
+ $cgi->param('_password') =~ /^(.+)$/
+ or die "fatal: invalid password got past FS::SignupClient::new_customer";
+ my $password = $1;
+ ( $cgi->param('first'). ' '. $cgi->param('last') ) =~ /^(.*)$/
+ or die "fatal: invalid email_name got past FS::SignupClient::new_customer";
+ $email_name = $1; #global for template
+
+ my $pop = $popnum2pop{$cgi->param('popnum')};
+ #or die "fatal: invalid popnum got past FS::SignupClient::new_customer";
+ if ( $pop ) {
+ ( $ac, $exch, $loc ) = ( $pop->{'ac'}, $pop->{'exch'}, $pop->{'loc'} );
+ } else {
+ ( $ac, $exch, $loc ) = ( '', '', ''); #presumably you're not using them.
+ }
+
+ #global for template
+ $pkg = ( grep { $_->{'pkgpart'} eq $pkgpart } @$packages )[0]->{'pkg'};
+
+ if ( $ieak_template && $user_agent->windows && $user_agent->ie ) {
+ #send an IEAK config
+ print $cgi->header('application/x-Internet-signup'),
+ $ieak_template->fill_in();
+ } else { #send a simple confirmation
+ print $cgi->header( '-expires' => 'now' ),
+ $success_template->fill_in();
+ }
+}
+
+sub success_default { #html to use if you don't specify a success file
+ <<'END';
+<HTML><HEAD><TITLE>Signup successful</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>Signup successful</FONT><BR><BR>
+Thanks for signing up!
+<BR><BR>
+Signup information for <%= $email_name %>:
+<BR><BR>
+Username: <%= $username %><BR>
+Password: <%= $password %><BR>
+Access number: (<%= $ac %>) / <%= $exch %> - <%= $local %><BR>
+Package: <%= $pkg %><BR>
+</BODY></HTML>
+END
+}
+
+sub decline_default { #html to use if there is a decline
+ <<'END';
+<HTML><HEAD><TITLE>Processing error</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>Processing error</FONT><BR><BR>
+There has been an error processing your account. Please contact customer
+support.
+</BODY></HTML>
+END
+}
+
diff --git a/fs_signup/FS-SignupClient/cgi/signup.html b/fs_signup/FS-SignupClient/cgi/signup.html
new file mode 100755
index 0000000..96bdac6
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/signup.html
@@ -0,0 +1,219 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8" onUnload="myclose()">
+<script language="JavaScript"><!--
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+//--></script>
+<FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM ACTION="<%= $self_url %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+Where did you hear about our service? <SELECT NAME="refnum">
+<%=
+ $OUT .= '<OPTION VALUE="">' unless $refnum;
+ foreach my $part_referral ( @{$init_data->{'part_referral'}} ) {
+ $OUT .= '<OPTION VALUE="'. $part_referral->{'refnum'}. '"';
+ $OUT .= ' SELECTED' if $part_referral->{'refnum'} eq $refnum;
+ $OUT .= '>'. $part_referral->{'referral'};
+ }
+%>
+</SELECT><BR><BR>
+Contact Information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ regionselector( $county, $state, $country );
+
+ "$county_html $state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+<BR>Billing information<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR><TD>
+
+ <%=
+ $OUT .= '<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $OUT .= ' CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+ $OUT .= '>';
+ %>
+
+ Postal mail invoice
+</TD></TR>
+<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ) %>">
+</TD></TR>
+<%= scalar(@payby) > 1 ? '<TR><TD>Billing type</TD></TR>' : '' %>
+</TABLE>
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>
+
+ <%=
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected = $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .= qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ my %payby = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", "12-2037"). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $payby{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ my( $account, $aba ) = split('@', $payinfo);
+ my %paybychecked = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", $paydate). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $paybychecked{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ for (@payby) {
+ if ( scalar(@payby) == 1) {
+ $OUT .= '<TD VALIGN=TOP>'.
+ qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$_">!.
+ "$paybychecked{$_}</TD>";
+ } else {
+ $OUT .= qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($payby eq $_) {
+ $OUT .= qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ $OUT .= qq!> $payby{$_}</TD>!;
+ }
+
+ }
+ }
+ %>
+
+</TR></TABLE><font color="#ff0000">*</font> required fields for each billing type
+<BR><BR>First package
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart"><OPTION VALUE="">(none)
+
+ <%=
+ foreach my $package ( @{$packages} ) {
+ $OUT .= '<OPTION VALUE="'. $package->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $package->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $package->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+<%=
+ if ( $init_data->{'security_phrase'} ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( scalar(@$pops) ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector($popnum). '</TD></TR>';
+ } else {
+ $OUT .= popselector($popnum);
+ }
+%>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" VALUE="Signup">
+</FORM></BODY></HTML>
diff --git a/fs_signup/FS-SignupClient/cgi/stateselect.html b/fs_signup/FS-SignupClient/cgi/stateselect.html
new file mode 100644
index 0000000..ba55bff
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/stateselect.html
@@ -0,0 +1,134 @@
+<HTML><HEAD><TITLE>ISP Signup</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup - state selection</FONT><BR><BR>
+<SCRIPT>
+function gotoURL(object) {
+ window.location.href = object.options[object.selectedIndex].value;
+}
+</SCRIPT>
+<FORM>
+Select your state from the map or dropdown:
+<MAP NAME=usmap>
+<area shape=poly COORDS="264,157,286,155,292,193,276,195,270,199,264,157" href="signup.cgi?init_popstate=AL">
+<area shape=poly COORDS="28,197,46,185,72,199,72,241,88,243,102,261,92,263,70,241,42,243,28,257,12,259,34,243,20,233,16,223,34,215,22,207,30,205,28,197" href="../states/Alaska.html">
+<area shape=poly COORDS="70,137,106,137,100,189,84,187,60,173,70,133,70,137,70,137" href="signup.cgi?init_popstate=AZ">
+<area shape=poly COORDS="250,153,242,179,220,177,218,171,216,145,252,143,250,155,250,153" href="signup.cgi?init_popstate=AR">
+<area shape=poly COORDS="10,79,38,81,30,109,62,151,56,173,40,169,20,145,4,101,10,75,26,79,10,79,10,79" href="signup.cgi?init_popstate=CA">
+<area shape=poly COORDS="108,103,158,107,154,141,104,137,110,101,128,103,108,103" href="signup.cgi?init_popstate=CO">
+<area shape=poly COORDS="374,107,405,105,405,123,372,125,374,107" href="signup.cgi?init_popstate=CT">
+<area shape=poly COORDS="370,143,402,145,405,157,362,157,370,143" href="signup.cgi?init_popstate=DE">
+<area shape=poly COORDS="275,193,325,187,327,197,341,219,341,233,335,237,317,215,315,205,307,195,293,203,275,193" href="signup.cgi?init_popstate=FL">
+<area shape=poly COORDS="297,153,283,155,297,191,321,189,321,169,297,153" href="signup.cgi?init_popstate=GA">
+<area shape=poly COORDS="98,233,142,263,156,251,162,239,164,229,136,231,94,221,100,235,98,233" href="signup.cgi?init_popstate=HI">
+<area shape=poly COORDS="68,21,76,21,72,35,80,47,80,55,84,65,100,69,94,93,56,83,66,51,70,19,68,21" href="signup.cgi?init_popstate=ID">
+<area shape=poly COORDS="242,91,258,89,266,123,256,139,234,109,248,87,242,91" href="signup.cgi?init_popstate=IL">
+<area shape=poly COORDS="261,95,265,123,265,131,285,117,277,91,261,95" href="signup.cgi?init_popstate=IN">
+<area shape=poly COORDS="198,87,206,111,232,109,240,99,240,91,232,79,198,87" href="signup.cgi?init_popstate=IA">
+<area shape=poly COORDS="158,111,158,135,214,139,214,127,208,113,158,111" href="signup.cgi?init_popstate=KS">
+<area shape=poly COORDS="263,133,275,129,289,115,303,121,307,129,299,135,251,141,269,131,263,133" href="signup.cgi?init_popstate=KY">
+<area shape=poly COORDS="222,179,246,179,244,197,258,193,262,213,226,209,224,177,222,179" href="signup.cgi?init_popstate=LA">
+<area shape=poly COORDS="363,37,373,59,373,47,387,31,377,9,365,15,363,37" href="signup.cgi?init_popstate=ME">
+<area shape=poly COORDS="376,159,405,159,405,175,374,177,376,159" href="signup.cgi?init_popstate=MD">
+<area shape=poly COORDS="378,74,380,88,404,88,404,72,378,74" href="signup.cgi?init_popstate=MA">
+<area shape=poly COORDS="265,73,269,83,265,93,293,91,295,71,281,53,271,53,267,69,265,73,265,73" href="signup.cgi?init_popstate=MI">
+<area shape=poly COORDS="194,31,222,33,242,35,224,51,222,63,222,73,234,79,196,85,194,31" href="signup.cgi?init_popstate=MN">
+<area shape=poly COORDS="265,159,271,199,257,201,259,195,241,197,251,155,265,159" href="signup.cgi?init_popstate=MS">
+<area shape=poly COORDS="206,113,234,111,256,139,248,147,214,145,208,111,206,113" href="signup.cgi?init_popstate=MO">
+<area shape=poly COORDS="78,23,148,31,146,67,84,63,78,35,80,19,78,23" href="signup.cgi?init_popstate=MT">
+<area shape=poly COORDS="146,85,148,103,158,105,164,109,206,109,198,85,144,87,146,85" href="signup.cgi?init_popstate=NE">
+<area shape=poly COORDS="40,83,76,87,64,151,32,109,40,83,40,83" href="signup.cgi?init_popstate=NV">
+<area shape=poly COORDS="298,11,330,9,330,25,298,25,298,11" href="signup.cgi?init_popstate=NH">
+<area shape=poly COORDS="372,127,404,125,405,141,368,139,376,125,372,127" href="signup.cgi?init_popstate=NJ">
+<area shape=poly COORDS="106,137,100,191,122,187,148,187,150,139,106,137,106,137" href="signup.cgi?init_popstate=NM">
+<area shape=poly COORDS="313,79,331,63,337,45,349,45,359,65,357,79,345,65,315,77,313,79,313,79" href="signup.cgi?init_popstate=NY">
+<area shape=poly COORDS="309,137,295,151,319,149,337,153,357,131,351,129,309,137,309,137" href="signup.cgi?init_popstate=NC">
+<area shape=poly COORDS="146,31,148,57,198,57,190,31,146,31,146,31" href="signup.cgi?init_popstate=ND">
+<area shape=poly COORDS="281,93,285,113,299,121,311,101,309,85,299,93,281,93,281,93" href="signup.cgi?init_popstate=OH">
+<area shape=poly COORDS="148,145,174,145,174,163,218,171,216,143,150,139,150,145,156,143,148,145,148,145" href="signup.cgi?init_popstate=OK">
+<area shape=poly COORDS="20,41,8,73,16,77,22,77,28,77,36,79,42,81,48,83,56,83,66,49,20,41,20,41" href="signup.cgi?init_popstate=OR">
+<area shape=poly COORDS="309,83,345,71,351,93,313,105,309,83,309,83" href="signup.cgi?init_popstate=PA">
+<area shape=poly COORDS="376,93,405,93,405,107,376,105,376,93" href="signup.cgi?init_popstate=RI">
+<area shape=poly COORDS="301,155,321,149,337,155,325,175,301,157,301,155,301,155" href="signup.cgi?init_popstate=SC">
+<area shape=poly COORDS="146,59,198,61,198,83,146,83,148,57,146,59,146,59" href="signup.cgi?init_popstate=SD">
+<area shape=poly COORDS="255,145,251,157,297,153,311,133,255,145,255,145" href="signup.cgi?init_popstate=TN">
+<area shape=poly COORDS="150,145,172,145,174,167,198,173,218,173,228,207,204,221,198,231,202,247,180,241,154,207,146,219,120,189,154,189,152,145,150,145,150,145" href="signup.cgi?init_popstate=TX">
+<area shape=poly COORDS="78,89,96,91,96,103,110,103,106,135,70,133,78,89,78,89" href="signup.cgi?init_popstate=UT">
+<area shape=poly COORDS="298,29,332,29,332,47,294,45,298,29" href="signup.cgi?init_popstate=VT">
+<area shape=poly COORDS="307,127,297,137,351,127,349,113,341,111,341,105,329,107,315,131,307,127,307,127" href="signup.cgi?init_popstate=VA">
+<area shape=poly COORDS="32,13,68,19,64,47,20,39,20,13,30,19,32,13,32,13" href="signup.cgi?init_popstate=WA">
+<area shape=poly COORDS="303,119,313,129,329,103,311,105,299,121,313,127,303,119,303,119" href="signup.cgi?init_popstate=WV">
+<area shape=poly COORDS="228,51,256,55,254,89,238,89,234,77,224,71,230,49,236,53,228,51,228,51" href="signup.cgi?init_popstate=WI">
+<area shape=poly COORDS="146,71,144,103,96,99,102,63,148,69,146,71,146,71" href="signup.cgi?init_popstate=WY">
+</MAP>
+<IMG SRC="map.gif" usemap=#usmap WIDTH=405 HEIGHT=270 border=0><BR>
+<SELECT NAME="init_popstate" onChange="gotoURL(this.form.init_popstate)">
+<OPTION VALUE="stateselect.html"></OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AL">Alabama</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AK">Alaska</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=AS">American Samoa</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=AZ">Arizona</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AR">Arkansas</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=CA">California</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=CO">Colorado</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=CT">Connecticut</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=DE">Delaware</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=DC">District of Columbia</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=FM">Federated States of Micronesia</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=FL">Florida</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=GA">Georgia</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=GU">Guam</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=HI">Hawaii</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=ID">Idaho</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=IL">Illinois</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=IN">Indiana</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=IA">Iowa</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=KS">Kansas</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=KY">Kentucky</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=LA">Louisiana</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=ME">Maine</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=MH">Marshall Islands</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=MD">Maryland</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MA">Massachusetts</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MI">Michigan</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MN">Minnesota</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MS">Mississippi</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MO">Missouri</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MT">Montana</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NE">Nebraska</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NV">Nevada</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NH">New Hampshire</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NJ">New Jersey</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NM">New Mexico</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NY">New York</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NC">North Carolina</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=ND">North Dakota</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=MP">Northern Mariana Islands</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=OH">Ohio</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=OK">Oklahoma</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=OR">Oregon</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=PW">Palau</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=PA">Pennsylvania</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=PR">Puerto Rico</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=RI">Rhode Island</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=SC">South Carolina</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=SD">South Dakota</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=TN">Tennessee</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=TX">Texas</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=UT">Utah</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=VT">Vermont</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=VI">Virgin Islands</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=VA">Virginia</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=WA">Washington</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=WV">West Virginia</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=WI">Wisconsin</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=WY">Wyoming</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=AE">Armed Forces Africa</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AA">Armed Forces Americas</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AE">Armed Forces Canada</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AE">Armed Forces Europe</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AE">Armed Forces Middle East</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AP">Armed Forces Pacific</OPTION>
+-->
+</SELECT>
+</FORM>
+</BODY>
+</HTML>
diff --git a/fs_signup/FS-SignupClient/cgi/success.html b/fs_signup/FS-SignupClient/cgi/success.html
new file mode 100644
index 0000000..397cc6c
--- /dev/null
+++ b/fs_signup/FS-SignupClient/cgi/success.html
@@ -0,0 +1,11 @@
+<HTML><HEAD><TITLE>Signup successful</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>Signup successful</FONT><BR><BR>
+Thanks for signing up!
+<BR><BR>
+Signup information for <%= $email_name %>:
+<BR><BR>
+Username: <%= $username %><BR>
+Password: <%= $password %><BR>
+Access number: (<%= $ac %>) / <%= $exch %> - <%= $local %><BR>
+Package: <%= $pkg %><BR>
+</BODY></HTML>
diff --git a/fs_signup/FS-SignupClient/test.pl b/fs_signup/FS-SignupClient/test.pl
new file mode 100644
index 0000000..b613695
--- /dev/null
+++ b/fs_signup/FS-SignupClient/test.pl
@@ -0,0 +1,20 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+######################### We start with some black magic to print on failure.
+
+# Change 1..1 below to 1..last_test_to_print .
+# (It may become useful if the test is moved to ./t subdirectory.)
+
+BEGIN { $| = 1; print "1..1\n"; }
+END {print "not ok 1\n" unless $loaded;}
+#blah#use FS::SignupClient;
+$loaded = 1;
+print "ok 1\n";
+
+######################### End of black magic.
+
+# Insert your test code below (better if it prints "ok 13"
+# (correspondingly "not ok 13") depending on the success of chunk 13
+# of the test code):
+
diff --git a/fs_signup/cck.template b/fs_signup/cck.template
new file mode 100644
index 0000000..f1db554
--- /dev/null
+++ b/fs_signup/cck.template
@@ -0,0 +1,14 @@
+SITE_FILE 8chrfile
+SITE_NAME YourISP
+LOGIN { $username }
+PASSWORD { $password }
+PHONE_NUM +1({ $ac }){ $exch }-{ $loc }
+DNS_ADDR 10.0.0.1
+DNS_ADDR2 10.0.0.2
+NNTP_HOST news.yourisp.com
+SMTP_HOST mail.yourisp.com
+DOMAIN_NAME yourisp.com
+POP_SERVER { $username }@mail.yourisp.com
+POP_PASSWORD { $password }
+HOME_URL http://www.yourisp.com
+EMAIL_ADDR { $username }@yourisp.com
diff --git a/fs_signup/ieak.template b/fs_signup/ieak.template
new file mode 100755
index 0000000..52edaa9
--- /dev/null
+++ b/fs_signup/ieak.template
@@ -0,0 +1,40 @@
+[Entry]
+Entry_Name = The Internet
+[Phone]
+Dial_As_Is=no
+Phone_Number = { $exch. $loc }
+Area_Code = { $ac }
+Country_Code = 1
+Country_Id = 1
+[Server]
+Type = PPP
+SW_Compress = Yes
+PW_Encrypt = Yes
+Negotiate_TCP/IP = Yes
+Disable_LCP = No
+[TCP/IP]
+Specify_IP_Address = No
+Specity_Server_Address = No
+IP_Header_Compress = Yes
+Gateway_On_Remote = Yes
+[User]
+Name = { $username }
+Password = { $password }
+Display_Password = Yes
+[Internet_Mail]
+Email_Name = { $email_name }
+Email_Address = { $username }\@domain.tld
+POP_Server = mail.domain.tld
+POP_Server_Port_Number = 110
+POP_Login_Name = { $username }
+POP_Login_Password = { $password }
+SMTP_Server = mail.domain.tld
+SMTP_Server_Port_Number = 25
+Install_Mail = 1
+[Internet_News]
+NNTP_Server = news.domain.tld
+NNTP_Server_Port_Number = 119
+Logon_Required = No
+Install_News = 1
+[Branding]
+Window_Title = The Internet
diff --git a/fs_webdemo/register.cgi b/fs_webdemo/register.cgi
new file mode 100755
index 0000000..8255822
--- /dev/null
+++ b/fs_webdemo/register.cgi
@@ -0,0 +1,136 @@
+#!/usr/bin/perl -Tw
+#
+# $Id: register.cgi,v 1.5 2000-03-03 18:22:42 ivan Exp $
+
+use strict;
+use vars qw(
+ $datasrc $user $pass $x
+ $cgi $username $email
+ $dbh $sth
+ );
+ #$freeside_bin $freeside_test $freeside_conf
+ #@pw_set @saltset
+ #$user_pw $crypt_pw
+ #$header $msg
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use DBI;
+#use Mail::Internet;
+#use Mail::Header;
+#use Date::Format;
+
+$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+#$freeside_bin = '/home/freeside/bin/';
+#$freeside_test = '/home/freeside/test/';
+#$freeside_conf = '/usr/local/etc/freeside/';
+
+$datasrc = 'DBI:mysql:http_auth';
+$user = "freeside";
+$pass = "maelcolm";
+
+##my(@pw_set)= ( 'a'..'z', 'A'..'Z', '0'..'9', '(', ')', '#', '!', '.', ',' );
+##my(@pw_set)= ( 'a'..'z', 'A'..'Z', '0'..'9' );
+#@pw_set = ( 'a'..'z', '0'..'9' );
+#@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+
+###
+
+$cgi = new CGI;
+
+$username = $cgi->param('username');
+$username =~ /^\s*([a-z][\w]{0,15})\s*$/i
+ or &idiot("Illegal username. Please use 1-16 alphanumeric characters, and start your username with a letter.");
+$username = lc($1);
+
+$email = $cgi->param('email');
+$email =~ /^([\w\-\.\+]+\@[\w\-\.]+)$/
+ or &idiot("Illegal email address.");
+$email = $1;
+
+###
+
+#$user_pw = join('',map($pw_set[ int(rand $#pw_set) ], (0..7) ) );
+#$crypt_pw = crypt($user_pw,$saltset[int(rand(64))].$saltset[int(rand(64))]);
+
+###
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+###
+
+$dbh = DBI->connect( $datasrc, $user, $pass, {
+ 'AutoCommit' => 'true',
+} ) or die "DBI->connect error: $DBI::errstr\n";
+$x = $DBI::errstr; #silly; to avoid "used only once" warning
+
+$sth = $dbh->prepare("INSERT INTO mysql_auth VALUES (". join(", ",
+ $dbh->quote($username),
+# $dbh->quote("X"),
+# $dbh->quote($crypt_pw),
+ $dbh->quote($email),
+ $dbh->quote('freeside'),
+ $dbh->quote('unconfigured'),
+). ")" );
+
+$sth->execute or &idiot("Username in use: ". $sth->errstr);
+
+$dbh->disconnect or die $dbh->errstr;
+
+###
+
+$|=1;
+print $cgi->header;
+print <<END;
+<HTML>
+ <HEAD>
+ <TITLE>Freeside demo registration successful</TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#FFFFFF">
+ <table>
+ <tr><td>
+ <p align=center>
+ <img border=0 alt="Silicon Interactive Software Design" src="http://www.sisd.com/freeside/small-logo.gif">
+ </td><td>
+ <center><font color="#ff0000" size=7>freeside demo registration successful</font></center>
+ </td></tr>
+ </table>
+ <P>Your sample database has been setup. Your password and the URL for the
+ Freeside demo have been emailed to you.
+ </BODY>
+</HTML>
+END
+
+###
+
+sub idiot {
+ my($error)=@_;
+ print $cgi->header, <<END;
+<HTML>
+ <HEAD>
+ <TITLE>Registration error</TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#FFFFFF">
+ <CENTER>
+ <H4>Registration error</H4>
+ </CENTER>
+ <P><B>$error</B>
+ <P>Hit the <I>Back</I> button in your web browser, correct this mistake,
+ and submit the form again.
+ </BODY>
+</HTML>
+END
+
+ exit;
+
+}
diff --git a/fs_webdemo/register.html b/fs_webdemo/register.html
new file mode 100644
index 0000000..acf9cff
--- /dev/null
+++ b/fs_webdemo/register.html
@@ -0,0 +1,33 @@
+<HTML>
+ <HEAD>
+ <TITLE>
+ Freeside - Billing and account administration software for ISPs
+ </TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#ffffff">
+ <table>
+ <tr><td>
+ <A HREF="http://www.sisd.com/">
+ <IMG BORDER=0 SRC="small-logo.gif" ALIGN=LEFT>
+ </A>
+ </td><td>
+ <center><font color="#ff0000" size=7 size=+4>freeside demo registration</font></center>
+ </td></tr>
+ </table>
+<P>You will need to choose a username for access to the Freeside web demo.
+
+<P><FONT SIZE=+1 COLOR="#ff0000">A password
+ and the URL for your demo will be emailed to you, so don't waste your
+ time with non-deliverable addresses.</FONT>
+We will <B>not</B> give your email address to any third party,
+ nor will we send you any unsolicited email (or in fact any email after the automatic registration).
+ <FORM ACTION="register.cgi" METHOD="POST">
+ <PRE>
+Freeside username: <INPUT TYPE="text" NAME="username" MAXLENGTH=16>
+
+Email address: <INPUT TYPE="text" NAME="email">
+</PRE>
+<BR><INPUT TYPE="Submit" VALUE="Register">
+ </FORM>
+ </BODY>
+</HTML>
diff --git a/fs_webdemo/registerd b/fs_webdemo/registerd
new file mode 100755
index 0000000..6314d0a
--- /dev/null
+++ b/fs_webdemo/registerd
@@ -0,0 +1,192 @@
+#!/usr/bin/perl -w
+#
+# $Id: registerd,v 1.8 2000-03-03 12:27:54 ivan Exp $
+
+use strict;
+use vars qw(
+ $freeside_conf
+ $mysql_data
+ $datasrc $user $pass $x
+ $dbh $sth
+ @pw_set @saltset
+ $header $msg
+ );
+ # $freeside_bin $freeside_test
+ # $cgi $username $name $email $user_pw $crypt_pw
+#use CGI;
+#use CGI::Carp qw(fatalsToBrowser);
+use DBI;
+use Mail::Internet;
+use Mail::Header;
+use Date::Format;
+
+#$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
+#$ENV{'SHELL'} = '/bin/sh';
+#$ENV{'IFS'} = " \t\n";
+#$ENV{'CDPATH'} = '';
+#$ENV{'ENV'} = '';
+#$ENV{'BASH_ENV'} = '';
+
+#$freeside_bin = '/home/freeside/bin/';
+#$freeside_test = '/home/freeside/test/';
+$freeside_conf = '/usr/local/etc/freeside/';
+
+$mysql_data = "/var/lib/mysql";
+
+$datasrc = 'DBI:mysql:http_auth';
+$user = "freeside";
+$pass = "maelcolm";
+
+#my(@pw_set)= ( 'a'..'z', 'A'..'Z', '0'..'9', '(', ')', '#', '!', '.', ',' );
+#my(@pw_set)= ( 'a'..'z', 'A'..'Z', '0'..'9' );
+@pw_set = ( 'a'..'z', '0'..'9' );
+@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+
+#die "not running as system user freeside"
+# unless $> == scalar(getpwnam('freeside'));
+die "not running as root user"
+ unless $> == 0;
+
+$dbh = DBI->connect( $datasrc, $user, $pass, {
+ 'AutoCommit' => 'true',
+} ) or die "DBI->connect error: $DBI::errstr\n";
+$x = $DBI::errstr; #silly; to avoid "used only once" warning
+
+while ( 1 ) {
+
+ $SIG{HUP} = 'IGNORE';
+ $SIG{INT} = 'IGNORE';
+ $SIG{QUIT} = 'IGNORE';
+ $SIG{TERM} = 'IGNORE';
+ $SIG{TSTP} = 'IGNORE';
+ $SIG{PIPE} = 'IGNORE';
+
+ $sth = $dbh->prepare("LOCK TABLES mysql_auth WRITE");
+ $sth->execute or die $sth->errstr;
+
+ $sth = $dbh->prepare(
+ 'SELECT * FROM mysql_auth WHERE status = "unconfigured"'
+ );
+ $sth->execute or die $sth->errstr;
+ my $pending = $sth->fetchall_arrayref( {} );
+
+ $sth = $dbh->prepare(
+ 'UPDATE mysql_auth SET status = "locked" WHERE status = "unconfigured"'
+ );
+ $sth->execute or die $sth->errstr;
+
+ $sth = $dbh->prepare("UNLOCK TABLES");
+ $sth->execute or die $sth->errstr;
+
+ #
+
+ foreach my $row ( @{$pending} ) {
+
+ my $username = $row->{'username'};
+ my $email = $row->{'passwd'};
+
+ system("/usr/bin/mysqladmin --user=$user --password=$pass ".
+ "create demo_$username >/dev/null");
+
+ system "cp -p $mysql_data/demo_template/* $mysql_data/demo_$username";
+
+ mkdir "${freeside_conf}conf.DBI:mysql:demo_$username", 0755;
+ system "cp -pr ${freeside_conf}conf.DBI:mysql:demo_template/* ".
+ "${freeside_conf}conf.DBI:mysql:demo_$username";
+
+ mkdir "${freeside_conf}counters.DBI:mysql:demo_$username", 0755;
+ system "cp -p ${freeside_conf}counters.DBI:mysql:demo_template/* ".
+ "${freeside_conf}counters.DBI:mysql:demo_$username";
+ chown scalar(getpwnam('freeside')), scalar(getgrnam('freeside')),
+ "${freeside_conf}counters.DBI:mysql:demo_$username";
+
+ system "cp -p ${freeside_conf}dbdef.DBI:mysql:demo_template ".
+ "${freeside_conf}dbdef.DBI:mysql:demo_$username";
+
+ open(INVOICE_FROM, ">${freeside_conf}conf.DBI:mysql:demo_$username/invoice_from")
+ or die "Can\'t open ${freeside_conf}conf.DBI:mysql:demo_$username/invoice_from: $!";
+ print INVOICE_FROM "$email\n";
+ close INVOICE_FROM;
+
+ open(LPR, ">${freeside_conf}conf.DBI:mysql:demo_$username/lpr")
+ or die "Can\'t open ${freeside_conf}conf.DBI:mysql:demo_$username/lpr: $!";
+ print LPR "mail $email";
+ close LPR;
+
+ open(FROM, ">${freeside_conf}conf.DBI:mysql:demo_$username/registries/internic/from")
+ or die "Can\'t open ${freeside_conf}conf.DBI:mysql:demo_$username/registries/internic/from: $!";
+ print FROM "$email\n";
+ close FROM;
+
+ open(TO, ">${freeside_conf}conf.DBI:mysql:demo_$username/registries/internic/to")
+ or die "Can\'t open ${freeside_conf}conf.DBI:mysql:demo_$username/registries/internic/to: $!";
+ print TO "$email\n";
+ close TO;
+
+ open(SECRETS, ">${freeside_conf}secrets.demo_$username")
+ or die "Can\'t open ${freeside_conf}secrets.demo_$username: $!";
+ chown scalar(getpwnam('freeside')), scalar(getgrnam('freeside')),
+ "${freeside_conf}secrets.demo_$username";
+ chmod 0600, "${freeside_conf}secrets.demo_$username";
+ print SECRETS "DBI:mysql:demo_$username\nfreeside\nmaelcolm\n";
+ close SECRETS;
+
+ open(MAPSECRETS, ">>${freeside_conf}mapsecrets")
+ or die "Can\'t open ${freeside_conf}mapsecrets: $!";
+ print MAPSECRETS "$username secrets.demo_$username\n";
+ close MAPSECRETS;
+
+ my $user_pw = join('',map($pw_set[ int(rand $#pw_set) ], (0..7) ) );
+ my $crypt_pw =
+ crypt($user_pw,$saltset[int(rand(64))].$saltset[int(rand(64))]);
+
+ $sth = $dbh->prepare(
+ qq(UPDATE mysql_auth SET passwd = "$crypt_pw", status = "done" WHERE username = "$username")
+ );
+ $sth->execute or die $sth->errstr;
+
+ $ENV{SMTPHOSTS} = "localhost";
+ $ENV{MAILADDRESS} = 'ivan-fsreg@sisd.com';
+ $ENV{TZ} = "PST8PDT";
+ $header = Mail::Header->new( [
+ 'From: ivan-fsreg@sisd.com',
+ "To: $email",
+ 'Bcc: ivan-fsreg_bcc@sisd.com',
+ 'Sender: ivan-fsreg@sisd.com',
+ 'Reply-To: ivan-fsreg@sisd.com',
+ #'Date: '. time2str("%a, %d %b %Y %X %z", time ),
+ 'Date: '. time2str("%a, %d %b %Y %X ", time ). "-0800",
+ 'Subject: Freeside demo information',
+ ] );
+ $msg = Mail::Internet->new(
+ 'Header' => $header,
+ 'Body' => [
+ "Hello,\n",
+ "\n",
+ "Your sample Freeside database has been setup.\n",
+ "\n",
+ "Point your web browswer at http://freeside.sisd.com/ and use the following\n",
+ "authentication information:\n",
+ "\n",
+ "Username: $username\n",
+ "Password: $user_pw\n",
+ "\n",
+ "-- \n",
+ "ivan\n",
+ ]
+ );
+ $msg->smtpsend or die "Can\'t send registration email!";
+
+ }
+
+ $SIG{HUP} = 'DEFAULT';
+ $SIG{INT} = 'DEFAULT';
+ $SIG{QUIT} = 'DEFAULT';
+ $SIG{TERM} = 'DEFAULT';
+ $SIG{TSTP} = 'DEFAULT';
+ $SIG{PIPE} = 'DEFAULT';
+
+ sleep 5;
+
+}
+
diff --git a/fs_webdemo/registerd.Pg b/fs_webdemo/registerd.Pg
new file mode 100755
index 0000000..f166846
--- /dev/null
+++ b/fs_webdemo/registerd.Pg
@@ -0,0 +1,221 @@
+#!/usr/bin/perl -w
+#
+# $Id: registerd.Pg,v 1.11 2001-10-24 15:29:30 ivan Exp $
+
+use strict;
+use vars qw(
+ $freeside_conf
+ $mysql_data
+ $datasrc $user $pass $x
+ $dbh $sth
+ @pw_set @saltset
+ $header $msg
+ );
+ # $freeside_bin $freeside_test
+ # $cgi $username $name $email $user_pw $crypt_pw
+#use CGI;
+#use CGI::Carp qw(fatalsToBrowser);
+use DBI;
+use Mail::Internet;
+use Mail::Header;
+use Date::Format;
+
+#$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
+#$ENV{'SHELL'} = '/bin/sh';
+#$ENV{'IFS'} = " \t\n";
+#$ENV{'CDPATH'} = '';
+#$ENV{'ENV'} = '';
+#$ENV{'BASH_ENV'} = '';
+
+#$freeside_bin = '/home/freeside/bin/';
+#$freeside_test = '/home/freeside/test/';
+$freeside_conf = '/usr/local/etc/freeside/';
+
+#$mysql_data = "/var/lib/mysql";
+
+$datasrc = 'DBI:mysql:http_auth';
+$user = "freeside";
+$pass = "maelcolm";
+
+#my(@pw_set)= ( 'a'..'z', 'A'..'Z', '0'..'9', '(', ')', '#', '!', '.', ',' );
+#my(@pw_set)= ( 'a'..'z', 'A'..'Z', '0'..'9' );
+@pw_set = ( 'a'..'z', '0'..'9' );
+@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
+
+#die "not running as system user freeside"
+# unless $> == scalar(getpwnam('freeside'));
+die "not running as root user"
+ unless $> == 0;
+
+$dbh = DBI->connect( $datasrc, $user, $pass, {
+ 'AutoCommit' => 'true',
+} ) or die "DBI->connect error: $DBI::errstr\n";
+#$x = $DBI::errstr; #silly; to avoid "used only once" warning
+
+while ( 1 ) {
+
+ $SIG{HUP} = 'IGNORE';
+ $SIG{INT} = 'IGNORE';
+ $SIG{QUIT} = 'IGNORE';
+ $SIG{TERM} = 'IGNORE';
+ $SIG{TSTP} = 'IGNORE';
+ $SIG{PIPE} = 'IGNORE';
+
+ $sth = $dbh->prepare("LOCK TABLES mysql_auth WRITE");
+ $sth->execute or die $sth->errstr;
+
+ $sth = $dbh->prepare(
+ 'SELECT * FROM mysql_auth WHERE status = "unconfigured"'
+ );
+ $sth->execute or die $sth->errstr;
+ my $pending = $sth->fetchall_arrayref( {} );
+
+ $sth = $dbh->prepare(
+ 'UPDATE mysql_auth SET status = "locked" WHERE status = "unconfigured"'
+ );
+ $sth->execute or die $sth->errstr;
+
+ $sth = $dbh->prepare("UNLOCK TABLES");
+ $sth->execute or die $sth->errstr;
+
+ #
+
+ foreach my $row ( @{$pending} ) {
+
+ my $username = $row->{'username'};
+ my $email = $row->{'passwd'};
+
+ my $pdbh = DBI->connect( 'DBI:Pg:host=localhost;dbname=demo_template', 'freeside', 'maelcolm' )
+ or do { &myerr("$username: ". $DBI::errstr); next; };
+
+ my $psth = $pdbh->prepare("CREATE DATABASE demo_$username")
+ or do { &myerr("$username: ". $pdbh->errstr); next; };
+ $psth->execute()
+ or do { &myerr("$username: ". $psth->errstr); next; };
+
+ $pdbh->disconnect
+ or do { &myerr("fatal: $DBI::errstr"); die; };
+
+ open(PSQL,"|psql -U freeside demo_$username")
+ or do { &myerr("|psql -U freeside demo_$username: $!"); next; };
+ open(PSQLDATA, "</usr/local/etc/freeside/demo_template.Pg")
+ or do { &myerr("/usr/local/etc/freeside/demo_template.Pg: $!"); next; };
+ while(<PSQLDATA>) {
+ print PSQL $_;
+ }
+ close PSQLDATA
+ or do { &myerr("/usr/local/etc/freeside/demo_template.Pg: $!"); next; };
+ close PSQL
+ or do { &myerr("|psql -U freeside demo_$username: $!"); next; };
+
+ mkdir "${freeside_conf}conf.DBI:Pg:host=localhost;dbname=demo_$username", 0755;
+ system "cp -pr ${freeside_conf}conf.DBI:Pg:host=localhost\\;dbname=demo_template/* ".
+ "${freeside_conf}conf.DBI:Pg:host=localhost\\;dbname=demo_$username";
+
+ mkdir "${freeside_conf}counters.DBI:Pg:host=localhost;dbname=demo_$username", 0755;
+ system "cp -p ${freeside_conf}counters.DBI:Pg:host=localhost\\;dbname=demo_template/* ".
+ "${freeside_conf}counters.DBI:Pg:host=localhost\\;dbname=demo_$username";
+ chown scalar(getpwnam('freeside')), scalar(getgrnam('freeside')),
+ "${freeside_conf}counters.DBI:Pg:host=localhost;dbname=demo_$username";
+
+ system "cp -p ${freeside_conf}dbdef.DBI:Pg:host=localhost\\;dbname=demo_template ".
+ "${freeside_conf}dbdef.DBI:Pg:host=localhost\\;dbname=demo_$username";
+
+ open(INVOICE_FROM, ">${freeside_conf}conf.DBI:Pg:host=localhost;dbname=demo_$username/invoice_from")
+ or die "Can\'t open ${freeside_conf}conf.DBI:Pg:host=localhost;dbname=demo_$username/invoice_from: $!";
+ print INVOICE_FROM "$email\n";
+ close INVOICE_FROM;
+
+ open(LPR, ">${freeside_conf}conf.DBI:Pg:host=localhost;dbname=demo_$username/lpr")
+ or die "Can\'t open ${freeside_conf}conf.DBI:Pg:host=localhost;dbname=demo_$username/lpr: $!";
+ print LPR "mail $email";
+ close LPR;
+
+# open(FROM, ">${freeside_conf}conf.DBI:Pg:host=localhost;dbname=demo_$username/registries/internic/from")
+# or die "Can\'t open ${freeside_conf}conf.DBI:Pg:host=localhost;dbname=demo_$username/registries/internic/from: $!";
+# print FROM "$email\n";
+# close FROM;
+#
+# open(TO, ">${freeside_conf}conf.DBI:Pg:host=localhost;dbname=demo_$username/registries/internic/to")
+# or die "Can\'t open ${freeside_conf}conf.DBI:Pg:host=localhost;dbname=demo_$username/registries/internic/to: $!";
+# print TO "$email\n";
+# close TO;
+
+ open(SECRETS, ">${freeside_conf}secrets.demo_$username")
+ or die "Can\'t open ${freeside_conf}secrets.demo_$username: $!";
+ chown scalar(getpwnam('freeside')), scalar(getgrnam('freeside')),
+ "${freeside_conf}secrets.demo_$username";
+ chmod 0600, "${freeside_conf}secrets.demo_$username";
+ print SECRETS "DBI:Pg:host=localhost;dbname=demo_$username\nfreeside\nmaelcolm\n";
+ close SECRETS;
+
+ open(MAPSECRETS, ">>${freeside_conf}mapsecrets")
+ or die "Can\'t open ${freeside_conf}mapsecrets: $!";
+ print MAPSECRETS "$username secrets.demo_$username\n";
+ close MAPSECRETS;
+
+ my $user_pw = join('',map($pw_set[ int(rand $#pw_set) ], (0..7) ) );
+ my $crypt_pw =
+ crypt($user_pw,$saltset[int(rand(64))].$saltset[int(rand(64))]);
+
+ $sth = $dbh->prepare(
+ qq(UPDATE mysql_auth SET passwd = "$crypt_pw", status = "done" WHERE username = "$username")
+ );
+ $sth->execute or die $sth->errstr;
+
+ #$ENV{SMTPHOSTS} = "localhost";
+ $ENV{SMTPHOSTS} = "192.168.1.1";
+ $ENV{MAILADDRESS} = 'ivan-fsreg@sisd.com';
+ $ENV{TZ} = "PST8PDT";
+ $header = Mail::Header->new( [
+ 'From: ivan-fsreg@sisd.com',
+ "To: $email",
+ 'Bcc: ivan-fsreg_bcc@sisd.com',
+ 'Sender: ivan-fsreg@sisd.com',
+ 'Reply-To: ivan-fsreg@sisd.com',
+ #'Date: '. time2str("%a, %d %b %Y %X %z", time ),
+ 'Date: '. time2str("%a, %d %b %Y %X ", time ). "-0800",
+ 'Subject: Freeside demo information',
+ ] );
+ $msg = Mail::Internet->new(
+ 'Header' => $header,
+ 'Body' => [
+ "Hello,\n",
+ "\n",
+ "Your sample Freeside database has been setup.\n",
+ "\n",
+ "Your login and database will be automatically deleted in 1-2 months.\n",
+ "\n",
+ "Point your web browswer at http://freeside.sisd.com/ and use the following\n",
+ "authentication information:\n",
+ "\n",
+ "Username: $username\n",
+ "Password: $user_pw\n",
+ "\n",
+ "-- \n",
+ "ivan\n",
+ ]
+ );
+ $msg->smtpsend or die "Can\'t send registration email!";
+
+ }
+
+ $SIG{HUP} = 'DEFAULT';
+ $SIG{INT} = 'DEFAULT';
+ $SIG{QUIT} = 'DEFAULT';
+ $SIG{TERM} = 'DEFAULT';
+ $SIG{TSTP} = 'DEFAULT';
+ $SIG{PIPE} = 'DEFAULT';
+
+ sleep 5;
+
+}
+
+sub myerr {
+ my $msg = shift;
+ open(MAIL,"|mail ivan-fsdemoerr\@420.am");
+ print MAIL $msg, "\n\n";
+ print MAIL $msg, "\n\n";
+ close MAIL;
+};
+
diff --git a/htetc/global.asa b/htetc/global.asa
new file mode 100644
index 0000000..55cc8ed
--- /dev/null
+++ b/htetc/global.asa
@@ -0,0 +1,238 @@
+BEGIN { eval "use Devel::AutoProfiler;"; } #only if installed...
+#BEGIN { package Devel::AutoProfiler; use vars qw(%caller_info); }
+#use Devel::AutoProfiler;
+
+use strict;
+use vars qw( $cgi $p );
+use Apache::ASP 2.55;
+use CGI 2.47;
+#use CGI::Carp qw(fatalsToBrowser);
+use Date::Format;
+use Date::Parse;
+use Time::Local;
+use Tie::IxHash;
+use HTML::Entities;
+use IO::Handle;
+use IO::File;
+use Net::Whois::Raw qw(whois);
+use Business::CreditCard;
+use String::Approx qw(amatch);
+use Chart::LinesPoints;
+use HTML::Widgets::SelectLayers 0.03;
+use FS::UID qw(cgisuidsetup dbh getotaker datasrc driver_name);
+use FS::Record qw(qsearch qsearchs fields dbdef);
+use FS::Conf;
+use FS::CGI qw(header menubar popurl table itable ntable idiot eidiot
+ small_custview myexit http_header);
+use FS::Msgcat qw(gettext geterror);
+use FS::Misc qw( send_email );
+use FS::Report::Table::Monthly;
+
+use FS::agent;
+use FS::agent_type;
+use FS::domain_record;
+use FS::cust_bill;
+use FS::cust_bill_pay;
+use FS::cust_credit;
+use FS::cust_credit_bill;
+use FS::cust_main;
+use FS::cust_main_county;
+use FS::cust_pay;
+use FS::cust_pkg;
+use FS::cust_refund;
+use FS::cust_svc;
+use FS::nas;
+use FS::part_bill_event;
+use FS::part_pkg;
+use FS::part_referral;
+use FS::part_svc;
+use FS::part_svc_router;
+use FS::part_virtual_field;
+use FS::pkg_svc;
+use FS::port;
+use FS::queue qw(joblisting);
+use FS::raddb;
+use FS::session;
+use FS::svc_acct;
+use FS::svc_acct_pop qw(popselector);
+use FS::svc_domain;
+use FS::svc_forward;
+use FS::svc_www;
+use FS::router;
+use FS::addr_block;
+use FS::svc_broadband;
+use FS::svc_external;
+use FS::type_pkgs;
+use FS::part_export;
+use FS::part_export_option;
+use FS::export_svc;
+use FS::msgcat;
+
+sub Script_OnStart {
+ $Response->AddHeader('Cache-control' => 'no-cache');
+# $Response->AddHeader('Expires' => 0);
+ $Response->{Expires} = -36288000;
+
+ $cgi = new CGI;
+ &cgisuidsetup($cgi);
+ $p = popurl(2);
+ #print $cgi->header( '-expires' => 'now' );
+ #dbh->{'private_profile'} = {} if dbh->can('sprintProfile');
+ dbh->{'private_profile'} = {} if UNIVERSAL::can(dbh, 'sprintProfile');
+
+ #really should check for FS::Profiler or something
+ # Devel::AutoProfiler _our_ VERSION? thanks a fucking lot
+ if ( Devel::AutoProfiler->can('__recursively_fetch_subs_in_package') ) {
+ #should check to see it's my special version. well, switch to FS::Profiler
+
+ #nicked from Devel::AutoProfiler::INIT
+ my %subs = Devel::AutoProfiler::__recursively_fetch_subs_in_package('main');
+
+
+ SUB : while( my ($name, $ref) = each(%subs) )
+ {
+ #next if $name =~ /^(main::)?Apache::/;
+ next unless $name =~ /FS/;
+ foreach my $sub (@Devel::AutoProfiler::do_not_instrument_this_sub)
+ {
+ if ($name =~ /$sub/)
+ {
+ next SUB;
+ }
+ }
+ next if ($Devel::AutoProfiler::do_not_instrument_this_sub{$name});
+ #warn "INIT name is $name \n";
+ Devel::AutoProfiler::__instrument_sub($name, $ref);
+ }
+
+ }
+
+}
+
+sub Script_OnFlush {
+ my $ref = $Response->{BinaryRef};
+ #$$ref = $cgi->header( @FS::CGI::header ) . $$ref;
+ #$$ref = $cgi->header() . $$ref;
+ #warn "Script_OnFlush called with dbh ". dbh. "\n";
+ #if ( dbh->can('sprintProfile') ) {
+ if ( UNIVERSAL::can(dbh, 'sprintProfile') ) {
+ #warn "dbh can sprintProfile\n";
+ if ( lc($Response->{ContentType}) eq 'text/html' ) { #con
+ #warn "contenttype is sprintProfile\n";
+ $$ref =~ s/<\/BODY>[\s\n]*<\/HTML>[\s\n]*$//i
+ or warn "can't remove";
+
+ #$$ref .= '<PRE>'. ("\n"x96). encode_entities(dbh->sprintProfile()). '</PRE>';
+ # wtf? konqueror...
+ $$ref .= '<PRE>'. ("\n"x4096). encode_entities(dbh->sprintProfile()).
+ "\n\n". &sprintAutoProfile(). '</PRE>';
+
+ $$ref .= '</BODY></HTML>';
+ }
+ dbh->{'private_profile'} = {};
+ }
+}
+
+#if ( defined(@DBIx::Profile::ISA) && DBIx::Profile::db->can('sprintProfile') ) {
+#if ( defined(@DBIx::Profile::ISA) && UNIVERSAL::can('DBIx::Profile::db', 'sprintProfile') ) {
+if ( defined(@DBIx::Profile::ISA) ) {
+
+ #warn "enabling profiling redirects";
+ *CGI::redirect = sub {
+ my( $self, $location) = @_;
+ my $page =
+ $cgi->header.
+ qq!<HTML><BODY>Redirect to <A HREF="$location">$location</A>!.
+ '<BR><BR><PRE>'.
+ ( UNIVERSAL::can(dbh, 'sprintProfile')
+ ? encode_entities(dbh->sprintProfile())
+ : 'DBIx::Profile missing sprintProfile method;'.
+ 'unpatched or too old?' ).
+ "\n\n". &sprintAutoProfile(). '</PRE>'.
+ '</BODY></HTML>';
+ dbh->{'private_profile'} = {};
+ return $page;
+ };
+
+}
+
+sub by_total_time
+{
+ return $a->{total_time_in_sub} <=> $b->{total_time_in_sub};
+}
+
+sub sprintAutoProfile {
+ my %caller_info = %Devel::AutoProfiler::caller_info;
+ return unless keys %caller_info;
+
+ %Devel::AutoProfiler::caller_info = ();
+
+ my @keys = keys(%caller_info);
+
+ foreach my $key (@keys)
+ {
+ my $href = $caller_info{$key};
+
+ $href->{who_am_i} = $key;
+ }
+
+ my @subs = values(%caller_info);
+
+ #my @sorted = sort by_total_time ( @subs );
+ my @sorted = reverse sort by_total_time ( @subs );
+
+ # print Dumper \@sorted;
+
+ my @readable_info;
+
+ foreach my $sort (@sorted)
+ {
+ push(@readable_info, delete($sort->{who_am_i}));
+ push(@readable_info, $sort);
+ }
+
+ use Data::Dumper;
+ return encode_entities(Dumper(\@readable_info));
+
+}
+
+sub include {
+ ( my $file = shift ) =~ s(^/)(%%%FREESIDE_DOCUMENT_ROOT%%%/);
+ #broken in 5.005# ${$Response->TrapInclude($file, @_)};
+ my $ref = $Response->TrapInclude($file, @_);
+ $$ref;
+}
+
+if ( defined(@DBIx::Profile::ISA) ) {
+
+ #false laziness w/above
+ *redirect = sub {
+ my($location) = @_;
+
+ ${$Response->{BinaryRef}} =
+ $cgi->header.
+ qq!<HTML><BODY>Redirect to <A HREF="$location">$location</A>!.
+ '<BR><BR><PRE>'.
+ ( UNIVERSAL::can(dbh, 'sprintProfile')
+ ? encode_entities(dbh->sprintProfile())
+ : 'DBIx::Profile missing sprintProfile method;'.
+ 'unpatched or too old?' ).
+ "\n\n". &sprintAutoProfile(). '</PRE>'.
+ '</BODY></HTML>';
+
+ dbh->{'private_profile'} = {};
+
+ $Response->End;
+
+ };
+
+} else {
+
+ *redirect = sub {
+ $Response->Redirect(@_);
+ }
+
+}
+
+1;
+
diff --git a/htetc/handler.pl b/htetc/handler.pl
new file mode 100644
index 0000000..d425c22
--- /dev/null
+++ b/htetc/handler.pl
@@ -0,0 +1,301 @@
+#!/usr/bin/perl
+#
+# This is a basic, fairly fuctional Mason handler.pl.
+#
+# For something a little more involved, check out session_handler.pl
+
+package HTML::Mason;
+
+# Bring in main Mason package.
+use HTML::Mason 1.1;
+
+# Bring in ApacheHandler, necessary for mod_perl integration.
+# Uncomment the second line (and comment the first) to use
+# Apache::Request instead of CGI.pm to parse arguments.
+use HTML::Mason::ApacheHandler;
+# use HTML::Mason::ApacheHandler (args_method=>'mod_perl');
+
+# Uncomment the next line if you plan to use the Mason previewer.
+#use HTML::Mason::Preview;
+
+use strict;
+
+# List of modules that you want to use from components (see Admin
+# manual for details)
+#{ package HTML::Mason::Commands;
+# use CGI;
+#}
+
+# Create Mason objects
+#
+
+#my $parser = new HTML::Mason::Parser;
+#my $interp = new HTML::Mason::Interp (parser=>$parser,
+# comp_root=>'/var/www/masondocs',
+# data_dir=>'/usr/local/etc/freeside/masondata',
+# out_mode=>'stream',
+# );
+
+use vars qw($r);
+
+if ( %%%RT_ENABLED%%% ) {
+ eval '
+ use lib ("/opt/rt3/local/lib", "/opt/rt3/lib");
+ use RT;
+ use vars qw($Nobody $SystemUser);
+ RT::LoadConfig();
+ ';
+ die $@ if $@;
+
+
+}
+
+
+my $ah = new HTML::Mason::ApacheHandler (
+ #interp => $interp,
+ #auto_send_headers => 0,
+ comp_root=> [
+ [ 'freeside' => '%%%FREESIDE_DOCUMENT_ROOT%%%' ],
+ [ 'rt' => '%%%FREESIDE_DOCUMENT_ROOT%%%/rt' ],
+ ],
+ data_dir=>'/usr/local/etc/freeside/masondata',
+ #out_mode=>'stream',
+
+ #RT
+ args_method => 'CGI',
+ default_escape_flags => 'h',
+ allow_globals => [qw(%session)],
+ #autoflush => 1,
+);
+
+# Activate the following if running httpd as root (the normal case).
+# Resets ownership of all files created by Mason at startup.
+#
+#chown (Apache->server->uid, Apache->server->gid, $interp->files_written);
+
+sub handler
+{
+ ($r) = @_;
+
+ # If you plan to intermix images in the same directory as
+ # components, activate the following to prevent Mason from
+ # evaluating image files as components.
+ #
+ #return -1 if $r->content_type && $r->content_type !~ m|^text/|i;
+
+ #rar
+ { package HTML::Mason::Commands;
+ use strict;
+ use vars qw( $cgi $p );
+ use vars qw( %session );
+ use CGI 2.47 qw(-private_tempfiles);
+ #use CGI::Carp qw(fatalsToBrowser);
+ use Date::Format;
+ use Date::Parse;
+ use Time::Local;
+ use Tie::IxHash;
+ use HTML::Entities;
+ use IO::Handle;
+ use IO::File;
+ use Net::Whois::Raw qw(whois);
+ use Business::CreditCard;
+ use String::Approx qw(amatch);
+ use Chart::LinesPoints;
+ use HTML::Widgets::SelectLayers 0.03;
+ use FS::UID qw(cgisuidsetup dbh getotaker datasrc driver_name);
+ use FS::Record qw(qsearch qsearchs fields dbdef);
+ use FS::Conf;
+ use FS::CGI qw(header menubar popurl table itable ntable idiot eidiot
+ small_custview myexit http_header);
+ use FS::Msgcat qw(gettext geterror);
+ use FS::Misc qw( send_email );
+ use FS::Report::Table::Monthly;
+
+ use FS::agent;
+ use FS::agent_type;
+ use FS::domain_record;
+ use FS::cust_bill;
+ use FS::cust_bill_pay;
+ use FS::cust_credit;
+ use FS::cust_credit_bill;
+ use FS::cust_main;
+ use FS::cust_main_county;
+ use FS::cust_pay;
+ use FS::cust_pkg;
+ use FS::cust_refund;
+ use FS::cust_svc;
+ use FS::nas;
+ use FS::part_bill_event;
+ use FS::part_pkg;
+ use FS::part_referral;
+ use FS::part_svc;
+ use FS::part_svc_router;
+ use FS::part_virtual_field;
+ use FS::pkg_svc;
+ use FS::port;
+ use FS::queue qw(joblisting);
+ use FS::raddb;
+ use FS::session;
+ use FS::svc_acct;
+ use FS::svc_acct_pop qw(popselector);
+ use FS::svc_domain;
+ use FS::svc_forward;
+ use FS::svc_www;
+ use FS::router;
+ use FS::addr_block;
+ use FS::svc_broadband;
+ use FS::svc_external;
+ use FS::type_pkgs;
+ use FS::part_export;
+ use FS::part_export_option;
+ use FS::export_svc;
+ use FS::msgcat;
+
+ if ( %%%RT_ENABLED%%% ) {
+ eval '
+ use RT::Tickets;
+ use RT::Transactions;
+ use RT::Users;
+ use RT::CurrentUser;
+ use RT::Templates;
+ use RT::Queues;
+ use RT::ScripActions;
+ use RT::ScripConditions;
+ use RT::Scrips;
+ use RT::Groups;
+ use RT::GroupMembers;
+ use RT::CustomFields;
+ use RT::CustomFieldValues;
+ use RT::TicketCustomFieldValues;
+
+ use RT::Interface::Web;
+ use MIME::Entity;
+ use Text::Wrapper;
+ use CGI::Cookie;
+ use Time::ParseDate;
+ ';
+ die $@ if $@;
+ }
+
+ *CGI::redirect = sub {
+ my( $self, $location ) = @_;
+ use vars qw($m);
+
+ if ( defined(@DBIx::Profile::ISA) ) { #profiling redirect
+
+ my $page =
+ qq!<HTML><BODY>Redirect to <A HREF="$location">$location</A>!.
+ '<BR><BR><PRE>'.
+ ( UNIVERSAL::can(dbh, 'sprintProfile')
+ ? encode_entities(dbh->sprintProfile())
+ : 'DBIx::Profile missing sprintProfile method;'.
+ 'unpatched or too old?' ).
+ #"\n\n". &sprintAutoProfile(). '</PRE>'.
+ "\n\n". '</PRE>'.
+ '</BODY></HTML>';
+ dbh->{'private_profile'} = {};
+ return $page;
+
+ } else { #normal redirect
+
+ $m->redirect($location);
+ '';
+
+ }
+
+ };
+
+ $cgi = new CGI;
+ &cgisuidsetup($cgi);
+ #&cgisuidsetup($r);
+ $p = popurl(2);
+
+ sub include {
+ use vars qw($m);
+ $m->scomp(@_);
+ }
+
+ sub redirect {
+ my( $location ) = @_;
+ use vars qw($m);
+ $m->clear_buffer;
+ #false laziness w/above
+ if ( defined(@DBIx::Profile::ISA) ) { #profiling redirect
+
+ $m->print(
+ qq!<HTML><BODY>Redirect to <A HREF="$location">$location</A>!.
+ '<BR><BR><PRE>'.
+ ( UNIVERSAL::can(dbh, 'sprintProfile')
+ ? encode_entities(dbh->sprintProfile())
+ : 'DBIx::Profile missing sprintProfile method;'.
+ 'unpatched or too old?' ).
+ #"\n\n". &sprintAutoProfile(). '</PRE>'.
+ "\n\n". '</PRE>'.
+ '</BODY></HTML>'
+ );
+ dbh->{'private_profile'} = {};
+
+ $m->abort(200);
+
+ } else { #normal redirect
+
+ $m->redirect($location);
+
+ }
+
+ }
+
+ } # end package HTML::Mason::Commands;
+
+ $r->content_type('text/html');
+ #eorar
+
+ my $headers = $r->headers_out;
+ $headers->{'Cache-control'} = 'no-cache';
+ #$r->no_cache(1);
+ $headers->{'Expires'} = '0';
+
+# $r->send_http_header;
+
+ #$ah->interp->remove_escape('h');
+
+ if ( $r->filename =~ /\/rt\// ) { #RT
+ #warn "processing RT file". $r->filename. "; escaping for RT\n";
+
+ # MasonX::Request::ExtendedCompRoot
+ #$ah->interp->comp_root( '/rt'. $ah->interp->comp_root() );
+
+ $ah->interp->set_escape( h => \&RT::Interface::Web::EscapeUTF8 );
+
+ local $SIG{__WARN__};
+ local $SIG{__DIE__};
+
+ RT::Init();
+
+ # We don't need to handle non-text items
+ return -1 if defined( $r->content_type ) && $r->content_type !~ m|^text/|io;
+
+ } else {
+ $ah->interp->set_escape( 'h' => sub { ${$_[0]}; } );
+ }
+
+ my %session;
+ my $status;
+ eval { $status = $ah->handle_request($r); };
+#!!
+# if ( $@ ) {
+# $RT::Logger->crit($@);
+# }
+
+ undef %session;
+
+#!!
+# if ($RT::Handle->TransactionDepth) {
+# $RT::Handle->ForceRollback;
+# $RT::Logger->crit("Transaction not committed. Usually indicates a software fault. Data loss may have occurred") ;
+# }
+
+ $status;
+}
+
+1;
diff --git a/httemplate/.htaccess b/httemplate/.htaccess
new file mode 100755
index 0000000..f8c6b9c
--- /dev/null
+++ b/httemplate/.htaccess
@@ -0,0 +1,3 @@
+AuthName Freeside
+AuthType Basic
+require valid-user
diff --git a/httemplate/autohandler b/httemplate/autohandler
new file mode 100644
index 0000000..2bd3adf
--- /dev/null
+++ b/httemplate/autohandler
@@ -0,0 +1,21 @@
+% $m->call_next;
+<%init>
+ dbh->{'private_profile'} = {} if UNIVERSAL::can(dbh, 'sprintProfile');
+</%init>
+<%filter>
+
+my $profile = '';
+if ( UNIVERSAL::can(dbh, 'sprintProfile') ) {
+
+ if ( lc($r->content_type) eq 'text/html' ) {
+
+ $profile = '<PRE>'. ("\n"x4096). encode_entities(dbh->sprintProfile()).
+ #"\n\n". &sprintAutoProfile(). '</PRE>';
+ "\n\n". '</PRE>';
+ }
+
+ dbh->{'private_profile'} = {};
+}
+
+s/(<\/BODY>[\s\n]*<\/HTML>[\s\n]*)$/$profile$1/i;
+</%filter>
diff --git a/httemplate/browse/addr_block.cgi b/httemplate/browse/addr_block.cgi
new file mode 100644
index 0000000..06ac556
--- /dev/null
+++ b/httemplate/browse/addr_block.cgi
@@ -0,0 +1,76 @@
+<%= header('Address Blocks', menubar('Main Menu' => $p)) %>
+<%
+
+use NetAddr::IP;
+
+my @addr_block = qsearch('addr_block', {});
+my @router = qsearch('router', {});
+my $block;
+my $p2 = popurl(2);
+my $path = $p2 . "edit/process/addr_block";
+
+%>
+
+<% if ($cgi->param('error')) { %>
+ <FONT SIZE="+1" COLOR="#ff0000">Error: <%=$cgi->param('error')%></FONT>
+ <BR><BR>
+<% } %>
+
+<%=table()%>
+
+<% foreach $block (sort {$a->NetAddr cmp $b->NetAddr} @addr_block) { %>
+ <TR>
+ <TD><%=$block->NetAddr%></TD>
+ <% if (my $router = $block->router) { %>
+ <% if (scalar($block->svc_broadband) == 0) { %>
+ <TD>
+ <%=$router->routername%>
+ </TD>
+ <TD>
+ <FORM ACTION="<%=$path%>/deallocate.cgi" METHOD="POST">
+ <INPUT TYPE="hidden" NAME="blocknum" VALUE="<%=$block->blocknum%>">
+ <INPUT TYPE="submit" NAME="submit" VALUE="Deallocate">
+ </FORM>
+ </TD>
+ <% } else { %>
+ <TD COLSPAN="2">
+ <%=$router->routername%>
+ </TD>
+ <% } %>
+ <% } else { %>
+ <TD>
+ <FORM ACTION="<%=$path%>/allocate.cgi" METHOD="POST">
+ <INPUT TYPE="hidden" NAME="blocknum" VALUE="<%=$block->blocknum%>">
+ <SELECT NAME="routernum" SIZE="1">
+ <% foreach (@router) { %>
+ <OPTION VALUE="<%=$_->routernum %>"><%=$_->routername%></OPTION>
+ <% } %>
+ </SELECT>
+ <INPUT TYPE="submit" NAME="submit" VALUE="Allocate">
+ </FORM>
+ </TD>
+ <TD>
+ <FORM ACTION="<%=$path%>/split.cgi" METHOD="POST">
+ <INPUT TYPE="hidden" NAME="blocknum" VALUE="<%=$block->blocknum%>">
+ <INPUT TYPE="submit" NAME="submit" VALUE="Split">
+ </FORM>
+ </TD>
+ </TR>
+<% }
+ } %>
+ <TR><TD COLSPAN="3"><BR></TD></TR>
+ <TR>
+ <FORM ACTION="<%=$path%>/add.cgi" METHOD="POST">
+ <TD>Gateway/Netmask</TD>
+ <TD>
+ <INPUT TYPE="text" NAME="ip_gateway" SIZE="15">/<INPUT TYPE="text" NAME="ip_netmask" SIZE="2">
+ </TD>
+ <TD>
+ <INPUT TYPE="submit" NAME="submit" VALUE="Add">
+ </TD>
+ </FORM>
+ </TR>
+</TABLE>
+</BODY>
+</HTML>
+
diff --git a/httemplate/browse/agent.cgi b/httemplate/browse/agent.cgi
new file mode 100755
index 0000000..f389342
--- /dev/null
+++ b/httemplate/browse/agent.cgi
@@ -0,0 +1,100 @@
+<!-- mason kludge -->
+
+<%
+
+ my %search;
+ if ( $cgi->param('showdisabled')
+ || !dbdef->table('agent')->column('disabled') ) {
+ %search = ();
+ } else {
+ %search = ( 'disabled' => '' );
+ }
+
+%>
+
+<%= header('Agent Listing', menubar(
+ 'Main Menu' => $p,
+ 'Agent Types' => $p. 'browse/agent_type.cgi',
+# 'Add new agent' => '../edit/agent.cgi'
+)) %>
+Agents are resellers of your service. Agents may be limited to a subset of your
+full offerings (via their type).<BR><BR>
+<A HREF="<%= $p %>edit/agent.cgi"><I>Add a new agent</I></A><BR><BR>
+
+<% if ( dbdef->table('agent')->column('disabled') ) { %>
+ <%= $cgi->param('showdisabled')
+ ? do { $cgi->param('showdisabled', 0);
+ '( <a href="'. $cgi->self_url. '">hide disabled agents</a> )'; }
+ : do { $cgi->param('showdisabled', 1);
+ '( <a href="'. $cgi->self_url. '">show disabled agents</a> )'; }
+ %>
+<% } %>
+
+<%= table() %>
+<TR>
+ <TH COLSPAN=<%= ( $cgi->param('showdisabled') || !dbdef->table('agent')->column('disabled') ) ? 2 : 3 %>>Agent</TH>
+ <TH>Type</TH>
+ <TH>Customers</TH>
+ <TH><FONT SIZE=-1>Freq.</FONT></TH>
+ <TH><FONT SIZE=-1>Prog.</FONT></TH>
+</TR>
+<%
+# <TH><FONT SIZE=-1>Agent #</FONT></TH>
+# <TH>Agent</TH>
+
+foreach my $agent ( sort {
+ #$a->getfield('agentnum') <=> $b->getfield('agentnum')
+ $a->getfield('agent') cmp $b->getfield('agent')
+} qsearch('agent', \%search ) ) {
+
+ my $cust_main_link = $p. 'search/cust_main.cgi?agentnum_on=1&'.
+ 'agentnum='. $agent->agentnum;
+
+%>
+
+ <TR>
+ <TD><A HREF="<%=$p%>edit/agent.cgi?<%= $agent->agentnum %>">
+ <%= $agent->agentnum %></A></TD>
+<% if ( dbdef->table('agent')->column('disabled')
+ && !$cgi->param('showdisabled') ) { %>
+ <TD><%= $agent->disabled ? 'DISABLED' : '' %></TD>
+<% } %>
+
+ <TD><A HREF="<%=$p%>edit/agent.cgi?<%= $agent->agentnum %>">
+ <%= $agent->agent %></A></TD>
+ <TD><A HREF="<%=$p%>edit/agent_type.cgi?<%= $agent->typenum %>"><%= $agent->agent_type->atype %></A></TD>
+ <TD>
+
+ <B>
+ <%= my $num_prospect = $agent->num_prospect_cust_main %>
+ </B>
+ <% if ( $num_prospect ) { %>
+ <A HREF="<%= $cust_main_link %>&prospect=1"><% } %>prospects<% if ($num_prospect ) { %></A><% } %>
+
+ <BR><FONT COLOR="#00CC00"><B>
+ <%= my $num_active = $agent->num_active_cust_main %>
+ </B></FONT>
+ <% if ( $num_active ) { %>
+ <A HREF="<%= $cust_main_link %>&active=1"><% } %>active<% if ( $num_active ) { %></A><% } %>
+
+ <BR><FONT COLOR="#FF9900"><B>
+ <%= my $num_susp = $agent->num_susp_cust_main %>
+ </B></FONT>
+ <% if ( $num_susp ) { %>
+ <A HREF="<%= $cust_main_link %>&suspended=1"><% } %>suspended<% if ( $num_susp ) { %></A><% } %>
+
+ <BR><FONT COLOR="#FF0000"><B>
+ <%= my $num_cancel = $agent->num_cancel_cust_main %>
+ </B></FONT>
+ <% if ( $num_cancel ) { %>
+ <A HREF="<%= $cust_main_link %>&showcancelledcustomers=1&cancelled=1"><% } %>cancelled<% if ( $num_cancel ) { %></A><% } %>
+ </TD>
+ <TD><%= $agent->freq %></TD>
+ <TD><%= $agent->prog %></TD>
+ </TR>
+
+<% } %>
+
+ </TABLE>
+ </BODY>
+</HTML>
diff --git a/httemplate/browse/agent_type.cgi b/httemplate/browse/agent_type.cgi
new file mode 100755
index 0000000..5473804
--- /dev/null
+++ b/httemplate/browse/agent_type.cgi
@@ -0,0 +1,60 @@
+<!-- mason kludge -->
+<%= header("Agent Type Listing", menubar(
+ 'Main Menu' => $p,
+ 'Agents' => $p. 'browse/agent.cgi',
+)) %>
+Agent types define groups of packages that you can then assign to particular
+agents.<BR><BR>
+<A HREF="<%= $p %>edit/agent_type.cgi"><I>Add a new agent type</I></A><BR><BR>
+
+<%= table() %>
+<TR>
+ <TH COLSPAN=2>Agent Type</TH>
+ <TH COLSPAN=2>Packages</TH>
+</TR>
+
+<%
+foreach my $agent_type ( sort {
+ $a->getfield('typenum') <=> $b->getfield('typenum')
+} qsearch('agent_type',{}) ) {
+ my $hashref = $agent_type->hashref;
+ #more efficient to do this with SQL...
+ my @type_pkgs = grep { $_->part_pkg and ! $_->part_pkg->disabled }
+ qsearch('type_pkgs',{'typenum'=> $hashref->{typenum} });
+ my $rowspan = scalar(@type_pkgs);
+ $rowspan = int($rowspan/2+0.5) ;
+ print <<END;
+ <TR>
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/agent_type.cgi?$hashref->{typenum}">
+ $hashref->{typenum}
+ </A></TD>
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/agent_type.cgi?$hashref->{typenum}">$hashref->{atype}</A></TD>
+END
+
+ my($type_pkgs);
+ my($tdcount) = -1 ;
+ foreach $type_pkgs ( @type_pkgs ) {
+ my($pkgpart)=$type_pkgs->getfield('pkgpart');
+ my($part_pkg) = qsearchs('part_pkg',{'pkgpart'=> $pkgpart });
+ print qq!<TR>! if ($tdcount == 0) ;
+ $tdcount = 0 if ($tdcount == -1) ;
+ print qq!<TD><A HREF="${p}edit/part_pkg.cgi?$pkgpart">!,
+ $part_pkg->getfield('pkg'),"</A></TD>";
+ $tdcount ++ ;
+ if ($tdcount == 2)
+ {
+ print qq!</TR>\n! ;
+ $tdcount = 0 ;
+ }
+ }
+
+ print "</TR>";
+}
+
+print <<END;
+ </TABLE>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/browse/cust_main_county.cgi b/httemplate/browse/cust_main_county.cgi
new file mode 100755
index 0000000..1e0e088
--- /dev/null
+++ b/httemplate/browse/cust_main_county.cgi
@@ -0,0 +1,142 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+my $enable_taxclasses = $conf->exists('enable_taxclasses');
+
+print header("Tax Rate Listing", menubar(
+ 'Main Menu' => $p,
+ 'Edit tax rates' => $p. "edit/cust_main_county.cgi",
+)),<<END;
+ Click on <u>expand country</u> to specify a country's tax rates by state.
+ <BR>Click on <u>expand state</u> to specify a state's tax rates by county.
+END
+
+if ( $enable_taxclasses ) {
+ print '<BR>Click on <u>expand taxclasses</u> to specify tax classes';
+}
+
+print '<BR><BR>'. &table(). <<END;
+ <TR>
+ <TH><FONT SIZE=-1>Country</FONT></TH>
+ <TH><FONT SIZE=-1>State</FONT></TH>
+ <TH>County</TH>
+ <TH>Taxclass<BR><FONT SIZE=-1>(per-package classification)</FONT></TH>
+ <TH>Tax name<BR><FONT SIZE=-1>(printed on invoices)</FONT></TH>
+ <TH><FONT SIZE=-1>Tax</FONT></TH>
+ <TH><FONT SIZE=-1>Exemption</TH>
+ </TR>
+END
+
+my @regions = sort { $a->country cmp $b->country
+ or $a->state cmp $b->state
+ or $a->county cmp $b->county
+ or $a->taxclass cmp $b->taxclass
+ } qsearch('cust_main_county',{});
+
+my $sup=0;
+#foreach $cust_main_county ( @regions ) {
+for ( my $i=0; $i<@regions; $i++ ) {
+ my $cust_main_county = $regions[$i];
+ my $hashref = $cust_main_county->hashref;
+ print <<END;
+ <TR>
+ <TD BGCOLOR="#ffffff">$hashref->{country}</TD>
+END
+
+ my $j;
+ if ( $sup ) {
+ $sup--;
+ } else {
+
+ #lookahead
+ for ( $j=1; $i+$j<@regions; $j++ ) {
+ last if $hashref->{country} ne $regions[$i+$j]->country
+ || $hashref->{state} ne $regions[$i+$j]->state
+ || $hashref->{tax} != $regions[$i+$j]->tax
+ || $hashref->{exempt_amount} != $regions[$i+$j]->exempt_amount
+ || $hashref->{setuptax} ne $regions[$i+$j]->setuptax
+ || $hashref->{recurtax} ne $regions[$i+$j]->recurtax;
+ }
+
+ my $newsup=0;
+ if ( $j>1 && $i+$j+1 < @regions
+ && ( $hashref->{state} ne $regions[$i+$j+1]->state
+ || $hashref->{country} ne $regions[$i+$j+1]->country
+ )
+ && ( ! $i
+ || $hashref->{state} ne $regions[$i-1]->state
+ || $hashref->{country} ne $regions[$i-1]->country
+ )
+ ) {
+ $sup = $j-1;
+ } else {
+ $j = 1;
+ }
+
+ print "<TD ROWSPAN=$j", $hashref->{state}
+ ? ' BGCOLOR="#ffffff">'. $hashref->{state}
+ : qq! BGCOLOR="#cccccc">(ALL) <FONT SIZE=-1>!.
+ qq!<A HREF="${p}edit/cust_main_county-expand.cgi?!. $hashref->{taxnum}.
+ qq!">expand country</A></FONT>!;
+
+ print qq! <FONT SIZE=-1><A HREF="${p}edit/process/cust_main_county-collapse.cgi?!. $hashref->{taxnum}. qq!">collapse state</A></FONT>! if $j>1;
+
+ print "</TD>";
+ }
+
+# $sup=$newsup;
+
+ print "<TD";
+ if ( $hashref->{county} ) {
+ print ' BGCOLOR="#ffffff">'. $hashref->{county};
+ } else {
+ print ' BGCOLOR="#cccccc">(ALL)';
+ if ( $hashref->{state} ) {
+ print qq!<FONT SIZE=-1>!.
+ qq!<A HREF="${p}edit/cust_main_county-expand.cgi?!. $hashref->{taxnum}.
+ qq!">expand state</A></FONT>!;
+ }
+ }
+ print "</TD>";
+
+ print "<TD";
+ if ( $hashref->{taxclass} ) {
+ print ' BGCOLOR="#ffffff">'. $hashref->{taxclass};
+ } else {
+ print ' BGCOLOR="#cccccc">(ALL)';
+ if ( $enable_taxclasses ) {
+ print qq!<FONT SIZE=-1>!.
+ qq!<A HREF="${p}edit/cust_main_county-expand.cgi?taxclass!.
+ $hashref->{taxnum}. qq!">expand taxclasses</A></FONT>!;
+ }
+
+ }
+ print "</TD>";
+
+ print "<TD";
+ if ( $hashref->{taxname} ) {
+ print ' BGCOLOR="#ffffff">'. $hashref->{taxname};
+ } else {
+ print ' BGCOLOR="#cccccc">Tax';
+ }
+ print "</TD>";
+
+ print "<TD BGCOLOR=\"#ffffff\">$hashref->{tax}%</TD>".
+ '<TD BGCOLOR="#ffffff">';
+ print '$'. sprintf("%.2f", $hashref->{exempt_amount} ).
+ '&nbsp;per&nbsp;month<BR>'
+ if $hashref->{exempt_amount} > 0;
+ print 'Setup&nbsp;fee<BR>' if $hashref->{setuptax} =~ /^Y$/i;
+ print 'Recurring&nbsp;fee<BR>' if $hashref->{recurtax} =~ /^Y$/i;
+ print '</TD></TR>';
+
+}
+
+print <<END;
+ </TABLE>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/browse/cust_pay_batch.cgi b/httemplate/browse/cust_pay_batch.cgi
new file mode 100755
index 0000000..3420e97
--- /dev/null
+++ b/httemplate/browse/cust_pay_batch.cgi
@@ -0,0 +1,76 @@
+<!-- mason kludge -->
+<%= header("Pending credit card batch", menubar( 'Main Menu' => $p,)) %>
+
+<FORM ACTION="<%=$p%>misc/download-batch.cgi" METHOD="POST">
+Download batch in format <SELECT NAME="format">
+<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV file for TD Canada Trust Merchant PC Batch</OPTION>
+</SELECT><INPUT TYPE="submit" VALUE="Download"></FORM>
+<BR><BR>
+
+<FORM ACTION="<%=$p%>misc/upload-batch.cgi" METHOD="POST" ENCTYPE="multipart/form-data">
+Upload results<BR>
+Filename <INPUT TYPE="file" NAME="batch_results"><BR>
+Format <SELECT NAME="format">
+<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV results from TD Canada Trust Merchant PC Batch</OPTION>
+</SELECT><BR>
+<INPUT TYPE="submit" VALUE="Upload"></FORM>
+<BR>
+
+<%
+ my $statement = "SELECT SUM(amount) from cust_pay_batch";
+ my $sth = dbh->prepare($statement) or die dbh->errstr. "doing $statement";
+ $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
+ my $total = $sth->fetchrow_arrayref->[0];
+
+ my $c_statement = "SELECT COUNT(*) from cust_pay_batch";
+ my $c_sth = dbh->prepare($c_statement)
+ or die dbh->errstr. "doing $c_statement";
+ $c_sth->execute or die "Error executing \"$c_statement\": ". $c_sth->errstr;
+ my $cards = $c_sth->fetchrow_arrayref->[0];
+%>
+<%= $cards %> credit card payments batched<BR>
+$<%= sprintf("%.2f", $total) %> total in pending batch<BR>
+
+<BR>
+<%= &table() %>
+ <TR>
+ <TH>#</TH>
+ <TH><font size=-1>inv#</font></TH>
+ <TH COLSPAN=2>Customer</TH>
+ <TH>Card name</TH>
+ <TH>Card</TH>
+ <TH>Exp</TH>
+ <TH>Amount</TH>
+ </TR>
+
+<%
+foreach my $cust_pay_batch ( sort { $a->paybatchnum <=> $b->paybatchnum }
+ qsearch('cust_pay_batch', {} )
+) {
+ my $cardnum = $cust_pay_batch->cardnum;
+ #$cardnum =~ s/.{4}$/xxxx/;
+ $cardnum = 'x'x(length($cardnum)-4). substr($cardnum,(length($cardnum)-4));
+
+ $cust_pay_batch->exp =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
+ my( $mon, $year ) = ( $2, $1 );
+ $mon = "0$mon" if $mon < 10;
+ my $exp = "$mon/$year";
+
+%>
+
+ <TR>
+ <TD><%= $cust_pay_batch->paybatchnum %></TD>
+ <TD><A HREF="../view/cust_bill.cgi?<%= $cust_pay_batch->invnum %>"><%= $cust_pay_batch->invnum %></TD>
+ <TD><A HREF="../view/cust_main.cgi?<%= $cust_pay_batch->custnum %>"><%= $cust_pay_batch->custnum %></TD>
+ <TD><%= $cust_pay_batch->get('last'). ', '. $cust_pay_batch->first %></TD>
+ <TD><%= $cust_pay_batch->payname %></TD>
+ <TD><%= $cardnum %></TD>
+ <TD><%= $exp %></TD>
+ <TD align="right">$<%= $cust_pay_batch->amount %></TD>
+ </TR>
+
+<% } %>
+
+ </TABLE>
+ </BODY>
+</HTML>
diff --git a/httemplate/browse/generic.cgi b/httemplate/browse/generic.cgi
new file mode 100644
index 0000000..9ac0f23
--- /dev/null
+++ b/httemplate/browse/generic.cgi
@@ -0,0 +1,46 @@
+<%
+
+use FS::Record qw(qsearch dbdef);
+use DBIx::DBSchema;
+use DBIx::DBSchema::Table;
+
+my $error;
+my $p2 = popurl(2);
+my ($table) = $cgi->keywords;
+my $dbdef = dbdef or die "Cannot fetch dbdef!";
+my $dbdef_table = $dbdef->table($table) or die "Cannot fetch schema for $table";
+
+my $pkey = $dbdef_table->primary_key or die "Cannot fetch pkey for $table";
+print header("Browse $table", menubar('Main Menu' => $p));
+
+my @rec = qsearch($table, {});
+my @col = $dbdef_table->columns;
+
+if ($cgi->param('error')) { %>
+ <FONT SIZE="+1" COLOR="#ff0000">Error: <%=$cgi->param('error')%></FONT>
+ <BR><BR>
+<% }
+%>
+<A HREF="<%=$p2%>edit/<%=$table%>.cgi"><I>Add a new <%=$table%></I></A><BR><BR>
+
+<%=table()%>
+<TH>
+<% foreach (grep { $_ ne $pkey } @col) {
+ %><TD><%=$_%></TD>
+ <% } %>
+</TH>
+<% foreach $rec (sort {$a->getfield($pkey) cmp $b->getfield($pkey) } @rec) {
+ %>
+ <TR>
+ <TD>
+ <A HREF="<%=$p2%>edit/<%=$table%>.cgi?<%=$rec->getfield($pkey)%>">
+ <%=$rec->getfield($pkey)%></A> </TD> <%
+ foreach $col (grep { $_ ne $pkey } @col) { %>
+ <TD><%=$rec->getfield($col)%></TD> <% } %>
+ </A>
+ </TR>
+<% } %>
+</TABLE>
+</BODY>
+</HTML>
+
diff --git a/httemplate/browse/msgcat.cgi b/httemplate/browse/msgcat.cgi
new file mode 100755
index 0000000..d4adf9f
--- /dev/null
+++ b/httemplate/browse/msgcat.cgi
@@ -0,0 +1,50 @@
+<!-- mason kludge -->
+<%
+
+print header("View Message catalog", menubar(
+ 'Main Menu' => $p,
+ 'Edit message catalog' => $p. "edit/msgcat.cgi",
+)), '<BR>';
+
+my $widget = new HTML::Widgets::SelectLayers(
+ 'selected_layer' => 'en_US',
+ 'options' => { 'en_US'=>'en_US' },
+ 'layer_callback' => sub {
+ my $layer = shift;
+ my $html = "<BR>Messages for locale $layer<BR>". table().
+ "<TR><TH COLSPAN=2>Code</TH>".
+ "<TH>Message</TH>";
+ $html .= "<TH>en_US Message</TH>" unless $layer eq 'en_US';
+ $html .= '</TR>';
+
+ #foreach my $msgcat ( sort { $a->msgcode cmp $b->msgcode }
+ # qsearch('msgcat', { 'locale' => $layer } ) ) {
+ foreach my $msgcat ( qsearch('msgcat', { 'locale' => $layer } ) ) {
+ $html .= '<TR><TD>'. $msgcat->msgnum. '</TD>'.
+ '<TD>'. $msgcat->msgcode. '</TD>'.
+ '<TD>'. $msgcat->msg. '</TD>';
+ unless ( $layer eq 'en_US' ) {
+ my $en_msgcat = qsearchs('msgcat', {
+ 'locale' => 'en_US',
+ 'msgcode' => $msgcat->msgcode,
+ } );
+ $html .= '<TD>'. $en_msgcat->msg. '</TD>';
+ }
+ $html .= '</TR>';
+ }
+
+ $html .= '</TABLE>';
+ $html;
+ },
+
+);
+
+print $widget->html;
+
+print <<END;
+ </TABLE>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/browse/nas.cgi b/httemplate/browse/nas.cgi
new file mode 100755
index 0000000..9ccbfe6
--- /dev/null
+++ b/httemplate/browse/nas.cgi
@@ -0,0 +1,80 @@
+<!-- mason kludge -->
+<%
+
+print header('NAS ports', menubar(
+ 'Main Menu' => $p,
+));
+
+my $now = time;
+
+foreach my $nas ( sort { $a->nasnum <=> $b->nasnum } qsearch( 'nas', {} ) ) {
+ print $nas->nasnum. ": ". $nas->nas. " ".
+ $nas->nasfqdn. " (". $nas->nasip. ") ".
+ "as of ". time2str("%c",$nas->last).
+ " (". &pretty_interval($now - $nas->last). " ago)<br>".
+ &table(). "<TR><TH>Nas<BR>Port #</TH><TH>Global<BR>Port #</BR></TH>".
+ "<TH>IP address</TH><TH>User</TH><TH>Since</TH><TH>Duration</TH><TR>",
+ ;
+ foreach my $port ( sort {
+ $a->nasport <=> $b->nasport || $a->portnum <=> $b->portnum
+ } qsearch( 'port', { 'nasnum' => $nas->nasnum } ) ) {
+ my $session = $port->session;
+ my($user, $since, $pretty_since, $duration);
+ if ( ! $session ) {
+ $user = "(empty)";
+ $since = 0;
+ $pretty_since = "(never)";
+ $duration = '';
+ } elsif ( $session->logout ) {
+ $user = "(empty)";
+ $since = $session->logout;
+ } else {
+ my $svc_acct = $session->svc_acct;
+ $user = "<A HREF=\"$p/view/svc_acct.cgi?". $svc_acct->svcnum. "\">".
+ $svc_acct->username. "</A>";
+ $since = $session->login;
+ }
+ $pretty_since = time2str("%c", $since) if $since;
+ $duration = pretty_interval( $now - $since ). " ago"
+ unless defined($duration);
+ print "<TR><TD>". $port->nasport. "</TD><TD>". $port->portnum. "</TD><TD>".
+ $port->ip. "</TD><TD>$user</TD><TD>$pretty_since".
+ "</TD><TD>$duration</TD></TR>"
+ ;
+ }
+ print "</TABLE><BR>";
+}
+
+#Time::Duration??
+sub pretty_interval {
+ my $interval = shift;
+ my %howlong = (
+ '604800' => 'week',
+ '86400' => 'day',
+ '3600' => 'hour',
+ '60' => 'minute',
+ '1' => 'second',
+ );
+
+ my $pretty = "";
+ foreach my $key ( sort { $b <=> $a } keys %howlong ) {
+ my $value = int( $interval / $key );
+ if ( $value ) {
+ if ( $value == 1 ) {
+ $pretty .=
+ ( $howlong{$key} eq 'hour' ? 'an ' : 'a ' ). $howlong{$key}. " "
+ } else {
+ $pretty .= $value. ' '. $howlong{$key}. 's ';
+ }
+ }
+ $interval -= $value * $key;
+ }
+ $pretty =~ /^\s*(\S.*\S)\s*$/;
+ $1;
+}
+
+#print &table(), <<END;
+#<TR>
+# <TH>#</TH>
+# <TH>NAS</
+%>
diff --git a/httemplate/browse/part_bill_event.cgi b/httemplate/browse/part_bill_event.cgi
new file mode 100755
index 0000000..670474d
--- /dev/null
+++ b/httemplate/browse/part_bill_event.cgi
@@ -0,0 +1,71 @@
+<!-- mason kludge -->
+<%
+
+my %search;
+if ( $cgi->param('showdisabled') ) {
+ %search = ();
+} else {
+ %search = ( 'disabled' => '' );
+}
+
+my @part_bill_event = qsearch('part_bill_event', \%search );
+my $total = scalar(@part_bill_event);
+
+%>
+<%= header('Invoice Event Listing', menubar( 'Main Menu' => $p) ) %>
+
+ Invoice events are actions taken on overdue invoices.<BR><BR>
+<A HREF="<%= $p %>edit/part_bill_event.cgi"><I>Add a new invoice event</I></A>
+<BR><BR>
+<%= $total %> events
+<%= $cgi->param('showdisabled')
+ ? do { $cgi->param('showdisabled', 0);
+ '( <a href="'. $cgi->self_url. '">hide disabled events</a> )'; }
+ : do { $cgi->param('showdisabled', 1);
+ '( <a href="'. $cgi->self_url. '">show disabled events</a> )'; }
+%>
+<%= table() %>
+ <TR>
+ <TH COLSPAN=<%= $cgi->param('showdisabled') ? 2 : 3 %>>Event</TH>
+ <TH>Payby</TH>
+ <TH>After</TH>
+ <TH>Action</TH>
+ <TH>Options</TH>
+ <TH>Code</TH>
+ </TR>
+
+<% foreach my $part_bill_event ( sort { $a->payby cmp $b->payby
+ || $a->seconds <=> $b->seconds
+ || $a->weight <=> $b->weight
+ || $a->eventpart <=> $b->eventpart
+ } @part_bill_event ) {
+ my $url = "${p}edit/part_bill_event.cgi?". $part_bill_event->eventpart;
+ use Time::Duration;
+ my $delay = duration_exact($part_bill_event->seconds);
+ my $plandata = $part_bill_event->plandata;
+ $plandata =~ s/\n/<BR>/go;
+%>
+ <TR>
+ <TD><A HREF="<%= $url %>">
+ <%= $part_bill_event->eventpart %></A></TD>
+<% unless ( $cgi->param('showdisabled') ) { %>
+ <TD>
+ <%= $part_bill_event->disabled ? 'DISABLED' : '' %></TD>
+<% } %>
+ <TD><A HREF="<%= $url %>">
+ <%= $part_bill_event->event %></A></TD>
+ <TD>
+ <%= $part_bill_event->payby %></TD>
+ <TD>
+ <%= $delay %></TD>
+ <TD>
+ <%= $part_bill_event->plan %></TD>
+ <TD>
+ <%= $plandata %></TD>
+ <TD><FONT SIZE="-1">
+ <%= $part_bill_event->eventcode %></FONT></TD>
+ </TR>
+<% } %>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/httemplate/browse/part_export.cgi b/httemplate/browse/part_export.cgi
new file mode 100755
index 0000000..79c57ae
--- /dev/null
+++ b/httemplate/browse/part_export.cgi
@@ -0,0 +1,39 @@
+<!-- mason kludge -->
+<%= header("Export Listing", menubar( 'Main Menu' => "$p#sysadmin" )) %>
+Provisioning services to external machines, databases and APIs.<BR><BR>
+<A HREF="<%= $p %>edit/part_export.cgi"><I>Add a new export</I></A><BR><BR>
+<SCRIPT>
+function part_export_areyousure(href) {
+ if (confirm("Are you sure you want to delete this export?") == true)
+ window.location.href = href;
+}
+</SCRIPT>
+
+<%= table() %>
+ <TR>
+ <TH COLSPAN=2>Export</TH>
+ <TH>Options</TH>
+ </TR>
+
+<% foreach my $part_export ( sort {
+ $a->getfield('exportnum') <=> $b->getfield('exportnum')
+ } qsearch('part_export',{}) ) {
+%>
+ <TR>
+ <TD><A HREF="<%= $p %>edit/part_export.cgi?<%= $part_export->exportnum %>"><%= $part_export->exportnum %></A></TD>
+ <TD><%= $part_export->exporttype %> to <%= $part_export->machine %> (<A HREF="<%= $p %>edit/part_export.cgi?<%= $part_export->exportnum %>">edit</A>&nbsp;|&nbsp;<A HREF="javascript:part_export_areyousure('<%= $p %>misc/delete-part_export.cgi?<%= $part_export->exportnum %>')">delete</A>)</TD>
+ <TD>
+ <%= itable() %>
+ <% my %opt = $part_export->options;
+ foreach my $opt ( keys %opt ) { %>
+ <TR><TD><%= $opt %></TD><TD><%= encode_entities($opt{$opt}) %></TD></TR>
+ <% } %>
+ </TABLE>
+ </TD>
+ </TR>
+
+<% } %>
+
+</TABLE>
+</BODY>
+</HTML>
diff --git a/httemplate/browse/part_pkg.cgi b/httemplate/browse/part_pkg.cgi
new file mode 100755
index 0000000..180f182
--- /dev/null
+++ b/httemplate/browse/part_pkg.cgi
@@ -0,0 +1,173 @@
+<!-- mason kludge -->
+<%
+
+my %search;
+if ( $cgi->param('showdisabled') ) {
+ %search = ();
+} else {
+ %search = ( 'disabled' => '' );
+}
+
+my @part_pkg = qsearch('part_pkg', \%search );
+my $total = scalar(@part_pkg);
+
+my $sortby;
+my %num_active_cust_pkg = ();
+my( $suspended_sth, $canceled_sth ) = ( '', '' );
+if ( $cgi->param('active') ) {
+ my $active_sth = dbh->prepare(
+ 'SELECT COUNT(*) FROM cust_pkg WHERE pkgpart = ?'.
+ ' AND ( cancel IS NULL OR cancel = 0 )'.
+ ' AND ( susp IS NULL OR susp = 0 )'
+ ) or die dbh->errstr;
+ foreach my $part_pkg ( @part_pkg ) {
+ $active_sth->execute($part_pkg->pkgpart) or die $active_sth->errstr;
+ $num_active_cust_pkg{$part_pkg->pkgpart} =
+ $active_sth->fetchrow_arrayref->[0];
+ }
+ $sortby = sub {
+ $num_active_cust_pkg{$b->pkgpart} <=> $num_active_cust_pkg{$a->pkgpart};
+ };
+
+ $suspended_sth = dbh->prepare(
+ 'SELECT COUNT(*) FROM cust_pkg WHERE pkgpart = ?'.
+ ' AND ( cancel IS NULL OR cancel = 0 )'.
+ ' AND susp IS NOT NULL AND susp != 0'
+ ) or die dbh->errstr;
+
+ $canceled_sth = dbh->prepare(
+ 'SELECT COUNT(*) FROM cust_pkg WHERE pkgpart = ?'.
+ ' AND cancel IS NOT NULL AND cancel != 0'
+ ) or die dbh->errstr;
+
+} else {
+ $sortby = \*pkgpart_sort;
+}
+
+%>
+<%= header("Package Definition Listing",menubar( 'Main Menu' => $p )) %>
+<% unless ( $cgi->param('active') ) { %>
+ One or more service definitions are grouped together into a package
+ definition and given pricing information. Customers purchase packages
+ rather than purchase services directly.<BR><BR>
+ <A HREF="<%= $p %>edit/part_pkg.cgi"><I>Add a new package definition</I></A>
+ <BR><BR>
+<% } %>
+
+<%= $total %> package definitions
+<%
+if ( $cgi->param('showdisabled') ) {
+ $cgi->param('showdisabled', 0);
+ print qq!( <a href="!. $cgi->self_url. qq!">hide disabled packages</a> )!;
+} else {
+ $cgi->param('showdisabled', 1);
+ print qq!( <a href="!. $cgi->self_url. qq!">show disabled packages</a> )!;
+}
+
+my $colspan = $cgi->param('showdisabled') ? 2 : 3;
+print &table(), <<END;
+ <TR>
+ <TH COLSPAN=$colspan>Package</TH>
+ <TH>Comment</TH>
+END
+print ' <TH><FONT SIZE=-1>Customer<BR>packages</FONT></TH>'
+ if $cgi->param('active');
+print <<END;
+ <TH><FONT SIZE=-1>Freq.</FONT></TH>
+ <TH><FONT SIZE=-1>Plan</FONT></TH>
+ <TH><FONT SIZE=-1>Data</FONT></TH>
+ <TH>Service</TH>
+ <TH><FONT SIZE=-1>Quan.</FONT></TH>
+END
+print '<TH><FONT SIZE=-1>Primary</FONT></TH>'
+ if dbdef->table('pkg_svc')->column('primary_svc');
+print '</TR>';
+
+foreach my $part_pkg ( sort $sortby @part_pkg ) {
+ my($hashref)=$part_pkg->hashref;
+ my(@pkg_svc)=grep $_->getfield('quantity'),
+ qsearch('pkg_svc',{'pkgpart'=> $hashref->{pkgpart} });
+ my($rowspan)=scalar(@pkg_svc);
+ my $plandata;
+ if ( $hashref->{plan} ) {
+ $plandata = $hashref->{plandata};
+ $plandata =~ s/^(\w+)=/$1&nbsp;/mg;
+ $plandata =~ s/\n/<BR>/g;
+ } else {
+ $hashref->{plan} = "(legacy)";
+ $plandata = "Setup&nbsp;". $hashref->{setup}.
+ "<BR>Recur&nbsp;". $hashref->{recur};
+ }
+ print <<END;
+ <TR>
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/part_pkg.cgi?$hashref->{pkgpart}">$hashref->{pkgpart}</A></TD>
+END
+
+ unless ( $cgi->param('showdisabled') ) {
+ print "<TD ROWSPAN=$rowspan>";
+ print "DISABLED" if $hashref->{disabled};
+ print '</TD>';
+ }
+
+ print <<END;
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/part_pkg.cgi?$hashref->{pkgpart}">$hashref->{pkg}</A></TD>
+ <TD ROWSPAN=$rowspan>$hashref->{comment}</TD>
+END
+ if ( $cgi->param('active') ) {
+ print " <TD ROWSPAN=$rowspan>";
+ print '<FONT COLOR="#00CC00"><B>'.
+ $num_active_cust_pkg{$hashref->{'pkgpart'}}.
+ qq!</B></FONT>&nbsp;<A HREF="${p}search/cust_pkg.cgi?magic=active;pkgpart=$hashref->{pkgpart}">active</A><BR>!;
+
+ $suspended_sth->execute( $part_pkg->pkgpart ) or die $suspended_sth->errstr;
+ my $num_suspended = $suspended_sth->fetchrow_arrayref->[0];
+ print '<FONT COLOR="#FF9900"><B>'. $num_suspended.
+ qq!</B></FONT>&nbsp;<A HREF="${p}search/cust_pkg.cgi?magic=suspended;pkgpart=$hashref->{pkgpart}">suspended</A><BR>!;
+
+ $canceled_sth->execute( $part_pkg->pkgpart ) or die $canceled_sth->errstr;
+ my $num_canceled = $canceled_sth->fetchrow_arrayref->[0];
+ print '<FONT COLOR="#FF0000"><B>'. $num_canceled.
+ qq!</B></FONT>&nbsp;<A HREF="${p}search/cust_pkg.cgi?magic=canceled;pkgpart=$hashref->{pkgpart}">canceled</A>!;
+
+
+ print '</TD>';
+ }
+ print <<END;
+ <TD ROWSPAN=$rowspan>$hashref->{freq}</TD>
+ <TD ROWSPAN=$rowspan>$hashref->{plan}</TD>
+ <TD ROWSPAN=$rowspan>$plandata</TD>
+END
+
+ my($pkg_svc);
+ my($n)="";
+ foreach $pkg_svc ( @pkg_svc ) {
+ my($svcpart)=$pkg_svc->getfield('svcpart');
+ my($part_svc) = qsearchs('part_svc',{'svcpart'=> $svcpart });
+ print $n,qq!<TD><A HREF="${p}edit/part_svc.cgi?$svcpart">!,
+ $part_svc->getfield('svc'),"</A></TD><TD>",
+ $pkg_svc->getfield('quantity'),"</TD>";
+ if ( dbdef->table('pkg_svc')->column('primary_svc') ) {
+ print '<TD>';
+ print 'PRIMARY' if $pkg_svc->primary_svc =~ /^Y/i;
+ print '</TD>';
+ }
+ print "</TR>\n";
+ $n="<TR>";
+ }
+
+ print "</TR>";
+}
+
+$colspan = $cgi->param('showdisabled') ? 8 : 9;
+print <<END;
+
+ </TABLE>
+ </BODY>
+</HTML>
+END
+
+sub pkgpart_sort {
+ $a->pkgpart <=> $b->pkgpart;
+}
+
+%>
diff --git a/httemplate/browse/part_referral.cgi b/httemplate/browse/part_referral.cgi
new file mode 100755
index 0000000..581e01b
--- /dev/null
+++ b/httemplate/browse/part_referral.cgi
@@ -0,0 +1,97 @@
+<!-- mason kludge -->
+<%= header("Advertising source Listing", menubar(
+ 'Main Menu' => $p,
+# 'Add new referral' => "../edit/part_referral.cgi",
+)) %>
+Where a customer heard about your service. Tracked for informational purposes.
+<BR><BR>
+<A HREF="<%= $p %>edit/part_referral.cgi"><I>Add a new advertising source</I></A>
+<BR><BR>
+
+<%
+ my $today = timelocal(0, 0, 0, (localtime(time))[3..5] );
+ my %after;
+ tie %after, 'Tie::IxHash',
+ 'Today' => 0,
+ 'Yesterday' => 86400, # 60sec * 60min * 24hrs
+ 'Past week' => 518400, # 60sec * 60min * 24hrs * 6days
+ 'Past 30 days' => 2505600, # 60sec * 60min * 24hrs * 29days
+ 'Past 60 days' => 5097600, # 60sec * 60min * 24hrs * 59days
+ 'Past 90 days' => 7689600, # 60sec * 60min * 24hrs * 89days
+ 'Past 6 months' => 15724800, # 60sec * 60min * 24hrs * 182days
+ 'Past year' => 31486000, # 60sec * 60min * 24hrs * 364days
+ 'Total' => $today,
+ ;
+ my %before = (
+ 'Today' => 86400, # 60sec * 60min * 24hrs
+ 'Yesterday' => 0,
+ 'Past week' => 86400, # 60sec * 60min * 24hrs
+ 'Past 30 days' => 86400, # 60sec * 60min * 24hrs
+ 'Past 60 days' => 86400, # 60sec * 60min * 24hrs
+ 'Past 90 days' => 86400, # 60sec * 60min * 24hrs
+ 'Past 6 months' => 86400, # 60sec * 60min * 24hrs
+ 'Past year' => 86400, # 60sec * 60min * 24hrs
+ 'Total' => 86400, # 60sec * 60min * 24hrs
+ );
+
+ my $statement = "SELECT COUNT(*) FROM h_cust_main
+ WHERE history_action = 'insert'
+ AND refnum = ?
+ AND history_date >= ?
+ AND history_date < ?
+ ";
+ my $sth = dbh->prepare($statement)
+ or die dbh->errstr;
+%>
+
+<%= table() %>
+<TR>
+ <TH COLSPAN=2 ROWSPAN=2>Advertising source</TH>
+ <TH COLSPAN=<%= scalar(keys %after) %>>Customers</TH>
+</TR>
+<% for my $period ( keys %after ) { %>
+ <TH><FONT SIZE=-1><%= $period %></FONT></TH>
+<% } %>
+</TR>
+
+<%
+foreach my $part_referral ( sort {
+ $a->getfield('refnum') <=> $b->getfield('refnum')
+} qsearch('part_referral',{}) ) {
+%>
+ <TR>
+ <TD><A HREF="<%= $p %>edit/part_referral.cgi?<%= $part_referral->refnum %>">
+ <%= $part_referral->refnum %></A></TD>
+ <TD><A HREF="<%= $p %>edit/part_referral.cgi?<%= $part_referral->refnum %>">
+ <%= $part_referral->referral %></A></TD>
+ <% for my $period ( keys %after ) {
+ $sth->execute( $part_referral->refnum,
+ $today-$after{$period},
+ $today+$before{$period},
+ ) or die $sth->errstr;
+ my $number = $sth->fetchrow_arrayref->[0];
+ %>
+ <TD ALIGN="right"><%= $number %></TD>
+ <% } %>
+ </TR>
+<% } %>
+
+<%
+ $statement =~ s/AND refnum = \?//;
+ $sth = dbh->prepare($statement)
+ or die dbh->errstr;
+%>
+ <TR>
+ <TH COLSPAN=2>Total</TH>
+ <% for my $period ( keys %after ) {
+ $sth->execute( $today-$after{$period},
+ $today+$before{$period},
+ ) or die $sth->errstr;
+ my $number = $sth->fetchrow_arrayref->[0];
+ %>
+ <TD ALIGN="right"><%= $number %></TD>
+ <% } %>
+ </TR>
+ </TABLE>
+ </BODY>
+</HTML>
diff --git a/httemplate/browse/part_svc.cgi b/httemplate/browse/part_svc.cgi
new file mode 100755
index 0000000..ef0de13
--- /dev/null
+++ b/httemplate/browse/part_svc.cgi
@@ -0,0 +1,133 @@
+<!-- mason kludge -->
+<%
+
+my %search;
+if ( $cgi->param('showdisabled') ) {
+ %search = ();
+} else {
+ %search = ( 'disabled' => '' );
+}
+
+my @part_svc =
+ sort { $a->getfield('svcpart') <=> $b->getfield('svcpart') }
+ qsearch('part_svc', \%search );
+my $total = scalar(@part_svc);
+
+my %num_active_cust_svc = ();
+if ( $cgi->param('active') ) {
+ my $active_sth = dbh->prepare(
+ 'SELECT COUNT(*) FROM cust_svc WHERE svcpart = ?'
+ ) or die dbh->errstr;
+ foreach my $part_svc ( @part_svc ) {
+ $active_sth->execute($part_svc->svcpart) or die $active_sth->errstr;
+ $num_active_cust_svc{$part_svc->svcpart} =
+ $active_sth->fetchrow_arrayref->[0];
+ }
+ @part_svc = sort { $num_active_cust_svc{$b->svcpart} <=>
+ $num_active_cust_svc{$a->svcpart} } @part_svc;
+}
+
+%>
+<%= header('Service Definition Listing', menubar( 'Main Menu' => $p) ) %>
+
+<SCRIPT>
+function part_export_areyousure(href) {
+ if (confirm("Are you sure you want to delete this export?") == true)
+ window.location.href = href;
+}
+</SCRIPT>
+
+ Service definitions are the templates for items you offer to your customers.<BR><BR>
+
+<FORM METHOD="POST" ACTION="<%= $p %>edit/part_svc.cgi">
+<A HREF="<%= $p %>edit/part_svc.cgi"><I>Add a new service definition</I></A><% if ( @part_svc ) { %>&nbsp;or&nbsp;<SELECT NAME="clone"><OPTION></OPTION>
+<% foreach my $part_svc ( @part_svc ) { %>
+ <OPTION VALUE="<%= $part_svc->svcpart %>"><%= $part_svc->svc %></OPTION>
+<% } %>
+</SELECT><INPUT TYPE="submit" VALUE="Clone existing service">
+<% } %>
+</FORM><BR>
+
+<%= $total %> service definitions
+<%= $cgi->param('showdisabled')
+ ? do { $cgi->param('showdisabled', 0);
+ '( <a href="'. $cgi->self_url. '">hide disabled services</a> )'; }
+ : do { $cgi->param('showdisabled', 1);
+ '( <a href="'. $cgi->self_url. '">show disabled services</a> )'; }
+%>
+<%= table() %>
+ <TR>
+ <TH COLSPAN=<%= $cgi->param('showdisabled') ? 2 : 3 %>>Service</TH>
+ <TH>Table</TH>
+<% if ( $cgi->param('active') ) { %>
+ <TH><FONT SIZE=-1>Customer<BR>Services</FONT></TH>
+<% } %>
+ <TH>Export</TH>
+ <TH>Field</TH>
+ <TH COLSPAN=2>Modifier</TH>
+ </TR>
+
+<% foreach my $part_svc ( @part_svc ) {
+ my $hashref = $part_svc->hashref;
+ my $svcdb = $hashref->{svcdb};
+ my $svc_x = "FS::$svcdb"->new( { svcpart => $part_svc->svcpart } );
+ my @dfields = $svc_x->fields;
+ push @dfields, 'usergroup' if $svcdb eq 'svc_acct'; #kludge
+ my @fields =
+ grep { $svc_x->pvf($_)
+ or $_ ne 'svcnum' && $part_svc->part_svc_column($_)->columnflag }
+ @dfields ;
+ my $rowspan = scalar(@fields) || 1;
+ my $url = "${p}edit/part_svc.cgi?$hashref->{svcpart}";
+%>
+
+ <TR>
+ <TD ROWSPAN=<%= $rowspan %>><A HREF="<%= $url %>">
+ <%= $hashref->{svcpart} %></A></TD>
+<% unless ( $cgi->param('showdisabled') ) { %>
+ <TD ROWSPAN=<%= $rowspan %>>
+ <%= $hashref->{disabled} ? 'DISABLED' : '' %></TD>
+<% } %>
+ <TD ROWSPAN=<%= $rowspan %>><A HREF="<%= $url %>">
+ <%= $hashref->{svc} %></A></TD>
+ <TD ROWSPAN=<%= $rowspan %>>
+ <%= $hashref->{svcdb} %></TD>
+<% if ( $cgi->param('active') ) { %>
+ <TD ROWSPAN=<%= $rowspan %>>
+ <FONT COLOR="#00CC00"><B><%= $num_active_cust_svc{$hashref->{svcpart}} %></B></FONT>&nbsp;<A HREF="<%=$p%>search/<%= $hashref->{svcdb} %>.cgi?svcpart=<%= $hashref->{svcpart} %>">active</A>
+ </TD>
+<% } %>
+ <TD ROWSPAN=<%= $rowspan %>><%= itable() %>
+<%
+# my @part_export =
+map { qsearchs('part_export', { exportnum => $_->exportnum } ) } qsearch('export_svc', { svcpart => $part_svc->svcpart } ) ;
+ foreach my $part_export (
+ map { qsearchs('part_export', { exportnum => $_->exportnum } ) }
+ qsearch('export_svc', { svcpart => $part_svc->svcpart } )
+ ) {
+%>
+ <TR>
+ <TD><A HREF="<%= $p %>edit/part_export.cgi?<%= $part_export->exportnum %>"><%= $part_export->exportnum %>:&nbsp;<%= $part_export->exporttype %>&nbsp;to&nbsp;<%= $part_export->machine %></A></TD></TR>
+<% } %>
+ </TABLE></TD>
+
+<% my($n1)='';
+ foreach my $field ( @fields ) {
+ my $flag = $part_svc->part_svc_column($field)->columnflag;
+%>
+ <%= $n1 %><TD><%= $field %></TD><TD>
+
+<% if ( $flag eq "D" ) { print "Default"; }
+ elsif ( $flag eq "F" ) { print "Fixed"; }
+ elsif ( not $flag ) { }
+ else { print "(Unknown!)"; }
+%>
+ </TD><TD><%= $part_svc->part_svc_column($field)->columnvalue%></TD>
+<% $n1="</TR><TR>";
+ }
+%>
+ </TR>
+<% } %>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/httemplate/browse/part_virtual_field.cgi b/httemplate/browse/part_virtual_field.cgi
new file mode 100644
index 0000000..a0009da
--- /dev/null
+++ b/httemplate/browse/part_virtual_field.cgi
@@ -0,0 +1,39 @@
+<%= header('Virtual field definitions', menubar('Main Menu' => $p)) %>
+<%
+
+my %pvfs;
+my $block;
+my $p2 = popurl(2);
+my $dbtable;
+
+foreach (qsearch('part_virtual_field', {})) {
+ push @{ $pvfs{$_->dbtable} }, $_;
+}
+%>
+
+<% if ($cgi->param('error')) { %>
+ <FONT SIZE="+1" COLOR="#ff0000">Error: <%=$cgi->param('error')%></FONT>
+ <BR><BR>
+<% } %>
+
+<A HREF="<%=$p2%>edit/part_virtual_field.cgi"><I>Add a new field</I></A><BR><BR>
+
+<% foreach $dbtable (sort { $a cmp $b } keys (%pvfs)) { %>
+<H3><%=$dbtable%></H3>
+
+<%=table()%>
+<TH><TD>Field name</TD><TD>Description</TD></TH>
+<% foreach my $pvf (sort {$a->name cmp $b->name} @{ $pvfs{$dbtable} }) { %>
+ <TR>
+ <TD></TD>
+ <TD>
+ <A HREF="<%=$p2%>edit/part_virtual_field.cgi?<%=$pvf->vfieldpart%>">
+ <%=$pvf->name%></A></TD>
+ <TD><%=$pvf->label%></TD>
+ </TR>
+<% } %>
+</TABLE>
+<% } %>
+</BODY>
+</HTML>
+
diff --git a/httemplate/browse/queue.cgi b/httemplate/browse/queue.cgi
new file mode 100755
index 0000000..b53c140
--- /dev/null
+++ b/httemplate/browse/queue.cgi
@@ -0,0 +1,7 @@
+<!-- mason kludge -->
+<%
+
+print header("Job Queue", menubar( 'Main Menu' => $p, )).
+ joblisting({}). '</BODY></HTML>';
+
+%>
diff --git a/httemplate/browse/router.cgi b/httemplate/browse/router.cgi
new file mode 100644
index 0000000..149db49
--- /dev/null
+++ b/httemplate/browse/router.cgi
@@ -0,0 +1,57 @@
+<%= header('Routers', menubar('Main Menu' => $p)) %>
+<%
+
+my @router = qsearch('router', {});
+my $p2 = popurl(2);
+
+%>
+
+<% if ($cgi->param('error')) { %>
+ <FONT SIZE="+1" COLOR="#ff0000">Error: <%=$cgi->param('error')%></FONT>
+ <BR><BR>
+<% } %>
+
+<%
+my $hidecustomerrouters = 0;
+my $hideurl = '';
+if ($cgi->param('hidecustomerrouters') eq '1') {
+ $hidecustomerrouters = 1;
+ $cgi->param('hidecustomerrouters', 0);
+ $hideurl = '<A HREF="' . $cgi->self_url() . '">Show customer routers</A>';
+} else {
+ $hidecustomerrouters = 0;
+ $cgi->param('hidecustomerrouters', 1);
+ $hideurl = '<A HREF="' . $cgi->self_url() . '">Hide customer routers</A>';
+}
+%>
+
+<A HREF="<%=$p2%>edit/router.cgi">Add a new router</A>&nbsp;|&nbsp;<%=$hideurl%>
+
+<%=table()%>
+ <TR>
+ <TD><B>Router name</B></TD>
+ <TD><B>Address block(s)</B></TD>
+ </TR>
+<% foreach my $router (sort {$a->routernum <=> $b->routernum} @router) {
+ next if $hidecustomerrouters && $router->svcnum;
+ my @addr_block = $router->addr_block;
+ if (scalar(@addr_block) == 0) {
+ push @addr_block, '&nbsp;';
+ }
+%>
+ <TR>
+ <TD ROWSPAN="<%=scalar(@addr_block)+1%>">
+ <A HREF="<%=$p2%>edit/router.cgi?<%=$router->routernum%>"><%=$router->routername%></A>
+ </TD>
+ </TR>
+ <% foreach my $block ( @addr_block ) { %>
+ <TR>
+ <TD><%=UNIVERSAL::isa($block, 'FS::addr_block') ? $block->NetAddr : '&nbsp;'%></TD>
+ </TR>
+ <% } %>
+ </TR>
+<% } %>
+</TABLE>
+</BODY>
+</HTML>
+
diff --git a/httemplate/browse/svc_acct_pop.cgi b/httemplate/browse/svc_acct_pop.cgi
new file mode 100755
index 0000000..44cda81
--- /dev/null
+++ b/httemplate/browse/svc_acct_pop.cgi
@@ -0,0 +1,63 @@
+<!-- mason kludge -->
+<%
+ my $accounts_sth = dbh->prepare("SELECT COUNT(*) FROM svc_acct
+ WHERE popnum = ? ")
+ or die dbh->errstr;
+%>
+<%= header('Access Number Listing', menubar( 'Main Menu' => $p )) %>
+Points of Presence<BR><BR>
+<A HREF="<%= $p %>edit/svc_acct_pop.cgi"><I>Add new Access Number</I></A><BR><BR>
+<%= table() %>
+ <TR>
+ <TH></TH>
+ <TH>City</TH>
+ <TH>State</TH>
+ <TH>Area code</TH>
+ <TH>Exchange</TH>
+ <TH>Local</TH>
+ <TH>Accounts</TH>
+ </TR>
+
+<%
+foreach my $svc_acct_pop ( sort {
+ #$a->getfield('popnum') <=> $b->getfield('popnum')
+ $a->state cmp $b->state || $a->city cmp $b->city
+ || $a->ac <=> $b->ac || $a->exch <=> $b->exch || $a->loc <=> $b->loc
+} qsearch('svc_acct_pop',{}) ) {
+
+ my $svc_acct_pop_link = $p . 'edit/svc_acct_pop.cgi?'. $svc_acct_pop->popnum;
+
+ $accounts_sth->execute($svc_acct_pop->popnum) or die $accounts_sth->errstr;
+ my $num_accounts = $accounts_sth->fetchrow_arrayref->[0];
+
+ my $svc_acct_link = $p. 'search/svc_acct.cgi?popnum='. $svc_acct_pop->popnum;
+
+%>
+ <TR>
+ <TD><A HREF="<%= $svc_acct_pop_link %>">
+ <%= $svc_acct_pop->popnum %></A></TD>
+ <TD><A HREF="<%= $svc_acct_pop_link %>">
+ <%= $svc_acct_pop->city %></A></TD>
+ <TD><A HREF="<%= $svc_acct_pop_link %>">
+ <%= $svc_acct_pop->state %></A></TD>
+ <TD><A HREF="<%= $svc_acct_pop_link %>">
+ <%= $svc_acct_pop->ac %></A></TD>
+ <TD><A HREF="<%= $svc_acct_pop_link %>">
+ <%= $svc_acct_pop->exch %></A></TD>
+ <TD><A HREF="<%= $svc_acct_pop_link %>">
+ <%= $svc_acct_pop->loc %></A></TD>
+ <TD>
+ <FONT COLOR="#00CC00"><B><%= $num_accounts %></B></FONT>
+ <% if ( $num_accounts ) { %><A HREF="<%= $svc_acct_link %>"><% } %>
+ active
+ <% if ( $num_accounts ) { %></A><% } %>
+ </TD>
+ </TR>
+<% } %>
+
+ <TR>
+ </TR>
+ </TABLE>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/config/config-process.cgi b/httemplate/config/config-process.cgi
new file mode 100644
index 0000000..2597132
--- /dev/null
+++ b/httemplate/config/config-process.cgi
@@ -0,0 +1,51 @@
+<%
+ my $conf = new FS::Conf;
+ $FS::Conf::DEBUG = 1;
+ my @config_items = $conf->config_items;
+
+ foreach my $i ( @config_items ) {
+ my @touch = ();
+ my @delete = ();
+ my $n = 0;
+ foreach my $type ( ref($i->type) ? @{$i->type} : $i->type ) {
+ if ( $type eq '' ) {
+ } elsif ( $type eq 'textarea' ) {
+ if ( $cgi->param($i->key. $n) ne '' ) {
+ my $value = $cgi->param($i->key. $n);
+ $value =~ s/\r\n/\n/g; #browsers?
+ $conf->set($i->key, $value);
+ } else {
+ $conf->delete($i->key);
+ }
+ } elsif ( $type eq 'checkbox' ) {
+# if ( defined($cgi->param($i->key. $n)) && $cgi->param($i->key. $n) ) {
+ if ( defined $cgi->param($i->key. $n) ) {
+ #$conf->touch($i->key);
+ push @touch, $i->key;
+ } else {
+ #$conf->delete($i->key);
+ push @delete, $i->key;
+ }
+ } elsif ( $type eq 'text' || $type eq 'select' ) {
+ if ( $cgi->param($i->key. $n) ne '' ) {
+ $conf->set($i->key, $cgi->param($i->key. $n));
+ } else {
+ $conf->delete($i->key);
+ }
+ } elsif ( $type eq 'editlist' || $type eq 'selectmultiple' ) {
+ if ( scalar(@{[ $cgi->param($i->key. $n) ]}) ) {
+ $conf->set($i->key, join("\n", @{[ $cgi->param($i->key. $n) ]} ));
+ } else {
+ $conf->delete($i->key);
+ }
+ } else {
+ }
+ $n++;
+ }
+ # warn @touch;
+ $conf->touch($_) foreach @touch;
+ $conf->delete($_) foreach @delete;
+ }
+
+%>
+<%= $cgi->redirect("config-view.cgi") %>
diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi
new file mode 100644
index 0000000..9a00067
--- /dev/null
+++ b/httemplate/config/config-view.cgi
@@ -0,0 +1,64 @@
+<!-- mason kludge -->
+<%= header('View Configuration', menubar( 'Main Menu' => $p,
+ 'Edit Configuration' => 'config.cgi' ) ) %>
+
+<% my $conf = new FS::Conf; my @config_items = $conf->config_items; %>
+
+<% foreach my $section ( qw(required billing username password UI session
+ shell BIND
+ ),
+ '', 'deprecated') { %>
+ <A NAME="<%= $section || 'unclassified' %>"></A>
+ <FONT SIZE="-2">
+ <% foreach my $nav_section ( qw(required billing username password UI session
+ shell BIND
+ ),
+ '', 'deprecated') { %>
+ <% if ( $section eq $nav_section ) { %>
+ [<A NAME="not<%= $nav_section || 'unclassified' %>" style="background-color: #cccccc"><%= ucfirst($nav_section || 'unclassified') %></A>]
+ <% } else { %>
+ [<A HREF="#<%= $nav_section || 'unclassified' %>"><%= ucfirst($nav_section || 'unclassified') %></A>]
+ <% } %>
+ <% } %>
+ </FONT><BR>
+ <%= table("#cccccc", 2) %>
+ <tr>
+ <th colspan="2" bgcolor="#dcdcdc">
+ <%= ucfirst($section || 'unclassified') %> configuration options
+ </th>
+ </tr>
+ <% foreach my $i (grep $_->section eq $section, @config_items) { %>
+ <tr>
+ <td><a name="<%= $i->key %>">
+ <b><%= $i->key %></b>&nbsp;-&nbsp;<%= $i->description %>
+ </a></td>
+ <td><table border=0>
+ <% foreach my $type ( ref($i->type) ? @{$i->type} : $i->type ) {
+ my $n = 0; %>
+ <% if ( $type eq '' ) { %>
+ <tr><td><font color="#ff0000">no type</font></td></tr>
+ <% } elsif ( $type eq 'textarea'
+ || $type eq 'editlist'
+ || $type eq 'selectmultiple' ) { %>
+ <tr><td bgcolor="#ffffff">
+<pre>
+<%= encode_entities(join("\n", $conf->config($i->key) ) ) %>
+</pre>
+ </td></tr>
+ <% } elsif ( $type eq 'checkbox' ) { %>
+ <tr><td bgcolor="#<%= $conf->exists($i->key) ? '00ff00">YES' : 'ff0000">NO' %></td></tr>
+ <% } elsif ( $type eq 'text' || $type eq 'select' ) { %>
+ <tr><td bgcolor="#ffffff"><%= $conf->exists($i->key) ? $conf->config($i->key) : '' %></td></tr>
+ <% } else { %>
+ <tr><td>
+ <font color="#ff0000">unknown type <%= $type %></font>
+ </td></tr>
+ <% } %>
+ <% $n++; } %>
+ </table></td>
+ </tr>
+ <% } %>
+ </table><br><br>
+<% } %>
+
+</body></html>
diff --git a/httemplate/config/config.cgi b/httemplate/config/config.cgi
new file mode 100644
index 0000000..409869e
--- /dev/null
+++ b/httemplate/config/config.cgi
@@ -0,0 +1,176 @@
+<!-- mason kludge -->
+<%= header('Edit Configuration', menubar( 'Main Menu' => $p ) ) %>
+<SCRIPT>
+var gSafeOnload = new Array();
+var gSafeOnsubmit = new Array();
+window.onload = SafeOnload;
+function SafeAddOnLoad(f) {
+ gSafeOnload[gSafeOnload.length] = f;
+}
+function SafeOnload() {
+ for (var i=0;i<gSafeOnload.length;i++)
+ gSafeOnload[i]();
+}
+function SafeAddOnSubmit(f) {
+ gSafeOnsubmit[gSafeOnsubmit.length] = f;
+}
+function SafeOnsubmit() {
+ for (var i=0;i<gSafeOnsubmit.length;i++)
+ gSafeOnsubmit[i]();
+}
+</SCRIPT>
+
+<% my $conf = new FS::Conf; my @config_items = $conf->config_items; %>
+
+<form name="OneTrueForm" action="config-process.cgi" METHOD="POST" onSubmit="SafeOnsubmit()">
+
+<% foreach my $section ( qw(required billing username password UI session
+ shell BIND
+ ),
+ '', 'deprecated') { %>
+ <A NAME="<%= $section || 'unclassified' %>"></A>
+ <FONT SIZE="-2">
+ <% foreach my $nav_section ( qw(required billing username password UI session
+ shell BIND
+ ),
+ '', 'deprecated') { %>
+ <% if ( $section eq $nav_section ) { %>
+ [<A NAME="not<%= $nav_section || 'unclassified' %>" style="background-color: #cccccc"><%= ucfirst($nav_section || 'unclassified') %></A>]
+ <% } else { %>
+ [<A HREF="#<%= $nav_section || 'unclassified' %>"><%= ucfirst($nav_section || 'unclassified') %></A>]
+ <% } %>
+ <% } %>
+ </FONT><BR>
+ <%= table("#cccccc", 2) %>
+ <tr>
+ <th colspan="2" bgcolor="#dcdcdc">
+ <%= ucfirst($section || 'unclassified') %> configuration options
+ </th>
+ </tr>
+ <% foreach my $i (grep $_->section eq $section, @config_items) { %>
+ <tr>
+ <td>
+ <% my $n = 0;
+ foreach my $type ( ref($i->type) ? @{$i->type} : $i->type ) {
+ #warn $i->key unless defined($type);
+ %>
+ <% if ( $type eq '' ) { %>
+ <font color="#ff0000">no type</font>
+ <% } elsif ( $type eq 'textarea' ) { %>
+ <textarea name="<%= $i->key. $n %>" rows=5><%= "\n". join("\n", $conf->config($i->key) ) %></textarea>
+ <% } elsif ( $type eq 'checkbox' ) { %>
+ <input name="<%= $i->key. $n %>" type="checkbox" value="1"<%= $conf->exists($i->key) ? ' CHECKED' : '' %>>
+ <% } elsif ( $type eq 'text' ) { %>
+ <input name="<%= $i->key. $n %>" type="<%= $type %>" value="<%= $conf->exists($i->key) ? $conf->config($i->key) : '' %>">
+ <% } elsif ( $type eq 'select' || $type eq 'selectmultiple' ) { %>
+ <select name="<%= $i->key. $n %>" <%= $type eq 'selectmultiple' ? 'MULTIPLE' : '' %>>
+ <% my %saw;
+ foreach my $value ( "", @{$i->select_enum} ) {
+ local($^W)=0; next if $saw{$value}++; %>
+ <option value="<%= $value %>"<%= $value eq $conf->config($i->key) || ( $type eq 'selectmultiple' && grep { $_ eq $value } $conf->config($i->key) ) ? ' SELECTED' : '' %>><%= $value %>
+ <% } %>
+ <% if ( $conf->exists($i->key) && $conf->config($i->key) && ! grep { $conf->config($i->key) eq $_ } @{$i->select_enum}) { %>
+ <option value=<%= $conf->config($i->key) %> SELECTED><%= $conf->config($i->key) %>
+ <% } %>
+ </select>
+ <% } elsif ( $type eq 'editlist' ) { %>
+ <script>
+ function doremove<%= $i->key. $n %>() {
+ fromObject = document.OneTrueForm.<%= $i->key. $n %>;
+ for (var i=fromObject.options.length-1;i>-1;i--) {
+ if (fromObject.options[i].selected)
+ deleteOption<%= $i->key. $n %>(fromObject,i);
+ }
+ }
+ function deleteOption<%= $i->key. $n %>(object,index) {
+ object.options[index] = null;
+ }
+ function selectall<%= $i->key. $n %>() {
+ fromObject = document.OneTrueForm.<%= $i->key. $n %>;
+ for (var i=fromObject.options.length-1;i>-1;i--) {
+ fromObject.options[i].selected = true;
+ }
+ }
+ function doadd<%= $i->key. $n %>(object) {
+ var myvalue = "";
+ <% if ( defined($i->editlist_parts) ) { %>
+
+ <% foreach my $pnum ( 0 .. scalar(@{$i->editlist_parts})-1 ) { %>
+
+ if ( myvalue != "" ) { myvalue = myvalue + " "; }
+ <% if ( $i->editlist_parts->[$pnum]{type} eq 'select' ) { %>
+ myvalue = myvalue + object.add<%= $i->key. $n . "_$pnum" %>.options[object.add<%= $i->key. $n . "_$pnum" %>.selectedIndex].value;
+ <!-- #RESET SELECT?? maybe not... -->
+ <% } elsif ( $i->editlist_parts->[$pnum]{type} eq 'immutable' ) { %>
+ myvalue = myvalue + object.add<%= $i->key. $n . "_$pnum" %>.value;
+ <% } else { %>
+ myvalue = myvalue + object.add<%= $i->key. $n . "_$pnum" %>.value;
+ object.add<%= $i->key. $n. "_$pnum" %>.value = "";
+ <% } %>
+
+
+ <% } %>
+ <% } else { %>
+ myvalue = object.add<%= $i->key. $n. "_1" %>.value;
+ <% } %>
+ var optionName = new Option(myvalue, myvalue);
+ var length = object.<%= $i->key. $n %>.length;
+ object.<%= $i->key. $n %>.options[length] = optionName;
+ }
+ </script>
+ <select multiple size=5 name="<%= $i->key. $n %>">
+ <option selected>----------------------------------------------------------------</option>
+ <% foreach my $line ( $conf->config($i->key) ) { %>
+ <option value="<%= $line %>"><%= $line %></option>
+ <% } %>
+ </select><br>
+ <input type="button" value="remove selected" onClick="doremove<%= $i->key. $n %>()">
+ <script>SafeAddOnLoad(doremove<%= $i->key. $n %>);
+ SafeAddOnSubmit(selectall<%= $i->key. $n %>);</script>
+ <br>
+ <%= itable() %><tr>
+ <% if ( defined $i->editlist_parts ) { %>
+ <% my $pnum=0; foreach my $part ( @{$i->editlist_parts} ) { %>
+ <td>
+ <% if ( $part->{type} eq 'text' ) { %>
+ <input type="text" name="add<%= $i->key. $n."_$pnum" %>">
+ <% } elsif ( $part->{type} eq 'immutable' ) { %>
+ <%= $part->{value} %><input type="hidden" name="add<%= $i->key. $n. "_$pnum" %>" value="<%= $part->{value} %>">
+ <% } elsif ( $part->{type} eq 'select' ) { %>
+ <select name="add<%= $i->key. $n. "_$pnum" %>">
+ <% foreach my $key ( keys %{$part->{select_enum}} ) { %>
+ <option value="<%= $key %>"><%= $part->{select_enum}{$key} %></option>
+ <% } %>
+ </select>
+ <% } else { %>
+ <font color="#ff0000">unknown type <%= $part->type %></font>
+ <% } %>
+ </td>
+ <% $pnum++; } %>
+ <% } else { %>
+ <td><input type="text" name="add<%= $i->key. $n %>_0"></td>
+ <% } %>
+ <td><input type="button" value="add" onClick="doadd<%= $i->key. $n %>(this.form)"></td>
+ </tr></table>
+ <% } else { %>
+ <font color="#ff0000">unknown type <%= $type %></font>
+ <% } %>
+ <% $n++; } %>
+ </td>
+ <td><a name="<%= $i->key %>">
+ <b><%= $i->key %></b> - <%= $i->description %>
+ </a></td>
+ </tr>
+ <% } %>
+ </table><br>
+
+ You may need to restart Apache and/or freeside-queued for configuration
+ changes to take effect.<br>
+
+ <input type="submit" value="Apply changes"><br><br>
+
+<% } %>
+
+</form>
+
+</body></html>
diff --git a/httemplate/docs/ach.html b/httemplate/docs/ach.html
new file mode 100644
index 0000000..b79df78
--- /dev/null
+++ b/httemplate/docs/ach.html
@@ -0,0 +1,12 @@
+<HTML>
+ <HEAD>
+ <TITLE>
+ Electronic check (ACH) information
+ </TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <IMG BORDER=0 SRC="../images/ach.png">
+ <BR>
+ <CENTER><A HREF="javascript:close()">(close window)</A></CENTER>
+ </BODY>
+</HTML>
diff --git a/httemplate/docs/admin.html b/httemplate/docs/admin.html
new file mode 100755
index 0000000..50beafe
--- /dev/null
+++ b/httemplate/docs/admin.html
@@ -0,0 +1,81 @@
+<head>
+ <title>Administration</title>
+</head>
+<body>
+ <h1>Administration</h1>
+</body>
+<ul>
+ <li>Open up the root of the Freeside document tree in your web
+ browser. For example, if you created the Freeside document tree in
+ /home/httpd/html/freeside, and your web browser's DocumentRoot is
+ /home/httpd/html, open https://your_host/freeside/. Replace
+ "your_host" with the name or network address of your web server.
+ <li>Select <u>Configuration</u> from the main menu and update your configuration values.
+ <li>Next you must create a service definition. An example of a service
+ definition would be a dial-up account or a domain. First, it is
+ necessary to create a domain definition. Click on <u>View/Edit service
+ definitions</u> and <u>Add a new service definition</u> with <i>Table</i>
+ <b>svc_domain</b> (and no modifiers).
+
+ <li>Now that you have created your first service, you must create a package
+ including this service which you can sell to customers. Zero, one, or many
+ services are bundled into a package. Click on <u>View/Edit package
+ definitions</u> and <u>Add a new package definition</u> which includes
+ quantity <b>1</b> of the svc_domain service you created above.
+
+ <li>After you create your first package, then you must define who is
+ able to sell that package by creating an agent type. An example of
+ an agent type would be an internal sales representitive which sells
+ regular and promotional packages, as opposed to an external sales
+ representitive which would only sell regular packages of services. Click on
+ <u>View/Edit agent types</u> and <u>Add a new agent type</u>. Allow this
+ agent type to sell the package you created above.
+
+ <li>After creating a new agent type, you must create an agent. Click on
+ <u>View/Edit agents</u> and <u>Add a new agent</u>.
+
+ <li>Set up at least one Advertising source. Advertising sources will help
+ you keep track of how effective your advertising is, tracking where customers
+ heard of your service offerings. You must create at least one advertising
+ source. If you do not wish to use the referral functionality, simply create
+ a single advertising source only. Click on <u>View/Edit advertising
+ sources</u> and <u>Add a new advertising source</u>.
+
+ <li>Click on <u>New Customer</u> and create a new customer for your system
+ accounts with billing type <b>Complimentary</b>.
+
+ <li>From the Customer View screen of the newly created customer, order the
+ package you defined above.
+
+ <li>From the Package View screen of the newly created package, choose
+ <u>(Provision)</u> to add the customer's service for this new package.
+
+ <li>Add your own domain.
+
+ <li>Go back to <u>View/Edit service definitions</u> on the main menu, and
+ <u>Add a new service definition</u> with <i>Table</i> <b>svc_acct</b>.
+ Select your domain in the <b>domsvc</b> Modifier. Set <b>Fixed</b> to define
+ a service locked-in to this domain, or <b>Default</b> to define a service
+ which may select from among this domain and the customer's domains.
+
+ <li><table><tr>
+ <td> Create at least POP (Point of Presence) by selecting
+ <u>View/Edit POPs</u> from the main menu.</td>
+ <th align="left"> OR </th>
+ <td>If you are not doing dialup, set slipip to fixed and blank for all your
+ Service Definitions which have Table <b>svc_acct</b>.</td>
+ </tr></table>
+
+ <li>If you are using Freeside to keep track of sales taxes, define tax
+ information for your locales by clicking on the <u>View/Edit locales and tax
+ rates</b> on the main menu.
+
+ <li>If you would like Freeside to notify your customers when their credit
+ cards and other billing arrangements are about to expire, arrange for
+ <b>freeside-expiration-alerter</b> to be run daily by cron or similar
+ facility. The message it sends can be configured from the
+ <u>Configuration</u> choice of the main menu as <u>alerter_template</u>.
+
+</ul>
+</body>
+</html>
diff --git a/httemplate/docs/billing.html b/httemplate/docs/billing.html
new file mode 100644
index 0000000..1d6f8c4
--- /dev/null
+++ b/httemplate/docs/billing.html
@@ -0,0 +1,54 @@
+<head>
+ <title>Billing</title>
+</head>
+<body>
+ <h1>Billing</h1>
+ <ul>
+ <li>You can bill individual customers by clicking on the <i>Bill now</i> link on the main customer view.
+ <li>The <a href="man/bin/freeside-daily.html"><b>freeside-daily</b></a> script should be run daily to bill customers and run invoice collection events.
+ <li>Real-time credit card processing: Install the <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> module for your processor. Configure the <a href="../config/config-view.cgi#business-onlinepayment">business-onlinepayment</a> configuration option. Disable the default <b>Batch card</b> <a href="../browse/part_bill_event.cgi">invoice event</a> and add one for Business::OnlinePayment.
+ <li>Optional: Credit card expiration alerts: Customize <a href="../config/config.cgi#alerter_template">alerter_template</a> configuration option and run <a href="man/bin/freeside-expiration-alerter.html">freeside-expiration-alerter</a> daily.
+ <li>Credit card decline alerts: Customize the <a href="../config/config.cgi#declinetemplate">declinetemplate</a> configuration option and set the <a href="../config/config.cgi#emaildecline">emaildecline</a> configuration option.
+ <li>Optional: Invoice template customization
+ <ul>
+ <li>See the <a href="http://search.cpan.org/~mjd/Text-Template/lib/Text/Template.pm">Text::Template</a> documentation for details on the substitution language.
+ <li>You <b>must</b> call the invoice_lines() function at least once - pass it a number of lines, and it returns a list of array references, each of two elements: a service description column, and a price column. Alternatively, call invoice_lines() with no arguments, and pagination will be disabled - all invoice line items will print on one page, with no padding (recommended for email invoices).
+ <li>In addition, the following variables are available:
+ <ul>
+ <li>$invnum - invoice number
+ <li>$date - as a UNIX timestamp (see <a href="http://search.cpan.org/doc/GBARR/TimeDate-1.09/lib/Date/Format.pm">Date::Format</a> for conversion functions).
+ <li>$page - current page
+ <li>$total_pages - total pages
+ <li>@address - A six-element array containing the customer name, company, and address.
+<!-- <li>$overdue - true if this invoice is overdue -->
+ </ul>
+ </ul>
+ <li>Batch credit card processing
+ <ul>
+ <li>After <a href="man/bin/freeside-daily.html"><b>freeside-daily</b></a> is run, a credit card batch will be in the <a href="schema.html#cust_pay_batch">cust_pay_batch</a> table. Export this table to your credit card batching.
+ <li>When your batch completes, erase the cust_pay_batch records in that batch and add any necessary paymants to the <a href="schema.html#cust_pay">cust_pay</a> table. Example code to add payments is:
+ <pre>use FS::cust_pay;
+
+# loop over all records in batch
+
+my $payment=create FS::cust_pay (
+ 'invnum' => $invnum,
+ 'paid' => $paid,
+ '_date' => $_date,
+ 'payby' => $payby,
+ 'payinfo' => $payinfo,
+ 'paybatch' => $paybatch,
+);
+
+my $error=$payment->insert;
+if ( $error ) {
+ #process error
+}
+
+# end loop
+</pre>
+All fields except paybatch are contained in the cust_pay_batch table. You can use paybatch field to track particular batches and/or particular transactions within a batch.
+ </ul>
+<!-- <li>The <a href="man/bin/freeside-print-batch.html"><b>freeside-print-batch</b></a> script can print or email pending credit card batches for manual entry. -->
+ </ul>
+</body>
diff --git a/httemplate/docs/config.html b/httemplate/docs/config.html
new file mode 100644
index 0000000..9caf3bb
--- /dev/null
+++ b/httemplate/docs/config.html
@@ -0,0 +1,36 @@
+<head>
+ <title>Configuration files</title>
+</head>
+<body>
+ <h1>Configuration files</h1>
+<font size="+1" color="#ff0000">Configuration is now done by the top-level Makefile and web interface. The instructions below are no longer necessary.</font>
+<ul>
+ <li>Create the <b>/usr/local/etc/freeside</b> directory to hold your configuration.
+ <li>Setting up <a href="http://www.apache.org/docs/misc/FAQ.html#user-authentication">Apache user authetication</a> is mandatory.
+ <li>Create the <b>/usr/local/etc/freeside/mapsecrets</b> file, which maps Apache users to a secrets file which contains a DBI data source, username and password. Every
+line in <b>/usr/local/etc/freeside/mapsecrets</b> should contain a username and
+filename, separated by whitespace. Note that these are not local usernames -
+they are passed from Apache. <a href="http://www.apache.org/docs/misc/FAQ.html#user-authentication">
+Apache user authetication</a> is mandatory. For example, if you had the Apache users admin,
+john, and sam,
+you mapsecrets file might look like:
+<pre>
+admin secretfile
+john secretfile
+sam secretfile
+</pre>
+ <li>Next, the filename(s) referenced in <b>/usr/local/etc/freeside/mapsecrets</b> file should be created in the <b>/usr/local/etc/freeside/</b> directory. Each file contains three lines: <a href="http://search.cpan.org/doc/TIMB/DBI-1.20/DBI.pm">DBI data source</a> (for example,
+ <tt>DBI:mysql:freeside</tt> or <tt>DBI:Pg:host=localhost;dbname=freeside</tt>), database username, and database password.
+ These files should not be world readable. See the <a href="http://search.cpan.org/doc/TIMB/DBI-1.20/DBI.pm">DBI manpage</a> and the <a href="http://search.cpan.org/search?mode=module&query=DBD">manpage for your DBD</a> for the exact syntax of a DBI data source. In a normal installation such as the example above, a single file <b>/usr/local/etc/freeside/secretfile</b> would be created - for example:
+<pre>
+DBI:Pg:host=localhost;dbname=freeside
+dbusername
+dbpassword
+</pre>
+<li>Create the <b>/usr/local/etc/freeside/conf.<i>datasource</i></b> directory, for example, <b>/usr/local/etc/freeside/conf.DBI:Pg:host=localhost;dbname=freeside</b> (remember to backslash-escape the ; character when creating directories in the shell:
+<pre>mkdir&nbsp;/usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=freeside
+</pre>
+<li>The rest of the configuration can be done with the web interface. Select <u>Configuration</u> from the main menu and update your configuration values.
+</ul>
+</body>
+</html>
diff --git a/httemplate/docs/cvv2.html b/httemplate/docs/cvv2.html
new file mode 100644
index 0000000..fe8a17f
--- /dev/null
+++ b/httemplate/docs/cvv2.html
@@ -0,0 +1,25 @@
+<HTML>
+ <HEAD>
+ <TITLE>
+ CVV2 information
+ </TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ The CVV2 number (also called CVC2 or CID) is a three- or four-digit
+ security code used to reduce credit card fraud.<BR><BR>
+ <TABLE BORDER=0 CELLSPACING=4>
+ <TR>
+ <TH>Visa / MasterCard / Discover</TH>
+ <TH>American Express</TH>
+ </TR>
+ <TR>
+ <TD>
+ <IMG BORDER=0 ALT="Visa/MasterCard/Discover" SRC="../images/cvv2.png">
+ </TD>
+ <TD>
+ <IMG BORDER=0 ALT="American Express" SRC="../images/cvv2_amex.png">
+ </TD>
+ </TABLE>
+ <CENTER><A HREF="javascript:close()">(close window)</A></CENTER>
+ </BODY>
+</HTML>
diff --git a/httemplate/docs/export.html b/httemplate/docs/export.html
new file mode 100755
index 0000000..71e3acf
--- /dev/null
+++ b/httemplate/docs/export.html
@@ -0,0 +1,55 @@
+<head>
+ <title>File exporting</title>
+</head>
+<body>
+ <h1>File exporting</h1>
+ <font size="+2">NOTE: This file is OUT OF DATE with the landing of the new export code and is only here for reference. DO NOT follow these instructions. Instead use the new exports in the web interface.</font>
+ <ul>
+ <li>bin/svc_acct.export will create UNIX <b>passwd</b>, <b>shadow</b> and <b>master.passwd</b> files, ERPCD <b>acp_passwd</b> and <b>acp_dialup</b> files and a RADIUS <b>users</b> file in the <b>/usr/local/etc/freeside/export.<i>datasrc</i></b> directory. Some RADIUS servers (such as <a href="http://www.open.com.au/radiator/">Radiator</a>, <a href="ftp://ftp.cheapnet.net/pub/icradius/">ICRADIUS</a> and <a href="http://www.freeradius.org/">FreeRADIUS</a>) will authenticate directly out of an SQL database. In these cases,
+it is reccommended that you replicate (<a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Replication">Replication in MySQL</a>) the data to an external RADIUS machine or point icradius_secrets to the external machine rather than running the RADIUS server on your Freeside machine. Using the appropriate <a href="../config/config-view.cgi">configuration settings</a>, you can export these files to your remote machines unattended:
+ <ul>
+ <li>shellmachines - <b>passwd</b> and <b>shadow</b> are copied to the remote machine as <b>/etc/passwd.new</b> and <b>/etc/shadow.new</b> and then moved to <b>/etc/passwd</b> and <b>/etc/shadow</b> if no errors occur.
+ <li>bsdshellmachines - <b>passwd</b> and <b>master.passwd</b> are copied to the remote machine as <b>/etc/passwd.new</b> and <b>/etc/master.passwd.new</b> and moved to <b>/etc/passwd</b> and <b>/etc/master.passwd</b> if no errors occur.
+ <li>nismachines - <b>passwd</b> and <b>shadow</b> are copied to the <b>/etc/global</b> directory on the remote machine. If no errors occur, the command <b>( cd /var/yp; make; )</b> is executed on the remote machine.
+ <li>erpcdmachines - <b>acp_passwd</b> and <b>acp_dialup</b> are copied to the <b>/usr/annex</b> directory on the remote machine. If no errors occur, the command <b>( kill -USR1 `cat /usr/annex/erpcd.pid` )</b> is executed on the remote machine.
+ <li>radiusmachines - <b>users</b> is copied to the <b>/etc/raddb</b> directory on the remote machine. If no errors occur, the command <b>( builddbm )</b> is executed on the remote machine.
+ <li>icradiusmachines - Turn this option on to enable radcheck table population - by default in the Freeside database, or in the database specified by the <a href="http://rootwood.haze.st/aspside/config/config-view.cgi#icradius_secrets">icradius_secrets</a> config option (the radcheck table needs to be created manually). You do not need to use MySQL for your Freeside database to export to an ICRADIUS/FreeRADIUS MySQL database with this option. <blockquote><b>ADDITIONAL DEPRECATED FUNCTIONALITY</b> (instead use <a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Replication">MySQL replication</a> or point icradius_secrets to the external database) - your <a href="ftp://ftp.cheapnet.net/pub/icradius">ICRADIUS</a> machines or <a href="http://www.freeradius.org/">FreeRADIUS</a> (with MySQL authentication) machines, one per line. Machines listed in this file will have the radcheck table exported to them. Each line should contain four items, separted by whitespace: machine name, MySQL database name, MySQL username, and MySQL password. For example: <CODE>"radius.isp.tld&nbsp;radius_db&nbsp;radius_user&nbsp;passw0rd"</CODE></blockquote>
+ </ul>
+ <li>svc_acct.pm - If a shellmachine is defined, users can be created, modified and deleted remotely; see below.
+ <ul>
+ <li>Account creation - If the <b>username</b>, <b>uid</b> and <b>dir</b> fields are defined for a new user, the command(s) specified in the <a href="../config/config-view.cgi#shellmachine-useradd">shellmachine-useradd</a> configuration file are executed on shellmachine via ssh. If this file does not exist, <code>useradd -d $dir -m -s $shell -u $uid $username</code> is the default. If the file exists but is empty, <code>cp -pr /etc/skel $dir; chown -R $uid.$gid $dir</code> is the default instead. Otherwise the contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$username</code>, <code>$uid</code>, <code>$gid</code>, <code>$dir</code>, and <code>$shell</code>.
+ <li>Account deletion - The command(s) specified in the <a href="../config/config-view.cgi#shellmachine-userdel">shellmachine-userdel</a> configuration file are executed on shellmachine via ssh. If this file does not exist, <code>userdel $username</code> is the default. If the file exists but is empty, <code>rm -rf $dir</code> is the default instead. Otherwise the contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$username</code> and <code>$dir</code>.
+ <li>Account modification - If a user's home directory changes, the command(s) specified in the <a href="../config/config-view.cgi#shellmachine-usermod">shellmachine-usermod</a> configuration file are execute on shellmachine via ssh. If this file does not exist or is empty, <code>[ -d $old_dir ] &amp;&amp; mv $old_dir $new_dir || ( chmod u+t $old_dir; mkdir $new_dir; cd $old_dir; find . -depth -print | cpio -pdm $new_dir; chmod u-t $new_dir; chown -R $uid.$gid $new_dir; rm -rf $old_dir )</code> is the default. Otherwise the contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$old_dir</code>, <code>$new_dir</code>, <code>$uid</code> and <code>$gid</code>.
+ </ul>
+ <li>svc_acct.pm - <a href="http://asg.web.cmu.edu/cyrus/imapd/">Cyrus IMAP Server</a> integration, enabled by the <a href="../config/config-view.cgi#cyrus">cyrus configuration file</a>
+ <ul>
+ <li>Account creation - (Cyrus::IMAP::Admin should be installed locally)
+ <li>Account deletion - (Cyrus::IMAP::Admin should be installed locally)
+ <li>Account modification - (not yet implemented)
+ </ul>
+ <li>bin/svc_acct_sm.export will create <a href="http://www.qmail.org">Qmail</a> <b>rcpthosts</b>, <b>recipientmap</b> and <b>virtualdomains</b> files and <a href="http://www.sendmail.org">Sendmail</a> <b>virtusertable</b> and <b>sendmail.cw</b> files in the <b>/usr/local/etc/freeside/export.<i>datasrc</i></b> directory. Using the appropriate <a href="../config/config-view.cgi">configuration files</a>, you can export these files to your remote machines unattemded:
+ <ul>
+ <li>qmailmachines - <b>recipientmap</b>, <b>virtualdomains</b> and <b>rcpthosts</b> are copied to the <b>/var/qmail/control</b> directory on the remote machine. Note: If you <a href="legacy.html#svc_acct_sm">imported</a> qmail configuration files, run the generated <b>/usr/local/etc/freeside/export.<i>datasrc</i>/virtualdomains.FIX</b> on a machine with your user home directories before exporting qmail configuration files.
+ <li>shellmachine - The command <b>[ -e <i>homedir</i>/.qmail-default ] || { touch <i>homedir</i>/.qmail-default; chown <i>uid</i>.<i>gid</i> <i>homedir</i>/.qmail-default; }</b> will be run on this machine for users in the virtualdomains file.
+ <li>sendmailmachines - <b>sendmail.cw</b> and <b>virtusertable</b> are copied to the remote machine as <b>/etc/sendmail.cw.new</b> and <b>/etc/virtusertable.new</b>. If no errors occur, they are moved to <b>/etc/sendmail.cw</b> and <b>/etc/virtusertable</b> and the command specified in the <a href="../config/config-view.cgi#sendmailrestart">sendmailrestart</a> configuration file is executed. (The path can be changed from the default <b>/etc</b> with the <a href="../config/config-view.cgi#sendmailconfigpath">sendmailconfigpath</a> configuration file.)
+ </ul>
+ <li>svc_domain.pm - If the qmailmachines configuration file exists and a shellmachine is defined, user <b>.qmail-</b> files can be updated for catchall mailboxes.
+ <ul>
+ <li>The command <pre>[ -e <i>homedir</i>/.qmail-<i>domain</i>-default ] || {
+ touch <i>homedir</i>/.qmail-<i>domain</i>-default;
+ chown <i>uid</i>.<i>gid</i> <i>homedir</i>/.qmail-<i>domain</i>-default;
+}</pre> is run.
+ </ul>
+ <li>svc_forward.pm - Not yet documented; see manpage.
+ <li>svc_www.pm - Not yet documented; see manpage.
+ </ul>
+ <br><a name=ssh>Unattended remote login</a> - Freeside can login to remote machines unattended using SSH. This can pose a security risk if not configured correctly, and will allow an intruder who breaks into your freeside machine full access to your remote machines. <b>Do not use this feature unless you understand what you are doing!</b>
+ <ul>
+ <li>As the freeside user (on your freeside machine), generate an authentication key using <a href="http://www.tac.eu.org/cgi-bin/man-cgi?ssh-keygen+1">ssh-keygen</a>. Since this is for unattended operation, use a blank passphrase.
+ <li>Append the newly-created <code>identity.pub</code> file to <code>~root/.ssh/authorized_keys</code> on the remote machine(s).
+ <li>Some new SSH v2 implementation accept v2 style keys only. Use the <code>-t</code> option to <a href="http://www.tac.eu.org/cgi-bin/man-cgi?ssh-keygen+1">ssh-keygen</a>, and append the created <code>id_dsa.pub</code> or <code>id_rsa.pub</code> to <code>~root/.ssh/authorized_keys2</code> on the remote machine(s).
+ <li>You may need to set <code>PermitRootLogin without-password</code> (meaning with keys only) in your <code>sshd_config</code> file on the remote machine(s).
+ </ul>
+
+</body>
+
diff --git a/httemplate/docs/ieak.html b/httemplate/docs/ieak.html
new file mode 100644
index 0000000..00c5342
--- /dev/null
+++ b/httemplate/docs/ieak.html
@@ -0,0 +1,75 @@
+<pre>
+this is incomplete
+mostly it should be merged into signup.html and fs_signup/ieak.template
+
+- download and install the IEAK from
+ http://www.microsoft.com/windows/ieak/default.asp
+
+- Good examples may be found in
+ C:\Program Files\IEAK\toolkit\isp\server\ICW\signup\perl\signup08.pl
+ C:\Program Files\IEAK\toolkit\isp\server\ICW\reconfig\perl\reconfig04.pl
+ C:\Program Files\IEAK6\toolkit\isp\servless\basic\sample.ins
+ C:\Program Files\IEAK6\toolkit\isp\servless\advanced\4567.ins
+ C:\Program Files\IEAK6\toolkit\isp\servless\advanced\4568.ins
+ C:\Program Files\IEAK6\toolkit\isp\servless\advanced\7890.ins
+ C:\Program Files\IEAK6\toolkit\isp\servless\advanced\7891.ins
+
+- Full documentation on all the settings available in .INS files is
+ avaialble under Program Files | Microsoft IEAK 6 | IEAK Help
+ | Reference | Internet Settings (.ins) Files
+
+- Freeside will make the following substitutions before sending the file
+ to the user:
+
+ { $ac } - area code of selected POP
+ { $exch } - exchange of selected POP
+ { $loc } - local part of selected POP
+ { $username }
+ { $password }
+ { $email_name } - first and last name
+ { $pkg } - package name
+
+- Simple example follows:
+
+[Entry]
+Entry Name = IEAK Sample
+[Phone]
+Dial_As_Is = No
+Phone_Number = { $exch }{ $loc }
+Area_Code = { $ac }
+Country_Code = 1
+Country_Id = 1
+[Server]
+Type = PPP
+SW_Compress = Yes
+PW_Encrypt = Yes
+Negotiate_TCP/IP = Yes
+Disable_LCP = No
+[TCP/IP]
+Specity_IP_Address = No
+Specity_Server_Address = No
+IP_Header_Compress = Yes
+Gateway_On_Remote = Yes
+[User]
+Name = { $username }
+Passowrd = { $password }
+Display_Password = Yes
+[Internet_Mail]
+Email_Name = { $email_name }
+Email_Address = { $username }@example.com
+POP_Server = mail.example.com
+POP_Server_Port_Number = 110
+POP_Logon_Password = { $password }
+SMTP_Server = mail.example.com
+SMTP_Server_Port_Number = 25
+Install_Mail = 1
+[URL]
+Help_Page = http://www.ieaksample.net/helpdesk
+Home_Page = http://www.ieaksample.net
+Search_Page = http://www.ieaksample,net/search
+[Favorites]
+IEAK Sample \\ IEAK Sample Home Page.url = http://acme.ieaksample.net/
+[Branding]
+Window_Title = Internet Explorer from Acme Internet Services
+
+</pre>
diff --git a/httemplate/docs/index.html b/httemplate/docs/index.html
new file mode 100644
index 0000000..648cb98
--- /dev/null
+++ b/httemplate/docs/index.html
@@ -0,0 +1,30 @@
+<head>
+ <title>Documentation</title>
+</head>
+<body bgcolor="#ffffff">
+ <h1>Documentation</h1>
+<img src="overview.png">
+<ul>
+ <li><a href="install.html">New Installation</a>
+ <li><a href="upgrade7.html">Upgrading from 1.3.0 to 1.3.1</a>
+ <li><a href="upgrade8.html">Upgrading from 1.3.1 to 1.4.0</a>
+ <li><a href="upgrade9.html">Upgrading from 1.4.0 to 1.4.1</a>
+ <li><a href="upgrade-1.4.2.html">Upgrading from 1.4.1 to 1.4.2</a>
+ <li><a href="upgrade10.html">Upgrading from 1.4.1 (or 1.4.2?) to 1.5.0</a>
+<!--
+ <li><a href="config.html">Configuration files</a>
+!-->
+ <li><a href="admin.html">Administration</a>
+<!--
+ <li><a href="../index.html#admin">Administration</a>
+!-->
+ <li><a href="legacy.html">Importing legacy data</a>
+ <li><a href="export.html">File exporting and remote setup</a>
+ <li><a href="passwd.html">fs_passwd</a>
+ <li><a href="signup.html">Signup server</a>
+ <li><a href="session.html">Session monitor</a>
+ <li><a href="billing.html">Billing</a>
+ <li><a href="schema.html">Schema reference</a>
+ <li><a href="man/FS.html">Perl API</a>
+</ul>
+</body>
diff --git a/httemplate/docs/install.html b/httemplate/docs/install.html
new file mode 100644
index 0000000..d4507a2
--- /dev/null
+++ b/httemplate/docs/install.html
@@ -0,0 +1,212 @@
+<head>
+ <title>Installation</title>
+</head>
+<body>
+<h1>Installation</h1>
+<i>Note: Install Freeside on a firewalled, private server, not a public (web, RADIUS, etc.) server.</i><br><br>
+Before installing, you need:
+<ul>
+ <li><a href="http://www.perl.com/">Perl</a>
+ <li><a href="http://www.apache.org">Apache</a> (<a href="http://www.modssl.org/">mod_ssl</a> or <a href="http://www.apache-ssl.org">Apache-SSL</a> highly recommended)
+ <li><a href="http://perl.apache.org/">mod_perl</a> (if compiling your own mod_perl, make sure you set the <a href="http://perl.apache.org/guide/install.html#EVERYTHING">EVERYTHING</a>=1 compile-time option)
+ <li><a href="http://www.openssh.com/">SSH</a> (<a href="http://www.openssh.com//">OpenSSH</a> is recommended. SSH Communications Security <a href="http://www.ssh.com/products/ssh/download.cfm">commercial SSH version 3</a> has been reported incompatible with Freeside.)
+ <li><a href="http://rsync.samba.org/">rsync</a>
+ <li>A <b>transactional</b> database engine <a href="http://search.cpan.org/search?mode=module&query=DBD%3A%3A">supported</a> by Perl's <a href="http://dbi.perl.org">DBI</a>.
+ <ul>
+ <li><a href="http://www.postgresql.org/">PostgreSQL</a> is recommended (v7or later).
+ <li><a href="http://www.mysql.com/">MySQL</a> <b>MINIMUM VERSION 4.1</b> is untested but may work. Versions before 4.1 do not support standard SQL subqueries and are <b>NOT SUPPORTED</b>. If you are a developer who wishes to contribute MySQL 3.x/4.0 support, see <a href="http://pouncequick.420.am/rt/Ticket/Display.html?id=438">ticket #438</a> in the bug-tracking system and ask on the -devel mailing list.
+<!-- <li>MySQL has been reported to work. -->
+ <b>MySQL's default <a href="http://www.mysql.com/doc/M/y/MyISAM.html">MyISAM</a> and <a href="http://www.mysql.com/doc/I/S/ISAM.html">ISAM</a> table types are not supported</b>. If you want to use MySQL, you <b>must</b> use one of the new <a href="http://www.mysql.com/doc/T/a/Table_types.html">transaction-safe table types</a> such as <a href="http://www.mysql.com/doc/B/D/BDB.html">BDB</a> or <a href="http://www.mysql.com/doc/I/n/InnoDB.html">InnoDB</a>, and set it as the default table type using the <code>--default-table-type=BDB</code> or <code>--default-table-type=InnoDB</code> <a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Command-line_options">mysqld command-line option</a> or by setting <code>default-table-type=BDB</code> or <code>default-table-type=InnoDB</code> in the <a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Option_files">my.cnf option file</a>.
+ </ul>
+ <li>Perl modules (<a href="http://search.cpan.org/~andk/CPAN/lib/CPAN.pm">CPAN</a> will query, download and build perl modules automatically)
+ <ul>
+<!-- <li><a href="http://search.cpan.org/search?dist=Array-PrintCols">Array-PrintCols</a>
+ <li><a href="http://search.cpan.org/search?dist=Term-Query">Term-Query</a> (make test broken; install manually) -->
+ <li><a href="http://search.cpan.org/search?dist=MIME-Base64">MIME-Base64</a>
+ <li><a href="http://search.cpan.org/search?dist=Digest-MD5">Digest-MD5</a>
+<!-- <li><a href="http://search.cpan.org/search?dist=MD5">MD5</a> -->
+ <li><a href="http://search.cpan.org/search?dist=URI">URI</a>
+ <li><a href="http://search.cpan.org/search?dist=HTML-Tagset">HTML-Tagset</a>
+ <li><a href="http://search.cpan.org/search?dist=HTML-Parser">HTML-Parser</a>
+ <li><a href="http://search.cpan.org/search?dist=libnet">libnet</a>
+ <li><a href="http://search.cpan.org/search?dist=Locale-Codes">Locale-Codes</a>
+ <li><a href="http://search.cpan.org/search?dist=Net-Whois-Raw">Net-Whois-Raw</a>
+ <li><a href="http://search.cpan.org/search?dist=libwww-perl">libwww-perl</a>
+ <li><a href="http://search.cpan.org/search?dist=Business-CreditCard">Business-CreditCard</a>
+<!-- <li><a href="http://search.cpan.org/search?dist=Data-ShowTable">Data-ShowTable</a> -->
+ <li><a href="http://search.cpan.org/search?dist=MailTools">MailTools</a>
+ <li><a href="http://search.cpan.org/search?dist=TimeDate">TimeDate</a>
+ <li><a href="http://search.cpan.org/search?dist=DateManip">DateManip</a>
+ <li><a href="http://search.cpan.org/search?dist=File-CounterFile">File-CounterFile</a>
+ <li><a href="http://search.cpan.org/search?dist=FreezeThaw">FreezeThaw</a>
+ <li><a href="http://search.cpan.org/search?dist=String-Approx">String-Approx</a>
+ <li><a href="http://search.cpan.org/search?dist=Text-Template">Text-Template</a>
+ <li><a href="http://search.cpan.org/search?dist=DBI">DBI</a>
+ <li><a href="http://search.cpan.org/search?mode=module&query=DBD">DBD for your database engine</a> (<a href="http://search.cpan.org/search?dist=DBD-Pg">DBD::Pg</a> for PostgreSQL, <a href="http://search.cpan.org/search?dist=DBD-mysql">DBD::mysql</a> for MySQL)
+ <li><a href="http://search.cpan.org/search?dist=DBIx-DataSource">DBIx-DataSource</a>
+ <li><a href="http://search.cpan.org/search?dist=DBIx-DBSchema">DBIx-DBSchema</a>
+ <li><a href="http://search.cpan.org/search?dist=Net-SSH">Net-SSH</a>
+ <li><a href="http://search.cpan.org/search?dist=String-ShellQuote">String-ShellQuote</a>
+ <li><a href="http://search.cpan.org/search?dist=Net-SCP">Net-SCP</a>
+ <li><a href="http://www.masonhq.com/">HTML::Mason</a> (recommended, enables full functionality) or <a href="http://www.apache-asp.org/">Apache::ASP</a> (deprecated, integrated RT ticketing will not be available)
+ <li><a href="http://search.cpan.org/search?dist=Tie-IxHash">Tie-IxHash</a>
+ <li><a href="http://search.cpan.org/search?dist=Time-Duration">Time-Duration</a>
+ <li><a href="http://search.cpan.org/search?dist=HTML-Widgets-SelectLayers">HTML-Widgets-SelectLayers</a>
+ <li><a href="http://search.cpan.org/search?dist=Storable">Storable</a>
+<!-- MyAccounts, maybe only for dev <li><a href="http://search.cpan.org/search?dist=Cache-Cache">Cache::Cache</a> -->
+ <li><a href="http://search.cpan.org/search?dist=NetAddr-IP">NetAddr-IP</a>
+ <li><a href="http://search.cpan.org/search?dist=Chart">Chart</a>
+ <li><a href="http://search.cpan.org/search?dist=Crypt-PasswdMD5">Crypt::PasswdMD5</a>
+ <li><a href="http://search.cpan.org/search?dist=ApacheDBI">Apache::DBI</a> <i>(optional but recommended for better webinterface performance)</i>
+ </ul>
+</ul>
+Install the Freeside distribution:
+<ul>
+ <li>Add the user and group `freeside' to your system.
+ <li>Allow the freeside user full access to the freeside database.
+ <ul>
+ <li> with <a href="http://www.postgresql.org/users-lounge/docs/7.1/postgres/user-manag.html#DATABASE-USERS">PostgreSQL</a>:
+ <pre>
+$ su postgres (pgsql on some distributions)
+$ createuser -P freeside
+Enter password for user "freeside":
+Enter it again:
+Shall the new user be allowed to create databases? (y/n) y
+Shall the new user be allowed to create more new users? (y/n) n
+CREATE USER</pre>
+ <li> with <a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#User_Account_Management">MySQL</a>:
+ <pre>
+$ mysqladmin -u root password '<i>set_a_root_database_password</i>'
+$ mysql -u root -p
+mysql> GRANT SELECT,INSERT,UPDATE,DELETE,INDEX,ALTER,CREATE,DROP on freeside.* TO freeside@localhost IDENTIFIED BY '<i>set_a_freeside_database_password</i>';</pre>
+ </ul>
+<!-- <li>Unpack the tarball: <pre>gunzip -c fs-x.y.z.tar.gz | tar xvf -</pre>-->
+ <li>Edit the top-level Makefile:
+ <ul>
+ <li>Set <tt>DATASOURCE</tt> to your <a href="http://search.cpan.org/doc/TIMB/DBI-1.28/DBI.pm">DBI data source</a>, for example, <tt>DBI:Pg:dbname=freeside</tt> for PostgresSQL or <tt>DBI:mysql:freeside</tt> for MySQL. See the <a href="http://search.cpan.org/doc/TIMB/DBI-1.28/DBI.pm">DBI manpage</a> and the <a href="http://search.cpan.org/search?mode=module&query=DBD%3A%3A">manpage for your DBD</a> for the exact syntax of your DBI data source.
+ <li>Set <tt>DB_PASSWORD</tt> to the freeside database user's password.
+ </ul>
+ <li>Add the freeside database to your database engine:
+ <pre>
+$ su
+# make create-database</pre>
+ (or manually, with Postgres:)
+ <pre>
+$ su freeside
+$ createdb freeside</pre>
+ (with MySQL:)
+ <pre>
+$ mysqladmin -u freeside -p create freeside </pre>
+ <li>Build and install the Perl modules:
+ <pre>
+$ make perl-modules
+$ su
+# make install-perl-modules</pre>
+ <li>Create the necessary configuration files:<pre>
+$ su
+# make create-config
+</pre>
+ <li>Run a <b>separate</b> iteration of Apache[-SSL] with mod_perl enabled <b>as the freeside user</b>.
+</ul>
+<table>
+ <tr>
+ <th>Apache::ASP</th><th>Mason</th>
+ </tr>
+ <tr>
+ <td><ul>
+ <li>Run <tt>make aspdocs</tt>
+ <li>Copy <tt>aspdocs/</tt> to your web server's document space:
+<font size="-1"><pre>
+cp&nbsp;aspdocs&nbsp;/usr/local/apache/htdocs/freeside-asp
+</pre></font>
+ <li>Create a <a href="http://www.apache-asp.org/config.html#Global">Global</a> directory, such as <tt>/usr/local/etc/freeside/asp-global/</tt>:
+<font size="-1"><pre>
+mkdir&nbsp;/usr/local/etc/freeside/asp-global/
+chown&nbsp;freeside&nbsp;/usr/local/etc/freeside/asp-global/
+</pre></font>
+ <li>Copy <tt>htetc/global.asa</tt> to the Global directory:
+<font size="-1"><pre>
+cp&nbsp;htetc/global.asa&nbsp;/usr/local/etc/freeside/asp-global/global.asa
+</pre></font>
+ <li>Configure Apache for the Global directory and to execute .cgi files using Apache::ASP. For example, add something like the following to your Apache httpd.conf file, adjusting for your actual paths:
+<font size="-1"><pre>
+PerlModule Apache::ASP
+# your freeside document root
+&lt;Directory&nbsp;/usr/local/apache/htdocs/freeside-asp&gt;
+&lt;Files ~ (\.cgi|\.html)&gt;
+AddHandler perl-script .cgi .html
+PerlHandler Apache::ASP
+&lt;/Files&gt;
+&lt;Perl&gt;
+$MLDBM::RemoveTaint = 1;
+&lt;/Perl&gt;
+PerlSetVar&nbsp;Global&nbsp;/usr/local/etc/freeside/asp-global/
+PerlSetVar&nbsp;Debug&nbsp;2
+PerlSetVar&nbsp;RequestBinaryRead&nbsp;Off
+# your freeside document root
+PerlSetVar&nbsp;IncludesDir&nbsp;/usr/local/apache/htdocs/freeside-asp
+&lt;/Directory&gt;
+</pre></font>
+ </ul></td>
+ <td><ul>
+ <li>Run <tt>make masondocs</tt>
+ <li>Copy <tt>masondocs/</tt> to your web server's document space. (For example: <tt>/usr/local/apache/htdocs/freeside-mason</tt>)
+ <li>Copy <tt>htetc/handler.pl</tt> to <tt>/usr/local/etc/freeside</tt>
+ <li>Edit <tt>handler.pl</tt> and:
+ <ul>
+ <li> set an appropriate <tt>comp_root</tt>, such as <tt>/usr/local/apache/htdocs/freeside-mason</tt>
+ <li> set an appropriate <tt>data_dir</tt>, such as <tt>/usr/local/etc/freeside/masondata</tt>
+ </ul>
+
+ <li>Configure Apache to use the <tt>handler.pl</tt> file and to execute .cgi files using HTML::Mason. For example, add something like the following to your Apache httpd.conf file, adjusting for your actual paths:
+<font size="-1"><pre>
+PerlModule HTML::Mason
+&lt;Directory&nbsp;/usr/local/apache/htdocs/freeside-mason&gt;
+&lt;Files ~ (\.cgi|\.html)&gt;
+AddHandler perl-script .cgi .html
+PerlHandler HTML::Mason
+&lt;/Files&gt;
+&lt;Perl&gt;
+require&nbsp;"/usr/local/etc/freeside/handler.pl";
+&lt;/Perl&gt;
+&lt;/Directory&gt;
+</pre></font>
+ </ul></td>
+ </tr>
+</table>
+<ul>
+<li>Restrict access to this web interface - see the <a href="http://httpd.apache.org/docs/misc/FAQ.html#user-authentication">Apache documentation on user authentication</a>. For example, to configure user authentication with <a href="http://httpd.apache.org/docs/mod/mod_auth.html">mod_auth</a> (flat files), add something like the following to your Apache httpd.conf file, adjusting for your actual paths:
+<pre>
+&lt;Directory /usr/local/apache/htdocs/freeside-asp&gt;
+AuthName Freeside
+AuthType Basic
+AuthUserFile /usr/local/etc/freeside/htpasswd
+require valid-user
+&lt;/Directory&gt;
+</pre>
+ <li>Create one or more Freeside users (your internal sales/tech folks, not customer accounts). These users are setup using using Apache authentication, not UNIX user accounts. For example, using <a href="http://httpd.apache.org/docs/mod/mod_auth.html">mod_auth</a> (flat files):
+ <ul>
+ <li>First user:<font size="-1">
+<pre>$ su
+$ <a href="man/bin/freeside-adduser.html">freeside-adduser</a> -c -h /usr/local/etc/freeside/htpasswd <i>username</i></pre></font>
+ <li>Additional users:<font size="-1">
+<pre>$ su
+$ <a href="man/bin/freeside-adduser.html">freeside-adduser</a> -h /usr/local/etc/freeside/htpasswd <i>username</i></pre></font>
+ </ul>
+ <i>(using other auth types, add each user to your <a href="http://httpd.apache.org/docs/misc/FAQ.html#user-authentication">Apache authentication</a> and then run: <tt>freeside-adduser <b>username</b></tt></i>
+ <li>As the freeside UNIX user, run <tt>freeside-setup <b>username</b></tt> to create the database tables, passing the username of a Freeside user you created above:
+<pre>
+$ su freeside
+$ freeside-setup <b>username</b>
+</pre>
+ Alternately, use the -s option to enable shipping addresses: <tt>freeside-setup -s <b>username</b></tt>
+ <li>As the freeside UNIX user, run <tt>bin/populate-msgcat <b>username</b></tt> (in the untar'ed freeside directory) to populate the message catalog, passing the username of a Freeside user you created above:
+<pre>
+$ su freeside
+$ cd <b>/path/to/freeside/</b>
+$ bin/populate-msgcat <b>username</b>
+</pre>
+ <li><tt>freeside-queued</tt> was installed with the Perl modules. Start it now and ensure that is run upon system startup (Do this manually, or edit the top-level Makefile, replacing INIT_FILE with the appropriate location on your systemand QUEUED_USER with the username of a Freeside user you created above, and run <tt>make install-init</tt>)
+ <li>Now proceed to the initial <a href="admin.html">administration</a> of your installation.
+</ul>
+</body>
diff --git a/httemplate/docs/legacy.html b/httemplate/docs/legacy.html
new file mode 100755
index 0000000..94efe53
--- /dev/null
+++ b/httemplate/docs/legacy.html
@@ -0,0 +1,39 @@
+<head>
+ <title>Importing legacy data</title>
+</head>
+<body>
+ <h1>Importing legacy data</h1>
+<font size="+2">In almost all cases, legacy data import will require writing custom code to deal with your particular legacy data. The example scripts here will probably <b>not</b> work "out-of-the-box", and are provided <b>as a starting point only</b>.</font>
+<br><br><i>Some import scripts may require installation of the <a href="http://search.cpan.org/search?dist=Array-PrintCols">Array-PrintCols</a> and <a href="http://search.cpan.org/search?dist=Term-Query">Term-Query</a> (make test broken; install manually) modules.</i><br>
+<ul>
+ <li><a name="bind">bin/bind.import</a> - Import domain information from BIND named
+ <li><a name="passwd">bin/passwd.import</a> - Just import `passwd' and `shadow' or `master.passwd', no RADIUS import.
+ <li><a name="svc_acct">bin/svc_acct.import</a> - Import `passwd', ( `shadow' or `master.passwd' ) and RADIUS `users'. Before running bin/svc_acct.import, you need <a href="../browse/part_svc.cgi">services</a> (with table svc_acct) as follows:
+ <ul>
+ <li>Most accounts probably have entries in passwd and users (with Port-Limit nonexistant or 1)
+ <li>Some accounts have entries in passwd and users, but with Port-Limit 2 (or more)
+ <li>Some accounts might have entries in users only (Port-Limit 1)
+ <li>Some accounts might have entries in users only (Port-Limit >= 2)
+ <li>POP mail accounts have entries in passwd only, and have a particular shell.
+ <li>Everything else in passwd is a shell account.
+ </ul>
+<!-- <li><a name="svc_acct_sm">bin/svc_acct_sm.import</a> - Import qmail ( `virtualdomains' and `rcpthosts' ), or sendmail ( `virtusertable' and `sendmail.cw' ) files. Before running bin/svc_acct_sm.import, you need <a href="../browse/part_svc.cgi">services</a> as follows:
+ <ul>
+ <li>Domain (table svc_acct)
+ <li>Mail alias (table svc_acct_sm)
+ </ul>
+-->
+ <li><a name="cust_main">Importing customer data</a>
+ <ul>
+ <li>Manually
+ <ul>
+ <li>Add a <a href="../edit/cust_main.cgi">new customer</a>
+ <li>Add one or more packages for this customer
+ <li>Enter a package by clicking on the package number
+ <li>Pick the `Link to existing' option
+ </ul>
+ <li>Batch - You will need to write a script to import your particular legacy data. You can use eg/TEMPLATE_cust_main.import as a starting point.
+ </ul>
+</ul>
+</body>
+
diff --git a/httemplate/docs/man/FS/part_export/.cvs_is_on_crack b/httemplate/docs/man/FS/part_export/.cvs_is_on_crack
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/httemplate/docs/man/FS/part_export/.cvs_is_on_crack
diff --git a/httemplate/docs/overview.dia b/httemplate/docs/overview.dia
new file mode 100644
index 0000000..a0e34c3
--- /dev/null
+++ b/httemplate/docs/overview.dia
Binary files differ
diff --git a/httemplate/docs/overview.png b/httemplate/docs/overview.png
new file mode 100644
index 0000000..bf2dbc2
--- /dev/null
+++ b/httemplate/docs/overview.png
Binary files differ
diff --git a/httemplate/docs/passwd.html b/httemplate/docs/passwd.html
new file mode 100755
index 0000000..fc1dde9
--- /dev/null
+++ b/httemplate/docs/passwd.html
@@ -0,0 +1,23 @@
+<head>
+ <title>fs_passwd</title>
+</head>
+<body>
+ <h1>fs_passwd</h1>
+You may use fs_passwd/fs_passwd as a "passwd", "chfn" and "chsh" replacement on your shell machine(s) to cause password, gecos and shell changes to update your freeside machine. You can also use the fs_passwd/fs_passwd.html and fs_passwd/fs_passwd.cgi to run a public password change CGI on a public web server. This can pose a security risk if not configured correctly. <b>Do not use this feature unless you understand what you are doing!</b>
+<br><br>Currently it is assumed that the the crypt(3) function in the C library is the same on the Freeside machine as on the target machine.
+<ul>
+ <li>Create a freeside account on the shell or web machine(s).
+ <li>Setup SSH keys:
+ <ul>
+ <li>As the freeside user (on your freeside machine), generate an authentication key using <a href="http://www.tac.eu.org/cgi-bin/man-cgi?ssh-keygen+1">ssh-keygen</a>. Since this is for unattended operation, use a blank passphrase.
+ <li>Append the newly-created <code>identity.pub</code> file to <code>~freeside
+/.ssh/authorized_keys</code> on the shell or web machine(s).
+ <li>Some new SSH v2 implementation accept v2 style keys only. Use the <code>-t</code> option to <a href="http://www.tac.eu.org/cgi-bin/man-cgi?ssh-keygen+1">ssh-keygen</a>, and append the created <code>id_dsa.pub</code> or <code>id_rsa.pub</code> to <code>~freeside/.ssh/authorized_keys2</code> on the remote machine(s).
+ </ul>
+ <li>Copy fs_passwd/fs_passwdd to /usr/local/sbin on the shell or web machine(s). (chown freeside, chmod 500)
+ <li>Create /usr/local/freeside on the shell or web machine(s). (chown freeside, chmod 700)
+ <li>Run an iteration of "fs_passwd/fs_passwd_server <i>user</i> shell.machine" as the freeside user for each shell or web machine (this is a daemon process). <i>user</i> refers to a freeside user added by <a href="man/bin/freeside-adduser.html">freeside-adduser</a>.
+ <li>Copy fs_passwd/fs_passwd to /usr/local/bin on the shell machine(s). (chown freeside, chmod 4755). You may link it to passwd, chfn and chsh as well.
+ <li>Copy fs_passwd/fs_passwd.cgi to the cgi-bin directory on your web machine(s). Use <a href="http://www.apache.org/docs/suexec.html">suEXEC</a> or <a href="http://www.perldoc.com/perl5.6.1/pod/perlsec.html">suidperl</a> to run fs_passwd.cgi as the freeside user.
+</ul>
+</body>
diff --git a/httemplate/docs/schema.dia b/httemplate/docs/schema.dia
new file mode 100644
index 0000000..7465615
--- /dev/null
+++ b/httemplate/docs/schema.dia
Binary files differ
diff --git a/httemplate/docs/schema.html b/httemplate/docs/schema.html
new file mode 100644
index 0000000..b380317
--- /dev/null
+++ b/httemplate/docs/schema.html
@@ -0,0 +1,435 @@
+<head>
+ <title>Schema reference</title>
+</head>
+<body>
+ <h1>Schema reference</h1>
+ Schema diagram: <a href="schema.png">as a giant .png</a> or <a href="schema.dia">dia source</a> (<a href="http://www.lysator.liu.se/~alla/dia/">dia homepage</a>).
+ <ul>
+ <li><a name="agent" href="man/FS/agent.html">agent</a> - Agents are resellers of your service. Agents may be limited to a subset of your full offerings (via their agent type).
+ <ul>
+ <li>agentnum - primary key
+ <li>agent - name of this agent
+ <li>typenum - <a href="#agent_type">agent type</a>
+ <li>prog - (unimplemented)
+ <li>freq - (unimplemented)
+ <li>disabled - Disabled flag, empty or 'Y'
+ <li>username - Username for the Agent interface
+ <li>_password - Password for the Agent interface
+ </ul>
+ <li><a name="agent_type" href="man/FS/agent_type.html">agent_type</a> - Agent types define groups of packages that you can then assign to particular agents.
+ <ul>
+ <li>typenum - primary key
+ <li>atype - name of this agent type
+ </ul>
+ <li><a name="cust_bill" href="man/FS/cust_bill.html">cust_bill</a> - Invoices. Declarations that a customer owes you money. The specific charges are itemized in <a href="#cust_bill_pkg">cust_bill_pkg</a>.
+ <ul>
+ <li>invnum - primary key
+ <li>custnum - <a href="#cust_main">customer</a>
+ <li>_date
+ <li>charged - amount of this invoice
+ <li>printed - how many times this invoice has been printed automatically
+ <li>closed - books closed flag, empty or `Y'
+ </ul>
+ <li><a name="cust_bill_event" href="man/FS/cust_bill_event.html">cust_bill_event</a> - Invoice event history
+ <ul>
+ <li>eventnum - primary key
+ <li>invnum - <a href="#cust_bill">invoice</a>
+ <li>eventpart - <a href="#part_bill_event">event definition</a>
+ <li>_date
+ <li>status
+ <li>statustext
+ </ul>
+ <li><a name="part_bill_event" href="man/FS/part_bill_event.html">part_bill_event</a> - Invoice event definitions
+ <ul>
+ <li>eventpart - primary key
+ <li>payby - CARD, DCRD, CHEK, DCHK, LECB, BILL, or COMP
+ <li>event - event name
+ <li>eventcode - event action
+ <li>seconds - how long after the invoice date (<a href="#cust_bill">cust_bill</a>._date) events of this type are triggered
+ <li>weight - ordering for events with identical seconds
+ <li>plan - eventcode plan
+ <li>plandata - additional plan data
+ <li>disabled - Disabled flag, empty or `Y'
+ <li>taxclass - Texas tax class flag, empty or "none", "access", or "hosting"
+ </ul>
+ <li><a name="cust_bill_pkg" href="man/FS/cust_bill_pkg.html">cust_bill_pkg</a> - Invoice line items
+ <ul>
+ <li>invnum - (multiple) key
+ <li>pkgnum - <a href="#cust_pkg">package</a> or 0 for the special virtual sales tax package
+ <li>setup - setup fee
+ <li>recur - recurring fee
+ <li>sdate - starting date
+ <li>edate - ending date
+ <li>itemdesc - Line item description (currently used only when pkgnum is 0)
+ </ul>
+ <li><a name="cust_bill_pkg_detail" href="man/FS/cust_bill_pkg_detail.html">cust_bill_pkg_detail</a> - Invoice line items detail
+ <ul>
+ <li>detailnum - primary key
+ <li>pkgnum -
+ <li>invnum -
+ <li>detail - Detail description
+ </ul>
+ <li><a name="cust_credit" href="man/FS/cust_credit.html">cust_credit</a> - Credits. The equivalent of a negative <a href="#cust_bill">cust_bill</a> record.
+ <ul>
+ <li>crednum - primary key
+ <li>custnum - <a href="#cust_main">customer</a>
+ <li>amount - amount credited
+ <li>_date
+ <li>otaker - order taker
+ <li>reason
+ <li>closed - books closed flag, empty or `Y'
+ </ul>
+ <li><a name="cust_credit_bill" href="man/FS/cust_credit_bill.html">cust_credit_bill</a> - Credit invoice application. Links a credit to an invoice.
+ <ul>
+ <li>creditbillnum - primary key
+ <li>crednum - <a href="#cust_credit">credit</a> being applied
+ <li>invnum - <a href="#cust_bill">invoice</a> to which credit is applied
+ <li>amount - amount applied
+ <li>_date
+ </ul>
+ <li><a name="cust_main" href="man/FS/cust_main.html">cust_main</a> - Customers
+ <ul>
+ <li>custnum - primary key
+ <li>agentnum - <a href="#agent">agent</a>
+ <li>refnum - <a href="#part_referral">referral</a>
+ <li>first - name
+ <li>last - name
+ <li>ss - social security number
+ <li>company
+ <li>address1
+ <li>address2
+ <li>city
+ <li>county
+ <li>state
+ <li>zip
+ <li>country
+ <li>daytime - phone
+ <li>night - phone
+ <li>fax - phone
+ <li><i>ship_first</i>
+ <li><i>ship_last</i>
+ <li><i>ship_company</i>
+ <li><i>ship_address1</i>
+ <li><i>ship_address2</i>
+ <li><i>ship_city</i>
+ <li><i>ship_county</i>
+ <li><i>ship_state</i>
+ <li><i>ship_zip</i>
+ <li><i>ship_country</i>
+ <li><i>ship_daytime</i>
+ <li><i>ship_night</i>
+ <li><i>ship_fax</i>
+ <li>payby - CARD, DCHK, CHEK, DCHK, LECB, BILL, or COMP
+ <li>payinfo - card number, P.O.#, or comp issuer
+ <li>paycvv - Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit number on the back (or front, for American Express) of the credit card
+ <li>paydate - expiration date
+ <li>payname - billing name (name on card)
+ <li>tax - tax exempt, Y or null
+ <li>otaker - order taker
+ <li>referral_custnum
+ <li>comments
+ </ul>
+ (columns in <i>italics</i> are optional)
+ <li><a name="cust_main_invoice" href="man/FS/cust_main_invoice.html">cust_main_invoice</a> - Invoice destinations for email invoices. Note that a customer can have many email destinations for their invoice (either literal or via svcnum), but only one postal destination.
+ <ul>
+ <li>destnum - primary key
+ <li>custnum - <a href="#cust_main">customer</a>
+ <li>dest - Invoice destination. Freeside supports three types of invoice delivery: send directly to a service defined in Freeside, send to an arbitrary email address, or print the invoice to a printer and have someone send it out via snail mail. Freeside determines which method to use based on the contents of the dest field. If the contents are numeric, a <a href="#svc_acct">svcnum</a> pointing to a valid service is expected in the field. If the contents are a string, a literal email address is expected to be in the field. If the special keyword `POST' is present, the snail mail method is used (which is the default if no cust_main_invoice records exist). Snail mail invoices get their address information from <A name="#cust_main">cust_main</A> and are printed with the printer defined in the configuration files.
+ </ul>
+ <li><a name="cust_main_county" href="man/FS/cust_main_county.html">cust_main_county</a> - Tax rates
+ <ul>
+ <li>taxnum - primary key
+ <li>state
+ <li>county
+ <li>country
+ <li>tax - % rate
+ <li>taxclass
+ <li>exempt_amount
+ <li>taxname - if defined, printed on invoices instead of "Tax"
+ <li>setuptax - if 'Y', this tax does not apply to setup fees
+ <li>recurtax - if 'Y', this tax does not apply to recurring fees
+ </ul>
+ <li><a name="cust_tax_exempt" href="man/FS/cust_tax_exempt.html">cust_tax_exempt</a> - Tax exemption record
+ <ul>
+ <li>exemptnum - primary key
+ <li>taxnum - <a href="#cust_main_county">tax rate</a>
+ <li>year
+ <li>month
+ <li>amount
+ </ul>
+ <li><a name="cust_pay" href="man/FS/cust_pay.html">cust_pay</a> - Payments. Money being transferred from a customer.
+ <ul>
+ <li>paynum - primary key
+ <li>custnum - <a href="#cust_main">customer</a>
+ <li>paid - amount
+ <li>_date
+ <li>payby - CARD, CHEK, LECB, BILL, or COMP
+ <li>payinfo - card number, P.O.#, or comp issuer
+ <li>paybatch - text field for tracking card processor batches
+ <li>closed - books closed flag, empty or `Y'
+ </ul>
+ <li><a name="cust_bill_pay" href="man/FS/cust_bill_pay.html">cust_bill_pay</a> - Applicaton of a payment to a specific invoice.
+ <ul>
+ <li>billpaynum
+ <li>invnum - <a href="#cust_bill">invoice</a>
+ <li>paynum - <a href="#cust_pay">payment</a>
+ <li>amount
+ <li>_date
+ </ul>
+ <li><a name="cust_pay_batch" href="man/FS/cust_pay_batch.html">cust_pay_batch</a> - Pending batch
+ <ul>
+ <li>paybatchnum
+ <li>cardnum
+ <li>exp - card expiration
+ <li>amount
+ <li>invnum - <a href="#cust_bill">invoice</a>
+ <li>custnum - <a href="#cust_main">customer</a>
+ <li>payname - name on card
+ <li>first - name
+ <li>last - name
+ <li>address1
+ <li>address2
+ <li>city
+ <li>state
+ <li>zip
+ <li>country
+ </ul>
+ <li><a name="cust_pkg" href="man/FS/cust_pkg.html">cust_pkg</a> - Customer billing items
+ <ul>
+ <li>pkgnum - primary key
+ <li>custnum - <a href="#cust_main">customer</a>
+ <li>pkgpart - <a href="#part_pkg">Package definition</a>
+ <li>setup - date
+ <li>bill - next bill date
+ <li>last_bill - last bill date
+ <li>susp - (past) suspension date
+ <li>expire - (future) cancellation date
+ <li>cancel - (past) cancellation date
+ <li>otaker - order taker
+ <li>manual_flag - If this field is set to 1, disables the automatic unsuspensiond of this package when using the <a href="config.html#unsuspendauto">unsuspendauto</a> config file.
+ </ul>
+ <li><a name="cust_refund" href="man/FS/cust_refund.html">cust_refund</a> - Refunds. The transfer of money to a customer; equivalent to a negative <a href="#cust_pay">cust_pay</a> record.
+ <ul>
+ <li>refundnum - primary key
+ <li>custnum - <a href="#cust_main">customer</a>
+ <li>refund - amount
+ <li>_date
+ <li>payby - CARD, CHEK, LECB, BILL or COMP
+ <li>payinfo - card number, P.O.#, or comp issuer
+ <li>otaker - order taker
+ <li>closed - books closed flag, empty or `Y'
+ </ul>
+ <li><a name="cust_credit_refund" href="man/FS/cust_credit_refund.html">cust_credit_refund</a> - Applicaton of a refund to a specific credit.
+ <ul>
+ <li>creditrefundnum - primary key
+ <li>crednum - <a href="#cust_credit">credit</a>
+ <li>refundnum - <a href="#cust_refund">refund</a>
+ <li>amount
+ <li>_date
+ </ul>
+ <li><a name="cust_svc" href="man/FS/cust_svc.html">cust_svc</a> - Customer services
+ <ul>
+ <li>svcnum - primary key
+ <li>pkgnum - <a href="#cust_pkg">package</a>
+ <li>svcpart - <a href="#part_svc">Service definition</a>
+ </ul>
+ <li><a name="nas" href="man/FS/nas.html">nas</a> - Network Access Server (terminal server)
+ <ul>
+ <li>nasnum - primary key
+ <li>nas - NAS name
+ <li>nasip - NAS ip address
+ <li>nasfqdn - NAS fully-qualified domain name
+ <li>last - timestamp indicating the last instant the NAS was in a known state (used by the session monitoring).
+ </ul>
+ <li><a name="part_pkg" href="man/FS/part_pkg.html">part_pkg</a> - Package definitions
+ <ul>
+ <li>pkgpart - primary key
+ <li>pkg - package name
+ <li>comment - non-customer visable package comment
+ <li>setup - setup fee expression
+ <li>freq - recurring frequency (months)
+ <li>recur - recurring fee expression
+ <li>setuptax - Setup fee tax exempt flag, empty or `Y'
+ <li>recurtax - Recurring fee tax exempt flag, empty or `Y'
+ <li>plan - price plan
+ <li>plandata - additional price plan data
+ <li>disabled - Disabled flag, empty or `Y'
+ </ul>
+ <li><a name="part_referral" href="man/FS/part_referral.html">part_referral</a> - Referral listing
+ <ul>
+ <li>refnum - primary key
+ <li>referral - referral
+ </ul>
+ <li><a name="part_svc" href="man/FS/part_svc.html">part_svc</a> - Service definitions
+ <ul>
+ <li>svcpart - primary key
+ <li>svc - name of this service
+ <li>svcdb - table used for this service: svc_acct, svc_forward, svc_domain, svc_charge or svc_wo
+ <li>disabled - Disabled flag, empty or `Y'
+<!-- <li><i>table</i>__<i>field</i> - Default or fixed value for <i>field</i> in <i>table</i>
+ <li><i>table</i>__<i>field</i>_flag - null, D or F
+-->
+ </ul>
+ <li><a name="part_svc_column" href="man/FS/part_svc_column.html">part_svc_column</a>
+ <ul>
+ <li>columnnum - primary key
+ <li>svcpart - <a href="#part_svc">Service definition</a>
+ <li>columnname - column name in part_svc.svcdb table
+ <li>columnvalue - default or fixed value for the column
+ <li>columnflag - null, D or F
+ </ul>
+ <li><a name="pkg_svc" href="man/FS/pkg_svc.html">pkg_svc</a>
+ <ul>
+ <li>pkgpart - <a href="#part_pkg">Package definition</a>
+ <li>svcpart - <a href="#part_svc">Service definition</a>
+ <li>quantity - quantity of this service that this package includes
+ <li>primary_svc - blank or Y: primary service
+ </ul>
+ <li><a name="export_svc" href="man/FS/export_svc.html">export_svc</a>
+ <ul>
+ <li>exportsvcnum - primary key
+ <li>svcpart - <a href="#part_svc">Service definition</a>
+ <li>exportnum - <a href="#exportnum">Export</a>
+ </ul>
+ <li><a name="part_export" href="man/FS/part_export.html">part_export</a> - Export to external provisioning
+ <ul>
+ <li>exportnum - primary key
+ <li>machine - Machine name
+ <li>exporttype - Export type
+ <li>nodomain - blank or Y: usernames are exported to this service with no domain
+ </ul>
+ <li><a name="part_export_option" href="man/FS/part_export_option.html">part_export_option</a> - provisioning options
+ <ul>
+ <li>optionnum - primary key
+ <li>exportnum - <a href="#part_export">Export</a>
+ <li>optionname - option name
+ <li>optionvalue - option value
+ </ul>
+ <li><a name="port" href="man/FS/port.html">port</a> - individual port on a <a href="#nas">nas</a>
+ <ul>
+ <li>portnum - primary key
+ <li>ip - IP address of this port
+ <li>nasport - port number on the NAS
+ <li>nasnum - <a href="#nas">NAS</a>
+ </ul>
+ <li><a name="prepay_credit" href="man/FS/prepay_credit.html">prepay_credit</a>
+ <ul>
+ <li>prepaynum - primary key
+ <li>identifier - text or numeric string used to receive this credit
+ <li>amount - amount of credit
+ </ul>
+ <li><a name="session" href="man/FS/session.html">session</a>
+ <ul>
+ <li>sessionnum - primary key
+ <li>portnum - <a href="#port">Port</a>
+ <li>svcnum - <a href="#svc_acct">Account</a>
+ <li>login - timestamp indicating the beginning of this user session.
+ <li>logout - timestamp indicating the end of this user session. May be null, which indicates a currently open session.
+ </ul>
+
+ <li><a name="svc_acct" href="man/FS/svc_acct.html">svc_acct</a> - Accounts
+ <ul>
+ <li>svcnum - <a href="#cust_svc">primary key</a>
+ <li>username
+ <li>_password
+ <li>sec_phrase - security phrase
+ <li>popnum - <a href="#svc_acct_pop">Point of Presence</a>
+ <li>uid
+ <li>gid
+ <li>finger - GECOS
+ <li>dir
+ <li>shell
+ <li>quota - (unimplementd)
+ <li>slipip - IP address
+ <li>seconds
+ <li>domsvc
+ <li>radius_<i>Radius_Reply_Attribute</i> - Radius-Reply-Attribute
+ <li>rc_<i>Radius_Check_Attribute</i> - Radius-Check-Attribute
+ </ul>
+ <li><a name="svc_acct_pop" href="man/FS/svc_acct_pop.html">svc_acct_pop</a> - Points of Presence
+ <ul>
+ <li>popnum - primary key
+ <li>city
+ <li>state
+ <li>ac - area code
+ <li>exch - exchange
+ <li>loc - rest of number
+ </ul>
+ <li><a name="part_pop_local" href="man/FS/part_pop_local.html">part_pop_local</a> - Local calling areas
+ <ul>
+ <li>localnum - primary key
+ <li>popnum - primary key
+ <li>city
+ <li>state
+ <li>npa - area code
+ <li>nxx - exchange
+ </ul>
+ <li><a name="svc_domain" href="man/FS/svc_domain.html">svc_domain</a> - Domains
+ <ul>
+ <li>svcnum - <a href="#cust_svc">primary key</a>
+ <li>domain
+ </ul>
+ <li><a name="svc_forward" href="man/FS/svc_forward.html">svc_forward</a> - Mail forwarding aliases
+ <ul>
+ <li>svcnum - <a href="#cust_svc">primary key</a>
+ <li>srcsvc - <a href="#svc_acct">svcnum of the source of this forward</a>
+ <li>src - literal source (username or full email address)
+ <li>dstsvc - <a href="#svc_acct">svcnum of the destination of this forward</a>
+ <li>dst - literal destination (username or full email address)
+ </ul>
+ <li><a name="domain_record" href="man/FS/domain_record.html">domain_record</a> - Domain zone detail
+ <ul>
+ <li>recnum - primary key
+ <li>svcnum - <a href="#svc_domain">Domain</a> (by svcnum)
+ <li>reczone - zone for this line
+ <li>recaf - address family, usually <b>IN</b>
+ <li>rectype - type for this record (<b>A</b>, <b>MX</b>, etc.)
+ <li>recdata - data for this record
+ </ul>
+ <li><a name="svc_www" href="man/FS/svc_www.html">svc_www</a>
+ <ul>
+ <li>svcnum - <a href="#cust-svc">primary key</a>
+ <li>recnum - <a href="#domain_record">host</a>
+ <li>usersvc - <a href="#svc_acct">account</a>
+ </ul>
+ <li><a name="type_pkgs" href="man/FS/type_pkgs.html">type_pkgs</a>
+ <ul>
+ <li>typenum - <a href="#agent_type">agent type</a>
+ <li>pkgpart - <a href="#part_pkg">Package definition</a>
+ </ul>
+ <li><a name="queue" href="man/FS/queue.html">queue</a> - job queue
+ <ul>
+ <li>jobnum - primary key
+ <li>job
+ <li>_date
+ <li>status
+ <li>statustext
+ <li>svcnum
+ </ul>
+ <li><a name="queue_arg" href="man/FS/queue_arg.html">queue_arg</a> - job arguments
+ <ul>
+ <li>argnum - primary key
+ <li>jobnum - <a href="#queue">job</a>
+ <li>arg - argument
+ </ul>
+ <li><a name="queue_depend" href="man/FS/queue_depend.html">queue_depend</a> - job dependancies
+ <ul>
+ <li>dependnum - primary key
+ <li>jobnum - source jobnum
+ <li>depend_jobnum - dependancy jobnum
+ </ul>
+ <li><a name="radius_usergroup" href="man/FS/radius_usergroup.html">radius_usergroup</a> - Link users to RADIUS groups.
+ <ul>
+ <li>usergroupnum - primary key
+ <li>svcnum - <a href="#svc_acct">account</a>
+ <li>groupname
+ </ul>
+ <li><a name="msgcat" href="man/FS/msgcat.html">msgcat</a> - i18n message catalog
+ <ul>
+ <li>msgnum - primary key
+ <li>msgcode - message code
+ <li>locale - locale
+ <li>msg - Message text
+ </ul>
+ </ul>
+</body>
diff --git a/httemplate/docs/schema.png b/httemplate/docs/schema.png
new file mode 100644
index 0000000..d0392e7
--- /dev/null
+++ b/httemplate/docs/schema.png
Binary files differ
diff --git a/httemplate/docs/session.html b/httemplate/docs/session.html
new file mode 100644
index 0000000..72e1642
--- /dev/null
+++ b/httemplate/docs/session.html
@@ -0,0 +1,59 @@
+<head>
+ <title>Session monitor</title>
+</head>
+<body>
+<h1>Session monitor</h1>
+<h2>Installation</h2>
+For security reasons, the client portion of the session montior may run on one
+or more external public machine(s). On these machines, install:
+<ul>
+ <li><a href="http://www.perl.com/CPAN/doc/relinfo/INSTALL.html">Perl</a> (at l
+east 5.004_05 for the 5.004 series or 5.005_03 for the 5.005 series. Don't enable experimental features like threads or the PerlIO abstraction layer.)
+ <li><a href="man/FS/SessionClient.html">FS::SessionClient</a> (copy the fs_session/FS-SessionClient directory to the external machine, then: perl Makefile.PL; make; make install)
+</ul>
+Then:
+<ul>
+ <li>Add the user `freeside' to the the external machine.
+ <li>Create the /usr/local/freeside directory on the external machine (owned by the freeside user).
+ <li>touch /usr/local/freeside/fs_sessiond_socket; chown freeside /usr/local/freeside/fs_sessiond_socket; chmod 600 /usr/local/freeside/fs_sessiond_socket
+ <li>Append the identity.pub from the freeside user on your freeside machine to the authorized_keys file of the newly created freeside user on the external machine(s).
+ <li>Run <pre>fs_session_server <i>user</i> <i>machine</i></pre> on the Freeside machine.
+ <ul>
+ <li><i>user</i> is a user from the mapsecrets file.
+ <li><i>machine</i> is the name of the external machine.
+ </ul>
+</ul>
+<h2>Usage</h2>
+<ul>
+ <li>Web
+ <ul>
+ <li>Copy FS-SessionClient/cgi/login.cgi and logout.cgi to your web
+ server's document space.
+ <li>Use <a href="http://www.apache.org/docs/suexec.html">suEXEC</a> or <a href="http://www.perl.com/CPAN-local/doc/manual/html/pod/perlsec.html#Security_Bugs">setuid</a> (see <a href="install.html">install.html</a> for details) to run login.cgi and logout.cgi as the freeside user.
+ </ul>
+ <li>Command-line
+ <br><pre>freeside-login username ( portnum | ip | nasnum nasport )
+freeside-logout username ( portnum | ip | nasnum nasport )</pre>
+ <ul>
+ <li><i>username</i> is a customer username from the svc_acct table
+ <li><i>portnum</i>, <i>ip</i> or <i>nasport</i> and <i>nasnum</i> uniquely identify a port in the <a href="schema.html#port">port</a> database table.
+ </ul>
+ <li>RADIUS - One of:
+ <ul>
+ <li>Run the <b>freeside-sqlradius-radacctd</b> daemon to import radacct
+ records from all configured sqlradius exports:
+ <tt>freeside-sqlradius-radacctd username</tt>
+ <li>Configure your RADIUS server's login and logout callbacks to use the command-line <tt>freeside-login</tt> and <tt>freeside-logout</tt> utilites.
+ <li> <i>(incomplete)</i>Use the <b>fs_radlog/fs_radlogd</b> tool to
+ import records from a text radacct file.
+ </ul>
+</ul>
+<h2>Callbacks</h2>
+<ul>
+ <li>Sesstion start - The command(s) specified in the <a href="config.html#session-start">session-start</a> configuration file are executed on the Freeside machine. The contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$ip</code>, <code>$nasip</code> and <code>$nasfqdn</code>, which are the IP address of the starting session, and the IP address and fully-qualified domain name of the NAS this session is on.
+ <li>Session end - The command(s) specified in the <a href="config.html#session-stop">session-stop</a> configuration file are executed on the Freeside machine. The contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$ip</code>, <code>$nasip</code> and <code>$nasfqdn</code>, which are the IP address of the starting session, and the IP address and fully-qualified domain name of the NAS this session is on.
+</ul>
+<h2>Dropping expired users</h2>
+Run <pre>bin/freeside-session-kill username</pre> periodically from cron.
+</body>
+</html>
diff --git a/httemplate/docs/signup.html b/httemplate/docs/signup.html
new file mode 100644
index 0000000..97d7aa7
--- /dev/null
+++ b/httemplate/docs/signup.html
@@ -0,0 +1,54 @@
+<head>
+ <title>Signup server</title>
+</head>
+<body>
+ <h1>Signup server</h1>
+For security reasons, the signup server should run on an external public
+webserver. On this machine, install:
+<ul>
+ <li>A web server, such as <a href="http://www.apache-ssl.org">Apache-SSL</a> or <a href="http://www.apache.org">Apache</a>
+ <li><a href="ftp://ftp.cs.hut.fi/pub/ssh/">SSH</a>
+ <li><a href="http://www.perl.com/CPAN/doc/relinfo/INSTALL.html">Perl</a> (at least 5.004_05 for the 5.004 series or 5.005_03 for the 5.005 series. Don't enable experimental features like threads or the PerlIO abstraction layer.)
+ <li><a href="http://search.cpan.org/search?dist=Text-Template">Text::Template</a>
+ <li><a href="http://search.cpan.org/search?dist=Storable">Storable</a>
+ <li><a href="http://search.cpan.org/search?dist=Business-CreditCard">Business-CreditCard</a>
+ <li><a href="http://search.cpan.org/search?dist=HTTP-BrowserDetect">HTTP::BrowserDetect</a>
+
+ <li><a href="man/FS/SignupClient.html">FS::SignupClient</a> (copy the fs_signup/FS-SignupClient directory to the external machine, then: perl Makefile.PL; make; make install)
+</ul>
+Then:
+<ul>
+ <li>Add the user `freeside' to the the external machine.
+ <li>Copy or symlink fs_signup/FS-SignupClient/cgi/signup.cgi into the web server's document space.
+ <li>When linking to signup.cgi, you can include a referring custnum in the URL as follows: <code>http://public.web.server/path/signup.cgi?ref=1542</code>
+ <li>Enable CGI execution for files with the `.cgi' extension. (with <a href="http://www.apache.org/docs/mod/mod_mime.html#addhandler">Apache</a>)
+ <li>Create the /usr/local/freeside directory on the external machine (owned by the freeside user).
+ <li>touch /usr/local/freeside/fs_signupd_socket; chown freeside /usr/local/freeside/fs_signupd_socket; chmod 600 /usr/local/freeside/fs_signupd_socket
+ <li>Use <a href="http://www.apache.org/docs/suexec.html">suEXEC</a> or <a href="http://www.perl.com/CPAN-local/doc/manual/html/pod/perlsec.html#Security_Bugs">setuid</a> (see <a href="install.html">install.html</a> for details) to run signup.cgi as the freeside user.
+ <li>Append the identity.pub from the freeside user on your freeside machine to the authorized_keys file of the newly created freeside user on the external machine(s).
+ <li>Run <pre>fs_signup_server <i>user</i> <i>machine</i> <i>agentnum</i> <i>refnum</i></pre> on the Freeside machine.
+ <ul>
+ <li><i>user</i> is a user from the mapsecrets file.
+ <li><i>machine</i> is the name of the external machine.
+ <li><i>agentnum</i> and <i>refnum</i> are the <a href="schema.html#agent">agent</a> and <a href="schema.html#part_referral">referral</a>, respectively, to use for customers who sign up via this signup server.
+ </ul>
+</ul>
+Optional:
+<ul>
+ <li>If you create a <b>/usr/local/freeside/ieak.template</b> file on the external machine, it will be sent to IE users with MIME type <i>application/x-Internet-signup</i>. This file will be processed with <a href="http://search.cpan.org/doc/MJD/Text-Template-1.23/Template.pm">Text::Template</a> with the variables listed below available.
+ (an example file is included as <b>fs_signup/ieak.template</b>) See the section on <a href="http://www.microsoft.com/windows/ieak/techinfo/deploy/60/en/INS.HTM">internet settings files</a> in the <a href="http://www.microsoft.com/windows/ieak/techinfo/deploy/60/en/toc.asp">IEAK documentation</a> for more information.
+ <li>If you create a <b>/usr/local/freeside/success.html</b> file on the external machine, it will be used as the success HTML page. Although template substiutions are available, a regular HTML file will work fine here, unlike signup.html. An example file is included as <b>fs_signup/FS-SignupClient/cgi/success.html</b>
+ <li>Variable substitutions available in <b>ieak.template</b>, <b>cck.template</b> and <b>success.html</b>:
+ <ul>
+ <li>$ac - area code of selected POP
+ <li>$exch - exchange of selected POP
+ <li>$loc - local part of selected POP
+ <li>$username
+ <li>$password
+ <li>$email_name - first and last name
+ <li>$pkg - package name
+ </ul>
+ <li>If you create a <b>/usr/local/freeside/signup.html</b> file on the external machine, it will be used as a template for the form HTML. This requires the template to be constructed appropriately; probably best to start with the example file included as <b>fs_signup/FS-SignupClient/cgi/signup.html</b>.
+ <li>If there are any entries in the <i>prepay_credit</i> table, a user can enter a string matching the <b>identifier</i> column to receive the credit specified in the <b>amount</b> column, and/or the time specified in the <b>seconds</b> column (for use with the <a href="session.html">session monitor</a>), after which that <b>identifier</b> is no longer valid. This can be used to implement pre-paid "calling card" type signups. The <i>bin/generate-prepay</i> script can be used to populate the <i>prepay_credit</i> table.
+</ul>
+</body>
diff --git a/httemplate/docs/ssh.html b/httemplate/docs/ssh.html
new file mode 100755
index 0000000..d2c501e
--- /dev/null
+++ b/httemplate/docs/ssh.html
@@ -0,0 +1,16 @@
+<head>
+ <title>Unattended SSH</title>
+</head>
+<body>
+ <h1>Unattended SSH</h1>
+ <br><a name=ssh>Unattended remote login</a> - Freeside can login to remote machines unattended using SSH. This can pose a security risk if not configured correctly, and will allow an intruder who breaks into your freeside machine full access to your remote machines. <b>Do not use this feature unless you understand what you are doing!</b>
+ <ul>
+ <li>As the freeside user (on your freeside machine), generate an authentication key using <a href="http://www.tac.eu.org/cgi-bin/man-cgi?ssh-keygen+1">ssh-keygen</a>. Since this is for unattended operation, use a blank passphrase.
+ <li>Append the newly-created <code>identity.pub</code> file to <code>~root/.ssh/authorized_keys</code> (or the appopriate <code>~username/.ssh/authorized_keys</code>) on the remote machine(s).
+ <li>Some new SSH v2 implementation accept v2 style keys only. Use the <code>-t</code> option to <a href="http://www.tac.eu.org/cgi-bin/man-cgi?ssh-keygen+1">ssh-keygen</a>, and append the created <code>id_dsa.pub</code> or <code>id_rsa.pub</code> to <code>~root/.ssh/authorized_keys2</code> (or the appopriate <code>~username/.ssh/authorized_keys</code>) on the remote machine(s).
+ <li>You may need to set <code>PermitRootLogin without-password</code> (meaning with keys only) in your <code>sshd_config</code> file on the remote machine(s).
+ <li>You may want to set <code>ForwardX11 = no</code> in <code>~root/.ssh/config</code> to prevent spurious errors if your distribution turns on X11 forwarding by default.
+ </ul>
+
+</body>
+
diff --git a/httemplate/docs/trouble.html b/httemplate/docs/trouble.html
new file mode 100755
index 0000000..fce7439
--- /dev/null
+++ b/httemplate/docs/trouble.html
@@ -0,0 +1,26 @@
+<head>
+ <title>Troubleshooting</title>
+</head>
+<body>
+ <h1>Troubleshooting</h1>
+ <ul>
+ <li>When troubleshooting the web interface, helpful information is often in your web server's error log.
+ <li>If bin/svc_acct.import fails with an "Out of memory!" error using MySQL, upgrede MySQL and recompile the Perl DBD. There was a memory leak in some older versions of MySQL.
+ <li>If you get tons of errors in your web server's error log like this:
+<pre>
+Ambiguous use of value => resolved to "value" =>
+at /usr/lib/perl5/site_perl/File/CounterFile.pm line 132.
+</pre>
+ This clutters up your log files but is otherwise harmless. Upgrade to the latest File::CounterFile.
+ <li>If you get errors like this:
+<pre>
+UID.pm: Can't open /var/spool/freeside/conf/secrets: Permission denied
+at <i>/your/path</i>/site_perl/FS/UID.pm line 26.
+BEGIN failed--compilation aborted at
+<i>/your/path</i>/edit/process/part_svc.cgi line 15.
+</pre>
+ Then the scripts are not running as the freeside freeside user. See
+the <a href="install.html">New Installation</a> section of the documentation.
+ <li>If you receive `can not connect to server' errors using MySQL on a system that doesn't support native threading, you may need to specify the full hostname in your DBI datasource. See the <a href="http://www.mysql.com/Manual_chapter/manual_Problems.html#Can_not_connect_to_server">MySQL documentation</a>, DBI manpage and the DBD::mysql manpage for details.
+ </ul>
+</body>
diff --git a/httemplate/docs/upgrade-1.4.2.html b/httemplate/docs/upgrade-1.4.2.html
new file mode 100644
index 0000000..a246611
--- /dev/null
+++ b/httemplate/docs/upgrade-1.4.2.html
@@ -0,0 +1,27 @@
+<head>
+ <title>Upgrading to 1.4.2</title>
+</head>
+<body>
+<h1>Upgrading to 1.4.2 from 1.4.1</h1>
+<ul>
+ <li>If migrating from less than 1.4.1, see these <a href="upgrade9.html">instructions</a> first.
+ <li>Back up your data and current Freeside installation.
+ <li>Install <a href="http://search.cpan.org/search?dist=Locale-SubCountry">Locale::SubCountry</a>
+ <li>Install <a href="http://search.cpan.org/search?dist=IPC-ShareLite">IPC::ShareLite</a>
+ <li>Install <a href="http://search.cpan.org/search?dist=HTML-Widgets-SelectLayers">HTML::Widgets::SelectLayers</a> 0.04.
+ <li>Install <a href="http://search.cpan.org/search?dist=DBIx-DBSchema">DBIx::DBSchema</a> 0.23.
+ <li>Install <a href="http://search.cpan.org/search?dist=DBD-Pg">DBD::Pg</a> 1.32.
+ <li>Install <a href="http://search.cpan.org/search?dist=Cache-Cache">Cache::Cache</a>.
+ <li>Install <a href="http://search.cpan.org/search?dist=Net-SSH">Net::SSH</a> 0.08.
+ <li>Install <a href="http://search.cpan.org/search?dist=Crypt-PasswdMD5">Crypt::PasswdMD5</a>
+ <li>Install <a href="http://search.cpan.org/search?dist=Net-Whois-Raw">Net::Whois::Raw</a>
+ <li>CGI.pm minimum version 2.47 is required. You will probably need to install a current CGI.pm from CPAN if you are using Perl 5.005 or earlier.
+ <li>File::Temp minimum version 0.14 is required. You will probably need to install a currrent File::Temp from CPAN if you are using Perl 5.6 or earlier.
+ <li>If using Apache::ASP, add <code>PerlSetVar RequestBinaryRead Off</code> to your Apache configuration and make sure you are using Apache::ASP minimum version 2.55.
+ <li>Run <code>make aspdocs</code> or <code>make masondocs</code>.
+ <li>Copy <code>aspdocs/</code> or <code>masondocs/</code> to your web server's document space.
+ <li>Run <code>make install-perl-modules</code>.
+ <li>The signup server and password server are deprecated in 1.4.2. Their functionality has been incorperated into the self-service server. Edit or reinstall your init script, and set the "signup_server-default_agentnum" and "signup_server-default_refnum" configuration options. The FS::SignupClient interface is still available as a compatibility wrapper, so you should be able to continue to use your current signup.cgi.
+ <li>Optional: To use typeset invoices, install tetex and ghostscript, and copy conf/invoice_latex, conf/invoice_latexnotes, and conf/invoice_latexfooter to /usr/local/etc/freeside/conf.<datasrc>/
+ <li>Restart Apache and freeside-queued.
+</body>
diff --git a/httemplate/docs/upgrade10.html b/httemplate/docs/upgrade10.html
new file mode 100644
index 0000000..08fc28e
--- /dev/null
+++ b/httemplate/docs/upgrade10.html
@@ -0,0 +1,226 @@
+<pre>
+this is incomplete
+
+install DBD::Pg 1.32 (or, if you're using a Perl version before 5.6, you could try installing DBD::Pg 1.22 with <a href="http://420.am/~ivan/DBD-Pg-1.22-fixvercmp.patch">this patch</a> and commenting out the "use DBD::Pg 1.32" at the top of DBIx/DBSchema/DBD/Pg.pm)
+install DBIx::DBSchema 0.23
+install Net::SSH 0.08
+- If using Apache::ASP, add PerlSetVar RequestBinaryRead Off and PerlSetVar IncludesDir /your/freeside/document/root/ to your Apache configuration and make sure you are using Apache::ASP minimum version 2.55.
+- In httpd.conf, change <Files ~ \.cgi> to <Files ~ (\.cgi|\.html)>
+- In httpd.conf, change <b>AddHandler perl-script .cgi</b> or <b>SetHandler perl-script</b> to <b>AddHandler perl-script .cgi .html</b>
+
+install NetAddr::IP, Chart::Base, IPC::ShareLite and Locale::SubCountry
+
+CREATE TABLE cust_bill_pkg_detail (
+ detailnum serial,
+ pkgnum int NOT NULL,
+ invnum int NOT NULL,
+ detail varchar(80),
+ PRIMARY KEY (detailnum)
+);
+CREATE INDEX cust_bill_pkg_detail1 ON cust_bill_pkg_detail ( pkgnum, invnum );
+
+CREATE TABLE part_virtual_field (
+ vfieldpart int NOT NULL,
+ dbtable varchar(32) NOT NULL,
+ name varchar(32) NOT NULL,
+ check_block text,
+ list_source text,
+ length integer,
+ label varchar(80),
+ PRIMARY KEY (vfieldpart)
+);
+
+CREATE TABLE virtual_field (
+ recnum integer NOT NULL,
+ vfieldpart integer NOT NULL,
+ value varchar(128) NOT NULL,
+ PRIMARY KEY (vfieldpart, recnum)
+);
+
+CREATE TABLE router (
+ routernum serial,
+ routername varchar(80),
+ svcnum int,
+ PRIMARY KEY (routernum)
+);
+
+CREATE TABLE part_svc_router (
+ svcpart int NOT NULL,
+ routernum int NOT NULL
+);
+
+CREATE TABLE addr_block (
+ blocknum serial,
+ routernum int NOT NULL,
+ ip_gateway varchar(15) NOT NULL,
+ ip_netmask int NOT NULL,
+ PRIMARY KEY (blocknum)
+);
+CREATE UNIQUE INDEX addr_block1 ON addr_block ( blocknum, routernum );
+
+CREATE TABLE svc_broadband (
+ svcnum int NOT NULL,
+ blocknum int NOT NULL,
+ speed_up int NOT NULL,
+ speed_down int NOT NULL,
+ ip_addr varchar(15),
+ PRIMARY KEY (svcnum)
+);
+
+CREATE TABLE acct_snarf (
+ snarfnum serial,
+ svcnum int NOT NULL,
+ machine varchar(255) NULL,
+ protocol varchar(80) NULL,
+ username varchar(80) NULL,
+ _password varchar(80) NULL,
+ PRIMARY KEY (snarfnum)
+);
+CREATE INDEX acct_snarf1 ON acct_snarf ( svcnum );
+
+CREATE TABLE svc_external (
+ svcnum int NOT NULL,
+ id int NOT NULL,
+ title varchar(80),
+ PRIMARY KEY (svcnum)
+);
+
+CREATE TABLE part_pkg_temp (
+ pkgpart serial NOT NULL,
+ pkg varchar(80) NOT NULL,
+ "comment" varchar(80) NOT NULL,
+ setup text NULL,
+ freq varchar(80) NOT NULL,
+ recur text NULL,
+ setuptax char(1) NULL,
+ recurtax char(1) NULL,
+ plan varchar(80) NULL,
+ plandata text NULL,
+ disabled char(1) NULL,
+ taxclass varchar(80) NULL,
+ PRIMARY KEY (pkgpart)
+);
+INSERT INTO part_pkg_temp SELECT * from part_pkg;
+DROP TABLE part_pkg;
+ALTER TABLE part_pkg_temp RENAME TO part_pkg;
+CREATE INDEX part_pkg1 ON part_pkg(disabled);
+
+On modern Pg:
+ALTER TABLE part_pkg DROP CONSTRAINT part_pkg_temp_pkey;
+ALTER TABLE part_pkg ADD PRIMARY KEY (pkgpart);
+select setval('public.part_pkg_temp_pkgpart_seq', ( select max(pkgpart) from part_pkg) );
+
+Or on Pg versions that don't support DROP CONSTRAINT and ADD PRIMARY KEY (tested on 7.1 and 7.2 so far):
+DROP INDEX part_pkg_temp_pkey;
+CREATE UNIQUE INDEX part_pkg_pkey ON part_pkg (pkgpart);
+7.1?: select setval('part_pkg_temp_pkgpart_seq', ( select max(pkgpart) from part_pkg) );
+7.2: select setval('part_pkg_pkgpart_seq', ( select max(pkgpart) from part_pkg) );
+
+CREATE TABLE h_part_pkg_temp (
+ historynum serial NOT NULL,
+ history_date int,
+ history_user varchar(80) NOT NULL,
+ history_action varchar(80) NOT NULL,
+ pkgpart int NOT NULL,
+ pkg varchar(80) NOT NULL,
+ "comment" varchar(80) NOT NULL,
+ setup text NULL,
+ freq varchar(80) NOT NULL,
+ recur text NULL,
+ setuptax char(1) NULL,
+ recurtax char(1) NULL,
+ plan varchar(80) NULL,
+ plandata text NULL,
+ disabled char(1) NULL,
+ taxclass varchar(80) NULL,
+ PRIMARY KEY (historynum)
+);
+INSERT INTO h_part_pkg_temp SELECT * from h_part_pkg;
+DROP TABLE h_part_pkg;
+ALTER TABLE h_part_pkg_temp RENAME TO h_part_pkg;
+CREATE INDEX h_part_pkg1 ON h_part_pkg(disabled);
+
+On modern Pg:
+ALTER TABLE h_part_pkg DROP CONSTRAINT h_part_pkg_temp_pkey;
+ALTER TABLE h_part_pkg ADD PRIMARY KEY (historynum);
+select setval('public.h_part_pkg_temp_historynum_seq', ( select max(historynum) from h_part_pkg) );
+
+Or on Pg versions that don't support DROP CONSTRAINT and ADD PRIMARY KEY (tested on 7.1 and 7.2 so far):
+DROP INDEX h_part_pkg_temp_pkey;
+CREATE UNIQUE INDEX h_part_pkg_pkey ON h_part_pkg (historynum);
+7.1?: select setval('h_part_pkg_temp_historynum_seq', ( select max(historynum) from h_part_pkg) );
+7.2: select setval('h_part_pkg_historynum_seq', ( select max(historynum) from h_part_pkg) );
+
+
+DROP INDEX cust_bill_pkg1;
+
+ALTER TABLE cust_bill_pkg ADD itemdesc varchar(80) NULL;
+ALTER TABLE h_cust_bill_pkg ADD itemdesc varchar(80) NULL;
+ALTER TABLE cust_main_county ADD taxname varchar(80) NULL;
+ALTER TABLE h_cust_main_county ADD taxname varchar(80) NULL;
+ALTER TABLE cust_main_county ADD setuptax char(1) NULL;
+ALTER TABLE h_cust_main_county ADD setuptax char(1) NULL;
+ALTER TABLE cust_main_county ADD recurtax char(1) NULL;
+ALTER TABLE h_cust_main_county ADD recurtax char(1) NULL;
+ALTER TABLE cust_pkg ADD last_bill int NULL;
+ALTER TABLE h_cust_pkg ADD last_bill int NULL;
+ALTER TABLE agent ADD disabled char(1) NULL;
+ALTER TABLE h_agent ADD disabled char(1) NULL;
+ALTER TABLE agent ADD username varchar(80) NULL;
+ALTER TABLE h_agent ADD username varchar(80) NULL;
+ALTER TABLE agent ADD _password varchar(80) NULL;
+ALTER TABLE h_agent ADD _password varchar(80) NULL;
+ALTER TABLE cust_main ADD paycvv varchar(4) NULL;
+ALTER TABLE h_cust_main ADD paycvv varchar(4) NULL;
+ALTER TABLE part_referral ADD disabled char(1) NULL;
+ALTER TABLE h_part_referral ADD disabled char(1) NULL;
+CREATE INDEX part_referral1 ON part_referral ( disabled );
+ALTER TABLE pkg_svc ADD primary_svc char(1) NULL;
+ALTER TABLE h_pkg_svc ADD primary_svc char(1) NULL;
+ALTER TABLE svc_forward ADD src varchar(255) NULL;
+ALTER TABLE h_svc_forward ADD src varchar(255) NULL;
+
+On recent Pg versions:
+
+ALTER TABLE svc_forward ALTER COLUMN srcsvc DROP NOT NULL;
+ALTER TABLE h_svc_forward ALTER COLUMN srcsvc DROP NOT NULL;
+ALTER TABLE svc_forward ALTER COLUMN dstsvc DROP NOT NULL;
+ALTER TABLE h_svc_forward ALTER COLUMN dstsvc DROP NOT NULL;
+
+Or on Pg versions that don't support DROP NOT NULL (tested on 7.1 and 7.2 so far):
+UPDATE pg_attribute SET attnotnull = FALSE WHERE ( attname = 'srcsvc' OR attname = 'dstsvc' ) AND ( attrelid = ( SELECT oid FROM pg_class WHERE relname = 'svc_forward' ) OR attrelid = ( SELECT oid FROM pg_class WHERE relname = 'h_svc_forward' ) );
+
+If you created your database with a version before 1.4.2, dump database, edit:
+- cust_main and h_cust_main: increase otaker from 8 to 32
+- cust_main and h_cust_main: change ss from char(11) to varchar(11) ( "character(11)" to "character varying(11)" )
+- cust_credit and h_cust_credit: increase otaker from 8 to 32
+- cust_pkg and h_cust_pkg: increase otaker from 8 to 32
+- cust_refund and h_cust_refund: increase otaker from 8 to 32
+- domain_record and h_domain_record: increase reczone from 80 to 255
+- domain_record and h_domain_record: change rectype from char to varchar ( "character(5)" to "character varying(5)" )
+- domain_record and h_domain_record: increase recdata from 80 to 255
+then reload
+
+optionally:
+
+ CREATE INDEX cust_main6 ON cust_main ( daytime );
+ CREATE INDEX cust_main7 ON cust_main ( night );
+ CREATE INDEX cust_main8 ON cust_main ( fax );
+ CREATE INDEX cust_main9 ON cust_main ( ship_daytime );
+ CREATE INDEX cust_main10 ON cust_main ( ship_night );
+ CREATE INDEX cust_main11 ON cust_main ( ship_fax );
+ CREATE INDEX agent2 ON agent ( disabled );
+ CREATE INDEX part_bill_event2 ON part_bill_event ( disabled );
+ CREATE INDEX cust_pay4 ON cust_pay (_date);
+
+ serial columns
+
+mandatory again:
+
+dbdef-create username
+create-history-tables username cust_bill_pkg_detail router part_svc_router addr_block svc_broadband acct_snarf svc_external
+dbdef-create username
+
+apache - fix <Files> sections to include .html also
+
+</pre>
diff --git a/httemplate/docs/upgrade7.html b/httemplate/docs/upgrade7.html
new file mode 100644
index 0000000..d9dcfe2
--- /dev/null
+++ b/httemplate/docs/upgrade7.html
@@ -0,0 +1,24 @@
+<head>
+ <title>Upgrading to 1.3.1</title>
+</head>
+<body>
+<h1>Upgrading to 1.3.1 from 1.3.0</h1>
+<ul>
+ <li>If migrating from 1.0.0, see these <a href="upgrade.html">instructions</a> first.
+ <li>If migrating from less than 1.1.4, see these <a href="upgrade2.html">instructions</a> first.
+ <li>If migrating from less than 1.2.0, see these <a href="upgrade3.html">instructions</a> first.
+ <li>If migrating from less than 1.2.2, see these <a href="upgrade4.html">instructions</a> first.
+ <li>If migrating from less than 1.2.3, see these <a href="upgrade5.html">instructions</a> first.
+ <li>If migrating from less than 1.3.0, see these <a href="upgrade6.html">instructions</a> first.
+ <li>Back up your data and current Freeside installation.
+ <li>Copy or symlink htdocs to the new copy.
+ <li>Change to the FS directory in the new tarball, and build and install the
+ Perl modules:
+ <pre>
+$ cd FS/
+$ perl Makefile.PL
+$ make
+$ su
+# make install UNINST=1</pre>
+ <li>Run bin/dbdef-create.
+</body>
diff --git a/httemplate/docs/upgrade8.html b/httemplate/docs/upgrade8.html
new file mode 100644
index 0000000..cf60a85
--- /dev/null
+++ b/httemplate/docs/upgrade8.html
@@ -0,0 +1,392 @@
+<head>
+ <title>Upgrading to 1.4.0</title>
+</head>
+<body>
+<h1>Upgrading to 1.4.0 from 1.3.1</h1>
+<ul>
+ <li>If migrating from less than 1.3.1, see these <a href="upgrade7.html">instructions</a> first.
+ <li><font size="+2" color="#ff0000">Backup your database and current Freeside installation.</font> (with&nbsp;<a href="http://www.ca.postgresql.org/devel-corner/docs/postgres/backup.html">PostgreSQL</a>) (with&nbsp;<a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Backup">MySQL</a>)
+ <li><a href="http://perl.apache.org/">mod_perl</a> is now required.
+ <li>Install <a href="http://search.cpan.org/search?dist=Time-Duration">Time-Duration</a>, <a href="http://search.cpan.org/search?dist=Tie-IxHash">Tie-IxHash</a> and <a href="http://search.cpan.org/search?dist=HTML-Widgets-SelectLayers">HTML-Widgets-SelectLayers</a> (minimum version 0.02).
+ <li>Install <a href="http://www.apache-asp.org/">Apache::ASP</a> or <a href="http://www.masonhq.com/">HTML::Mason</a> (use version 1.0x - Freeside is not yet compatible with version 1.1x).
+ <li>Install <a href="http://rsync.samba.org/">rsync</a>
+</ul>
+<table>
+ <tr>
+ <th>Apache::ASP</th><th>Mason</th>
+ </tr>
+ <tr>
+ <td><ul>
+ <li>Run <tt>make aspdocs</tt>
+ <li>Copy <tt>aspdocs/</tt> to your web server's document space.
+ <li>Create a <a href="http://www.apache-asp.org/config.html#Global">Global</a> directory, such as <tt>/usr/local/etc/freeside/asp-global/</tt>
+ <li>Copy <tt>htetc/global.asa</tt> to the Global directory.
+ <li>Configure Apache for the Global directory and to execute .cgi files using Apache::ASP. For example:
+<font size="-1"><pre>
+&lt;Directory /usr/local/apache/htdocs/freeside-asp&gt;
+&lt;Files ~ (\.cgi)&gt;
+AddHandler perl-script .cgi
+PerlHandler Apache::ASP
+&lt;/Files&gt;
+&lt;Perl&gt;
+$MLDBM::RemoveTaint = 1;
+&lt;/Perl&gt;
+PerlSetVar Global /usr/local/etc/freeside/asp-global/
+&lt;/Directory&gt;
+</pre></font>
+ </ul></td>
+ <td><ul>
+ <li>(use version 1.0x - Freeside is not yet compatible with version 1.1x)
+ <li>Run <tt>make masondocs</tt>
+ <li>Copy <tt>masondocs/</tt> to your web server's document space.
+ <li>Copy <tt>htetc/handler.pl</tt> to your web server's configuration directory.
+ <li>Edit <tt>handler.pl</tt> and set an appropriate <tt>data_dir</tt>, such as <tt>/usr/local/etc/freeside/mason-data</tt>
+ <li>Configure Apache to use the <tt>handler.pl</tt> file and to execute .cgi files using HTML::Mason. For example:
+<font size="-1"><pre>
+&lt;Directory /usr/local/apache/htdocs/freeside-mason&gt;
+&lt;Files ~ (\.cgi)&gt;
+AddHandler perl-script .cgi
+PerlHandler HTML::Mason
+&lt;/Files&gt;
+&lt;Perl&gt;
+require "/usr/local/apache/conf/handler.pl";
+&lt;/Perl&gt;
+&lt;/Directory&gt;
+</pre></font>
+ </ul></td>
+ </tr>
+</table>
+<ul>
+ <li>Build and install the Perl modules:
+ <pre>
+$ su
+# make install-perl-modules</pre>
+ <li>Apply the following changes to your database:
+<pre>
+CREATE TABLE svc_forward (
+ svcnum int NOT NULL,
+ srcsvc int NOT NULL,
+ dstsvc int NOT NULL,
+ dst varchar(80),
+ PRIMARY KEY (svcnum)
+);
+ALTER TABLE part_svc ADD svc_forward__srcsvc varchar(80) NULL;
+ALTER TABLE part_svc ADD svc_forward__srcsvc_flag char(1) NULL;
+ALTER TABLE part_svc ADD svc_forward__dstsvc varchar(80) NULL;
+ALTER TABLE part_svc ADD svc_forward__dstsvc_flag char(1) NULL;
+ALTER TABLE part_svc ADD svc_forward__dst varchar(80) NULL;
+ALTER TABLE part_svc ADD svc_forward__dst_flag char(1) NULL;
+
+CREATE TABLE cust_credit_bill (
+ creditbillnum int primary key,
+ crednum int not null,
+ invnum int not null,
+ _date int not null,
+ amount decimal(10,2) not null
+);
+
+CREATE TABLE cust_bill_pay (
+ billpaynum int primary key,
+ invnum int not null,
+ paynum int not null,
+ _date int not null,
+ amount decimal(10,2) not null
+);
+
+CREATE TABLE cust_credit_refund (
+ creditrefundnum int primary key,
+ crednum int not null,
+ refundnum int not null,
+ _date int not null,
+ amount decimal(10,2) not null
+);
+
+CREATE TABLE part_svc_column (
+ columnnum int primary key,
+ svcpart int not null,
+ columnname varchar(64) not null,
+ columnvalue varchar(80) null,
+ columnflag char(1) null
+);
+
+CREATE TABLE queue (
+ jobnum int primary key,
+ job text not null,
+ _date int not null,
+ status varchar(80) not null,
+ statustext text null,
+ svcnum int null
+);
+CREATE INDEX queue1 ON queue ( svcnum );
+CREATE INDEX queue2 ON queue ( status );
+
+CREATE TABLE queue_arg (
+ argnum int primary key,
+ jobnum int not null,
+ arg text null
+);
+CREATE INDEX queue_arg1 ON queue_arg ( jobnum );
+
+CREATE TABLE queue_depend (
+ dependnum int primary key,
+ jobnum int not null,
+ depend_jobnum int not null
+);
+CREATE INDEX queue_depend1 ON queue_depend ( jobnum );
+CREATE INDEX queue_depend2 ON queue_depend ( depend_jobnum );
+
+CREATE TABLE part_pop_local (
+ localnum int primary key,
+ popnum int not null,
+ city varchar(80) null,
+ state char(2) null,
+ npa char(3) not null,
+ nxx char(3) not null
+);
+CREATE UNIQUE INDEX part_pop_local1 ON part_pop_local ( npa, nxx );
+
+CREATE TABLE cust_bill_event (
+ eventnum int primary key,
+ invnum int not null,
+ eventpart int not null,
+ _date int not null
+);
+CREATE UNIQUE INDEX cust_bill_event1 ON cust_bill_event ( eventpart, invnum );
+CREATE INDEX cust_bill_event2 ON cust_bill_event ( invnum );
+
+CREATE TABLE part_bill_event (
+ eventpart int primary key,
+ payby char(4) not null,
+ event varchar(80) not null,
+ eventcode text null,
+ seconds int null,
+ weight int not null,
+ plan varchar(80) null,
+ plandata text null,
+ disabled char(1) null
+);
+CREATE INDEX part_bill_event1 ON part_bill_event ( payby );
+
+CREATE TABLE export_svc (
+ exportsvcnum int primary key,
+ exportnum int not null,
+ svcpart int not null
+);
+CREATE UNIQUE INDEX export_svc1 ON export_svc ( exportnum, svcpart );
+CREATE INDEX export_svc2 ON export_svc ( exportnum );
+CREATE INDEX export_svc3 ON export_svc ( svcpart );
+
+CREATE TABLE part_export (
+ exportnum int primary key,
+ machine varchar(80) not null,
+ exporttype varchar(80) not null,
+ nodomain char(1) NULL
+);
+CREATE INDEX part_export1 ON part_export ( machine );
+CREATE INDEX part_export2 ON part_export ( exporttype );
+
+CREATE TABLE part_export_option (
+ optionnum int primary key,
+ exportnum int not null,
+ optionname varchar(80) not null,
+ optionvalue text NULL
+);
+CREATE INDEX part_export_option1 ON part_export_option ( exportnum );
+CREATE INDEX part_export_option2 ON part_export_option ( optionname );
+
+CREATE TABLE radius_usergroup (
+ usergroupnum int primary key,
+ svcnum int not null,
+ groupname varchar(80) not null
+);
+CREATE INDEX radius_usergroup1 ON radius_usergroup ( svcnum );
+CREATE INDEX radius_usergroup2 ON radius_usergroup ( groupname );
+
+CREATE TABLE msgcat (
+ msgnum int primary key,
+ msgcode varchar(80) not null,
+ locale varchar(16) not null,
+ msg text not null
+);
+CREATE INDEX msgcat1 ON msgcat ( msgcode, locale );
+
+CREATE TABLE cust_tax_exempt (
+ exemptnum int primary key,
+ custnum int not null,
+ taxnum int not null,
+ year int not null,
+ month int not null,
+ amount decimal(10,2)
+);
+CREATE UNIQUE INDEX cust_tax_exempt1 ON cust_tax_exempt ( taxnum, year, month );
+
+ALTER TABLE svc_acct ADD domsvc integer NULL;
+ALTER TABLE part_svc ADD svc_acct__domsvc varchar(80) NULL;
+ALTER TABLE part_svc ADD svc_acct__domsvc_flag char(1) NULL;
+ALTER TABLE svc_domain ADD catchall integer NULL;
+ALTER TABLE cust_main ADD referral_custnum integer NULL;
+ALTER TABLE cust_main ADD comments text NULL;
+ALTER TABLE cust_pay ADD custnum integer;
+ALTER TABLE cust_pay_batch ADD paybatchnum integer;
+ALTER TABLE cust_refund ADD custnum integer;
+ALTER TABLE cust_pkg ADD manual_flag char(1) NULL;
+ALTER TABLE part_pkg ADD plan varchar(80) NULL;
+ALTER TABLE part_pkg ADD plandata text NULL;
+ALTER TABLE part_pkg ADD setuptax char(1) NULL;
+ALTER TABLE part_pkg ADD recurtax char(1) NULL;
+ALTER TABLE part_pkg ADD disabled char(1) NULL;
+ALTER TABLE part_svc ADD disabled char(1) NULL;
+ALTER TABLE cust_bill ADD closed char(1) NULL;
+ALTER TABLE cust_pay ADD closed char(1) NULL;
+ALTER TABLE cust_credit ADD closed char(1) NULL;
+ALTER TABLE cust_refund ADD closed char(1) NULL;
+ALTER TABLE cust_bill_event ADD status varchar(80);
+ALTER TABLE cust_bill_event ADD statustext text NULL;
+ALTER TABLE svc_acct ADD sec_phrase varchar(80) NULL;
+ALTER TABLE part_svc ADD svc_acct__sec_phrase varchar(80) NULL;
+ALTER TABLE part_svc ADD svc_acct__sec_phrase_flag char(1) NULL;
+ALTER TABLE part_pkg ADD taxclass varchar(80) NULL;
+ALTER TABLE cust_main_county ADD taxclass varchar(80) NULL;
+ALTER TABLE cust_main_county ADD exempt_amount decimal(10,2);
+CREATE INDEX cust_main3 ON cust_main ( referral_custnum );
+CREATE INDEX cust_credit_bill1 ON cust_credit_bill ( crednum );
+CREATE INDEX cust_credit_bill2 ON cust_credit_bill ( invnum );
+CREATE INDEX cust_bill_pay1 ON cust_bill_pay ( invnum );
+CREATE INDEX cust_bill_pay2 ON cust_bill_pay ( paynum );
+CREATE INDEX cust_credit_refund1 ON cust_credit_refund ( crednum );
+CREATE INDEX cust_credit_refund2 ON cust_credit_refund ( refundnum );
+CREATE UNIQUE INDEX cust_pay_batch_pkey ON cust_pay_batch ( paybatchnum );
+CREATE UNIQUE INDEX part_svc_column1 ON part_svc_column ( svcpart, columnname );
+CREATE INDEX cust_pay2 ON cust_pay ( paynum );
+CREATE INDEX cust_pay3 ON cust_pay ( custnum );
+CREATE INDEX cust_pay4 ON cust_pay ( paybatch );
+</pre>
+
+ <li>If you are using PostgreSQL, apply the following changes to your database:
+<pre>
+CREATE UNIQUE INDEX agent_pkey ON agent ( agentnum );
+CREATE UNIQUE INDEX agent_type_pkey ON agent_type ( typenum );
+CREATE UNIQUE INDEX cust_bill_pkey ON cust_bill ( invnum );
+CREATE UNIQUE INDEX cust_credit_pkey ON cust_credit ( crednum );
+CREATE UNIQUE INDEX cust_main_pkey ON cust_main ( custnum );
+CREATE UNIQUE INDEX cust_main_county_pkey ON cust_main_county ( taxnum );
+CREATE UNIQUE INDEX cust_main_invoice_pkey ON cust_main_invoice ( destnum );
+CREATE UNIQUE INDEX cust_pay_pkey ON cust_pay ( paynum );
+CREATE UNIQUE INDEX cust_pkg_pkey ON cust_pkg ( pkgnum );
+CREATE UNIQUE INDEX cust_refund_pkey ON cust_refund ( refundnum );
+CREATE UNIQUE INDEX cust_svc_pkey ON cust_svc ( svcnum );
+CREATE UNIQUE INDEX domain_record_pkey ON domain_record ( recnum );
+CREATE UNIQUE INDEX nas_pkey ON nas ( nasnum );
+CREATE UNIQUE INDEX part_pkg_pkey ON part_pkg ( pkgpart );
+CREATE UNIQUE INDEX part_referral_pkey ON part_referral ( refnum );
+CREATE UNIQUE INDEX part_svc_pkey ON part_svc ( svcpart );
+CREATE UNIQUE INDEX port_pkey ON port ( portnum );
+CREATE UNIQUE INDEX prepay_credit_pkey ON prepay_credit ( prepaynum );
+CREATE UNIQUE INDEX session_pkey ON session ( sessionnum );
+CREATE UNIQUE INDEX svc_acct_pkey ON svc_acct ( svcnum );
+CREATE UNIQUE INDEX svc_acct_pop_pkey ON svc_acct_pop ( popnum );
+CREATE UNIQUE INDEX svc_acct_sm_pkey ON svc_acct_sm ( svcnum );
+CREATE UNIQUE INDEX svc_domain_pkey ON svc_domain ( svcnum );
+CREATE UNIQUE INDEX svc_www_pkey ON svc_www ( svcnum );
+</pre>
+ <li>If you wish to enable service/shipping addresses, apply the following
+ changes to your database:
+<pre>
+ALTER TABLE cust_main ADD COLUMN ship_last varchar(80) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_first varchar(80) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_company varchar(80) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_address1 varchar(80) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_address2 varchar(80) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_city varchar(80) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_county varchar(80) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_state varchar(80) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_zip varchar(10) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_country char(2) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_daytime varchar(20) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_night varchar(20) NULL;
+ALTER TABLE cust_main ADD COLUMN ship_fax varchar(12) NULL;
+CREATE INDEX cust_main4 ON cust_main ( ship_last );
+CREATE INDEX cust_main5 ON cust_main ( ship_company );
+</pre>
+ <li>If you are using the signup server, reinstall it according to the <a href="signup.html">instructions</a>. The 1.3.x signup server is not compatible with 1.4.x.
+ <li>Run <tt>bin/dbdef-create <i>username</i></tt>
+ <li>If you have svc_acct_sm records or service definitions:
+ <ul>
+ <li>Create a service definition with table svc_forward
+ <li>Run <tt>bin/fs-migrate-svc_acct_sm <i>username</i></tt>
+ </ul>
+ <li>Or if you just have svc_acct records:
+ <ul>
+ <li>Order and provision a package for your default domain and note down the <b>Service #</b> or <i>svcnum</i>.
+ <li><tt>UPDATE svc_acct SET domsvc = </tt><i>svcnum</i>
+ <li>Update your service definitions to have default (or fixed) <b>domsvc</b>.
+ </ul>
+ <li>Run <tt>bin/fs-migrate-payref<i>username</i></tt>
+ <li>Run <tt>bin/fs-migrate-part_svc<i>username</i></tt>
+ <li><b>After running bin/fs-migrate-payref</b>, apply the following changes to your database:
+ <table border><tr><th>PostgreSQL</th><th>MySQL, others</th></tr>
+<tr><td>
+<font size=-1><pre>
+CREATE TABLE cust_pay_temp (
+ paynum int primary key,
+ custnum int not null,
+ paid decimal(10,2) not null,
+ _date int null,
+ payby char(4) not null,
+ payinfo varchar(16) null,
+ paybatch varchar(80) null,
+ closed char(1) null
+);
+INSERT INTO cust_pay_temp SELECT paynum, custnum, paid, _date, payby, payinfo, paybatch, closed FROM cust_pay;
+DROP TABLE cust_pay;
+ALTER TABLE cust_pay_temp RENAME TO cust_pay;
+CREATE UNIQUE INDEX cust_pay1 ON cust_pay (paynum);
+CREATE TABLE cust_refund_temp (
+ refundnum int primary key,
+ custnum int not null,
+ _date int null,
+ refund decimal(10,2) not null,
+ otaker varchar(8) not null,
+ reason varchar(80) not null,
+ payby char(4) not null,
+ payinfo varchar(16) null,
+ paybatch varchar(80) null,
+ closed char(1) null
+);
+INSERT INTO cust_refund_temp SELECT refundnum, custnum, _date, refund, otaker, reason, payby, payinfo, '', closed from cust_refund;
+DROP TABLE cust_refund;
+ALTER TABLE cust_refund_temp RENAME TO cust_refund;
+CREATE UNIQUE INDEX cust_refund1 ON cust_refund (refundnum);
+</pre></font>
+</td><td>
+<font size=-1><pre>
+ALTER TABLE cust_pay DROP COLUMN invnum;
+ALTER TABLE cust_refund DROP COLUMN crednum;
+</pre></font>
+</td></tr></table>
+ <li><b>IMPORTANT: After applying the second set of database changes</b>, run <tt>bin/dbdef-create <i>username</i></tt> again.
+ <li><b>IMPORTANT</b>: run <tt>bin/create-history-tables <i>username</i></tt>
+ <li><b>IMPORTANT: After running bin/create-history-tables</b>, run <tt>bin/dbdef-create <i>username</i></tt> again.
+ <li>As the freeside UNIX user, run <tt>bin/populate-msgcat <i>username</i></tt
+> to populate the message catalog
+<!-- <li>set the <a href="../config/config.cgi#username_policy">user_policy configuration value</a> as appropriate for your site. -->
+ <li>set the <a href="../config/config.cgi#locale">locale configuration value</a> to en_US.
+ <li>the mxmachines, nsmachines, arecords and cnamerecords configuration values have been deprecated. Set the <a href="../config/config.cgi#defaultrecords">defaultrecords configuration value</a> instead.
+ <li>Create the `/usr/local/etc/freeside/cache.<i>datasrc</i>' directory
+ (owned by the freeside user).
+ <li>freeside-queued was installed with the Perl modules. Start it now and ensure that is run upon system startup.
+ <li>Set appropriate <a href="../browse/part_bill_event.cgi">invoice events</a> for your site. At the very least, you'll want to set some invoice events "<i>After 0 days</i>": a <i>BILL</i> invoice event to print invoices, a <i>CARD</i> invoice event to batch or run cards real-time, and a <i>COMP</i> invoice event to "pay" complimentary customers. If you were using the <i>-i</i> option to <a href="man/bin/freeside-bill.html">freeside-bill</a> it should be removed.
+ <li>Use <a href="man/bin/freeside-daily.html">freeside-daily</a> instead of <a href="man/bin/freeside-bill.html">freeside-bill</a>.
+ <li>If you would like Freeside to notify your customers when their credit
+ cards and other billing arrangements are about to expire, arrange for
+ <b>freeside-expiration-alerter</b> to be run daily by cron or similar
+ facility. The message it sends can be configured from the
+ <u>Configuration</u> choice of the main menu as <u>alerter_template</u>.
+ <li>Export has been rewritten. If you were using the icradiusmachines,
+ icradius_mysqldest, icradius_mysqlsource, or icradius_secrets files, add
+ an appropriate "sqlradius" export to all relevant Service Definitions
+ instead. Use <a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Replication">MySQL replication</a> or
+ point the "sqlradius" export directly at your external ICRADIUS or FreeRADIUS
+ database (or through an SSL-necrypting proxy...)
+</ul>
+</body>
diff --git a/httemplate/docs/upgrade9.html b/httemplate/docs/upgrade9.html
new file mode 100644
index 0000000..6a8fd96
--- /dev/null
+++ b/httemplate/docs/upgrade9.html
@@ -0,0 +1,28 @@
+<head>
+ <title>Upgrading to 1.4.1</title>
+</head>
+<body>
+<h1>Upgrading to 1.4.1 from 1.4.0</h1>
+<ul>
+ <li>If migrating from less than 1.4.0, see these <a href="upgrade8.html">instructions</a> first.
+ <li>Back up your data and current Freeside installation.
+ <li>Run <code>make aspdocs</code> or <code>make masondocs</code>.
+ <li>Copy <code>aspdocs/</code> or <code>masondocs/</code> to your web server's document space.
+ <li>Run <code>make install-perl-modules</code>.
+ <li>Install <a href="http://search.cpan.org/search?dist=Net-SSH">Net::SSH</a> minimum version 0.07
+ <li>Apply the following changes to your database:
+<pre>
+INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 18, 'daytime', 'en_US', 'Day Phone' );
+INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 19, 'night', 'en_US', 'Night Phone' );
+</pre>
+ <li>Optionally, apply the following changes to your database (performance improvements):
+<pre>
+CREATE INDEX part_pkg1 ON part_pkg ( disabled );
+CREATE INDEX part_svc1 ON part_svc ( disabled );
+CREATE INDEX cust_bill2 ON cust_bill ( _date );
+</pre>
+ <li>If you want to use ACH (electronic checks), you will need to make changes to your database. The easiest way to make these changes is to dump your database (with pg_dump), change the payinfo field in the cust_pay, cust_refund, h_cust_pay and h_cust_refund tables from varchar(16) to varchar(80), reload the database from the dump.
+ <li>If you will be doing bind exports you should make additional changes to your database. Follow the directions above to dump the database and change the reczone and recdata fields in the domain_record and h_domain_record tables from varchar(80) to varchar(255).
+ <li>If you made changes to your db schema from a dump as listed above run dbdef-create.
+ <li>Restart Apache and freeside-queued.
+</body>
diff --git a/httemplate/edit/REAL_cust_pkg.cgi b/httemplate/edit/REAL_cust_pkg.cgi
new file mode 100755
index 0000000..d9b7579
--- /dev/null
+++ b/httemplate/edit/REAL_cust_pkg.cgi
@@ -0,0 +1,131 @@
+<!-- mason kludge -->
+<%
+# <!-- $Id: REAL_cust_pkg.cgi,v 1.7 2003-11-19 12:21:09 ivan Exp $ -->
+
+my $error ='';
+my $pkgnum = '';
+if ( $cgi->param('error') ) {
+ $error = $cgi->param('error');
+ $pkgnum = $cgi->param('pkgnum');
+} else {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/ or die "no pkgnum";
+ $pkgnum = $1;
+}
+
+#get package record
+my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+die "No package!" unless $cust_pkg;
+my $part_pkg = qsearchs('part_pkg',{'pkgpart'=>$cust_pkg->getfield('pkgpart')});
+
+if ( $error ) {
+ #$cust_pkg->$_(str2time($cgi->param($_)) foreach qw(setup bill);
+ $cust_pkg->setup(str2time($cgi->param('setup')));
+ $cust_pkg->bill(str2time($cgi->param('bill')));
+}
+
+#my $custnum = $cust_pkg->getfield('custnum');
+print header('Package Edit'); #, menubar(
+# "View this customer (#$custnum)" => popurl(2). "view/cust_main.cgi?$custnum",
+# 'Main Menu' => popurl(2)
+#));
+
+%>
+
+ <LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
+
+<%
+
+#print info
+my($susp,$cancel,$expire)=(
+ $cust_pkg->getfield('susp'),
+ $cust_pkg->getfield('cancel'),
+ $cust_pkg->getfield('expire'),
+);
+my($pkg,$comment)=($part_pkg->getfield('pkg'),$part_pkg->getfield('comment'));
+my($setup,$bill)=($cust_pkg->getfield('setup'),$cust_pkg->getfield('bill'));
+my $otaker = $cust_pkg->getfield('otaker');
+
+print '<FORM NAME="formname" ACTION="process/REAL_cust_pkg.cgi" METHOD="POST">', qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">!;
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT>!
+ if $error;
+
+#my $format = "%c %z (%Z)";
+my $format = "%m/%d/%Y %T %z (%Z)";
+
+print ntable("#cccccc",2),
+ '<TR><TD ALIGN="right">Package number</TD><TD BGCOLOR="#ffffff">',
+ $pkgnum, '</TD></TR>',
+ '<TR><TD ALIGN="right">Package</TD><TD BGCOLOR="#ffffff">',
+ $pkg, '</TD></TR>',
+ '<TR><TD ALIGN="right">Comment</TD><TD BGCOLOR="#ffffff">',
+ $comment, '</TD></TR>',
+ '<TR><TD ALIGN="right">Order taker</TD><TD BGCOLOR="#ffffff">',
+ $otaker, '</TD></TR>',
+ '<TR><TD ALIGN="right">Setup date</TD><TD>'.
+ '<INPUT TYPE="text" NAME="setup" SIZE=32 ID="setup_text" VALUE="',
+ ( $setup ? time2str($format, $setup) : "" ), '">'.
+ ' <IMG SRC="../images/calendar.png" ID="setup_button" STYLE="cursor: pointer" TITLE="Select date">'.
+ '</TD></TR>';
+
+print '<TR><TD ALIGN="right">Last bill date</TD><TD>',
+ '<INPUT TYPE="text" NAME="last_bill" SIZE=32 ID="last_bill_text" VALUE="',
+ ( $cust_pkg->last_bill
+ ? time2str($format, $cust_pkg->last_bill)
+ : "" ),
+ '">'.
+ ' <IMG SRC="../images/calendar.png" ID="last_bill_button" STYLE="cursor: pointer" TITLE="Select date">'.
+ '</TD></TR>'
+ if $cust_pkg->dbdef_table->column('last_bill');
+
+print '<TR><TD ALIGN="right">Next bill date</TD><TD>',
+ '<INPUT TYPE="text" NAME="bill" SIZE=32 ID="bill_text" VALUE="',
+ ( $bill ? time2str($format, $bill) : "" ), '">'.
+ ' <IMG SRC="../images/calendar.png" ID="bill_button" STYLE="cursor: pointer" TITLE="Select date">'.
+ '</TD></TR>';
+
+print '<TR><TD ALIGN="right">Suspension date</TD><TD BGCOLOR="#ffffff">',
+ time2str($format, $susp), '</TD></TR>'
+ if $susp;
+
+#print '<TR><TD ALIGN="right">Expiration date</TD><TD BGCOLOR="#ffffff">',
+# time2str("%D",$expire), '</TD></TR>'
+# if $expire;
+print '<TR><TD ALIGN="right">Expiration date'.
+ '</TD><TD>',
+ '<INPUT TYPE="text" NAME="expire" SIZE=32 ID="expire_text" VALUE="',
+ ( $expire ? time2str($format, $expire) : "" ), '">'.
+ ' <IMG SRC="../images/calendar.png" ID="expire_button" STYLE="cursor: pointer" TITLE="Select date">'.
+ '<BR><FONT SIZE=-1>(will <b>cancel</b> this package'.
+ ' when the date is reached)</FONT>'.
+ '</TD></TR>';
+
+print '<TR><TD ALIGN="right">Cancellation date</TD><TD BGCOLOR="#ffffff">',
+ time2str($format, $cancel), '</TD></TR>'
+ if $cancel;
+
+%>
+</TABLE>
+<SCRIPT TYPE="text/javascript">
+<%
+ my @cal = qw( setup bill expire );
+ push @cal, 'last_bill'
+ if $cust_pkg->dbdef_table->column('last_bill');
+ foreach my $cal (@cal) {
+%>
+ Calendar.setup({
+ inputField: "<%= $cal %>_text",
+ ifFormat: "%m/%d/%Y",
+ button: "<%= $cal %>_button",
+ align: "BR"
+ });
+<% } %>
+</SCRIPT>
+<BR><INPUT TYPE="submit" VALUE="Apply Changes">
+</FORM>
+</BODY>
+</HTML>
diff --git a/httemplate/edit/agent.cgi b/httemplate/edit/agent.cgi
new file mode 100755
index 0000000..8a1cb2a
--- /dev/null
+++ b/httemplate/edit/agent.cgi
@@ -0,0 +1,79 @@
+<!-- mason kludge -->
+<%
+
+my $agent;
+if ( $cgi->param('error') ) {
+ $agent = new FS::agent ( {
+ map { $_, scalar($cgi->param($_)) } fields('agent')
+ } );
+} elsif ( $cgi->keywords ) {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $agent = qsearchs( 'agent', { 'agentnum' => $1 } );
+} else { #adding
+ $agent = new FS::agent {};
+}
+my $action = $agent->agentnum ? 'Edit' : 'Add';
+my $hashref = $agent->hashref;
+
+%>
+
+<%= header("$action Agent", menubar(
+ 'Main Menu' => $p,
+ 'View all agents' => $p. 'browse/agent.cgi',
+)) %>
+
+<% if ( $cgi->param('error') ) { %>
+<FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT>
+<% } %>
+
+<FORM ACTION="<%=popurl(1)%>process/agent.cgi" METHOD=POST>
+<INPUT TYPE="hidden" NAME="agentnum" VALUE="<%= $hashref->{agentnum} %>">
+Agent #<%= $hashref->{agentnum} ? $hashref->{agentnum} : "(NEW)" %>
+
+<%= &ntable("#cccccc", 2, '') %>
+<TR>
+ <TH ALIGN="right">Agent</TH>
+ <TD><INPUT TYPE="text" NAME="agent" SIZE=32 VALUE="<%= $hashref->{agent} %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right">Agent type</TH>
+ <TD><SELECT NAME="typenum" SIZE=1>
+
+<% foreach my $agent_type (qsearch('agent_type',{})) { %>
+ <OPTION VALUE="<%= $agent_type->typenum %>"<%= ( $hashref->{typenum} && ( $hashref->{typenum} == $agent_type->typenum ) ) ? ' SELECTED' : '' %>>
+ <%= $agent_type->getfield('typenum') %>: <%= $agent_type->getfield('atype') %>
+<% } %>
+
+</SELECT></TD>
+</TR>
+<% if ( dbdef->table('agent')->column('disabled') ) { %>
+ <TR>
+ <TD ALIGN="right">Disable</TD>
+ <TD><INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<%= $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>></TD>
+ </TR>
+<% } %>
+<TR>
+ <TD ALIGN="right"><!--Frequency--></TD>
+ <TD><INPUT TYPE="hidden" NAME="freq" VALUE="<%= $hashref->{freq} %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right"><!--Program--></TD>
+ <TD><INPUT TYPE="hidden" NAME="prog" VALUE="<%= $hashref->{prog} %>"></TD>
+</TR>
+<% if ( dbdef->table('agent')->column('username') ) { %>
+ <TR>
+ <TD ALIGN="right">Agent interface username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $hashref->{username} %>"></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Agent interface password</TD>
+ <TD><INPUT TYPE="text" NAME="_password" VALUE="<%= $hashref->{_password} %>"></TD>
+ </TR>
+<% } %>
+</TABLE>
+
+<BR><INPUT TYPE="submit" VALUE="<%= $hashref->{agentnum} ? "Apply changes" : "Add agent" %>">
+ </FORM>
+ </BODY>
+</HTML>
diff --git a/httemplate/edit/agent_type.cgi b/httemplate/edit/agent_type.cgi
new file mode 100755
index 0000000..637c710
--- /dev/null
+++ b/httemplate/edit/agent_type.cgi
@@ -0,0 +1,63 @@
+<!-- mason kludge -->
+<%
+
+my($agent_type);
+if ( $cgi->param('error') ) {
+ $agent_type = new FS::agent_type ( {
+ map { $_, scalar($cgi->param($_)) } fields('agent')
+ } );
+} elsif ( $cgi->keywords ) { #editing
+ my( $query ) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $agent_type=qsearchs('agent_type',{'typenum'=>$1});
+} else { #adding
+ $agent_type = new FS::agent_type {};
+}
+my $action = $agent_type->typenum ? 'Edit' : 'Add';
+my $hashref = $agent_type->hashref;
+
+print header("$action Agent Type", menubar(
+ 'Main Menu' => "$p",
+ 'View all agent types' => "${p}browse/agent_type.cgi",
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print '<FORM ACTION="', popurl(1), 'process/agent_type.cgi" METHOD=POST>',
+ qq!<INPUT TYPE="hidden" NAME="typenum" VALUE="$hashref->{typenum}">!,
+ "Agent Type #", $hashref->{typenum} ? $hashref->{typenum} : "(NEW)";
+
+print <<END;
+<BR><BR>Agent Type <INPUT TYPE="text" NAME="atype" SIZE=32 VALUE="$hashref->{atype}">
+<BR><BR>Select which packages agents of this type may sell to customers<BR>
+END
+
+foreach my $part_pkg ( qsearch('part_pkg',{ 'disabled' => '' }) ) {
+ print qq!<BR><INPUT TYPE="checkbox" NAME="pkgpart!,
+ $part_pkg->getfield('pkgpart'), qq!" !,
+ # ( 'CHECKED 'x scalar(
+ qsearchs('type_pkgs',{
+ 'typenum' => $agent_type->getfield('typenum'),
+ 'pkgpart' => $part_pkg->getfield('pkgpart'),
+ })
+ ? 'CHECKED '
+ : '',
+ qq!VALUE="ON"> !,
+ qq!<A HREF="${p}edit/part_pkg.cgi?!, $part_pkg->pkgpart,
+ '">', $part_pkg->pkgpart. ": ". $part_pkg->getfield('pkg'), '</A>',
+ ;
+}
+
+print qq!<BR><BR><INPUT TYPE="submit" VALUE="!,
+ $hashref->{typenum} ? "Apply changes" : "Add agent type",
+ qq!">!;
+
+print <<END;
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/cust_bill_pay.cgi b/httemplate/edit/cust_bill_pay.cgi
new file mode 100755
index 0000000..8cdf450
--- /dev/null
+++ b/httemplate/edit/cust_bill_pay.cgi
@@ -0,0 +1,95 @@
+<!-- mason kludge -->
+<%
+
+my($paynum, $amount, $invnum);
+if ( $cgi->param('error') ) {
+ $paynum = $cgi->param('paynum');
+ $amount = $cgi->param('amount');
+ $invnum = $cgi->param('invnum');
+} else {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $paynum = $1;
+ $amount = '';
+ $invnum = '';
+}
+
+my $otaker = getotaker;
+
+my $p1 = popurl(1);
+
+print header("Apply Payment", '');
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT><BR><BR>"
+ if $cgi->param('error');
+print <<END;
+ <FORM ACTION="${p1}process/cust_bill_pay.cgi" METHOD=POST>
+END
+
+my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } );
+die "payment $paynum not found!" unless $cust_pay;
+
+my $unapplied = $cust_pay->unapplied;
+
+print "Payment # <B>$paynum</B>".
+ qq!<INPUT TYPE="hidden" NAME="paynum" VALUE="$paynum">!.
+ '<BR>Date: <B>'. time2str("%D", $cust_pay->_date). '</B>'.
+ '<BR>Amount: $<B>'. $cust_pay->paid. '</B>'.
+ "<BR>Unapplied amount: \$<B>$unapplied</B>"
+ ;
+
+my @cust_bill = grep $_->owed != 0,
+ qsearch('cust_bill', { 'custnum' => $cust_pay->custnum } );
+
+print <<END;
+<SCRIPT>
+function changed(what) {
+ cust_bill = what.options[what.selectedIndex].value;
+END
+
+foreach my $cust_bill ( @cust_bill ) {
+ my $invnum = $cust_bill->invnum;
+ my $changeto = $cust_bill->owed < $unapplied
+ ? $cust_bill->owed
+ : $unapplied;
+ print <<END;
+ if ( cust_bill == $invnum ) {
+ what.form.amount.value = "$changeto";
+ }
+END
+}
+
+# if ( cust_bill == "Refund" ) {
+# what.form.amount.value = "$credited";
+# }
+print <<END;
+}
+</SCRIPT>
+END
+
+print qq!<BR>Invoice #<SELECT NAME="invnum" SIZE=1 onChange="changed(this)">!,
+ '<OPTION VALUE="">';
+foreach my $cust_bill ( @cust_bill ) {
+ print '<OPTION'. ( $cust_bill->invnum eq $invnum ? ' SELECTED' : '' ).
+ ' VALUE="'. $cust_bill->invnum. '">'. $cust_bill->invnum.
+ ' - '. time2str("%D",$cust_bill->_date).
+ ' - $'. $cust_bill->owed;
+}
+#print qq!<OPTION VALUE="Refund">Refund!;
+print "</SELECT>";
+
+print qq!<BR>Amount \$<INPUT TYPE="text" NAME="amount" VALUE="$amount" SIZE=8 MAXLENGTH=8>!;
+
+print <<END;
+<BR>
+<INPUT TYPE="submit" VALUE="Apply">
+END
+
+print <<END;
+
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/cust_credit.cgi b/httemplate/edit/cust_credit.cgi
new file mode 100755
index 0000000..aae0df2
--- /dev/null
+++ b/httemplate/edit/cust_credit.cgi
@@ -0,0 +1,63 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+my($custnum, $amount, $reason);
+if ( $cgi->param('error') ) {
+ #$cust_credit = new FS::cust_credit ( {
+ # map { $_, scalar($cgi->param($_)) } fields('cust_credit')
+ #} );
+ $custnum = $cgi->param('custnum');
+ $amount = $cgi->param('amount');
+ #$refund = $cgi->param('refund');
+ $reason = $cgi->param('reason');
+} else {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $custnum = $1;
+ $amount = '';
+ #$refund = 'yes';
+ $reason = '';
+}
+my $_date = time;
+
+my $otaker = getotaker;
+
+my $p1 = popurl(1);
+
+print header("Post Credit", '');
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+print <<END, small_custview($custnum, $conf->config('countrydefault'));
+ <FORM ACTION="${p1}process/cust_credit.cgi" METHOD=POST>
+ <INPUT TYPE="hidden" NAME="crednum" VALUE="">
+ <INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">
+ <INPUT TYPE="hidden" NAME="paybatch" VALUE="">
+ <INPUT TYPE="hidden" NAME="_date" VALUE="$_date">
+ <INPUT TYPE="hidden" NAME="credited" VALUE="">
+ <INPUT TYPE="hidden" NAME="otaker" VALUE="$otaker">
+END
+
+print '<BR><BR>Credit'. ntable("#cccccc", 2).
+ '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'.
+ time2str("%D",$_date). '</TD></TR>';
+
+print qq!<TR><TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">\$<INPUT TYPE="text" NAME="amount" VALUE="$amount" SIZE=8 MAXLENGTH=8></TD></TR>!;
+
+#print qq! <INPUT TYPE="checkbox" NAME="refund" VALUE="$refund">Also post refund!;
+
+print qq!<TR><TD ALIGN="right">Reason</TD><TD BGCOLOR="#ffffff"><INPUT TYPE="text" NAME="reason" VALUE="$reason"></TD></TR>!;
+
+print qq!<TR><TD ALIGN="right">Auto-apply<BR>to invoices</TD><TD><SELECT NAME="apply"><OPTION VALUE="yes" SELECTED>yes<OPTION>no</SELECT></TD>!;
+
+print <<END;
+</TABLE>
+<BR>
+<INPUT TYPE="submit" VALUE="Post credit">
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/cust_credit_bill.cgi b/httemplate/edit/cust_credit_bill.cgi
new file mode 100755
index 0000000..1a97e13
--- /dev/null
+++ b/httemplate/edit/cust_credit_bill.cgi
@@ -0,0 +1,101 @@
+<!-- mason kludge -->
+<%
+
+my($crednum, $amount, $invnum);
+if ( $cgi->param('error') ) {
+ #$cust_credit_bill = new FS::cust_credit_bill ( {
+ # map { $_, scalar($cgi->param($_)) } fields('cust_credit_bill')
+ #} );
+ $crednum = $cgi->param('crednum');
+ $amount = $cgi->param('amount');
+ #$refund = $cgi->param('refund');
+ $invnum = $cgi->param('invnum');
+} else {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $crednum = $1;
+ $amount = '';
+ #$refund = 'yes';
+ $invnum = '';
+}
+
+my $otaker = getotaker;
+
+my $p1 = popurl(1);
+
+print header("Apply Credit", '');
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT><BR><BR>"
+ if $cgi->param('error');
+print <<END;
+ <FORM ACTION="${p1}process/cust_credit_bill.cgi" METHOD=POST>
+END
+
+my $cust_credit = qsearchs('cust_credit', { 'crednum' => $crednum } );
+die "credit $crednum not found!" unless $cust_credit;
+
+my $credited = $cust_credit->credited;
+
+print "Credit # <B>$crednum</B>".
+ qq!<INPUT TYPE="hidden" NAME="crednum" VALUE="$crednum">!.
+ '<BR>Date: <B>'. time2str("%D", $cust_credit->_date). '</B>'.
+ '<BR>Amount: $<B>'. $cust_credit->amount. '</B>'.
+ "<BR>Unapplied amount: \$<B>$credited</B>".
+ '<BR>Reason: <B>'. $cust_credit->reason. '</B>'
+ ;
+
+my @cust_bill = grep $_->owed != 0,
+ qsearch('cust_bill', { 'custnum' => $cust_credit->custnum } );
+
+print <<END;
+<SCRIPT>
+function changed(what) {
+ cust_bill = what.options[what.selectedIndex].value;
+END
+
+foreach my $cust_bill ( @cust_bill ) {
+ my $invnum = $cust_bill->invnum;
+ my $changeto = $cust_bill->owed < $cust_credit->credited
+ ? $cust_bill->owed
+ : $cust_credit->credited;
+ print <<END;
+ if ( cust_bill == $invnum ) {
+ what.form.amount.value = "$changeto";
+ }
+END
+}
+
+print <<END;
+ if ( cust_bill == "Refund" ) {
+ what.form.amount.value = "$credited";
+ }
+}
+</SCRIPT>
+END
+
+print qq!<BR>Invoice #<SELECT NAME="invnum" SIZE=1 onChange="changed(this)">!,
+ '<OPTION VALUE="">';
+foreach my $cust_bill ( @cust_bill ) {
+ print '<OPTION'. ( $cust_bill->invnum eq $invnum ? ' SELECTED' : '' ).
+ ' VALUE="'. $cust_bill->invnum. '">'. $cust_bill->invnum.
+ ' - '. time2str("%D",$cust_bill->_date).
+ ' - $'. $cust_bill->owed;
+}
+print qq!<OPTION VALUE="Refund">Refund!;
+print "</SELECT>";
+
+print qq!<BR>Amount \$<INPUT TYPE="text" NAME="amount" VALUE="$amount" SIZE=8 MAXLENGTH=8>!;
+
+print <<END;
+<BR>
+<INPUT TYPE="submit" VALUE="Apply">
+END
+
+print <<END;
+
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi
new file mode 100755
index 0000000..f9c80d8
--- /dev/null
+++ b/httemplate/edit/cust_main.cgi
@@ -0,0 +1,572 @@
+<!-- mason kludge -->
+<%
+
+ #for misplaced logic below
+ #use FS::part_pkg;
+
+ #for false laziness below (now more properly lazy)
+ #use FS::svc_acct_pop;
+
+ #for (other) false laziness below
+ #use FS::agent;
+ #use FS::type_pkgs;
+
+my $conf = new FS::Conf;
+
+#get record
+
+my $error = '';
+my($custnum, $username, $password, $popnum, $cust_main, $saved_pkgpart);
+my(@invoicing_list);
+if ( $cgi->param('error') ) {
+ $error = $cgi->param('error');
+ $cust_main = new FS::cust_main ( {
+ map { $_, scalar($cgi->param($_)) } fields('cust_main')
+ } );
+ $custnum = $cust_main->custnum;
+ $saved_pkgpart = $cgi->param('pkgpart_svcpart') || '';
+ if ( $saved_pkgpart =~ /^(\d+)_/ ) {
+ $saved_pkgpart = $1;
+ } else {
+ $saved_pkgpart = '';
+ }
+ $username = $cgi->param('username');
+ $password = $cgi->param('_password');
+ $popnum = $cgi->param('popnum');
+ @invoicing_list = split( /\s*,\s*/, $cgi->param('invoicing_list') );
+} elsif ( $cgi->keywords ) { #editing
+ my( $query ) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $custnum=$1;
+ $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
+ if ( $cust_main->dbdef_table->column('paycvv')
+ && length($cust_main->paycvv) ) {
+ my $paycvv = $cust_main->paycvv;
+ $paycvv =~ s/./*/g;
+ $cust_main->paycvv($paycvv);
+ }
+ $saved_pkgpart = 0;
+ $username = '';
+ $password = '';
+ $popnum = 0;
+ @invoicing_list = $cust_main->invoicing_list;
+} else {
+ $custnum='';
+ $cust_main = new FS::cust_main ( {} );
+ $cust_main->otaker( &getotaker );
+ $cust_main->referral_custnum( $cgi->param('referral_custnum') );
+ $saved_pkgpart = 0;
+ $username = '';
+ $password = '';
+ $popnum = 0;
+ @invoicing_list = ();
+}
+$cgi->delete_all();
+my $action = $custnum ? 'Edit' : 'Add';
+
+# top
+
+my $p1 = popurl(1);
+print header("Customer $action", '', ' onUnload="myclose()"');
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $error, "</FONT>"
+ if $error;
+
+print qq!<FORM ACTION="${p1}process/cust_main.cgi" METHOD=POST NAME="form1">!,
+ qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!,
+ qq!Customer # !, ( $custnum ? "<B>$custnum</B>" : " (NEW)" ),
+
+;
+
+# agent
+
+my $r = qq!<font color="#ff0000">*</font>&nbsp;!;
+
+my %agent_search = dbdef->table('agent')->column('disabled')
+ ? ( 'disabled' => '' ) : ();
+my @agents = qsearch( 'agent', \%agent_search );
+#die "No agents created!" unless @agents;
+eidiot "You have not created any agents (or all agents are disabled). You must create at least one agent before adding a customer. Go to ". popurl(2). "browse/agent.cgi and create one or more agents." unless @agents;
+my $agentnum = $cust_main->agentnum || $agents[0]->agentnum; #default to first
+if ( scalar(@agents) == 1 ) {
+ print qq!<INPUT TYPE="hidden" NAME="agentnum" VALUE="$agentnum">!;
+} else {
+ print qq!<BR><BR>${r}Agent <SELECT NAME="agentnum" SIZE="1">!;
+ my $agent;
+ foreach $agent (sort {
+ $a->agent cmp $b->agent;
+ } @agents) {
+ print '<OPTION VALUE="', $agent->agentnum, '"',
+ " SELECTED"x($agent->agentnum==$agentnum),
+ ">". $agent->agent;
+ #">", $agent->agentnum,": ", $agent->agent;
+ }
+ print "</SELECT>";
+}
+
+#referral
+
+my $refnum = $cust_main->refnum || $conf->config('referraldefault') || 0;
+if ( $custnum && ! $conf->exists('editreferrals') ) {
+ print qq!<INPUT TYPE="hidden" NAME="refnum" VALUE="$refnum">!;
+} else {
+ my(@referrals) = qsearch('part_referral',{});
+ if ( scalar(@referrals) == 0 ) {
+ eidiot "You have not created any advertising sources. You must create at least one advertising source before adding a customer. Go to ". popurl(2). "browse/part_referral.cgi and create one or more advertising sources.";
+ } elsif ( scalar(@referrals) == 1 ) {
+ $refnum ||= $referrals[0]->refnum;
+ print qq!<INPUT TYPE="hidden" NAME="refnum" VALUE="$refnum">!;
+ } else {
+ print qq!<BR><BR>${r}Advertising source <SELECT NAME="refnum" SIZE="1">!;
+ print "<OPTION> " unless $refnum;
+ my($referral);
+ foreach $referral (sort {
+ $a->refnum <=> $b->refnum;
+ } @referrals) {
+ print "<OPTION" . " SELECTED"x($referral->refnum==$refnum),
+ ">", $referral->refnum, ": ", $referral->referral;
+ }
+ print "</SELECT>";
+ }
+}
+
+#referring customer
+
+#print qq!<BR><BR>Referring Customer: !;
+my $referring_cust_main = '';
+if ( $cust_main->referral_custnum
+ and $referring_cust_main =
+ qsearchs('cust_main', { custnum => $cust_main->referral_custnum } )
+) {
+ print '<BR><BR>Referring Customer: <A HREF="'. popurl(1). '/cust_main.cgi?'.
+ $cust_main->referral_custnum. '">'.
+ $cust_main->referral_custnum. ': '.
+ ( $referring_cust_main->company
+ || $referring_cust_main->last. ', '. $referring_cust_main->first ).
+ '</A><INPUT TYPE="hidden" NAME="referral_custnum" VALUE="'.
+ $cust_main->referral_custnum. '">';
+} elsif ( ! $conf->exists('disable_customer_referrals') ) {
+ print '<BR><BR>Referring customer number: <INPUT TYPE="text" NAME="referral_custnum" VALUE="">';
+} else {
+ print '<INPUT TYPE="hidden" NAME="referral_custnum" VALUE="">';
+}
+
+# contact info
+
+my($last,$first,$ss,$company,$address1,$address2,$city,$zip)=(
+ $cust_main->last,
+ $cust_main->first,
+ $cust_main->ss,
+ $cust_main->company,
+ $cust_main->address1,
+ $cust_main->address2,
+ $cust_main->city,
+ $cust_main->zip,
+);
+
+print "<BR><BR>Billing address", &itable("#cccccc"), <<END;
+<TR><TH ALIGN="right">${r}Contact&nbsp;name<BR>(last,&nbsp;first)</TH><TD COLSPAN=3>
+END
+
+print <<END;
+<INPUT TYPE="text" NAME="last" VALUE="$last"> ,
+<INPUT TYPE="text" NAME="first" VALUE="$first">
+</TD>
+END
+
+if ( $conf->exists('show_ss') ) {
+ print qq!<TD ALIGN="right">SS#</TD><TD><INPUT TYPE="text" NAME="ss" VALUE="$ss" SIZE=11></TD>!;
+} else {
+ print qq!<TD><INPUT TYPE="hidden" NAME="ss" VALUE="$ss"></TD>!;
+}
+
+print <<END;
+</TR>
+<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="company" VALUE="$company" SIZE=70></TD></TR>
+<TR><TH ALIGN="right">${r}Address</TH><TD COLSPAN=5><INPUT TYPE="text" NAME="address1" VALUE="$address1" SIZE=70></TD></TR>
+<TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="address2" VALUE="$address2" SIZE=70></TD></TR>
+<TR><TH ALIGN="right">${r}City</TH><TD><INPUT TYPE="text" NAME="city" VALUE="$city"></TD><TH ALIGN="right">${r}State</TH><TD>
+END
+
+#false laziness with ship state
+my $countrydefault = $conf->config('countrydefault') || 'US';
+$cust_main->country( $countrydefault ) unless $cust_main->country;
+
+my $statedefault = $conf->config('statedefault')
+ || ($countrydefault eq 'US' ? 'CA' : '');
+$cust_main->state( $statedefault )
+ unless $cust_main->state || $cust_main->country ne $countrydefault;
+
+my($county_html, $state_html, $country_html) =
+ FS::cust_main_county::regionselector( $cust_main->county,
+ $cust_main->state,
+ $cust_main->country );
+
+print "$county_html $state_html";
+
+print qq!</TD><TH>${r}Zip</TH><TD><INPUT TYPE="text" NAME="zip" VALUE="$zip" SIZE=10></TD></TR>!;
+
+my($daytime,$night,$fax)=(
+ $cust_main->daytime,
+ $cust_main->night,
+ $cust_main->fax,
+);
+
+my $daytime_label = FS::Msgcat::_gettext('daytime') || 'Day Phone';
+my $night_label = FS::Msgcat::_gettext('night') || 'Night Phone';
+
+print <<END;
+<TR><TH ALIGN="right">${r}Country</TH><TD>$country_html</TD></TR>
+<TR><TD ALIGN="right">$daytime_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="$daytime" SIZE=18></TD></TR>
+<TR><TD ALIGN="right">$night_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="$night" SIZE=18></TD></TR>
+<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="$fax" SIZE=12></TD></TR>
+END
+
+print "</TABLE>${r}required fields<BR>";
+
+# service address
+
+if ( defined $cust_main->dbdef_table->column('ship_last') ) {
+
+ print "\n", <<END;
+ <SCRIPT>
+ function changed(what) {
+ what.form.same.checked = false;
+ }
+ function samechanged(what) {
+ if ( what.checked ) {
+END
+print " what.form.ship_$_.value = what.form.$_.value;\n"
+ for (qw( last first company address1 address2 city zip daytime night fax ));
+print <<END;
+ what.form.ship_country.selectedIndex = what.form.country.selectedIndex;
+ ship_country_changed(what.form.ship_country);
+ what.form.ship_state.selectedIndex = what.form.state.selectedIndex;
+ ship_state_changed(what.form.ship_state);
+ what.form.ship_county.selectedIndex = what.form.county.selectedIndex;
+ }
+ }
+ </SCRIPT>
+END
+
+ print '<BR>Service address ',
+ '(<INPUT TYPE="checkbox" NAME="same" VALUE="Y" onClick="samechanged(this)"';
+ unless ( $cust_main->ship_last && $cgi->param('same') ne 'Y' ) {
+ print ' CHECKED';
+ foreach (
+ qw( last first company address1 address2 city county state zip country
+ daytime night fax )
+ ) {
+ $cust_main->set("ship_$_", $cust_main->get($_) );
+ }
+ }
+ print '>same as billing address)<BR>';
+
+ my($ship_last,$ship_first,$ship_company,$ship_address1,$ship_address2,$ship_city,$ship_zip)=(
+ $cust_main->ship_last,
+ $cust_main->ship_first,
+ $cust_main->ship_company,
+ $cust_main->ship_address1,
+ $cust_main->ship_address2,
+ $cust_main->ship_city,
+ $cust_main->ship_zip,
+ );
+
+ print &itable("#cccccc"), <<END;
+ <TR><TH ALIGN="right">${r}Contact&nbsp;name<BR>(last,&nbsp;first)</TH><TD COLSPAN=5>
+END
+
+ print <<END;
+ <INPUT TYPE="text" NAME="ship_last" VALUE="$ship_last" onChange="changed(this)"> ,
+ <INPUT TYPE="text" NAME="ship_first" VALUE="$ship_first" onChange="changed(this)">
+END
+
+ print <<END;
+ </TD></TR>
+ <TR><TD ALIGN="right">Company</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_company" VALUE="$ship_company" SIZE=70 onChange="changed(this)"></TD></TR>
+ <TR><TH ALIGN="right">${r}Address</TH><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_address1" VALUE="$ship_address1" SIZE=70 onChange="changed(this)"></TD></TR>
+ <TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_address2" VALUE="$ship_address2" SIZE=70 onChange="changed(this)"></TD></TR>
+ <TR><TH ALIGN="right">${r}City</TH><TD><INPUT TYPE="text" NAME="ship_city" VALUE="$ship_city" onChange="changed(this)"></TD><TH ALIGN="right">${r}State</TH><TD>
+END
+
+ #false laziness with regular state
+ $cust_main->ship_country( $countrydefault ) unless $cust_main->ship_country;
+
+ $cust_main->ship_state( $statedefault )
+ unless $cust_main->ship_state
+ || $cust_main->ship_country ne $countrydefault;
+
+ my($ship_county_html, $ship_state_html, $ship_country_html) =
+ FS::cust_main_county::regionselector( $cust_main->ship_county,
+ $cust_main->ship_state,
+ $cust_main->ship_country,
+ 'ship_',
+ 'changed(this)', );
+
+ print "$ship_county_html $ship_state_html";
+
+ print qq!</TD><TH>${r}Zip</TH><TD><INPUT TYPE="text" NAME="ship_zip" VALUE="$ship_zip" SIZE=10 onChange="changed(this)"></TD></TR>!;
+
+ my($ship_daytime,$ship_night,$ship_fax)=(
+ $cust_main->ship_daytime,
+ $cust_main->ship_night,
+ $cust_main->ship_fax,
+ );
+
+ print <<END;
+ <TR><TH ALIGN="right">${r}Country</TH><TD>$ship_country_html</TD></TR>
+ <TR><TD ALIGN="right">$daytime_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_daytime" VALUE="$ship_daytime" SIZE=18 onChange="changed(this)"></TD></TR>
+ <TR><TD ALIGN="right">$night_label</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_night" VALUE="$ship_night" SIZE=18 onChange="changed(this)"></TD></TR>
+ <TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="ship_fax" VALUE="$ship_fax" SIZE=12 onChange="changed(this)"></TD></TR>
+END
+
+ print "</TABLE>${r}required fields<BR>";
+
+}
+
+# billing info
+
+sub expselect {
+ my $prefix = shift;
+ my( $m, $y ) = (0, 0);
+ if ( scalar(@_) ) {
+ my $date = shift || '01-2000';
+ if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format
+ ( $m, $y ) = ( $2, $1 );
+ } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) {
+ ( $m, $y ) = ( $1, $3 );
+ } else {
+ die "unrecognized expiration date format: $date";
+ }
+ }
+
+ my $return = qq!<SELECT NAME="$prefix!. qq!_month" SIZE="1">!;
+ for ( 1 .. 12 ) {
+ $return .= "<OPTION";
+ $return .= " SELECTED" if $_ == $m;
+ $return .= ">$_";
+ }
+ $return .= qq!</SELECT>/<SELECT NAME="$prefix!. qq!_year" SIZE="1">!;
+ my @t = localtime;
+ my $thisYear = $t[5] + 1900;
+ for ( ($thisYear > $y && $y > 0 ? $y : $thisYear) .. 2037 ) {
+ $return .= "<OPTION";
+ $return .= " SELECTED" if $_ == $y;
+ $return .= ">$_";
+ }
+ $return .= "</SELECT>";
+
+ $return;
+}
+
+my $payby_default = $conf->config('payby-default');
+
+if ( $payby_default eq 'HIDE' ) {
+
+ $cust_main->payby('BILL') unless $cust_main->payby;
+
+ foreach my $field (qw( tax payby )) {
+ print qq!<INPUT TYPE="hidden" NAME="$field" VALUE="!.
+ $cust_main->getfield($field). '">';
+ }
+
+ print qq!<INPUT TYPE="hidden" NAME="invoicing_list" VALUE="!.
+ join(', ', $cust_main->invoicing_list). '">';
+
+ foreach my $payby (qw( CARD DCRD CHEK DCHK LECB BILL COMP )) {
+ foreach my $field (qw( payinfo payname )) {
+ print qq!<INPUT TYPE="hidden" NAME="${payby}_$field" VALUE="!.
+ $cust_main->getfield($field). '">';
+ }
+
+ #false laziness w/expselect
+ my( $m, $y );
+ my $date = $cust_main->paydate || '12-2037';
+ if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format
+ ( $m, $y ) = ( $2, $1 );
+ } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) {
+ ( $m, $y ) = ( $1, $3 );
+ } else {
+ die "unrecognized expiration date format: $date";
+ }
+
+ print qq!<INPUT TYPE="hidden" NAME="${payby}_month" VALUE="$m">!.
+ qq!<INPUT TYPE="hidden" NAME="${payby}_year" VALUE="$y">!;
+
+ }
+
+} else {
+
+ print "<BR>Billing information", &itable("#cccccc"),
+ qq!<TR><TD><INPUT TYPE="checkbox" NAME="tax" VALUE="Y"!;
+ print qq! CHECKED! if $cust_main->tax eq "Y";
+ print qq!>Tax Exempt</TD></TR><TR><TD>!.
+ qq!<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"!;
+
+ #my @invoicing_list = $cust_main->invoicing_list;
+ print qq! CHECKED!
+ if ( ! @invoicing_list && ! $conf->exists('disablepostalinvoicedefault') )
+ || grep { $_ eq 'POST' } @invoicing_list;
+ print qq!>Postal mail invoice</TD></TR>!;
+ my $invoicing_list = join(', ', grep { $_ ne 'POST' } @invoicing_list );
+ print qq!<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="$invoicing_list"></TD></TR>!;
+
+ print "<TR><TD>Billing type</TD></TR>",
+ "</TABLE>", '<SCRIPT>
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1;
+ }
+ var achwindow = -1;
+ function achopen(filename,windowname,properties) {
+ achclose();
+ achwindow = window.open(filename,windowname,properties);
+ }
+ function achclose() {
+ if ( achwindow != -1 )
+ achwindow.close();
+ achwindow = -1;
+ }
+ </SCRIPT>',
+ &table("#cccccc"), "<TR>";
+
+ my($payinfo, $payname)=(
+ $cust_main->payinfo,
+ $cust_main->payname,
+ );
+
+ my %payby = (
+ 'CARD' => qq!Credit card (automatic)<BR>${r}<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR>${r}Exp !. expselect("CARD"). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card (on-demand)<BR>${r}<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR>${r}Exp !. expselect("DCRD"). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check (automatic)<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE=""><BR>${r}ABA/Routing number <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9> (<A HREF="javascript:achopen('../docs/ach.html','ach','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=384,height=256')">help</A>)<INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check (on-demand)<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE=""><BR>${r}ABA/Routing number <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9> (<A HREF="javascript:achopen('../docs/ach.html','ach','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=384,height=256')">help</A>)<INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><INPUT TYPE="hidden" NAME="BILL_month" VALUE="12"><INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="">!,
+ 'COMP' => qq!Complimentary<BR>${r}Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR>${r}Exp !. expselect("COMP"),
+);
+
+ if ( $cust_main->dbdef_table->column('paycvv') ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5 bs
+ $payby{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('../docs/cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ my( $account, $aba ) = split('@', $payinfo);
+
+ my %paybychecked = (
+ 'CARD' => qq!Credit card (automatic)<BR>${r}<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR>${r}Exp !. expselect("CARD", $cust_main->paydate). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'DCRD' => qq!Credit card (on-demand)<BR>${r}<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR>${r}Exp !. expselect("DCRD", $cust_main->paydate). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check (automatic)<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account"><BR>${r}ABA/Routing number <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9> (<A HREF="javascript:achopen('../docs/ach.html','ach','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=384,height=256')">help</A>)<INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check (on-demand)<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account"><BR>${r}ABA/Routing number <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9> (<A HREF="javascript:achopen('../docs/ach.html','ach','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=384,height=256')">help</A>)<INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><INPUT TYPE="hidden" NAME="BILL_month" VALUE="12"><INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR>${r}Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR>${r}Exp !. expselect("COMP", $cust_main->paydate),
+);
+
+ if ( $cust_main->dbdef_table->column('paycvv') ) {
+ my $paycvv = $cust_main->paycvv;
+
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5 bs
+ $paybychecked{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('../docs/cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+
+ $cust_main->payby($payby_default) unless $cust_main->payby;
+ for (qw(CARD DCRD CHEK DCHK LECB BILL COMP)) {
+ print qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($cust_main->payby eq "$_") {
+ print qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ print qq!> $payby{$_}</TD>!;
+ }
+ }
+
+ print "</TR></TABLE>$r required fields for each billing type";
+
+}
+
+if ( defined $cust_main->dbdef_table->column('comments') ) {
+ print "<BR><BR>Comments", &itable("#cccccc"),
+ qq!<TR><TD><TEXTAREA COLS=80 ROWS=5 WRAP="HARD" NAME="comments">!,
+ $cust_main->comments, "</TEXTAREA>",
+ "</TD></TR></TABLE>";
+}
+
+unless ( $custnum ) {
+ # pry the wrong place for this logic. also pretty expensive
+ #use FS::part_pkg;
+
+ #false laziness, copied from FS::cust_pkg::order
+ my $pkgpart;
+ if ( scalar(@agents) == 1 ) {
+ # $pkgpart->{PKGPART} is true iff $custnum may purchase PKGPART
+ my($agent)=qsearchs('agent',{'agentnum'=> $agentnum });
+ $pkgpart = $agent->pkgpart_hashref;
+ } else {
+ #can't know (agent not chosen), so, allow all
+ my %typenum;
+ foreach my $agent ( @agents ) {
+ next if $typenum{$agent->typenum}++;
+ #fixed in 5.004_05 #$pkgpart->{$_}++ foreach keys %{ $agent->pkgpart_hashref }
+ foreach ( keys %{ $agent->pkgpart_hashref } ) { $pkgpart->{$_}++; } #5.004_04 workaround
+ }
+ }
+ #eslaf
+
+ my @part_pkg = grep { $_->svcpart('svc_acct') && $pkgpart->{ $_->pkgpart } }
+ qsearch( 'part_pkg', { 'disabled' => '' } );
+
+ if ( @part_pkg ) {
+
+# print "<BR><BR>First package", &itable("#cccccc", "0 ALIGN=LEFT"),
+#apiabuse & undesirable wrapping
+ print "<BR><BR>First package", &itable("#cccccc"),
+ qq!<TR><TD COLSPAN=2><SELECT NAME="pkgpart_svcpart">!;
+
+ print qq!<OPTION VALUE="">(none)!;
+
+ foreach my $part_pkg ( @part_pkg ) {
+ print qq!<OPTION VALUE="!,
+# $part_pkg->pkgpart. "_". $pkgpart{ $part_pkg->pkgpart }, '"';
+ $part_pkg->pkgpart. "_". $part_pkg->svcpart('svc_acct'), '"';
+ print " SELECTED" if $saved_pkgpart && ( $part_pkg->pkgpart == $saved_pkgpart );
+ print ">", $part_pkg->pkg, " - ", $part_pkg->comment;
+ }
+ print "</SELECT></TD></TR>";
+
+ #false laziness: (mostly) copied from edit/svc_acct.cgi
+ #$ulen = $svc_acct->dbdef_table->column('username')->length;
+ my $ulen = dbdef->table('svc_acct')->column('username')->length;
+ my $ulen2 = $ulen+2;
+ my $passwordmax = $conf->config('passwordmax') || 8;
+ my $pmax2 = $passwordmax + 2;
+ print <<END;
+<TR><TD ALIGN="right">Username</TD>
+<TD><INPUT TYPE="text" NAME="username" VALUE="$username" SIZE=$ulen2 MAXLENGTH=$ulen></TD></TR>
+<TR><TD ALIGN="right">Password</TD>
+<TD><INPUT TYPE="text" NAME="_password" VALUE="$password" SIZE=$pmax2 MAXLENGTH=$passwordmax>
+(blank to generate)</TD></TR>
+END
+
+ print '<TR><TD ALIGN="right">Access number</TD><TD WIDTH="100%">'
+ .
+ &FS::svc_acct_pop::popselector($popnum).
+ '</TD></TR></TABLE>'
+ ;
+ }
+}
+
+my $otaker = $cust_main->otaker;
+print qq!<INPUT TYPE="hidden" NAME="otaker" VALUE="$otaker">!,
+ qq!<BR><INPUT TYPE="submit" VALUE="!,
+ $custnum ? "Apply Changes" : "Add Customer", qq!">!,
+ "</FORM></BODY></HTML>",
+;
+
+%>
diff --git a/httemplate/edit/cust_main_county-expand.cgi b/httemplate/edit/cust_main_county-expand.cgi
new file mode 100755
index 0000000..9f314a4
--- /dev/null
+++ b/httemplate/edit/cust_main_county-expand.cgi
@@ -0,0 +1,54 @@
+<!-- mason kludge -->
+<%
+
+my($taxnum, $delim, $expansion, $taxclass );
+my($query) = $cgi->keywords;
+if ( $cgi->param('error') ) {
+ $taxnum = $cgi->param('taxnum');
+ $delim = $cgi->param('delim');
+ $expansion = $cgi->param('expansion');
+ $taxclass = $cgi->param('taxclass');
+} else {
+ $query =~ /^(taxclass)?(\d+)$/
+ or die "Illegal taxnum (query $query)";
+ $taxclass = $1 ? 'taxclass' : '';
+ $taxnum = $2;
+ $delim = 'n';
+ $expansion = '';
+}
+
+my $cust_main_county = qsearchs('cust_main_county',{'taxnum'=>$taxnum})
+ or die "cust_main_county.taxnum $taxnum not found";
+die "Can't expand entry!" if $cust_main_county->getfield('county');
+
+my $p1 = popurl(1);
+print header("Tax Rate (expand)", menubar(
+ 'Main Menu' => popurl(2),
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print <<END;
+ <FORM ACTION="${p1}process/cust_main_county-expand.cgi" METHOD=POST>
+ <INPUT TYPE="hidden" NAME="taxnum" VALUE="$taxnum">
+ <INPUT TYPE="hidden" NAME="taxclass" VALUE="$taxclass">
+ Separate by
+END
+print '<INPUT TYPE="radio" NAME="delim" VALUE="n"';
+print ' CHECKED' if $delim eq 'n';
+print '>line (broken on some browsers) or',
+ '<INPUT TYPE="radio" NAME="delim" VALUE="s"';
+print ' CHECKED' if $delim eq 's';
+print '>whitespace.';
+print <<END;
+ <BR><INPUT TYPE="submit" VALUE="Submit">
+ <BR><TEXTAREA NAME="expansion" ROWS=100>$expansion</TEXTAREA>
+ </FORM>
+ </CENTER>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/cust_main_county.cgi b/httemplate/edit/cust_main_county.cgi
new file mode 100755
index 0000000..4bcfcbe
--- /dev/null
+++ b/httemplate/edit/cust_main_county.cgi
@@ -0,0 +1,98 @@
+<!-- mason kludge -->
+<%
+
+print header("Edit tax rates", menubar(
+ 'Main Menu' => popurl(2),
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print qq!<FORM ACTION="!, popurl(1),
+ qq!process/cust_main_county.cgi" METHOD=POST>!, &table(), <<END;
+ <TR>
+ <TH><FONT SIZE=-1>Country</FONT></TH>
+ <TH><FONT SIZE=-1>State</FONT></TH>
+ <TH><FONT SIZE=-1>County</FONT></TH>
+ <TH><FONT SIZE=-1>Taxclass</FONT><BR><FONT SIZE=-2>(per-package classification)</FONT></TH>
+END
+
+if ( dbdef->table('cust_main_county')->column('taxname') ) {
+ print '<TH><FONT SIZE=-1>Tax name</FONT><BR><FONT SIZE=-2>(printed on invoices)</FONT></TH>';
+}
+
+print <<END;
+ <TH><FONT SIZE=-1>Tax</FONT></TH>
+ <TH><FONT SIZE=-1>Exempt<BR>per<BR>month</TH>
+END
+
+if ( dbdef->table('cust_main_county')->column('setuptax') ) {
+ print '<TH><FONT SIZE=-1>Setup<BR>fee<BR>exempt</TH>';
+}
+if ( dbdef->table('cust_main_county')->column('recurtax') ) {
+ print '<TH><FONT SIZE=-1>Recurring<BR>fee<BR>exempt</TH>';
+}
+
+print '</TR>';
+
+foreach my $cust_main_county ( sort { $a->country cmp $b->country
+ or $a->state cmp $b->state
+ or $a->county cmp $b->county
+ } qsearch('cust_main_county',{}) ) {
+ my($hashref)=$cust_main_county->hashref;
+ print <<END;
+ <TR>
+ <TD BGCOLOR="#ffffff">$hashref->{country}</TD>
+END
+
+ print "<TD", $hashref->{state}
+ ? ' BGCOLOR="#ffffff">'.$hashref->{state}
+ : ' BGCOLOR="#cccccc">(ALL)'
+ , "</TD>";
+
+ print "<TD", $hashref->{county}
+ ? ' BGCOLOR="#ffffff">'. $hashref->{county}
+ : ' BGCOLOR="#cccccc">(ALL)'
+ , "</TD>";
+
+ print "<TD", $hashref->{taxclass}
+ ? ' BGCOLOR="#ffffff">'. $hashref->{taxclass}
+ : ' BGCOLOR="#cccccc">(ALL)'
+ , "</TD>";
+
+ print qq!<TD><INPUT TYPE="text" NAME="taxname!, $hashref->{taxnum},
+ qq!" VALUE="!, $hashref->{taxname}, qq!"></TD>!
+ if dbdef->table('cust_main_county')->column('taxname');
+
+ print qq!<TD><TABLE><TR><TD><INPUT TYPE="text" NAME="tax!, $hashref->{taxnum},
+ qq!" VALUE="!, $hashref->{tax}, qq!" SIZE=6 MAXLENGTH=6></TD><TD>%</TD></TR></TABLE></TD>!;
+ print qq!<TD><TABLE><TR><TD>\$</TD><TD><INPUT TYPE="text" NAME="exempt_amount!, $hashref->{taxnum},
+ qq!" VALUE="!, $hashref->{exempt_amount}||0, qq!" SIZE=6></TD></TR></TABLE></TD>!;
+
+ print qq!<TD><INPUT TYPE="checkbox" NAME="setuptax!. $hashref->{taxnum}.
+ '" VALUE="Y"'.
+ ( $hashref->{setuptax} =~ /^Y$/i ? ' CHECKED' : '' ).
+ '></TD>'
+ if dbdef->table('cust_main_county')->column('setuptax');
+
+ print qq!<TD><INPUT TYPE="checkbox" NAME="recurtax!. $hashref->{taxnum}.
+ '" VALUE="Y"'.
+ ( $hashref->{recurtax} =~ /^Y$/i ? ' CHECKED' : '' ).
+ '></TD>'
+ if dbdef->table('cust_main_county')->column('recurtax');
+
+ print '</TR>';
+
+}
+
+print <<END;
+ </TABLE>
+ <INPUT TYPE="submit" VALUE="Apply changes">
+ </FORM>
+ </CENTER>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/cust_pay.cgi b/httemplate/edit/cust_pay.cgi
new file mode 100755
index 0000000..f6ae7b2
--- /dev/null
+++ b/httemplate/edit/cust_pay.cgi
@@ -0,0 +1,129 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+
+my($link, $linknum, $paid, $payby, $payinfo, $quickpay);
+if ( $cgi->param('error') ) {
+ $link = $cgi->param('link');
+ $linknum = $cgi->param('linknum');
+ $paid = $cgi->param('paid');
+ $payby = $cgi->param('payby');
+ $payinfo = $cgi->param('payinfo');
+ $quickpay = $cgi->param('quickpay');
+} elsif ($cgi->keywords) {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $link = 'invnum';
+ $linknum = $1;
+ $paid = '';
+ $payby = 'BILL';
+ $payinfo = "";
+ $quickpay = '';
+} elsif ( $cgi->param('custnum') =~ /^(\d+)$/ ) {
+ $link = 'custnum';
+ $linknum = $1;
+ $paid = '';
+ $payby = 'BILL';
+ $payinfo = '';
+ $quickpay = $cgi->param('quickpay');
+} else {
+ die "illegal query ". $cgi->keywords;
+}
+my $_date = time;
+
+my $paybatch = "webui-$_date-$$-". rand() * 2**32;
+
+my $p1 = popurl(1);
+print header("Post payment", '');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT><BR><BR>"
+ if $cgi->param('error');
+
+print <<END, ntable("#cccccc",2);
+ <FORM ACTION="${p1}process/cust_pay.cgi" METHOD=POST>
+ <INPUT TYPE="hidden" NAME="link" VALUE="$link">
+ <INPUT TYPE="hidden" NAME="linknum" VALUE="$linknum">
+ <INPUT TYPE="hidden" NAME="quickpay" VALUE="$quickpay">
+END
+
+my $custnum;
+if ( $link eq 'invnum' ) {
+
+ my $cust_bill = qsearchs('cust_bill', { 'invnum' => $linknum } )
+ or die "unknown invnum $linknum";
+ print "Invoice #<B>$linknum</B>". ntable("#cccccc",2).
+ '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'.
+ time2str("%D", $cust_bill->_date). '</TD></TR>'.
+ '<TR><TD ALIGN="right" VALIGN="top">Items</TD><TD BGCOLOR="#ffffff">';
+ foreach ( $cust_bill->cust_bill_pkg ) { #false laziness with FS::cust_bill
+ if ( $_->pkgnum ) {
+
+ my($cust_pkg)=qsearchs('cust_pkg', { 'pkgnum', $_->pkgnum } );
+ my($part_pkg)=qsearchs('part_pkg',{'pkgpart'=>$cust_pkg->pkgpart});
+ my($pkg)=$part_pkg->pkg;
+
+ if ( $_->setup != 0 ) {
+ print "$pkg Setup<BR>"; # $money_char. sprintf("%10.2f",$_->setup);
+ print join('<BR>',
+ map { " ". $_->[0]. ": ". $_->[1] } $cust_pkg->labels
+ ). '<BR>';
+ }
+
+ if ( $_->recur != 0 ) {
+ print
+ "$pkg (" . time2str("%x",$_->sdate) . " - " .
+ time2str("%x",$_->edate) . ")<BR>";
+ #$money_char. sprintf("%10.2f",$_->recur)
+ print join('<BR>',
+ map { '--->'. $_->[0]. ": ". $_->[1] } $cust_pkg->labels
+ ). '<BR>';
+ }
+
+ } else { #pkgnum Tax
+ print "Tax<BR>" # $money_char. sprintf("%10.2f",$_->setup)
+ if $_->setup != 0;
+ }
+
+ }
+ print '</TD></TR></TABLE><BR><BR>';
+
+ $custnum = $cust_bill->custnum;
+
+} elsif ( $link eq 'custnum' ) {
+ $custnum = $linknum;
+}
+
+print small_custview($custnum, $conf->config('countrydefault'));
+
+print qq!<INPUT TYPE="hidden" NAME="_date" VALUE="$_date">!;
+print qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$payby">!;
+
+print '<BR><BR>Payment'. ntable("#cccccc", 2).
+ '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'.
+ time2str("%D",$_date). '</TD></TR>';
+
+print qq!<TR><TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">\$<INPUT TYPE="text" NAME="paid" VALUE="$paid" SIZE=8 MAXLENGTH=8></TD></TR>!;
+
+print qq!<TR><TD ALIGN="right">Payby</TD><TD BGCOLOR="#ffffff">$payby</TD></TR>!;
+
+#payinfo (check # now as payby="BILL" hardcoded.. what to do later?)
+print qq!<TR><TD ALIGN="right">Check #</TD><TD BGCOLOR="#ffffff"><INPUT TYPE="text" NAME="payinfo" VALUE="$payinfo"></TD></TR>!;
+
+print qq!<TR><TD ALIGN="right">Auto-apply<BR>to invoices</TD><TD><SELECT NAME="apply"><OPTION VALUE="yes" SELECTED>yes<OPTION>no</SELECT></TD>!;
+
+print "</TABLE>";
+
+#paybatch
+print qq!<INPUT TYPE="hidden" NAME="paybatch" VALUE="$paybatch">!;
+
+print <<END;
+<BR>
+<INPUT TYPE="submit" VALUE="Post payment">
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/cust_pkg.cgi b/httemplate/edit/cust_pkg.cgi
new file mode 100755
index 0000000..485d601
--- /dev/null
+++ b/httemplate/edit/cust_pkg.cgi
@@ -0,0 +1,117 @@
+<!-- mason kludge -->
+<%
+
+my %pkg = ();
+my %comment = ();
+my %all_pkg = ();
+my %all_comment = ();
+#foreach (qsearch('part_pkg', { 'disabled' => '' })) {
+# $pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg');
+# $comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment');
+#}
+foreach (qsearch('part_pkg', {} )) {
+ $all_pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg');
+ $all_comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment');
+ next if $_->disabled;
+ $pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg');
+ $comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment');
+}
+
+my($custnum, %remove_pkg);
+if ( $cgi->param('error') ) {
+ $custnum = $cgi->param('custnum');
+ %remove_pkg = map { $_ => 1 } $cgi->param('remove_pkg');
+} else {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $custnum = $1;
+ %remove_pkg = ();
+}
+
+my $p1 = popurl(1);
+print header("Add/Edit Packages", '');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print qq!<FORM ACTION="${p1}process/cust_pkg.cgi" METHOD=POST>!;
+
+print qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!;
+
+#current packages
+my @cust_pkg = qsearch('cust_pkg',{ 'custnum' => $custnum, 'cancel' => '' } );
+
+if (@cust_pkg) {
+ print <<END;
+Current packages - select to remove (services are moved to a new package below)
+<BR><BR>
+END
+
+ my $count = 0 ;
+ print qq!<TABLE>! ;
+ foreach (@cust_pkg) {
+ print '<TR>' if $count == 0;
+ my($pkgnum,$pkgpart)=( $_->getfield('pkgnum'), $_->getfield('pkgpart') );
+ print qq!<TD><INPUT TYPE="checkbox" NAME="remove_pkg" VALUE="$pkgnum"!;
+ print " CHECKED" if $remove_pkg{$pkgnum};
+ print qq!>$pkgnum: $all_pkg{$pkgpart} - $all_comment{$pkgpart}</TD>\n!;
+ $count ++ ;
+ if ($count == 2)
+ {
+ $count = 0 ;
+ print qq!</TR>\n! ;
+ }
+ }
+ print qq!</TABLE><BR><BR>!;
+}
+
+print <<END;
+Order new packages<BR><BR>
+END
+
+my $cust_main = qsearchs('cust_main',{'custnum'=>$custnum});
+my $agent = qsearchs('agent',{'agentnum'=> $cust_main->agentnum });
+
+my $count = 0;
+my $pkgparts = 0;
+print qq!<TABLE>!;
+foreach my $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) {
+ $pkgparts++;
+ my($pkgpart)=$type_pkgs->pkgpart;
+ next unless exists $pkg{$pkgpart}; #skip disabled ones
+ print qq!<TR>! if ( $count == 0 );
+ my $value = $cgi->param("pkg$pkgpart") || 0;
+ print <<END;
+ <TD>
+ <INPUT TYPE="text" NAME="pkg$pkgpart" VALUE="$value" SIZE="2" MAXLENGTH="2">
+ $pkgpart: $pkg{$pkgpart} - $comment{$pkgpart}</TD>\n
+END
+ $count ++ ;
+ if ( $count == 2 ) {
+ print qq!</TR>\n! ;
+ $count = 0;
+ }
+}
+print qq!</TABLE>!;
+
+unless ( $pkgparts ) {
+ my $p2 = popurl(2);
+ my $typenum = $agent->typenum;
+ my $agent_type = qsearchs( 'agent_type', { 'typenum' => $typenum } );
+ my $atype = $agent_type->atype;
+ print <<END;
+(No <a href="${p2}browse/part_pkg.cgi">package definitions</a>, or agent type
+<a href="${p2}edit/agent_type.cgi?$typenum">$atype</a> not allowed to purchase
+any packages.)
+END
+}
+
+#submit
+print <<END;
+<P><INPUT TYPE="submit" VALUE="Order">
+ </FORM>
+ </BODY>
+</HTML>
+END
+%>
diff --git a/httemplate/edit/msgcat.cgi b/httemplate/edit/msgcat.cgi
new file mode 100755
index 0000000..ee9b1c6
--- /dev/null
+++ b/httemplate/edit/msgcat.cgi
@@ -0,0 +1,58 @@
+<!-- mason kludge -->
+<%
+
+print header("Edit Message catalog", menubar(
+# 'Main Menu' => $p,
+)), '<BR>';
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !. $cgi->param('error').
+ '</FONT><BR><BR>'
+ if $cgi->param('error');
+
+my $widget = new HTML::Widgets::SelectLayers(
+ 'selected_layer' => 'en_US',
+ 'options' => { 'en_US'=>'en_US' },
+ 'form_action' => 'process/msgcat.cgi',
+ 'layer_callback' => sub {
+ my $layer = shift;
+ my $html = qq!<INPUT TYPE="hidden" NAME="locale" VALUE="$layer">!.
+ "<BR>Messages for locale $layer<BR>". table().
+ "<TR><TH COLSPAN=2>Code</TH>".
+ "<TH>Message</TH>";
+ $html .= "<TH>en_US Message</TH>" unless $layer eq 'en_US';
+ $html .= '</TR>';
+
+ #foreach my $msgcat ( sort { $a->msgcode cmp $b->msgcode }
+ # qsearch('msgcat', { 'locale' => $layer } ) ) {
+ foreach my $msgcat ( qsearch('msgcat', { 'locale' => $layer } ) ) {
+ $html .=
+ '<TR><TD>'. $msgcat->msgnum. '</TD><TD>'. $msgcat->msgcode. '</TD>'.
+ '<TD><INPUT TYPE="text" SIZE=32 '.
+ qq! NAME="!. $msgcat->msgnum. '" '.
+ qq!VALUE="!. ($cgi->param($msgcat->msgnum)||$msgcat->msg). qq!"></TD>!;
+ unless ( $layer eq 'en_US' ) {
+ my $en_msgcat = qsearchs('msgcat', {
+ 'locale' => 'en_US',
+ 'msgcode' => $msgcat->msgcode,
+ } );
+ $html .= '<TD>'. $en_msgcat->msg. '</TD>';
+ }
+ $html .= '</TR>';
+ }
+
+ $html .= '</TABLE><BR><INPUT TYPE="submit" VALUE="Apply changes">';
+
+ $html;
+ },
+
+);
+
+print $widget->html;
+
+print <<END;
+ </TABLE>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/part_bill_event.cgi b/httemplate/edit/part_bill_event.cgi
new file mode 100755
index 0000000..2f99ca5
--- /dev/null
+++ b/httemplate/edit/part_bill_event.cgi
@@ -0,0 +1,288 @@
+<!-- mason kludge -->
+<%
+
+if ( $cgi->param('eventpart') && $cgi->param('eventpart') =~ /^(\d+)$/ ) {
+ $cgi->param('eventpart', $1);
+} else {
+ $cgi->param('eventpart', '');
+}
+
+my ($query) = $cgi->keywords;
+my $action = '';
+my $part_bill_event = '';
+if ( $cgi->param('error') ) {
+ $part_bill_event = new FS::part_bill_event ( {
+ map { $_, scalar($cgi->param($_)) } fields('part_bill_event')
+ } );
+}
+if ( $query && $query =~ /^(\d+)$/ ) {
+ $part_bill_event ||= qsearchs('part_bill_event',{'eventpart'=>$1});
+} else {
+ $part_bill_event ||= new FS::part_bill_event {};
+}
+$action ||= $part_bill_event->eventpart ? 'Edit' : 'Add';
+my $hashref = $part_bill_event->hashref;
+
+print header("$action Invoice Event Definition", menubar(
+ 'Main Menu' => popurl(2),
+ 'View all invoice events' => popurl(2). 'browse/part_bill_event.cgi',
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print '<FORM ACTION="', popurl(1), 'process/part_bill_event.cgi" METHOD=POST>'.
+ '<INPUT TYPE="hidden" NAME="eventpart" VALUE="'.
+ $part_bill_event->eventpart .'">';
+print "Invoice Event #", $hashref->{eventpart} ? $hashref->{eventpart} : "(NEW)";
+
+print ntable("#cccccc",2), <<END;
+<TR><TD ALIGN="right">Payby</TD><TD><SELECT NAME="payby">
+END
+
+for (qw(CARD DCRD CHEK DCHK LECB BILL COMP)) {
+ print qq!<OPTION VALUE="$_"!;
+ if ($part_bill_event->payby eq $_) {
+ print " SELECTED>$_</OPTION>";
+ } else {
+ print ">$_</OPTION>";
+ }
+}
+
+my $days = $hashref->{seconds}/86400;
+
+print <<END;
+</SELECT></TD></TR>
+<TR><TD ALIGN="right">Event</TD><TD><INPUT TYPE="text" NAME="event" VALUE="$hashref->{event}"></TD></TR>
+<TR><TD ALIGN="right">After</TD><TD><INPUT TYPE="text" NAME="days" VALUE="$days"> days</TD></TR>
+END
+
+print '<TR><TD ALIGN="right">Disabled</TD><TD>';
+print '<INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"';
+print ' CHECKED' if $hashref->{disabled} eq "Y";
+print '>';
+print '</TD></TR>';
+
+print '<TR><TD ALIGN="right">Action</TD><TD>';
+
+#print ntable();
+
+sub select_pkgpart {
+ my $label = shift;
+ my $plandata = shift;
+ my %selected = map { $_=>1 } split(/,\s*/, $plandata->{$label});
+ qq(<SELECT NAME="$label" MULTIPLE>).
+ join("\n", map {
+ '<OPTION VALUE="'. $_->pkgpart. '"'.
+ ( $selected{$_->pkgpart} ? ' SELECTED' : '' ).
+ '>'. $_->pkg. ' - '. $_->comment
+ } qsearch('part_pkg', { 'disabled' => '' } ) ).
+ '</SELECT>';
+}
+
+sub select_agentnum {
+ my $plandata = shift;
+ my $agentnum = $plandata->{'agentnum'};
+ '<SELECT NAME="agentnum">'.
+ join("\n", map {
+ '<OPTION VALUE="'. $_->agentnum. '"'.
+ ( $_->agentnum == $agentnum ? ' SELECTED' : '' ).
+ '>'. $_->agent
+ } qsearch('agent', { 'disabled' => '' } ) ).
+ '</SELECT>';
+}
+
+#this is pretty kludgy right here.
+tie my %events, 'Tie::IxHash',
+
+ 'fee' => {
+ 'name' => 'Late fee',
+ 'code' => '$cust_main->charge( %%%charge%%%, \'%%%reason%%%\' );',
+ 'html' =>
+ 'Amount <INPUT TYPE="text" SIZE="7" NAME="charge" VALUE="%%%charge%%%">'.
+ '<BR>Reason <INPUT TYPE="text" NAME="reason" VALUE="%%%reason%%%">',
+ 'weight' => 10,
+ },
+ 'suspend' => {
+ 'name' => 'Suspend',
+ 'code' => '$cust_main->suspend();',
+ 'weight' => 10,
+ },
+ 'suspend-if-pkgpart' => {
+ 'name' => 'Suspend packages',
+ 'code' => '$cust_main->suspend_if_pkgpart(%%%if_pkgpart%%%);',
+ 'html' => sub { &select_pkgpart('if_pkgpart', @_) },
+ 'weight' => 10,
+ },
+ 'suspend-unless-pkgpart' => {
+ 'name' => 'Suspend packages except',
+ 'code' => '$cust_main->suspend_unless_pkgpart(%%%unless_pkgpart%%%);',
+ 'html' => sub { &select_pkgpart('unless_pkgpart', @_) },
+ 'weight' => 10,
+ },
+ 'cancel' => {
+ 'name' => 'Cancel',
+ 'code' => '$cust_main->cancel();',
+ 'weight' => 10,
+ },
+
+ 'addpost' => {
+ 'name' => 'Add postal invoicing',
+ 'code' => '$cust_main->invoicing_list_addpost(); "";',
+ 'weight' => 20,
+ },
+
+ 'comp' => {
+ 'name' => 'Pay invoice with a complimentary "payment"',
+ 'code' => '$cust_bill->comp();',
+ 'weight' => 30,
+ },
+
+ 'realtime-card' => {
+ 'name' => 'Run card with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway',
+ 'code' => '$cust_bill->realtime_card();',
+ 'weight' => 30,
+ },
+
+ 'realtime-check' => {
+ 'name' => 'Run check with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway',
+ 'code' => '$cust_bill->realtime_ach();',
+ 'weight' => 30,
+ },
+
+ 'realtime-lec' => {
+ 'name' => 'Run phone bill ("LEC") billing with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway',
+ 'code' => '$cust_bill->realtime_lec();',
+ 'weight' => 30,
+ },
+
+ 'batch-card' => {
+ 'name' => 'Add card to the pending credit card batch',
+ 'code' => '$cust_bill->batch_card();',
+ 'weight' => 40,
+ },
+
+ 'send' => {
+ 'name' => 'Send invoice (email/print)',
+ 'code' => '$cust_bill->send();',
+ 'weight' => 50,
+ },
+
+ 'send_alternate' => {
+ 'name' => 'Send invoice (email/print) with alternate template',
+ 'code' => '$cust_bill->send(\'%%%templatename%%%\');',
+ 'html' =>
+ '<INPUT TYPE="text" NAME="templatename" VALUE="%%%templatename%%%">',
+ 'weight' => 50,
+ },
+
+ 'send_agent' => {
+ 'name' => 'Send invoice (email/print) ',
+ 'code' => '$cust_bill->send(\'%%%agent_templatename%%%\', %%%agentnum%%%, \'%%%agent_invoice_from%%%\');',
+ 'html' => sub {
+ '<TABLE BORDER=0>
+ <TR>
+ <TD ALIGN="right">only for agent </TD>
+ <TD>'. &select_agentnum(@_). '</TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">with template </TD>
+ <TD>
+ <INPUT TYPE="text" NAME="agent_templatename" VALUE="%%%agent_templatename%%%">
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">email From: </TD>
+ <TD>
+ <INPUT TYPE="text" NAME="agent_invoice_from" VALUE="%%%agent_invoice_from%%%">
+ </TD>
+ </TR>
+ </TABLE>';
+ },
+ 'weight' => 50,
+ },
+
+ 'send_csv_ftp' => {
+ 'name' => 'Upload CSV invoice data to an FTP server',
+ 'code' => '$cust_bill->send_csv( protocol => \'ftp\',
+ server => \'%%%ftpserver%%%\',
+ username => \'%%%ftpusername%%%\',
+ password => \'%%%ftppassword%%%\',
+ dir => \'%%%ftpdir%%%\' );',
+ 'html' =>
+ '<TABLE BORDER=0><TR><TD ALIGN="right">FTP server: </TD>'.
+ '<TD><INPUT TYPE="text" NAME="ftpserver" VALUE="%%%ftpserver%%%">'.
+ '</TD></TR>'.
+ '<TR><TD ALIGN="right">FTP username: </TD><TD>'.
+ '<INPUT TYPE="text" NAME="ftpusername" VALUE="%%%ftpusername%%%">'.
+ '</TD></TR>'.
+ '<TR><TD ALIGN="right">FTP password: </TD><TD>'.
+ '<INPUT TYPE="text" NAME="ftppassword" VALUE="%%%ftppassword%%%">'.
+ '</TD></TR>'.
+ '<TR><TD ALIGN="right">FTP directory: </TD>'.
+ '<TD><INPUT TYPE="text" NAME="ftpdir" VALUE="%%%ftpdir%%%">'.
+ '</TD></TR>'.
+ '</TABLE>',
+ 'weight' => 50,
+ },
+
+ 'bill' => {
+ 'name' => 'Generate invoices (normally only used with a <i>Late Fee</i> event)',
+ 'code' => '$cust_main->bill();',
+ 'weight' => 60,
+ },
+
+ 'apply' => {
+ 'name' => 'Apply unapplied payments and credits',
+ 'code' => '$cust_main->apply_payments; $cust_main->apply_credits; "";',
+ 'weight' => 70,
+ },
+
+ 'collect' => {
+ 'name' => 'Collect on invoices (normally only used with a <i>Late Fee</i> and <i>Generate Invoice</i> events)',
+ 'code' => '$cust_main->collect();',
+ 'weight' => 80,
+ },
+
+;
+
+foreach my $event ( keys %events ) {
+ my %plandata = map { /^(\w+) (.*)$/; ($1, $2); }
+ split(/\n/, $part_bill_event->plandata);
+ my $html = $events{$event}{html};
+ if ( ref($html) eq 'CODE' ) {
+ $html = &{$html}(\%plandata);
+ }
+ while ( $html =~ /%%%(\w+)%%%/ ) {
+ my $field = $1;
+ $html =~ s/%%%$field%%%/$plandata{$field}/;
+ }
+
+ print ntable( "#cccccc", 2).
+ qq!<TR><TD><INPUT TYPE="radio" NAME="plan_weight_eventcode" !;
+ print "CHECKED " if $event eq $part_bill_event->plan;
+ print qq!VALUE="!. $event. ":". $events{$event}{weight}. ":".
+ encode_entities($events{$event}{code}).
+ qq!">$events{$event}{name}</TD>!;
+ print '<TD>'. $html. '</TD>' if $html;
+ print qq!</TR>!;
+ print '</TABLE>';
+}
+
+#print '</TABLE>';
+
+print <<END;
+</TD></TR>
+</TABLE>
+END
+
+print qq!<INPUT TYPE="submit" VALUE="!,
+ $hashref->{eventpart} ? "Apply changes" : "Add invoice event",
+ qq!">!;
+%>
+
+ </FORM>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi
new file mode 100644
index 0000000..b3d42bd
--- /dev/null
+++ b/httemplate/edit/part_export.cgi
@@ -0,0 +1,128 @@
+<!-- mason kludge -->
+<%
+
+#if ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {
+# $cgi->param('clone', $1);
+#} else {
+# $cgi->param('clone', '');
+#}
+
+my($query) = $cgi->keywords;
+my $action = '';
+my $part_export = '';
+if ( $cgi->param('error') ) {
+ $part_export = new FS::part_export ( {
+ map { $_, scalar($cgi->param($_)) } fields('part_export')
+ } );
+} elsif ( $query =~ /^(\d+)$/ ) {
+ $part_export = qsearchs('part_export', { 'exportnum' => $1 } );
+} else {
+ $part_export = new FS::part_export;
+}
+$action ||= $part_export->exportnum ? 'Edit' : 'Add';
+
+#my $exports = FS::part_export::export_info($svcdb);
+my $exports = FS::part_export::export_info();
+
+my %layers = map { $_ => "$_ - ". $exports->{$_}{desc} } keys %$exports;
+$layers{''}='';
+
+my $widget = new HTML::Widgets::SelectLayers(
+ 'selected_layer' => $part_export->exporttype,
+ 'options' => \%layers,
+ 'form_name' => 'dummy',
+ 'form_action' => 'process/part_export.cgi',
+ 'form_text' => [qw( exportnum machine )],
+# 'form_checkbox' => [qw()],
+ 'html_between' => "</TD></TR></TABLE>\n",
+ 'layer_callback' => sub {
+ my $layer = shift;
+ my $html = qq!<INPUT TYPE="hidden" NAME="exporttype" VALUE="$layer">!.
+ ntable("#cccccc",2);
+
+ $html .= '<TR><TD ALIGN="right">Description</TD><TD BGCOLOR=#ffffff>'.
+ $exports->{$layer}{notes}. '</TD></TR>'
+ if $layer;
+
+ foreach my $option ( keys %{$exports->{$layer}{options}} ) {
+ my $optinfo = $exports->{$layer}{options}{$option};
+ die "Retreived non-ref export info option from $layer export: $optinfo"
+ unless ref($optinfo);
+ my $label = $optinfo->{label};
+ my $type = defined($optinfo->{type}) ? $optinfo->{type} : 'text';
+ my $value = $cgi->param($option)
+ || ( $part_export->exportnum && $part_export->option($option) )
+ || ( (exists $optinfo->{default} && !$part_export->exportnum)
+ ? $optinfo->{default}
+ : ''
+ );
+ $html .= qq!<TR><TD ALIGN="right">$label</TD><TD>!;
+ if ( $type eq 'select' ) {
+ $html .= qq!<SELECT NAME="$option">!;
+ foreach my $select_option ( @{$optinfo->{options}} ) {
+ #if ( ref($select_option) ) {
+ #} else {
+ my $selected = $select_option eq $value ? ' SELECTED' : '';
+ $html .= qq!<OPTION VALUE="$select_option"$selected>!.
+ qq!$select_option</OPTION>!;
+ #}
+ }
+ $html .= '</SELECT>';
+ } elsif ( $type eq 'textarea' ) {
+ $html .= qq!<TEXTAREA NAME="$option" COLS=80 ROWS=8 WRAP="virtual">!.
+ encode_entities($value). '</TEXTAREA>';
+ } elsif ( $type eq 'text' ) {
+ $html .= qq!<INPUT TYPE="text" NAME="$option" VALUE="!.
+ encode_entities($value). '" SIZE=64>';
+ } elsif ( $type eq 'checkbox' ) {
+ $html .= qq!<INPUT TYPE="checkbox" NAME="$option" VALUE="1"!;
+ $html .= ' CHECKED' if $value;
+ $html .= '>';
+ } else {
+ $html .= "unknown type $type";
+ }
+ $html .= '</TD></TR>';
+ }
+ $html .= '</TABLE>';
+
+ $html .= '<INPUT TYPE="hidden" NAME="options" VALUE="'.
+ join(',', keys %{$exports->{$layer}{options}} ). '">';
+
+ $html .= '<INPUT TYPE="hidden" NAME="nodomain" VALUE="'.
+ $exports->{$layer}{nodomain}. '">';
+
+ $html .= '<INPUT TYPE="submit" VALUE="'.
+ ( $part_export->exportnum ? "Apply changes" : "Add export" ).
+ '">';
+
+ $html;
+ },
+);
+
+%>
+<%= header("$action Export", menubar(
+ 'Main Menu' => popurl(2),
+), ' onLoad="visualize()"')
+%>
+
+<% if ( $cgi->param('error') ) { %>
+ <FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT>
+ <BR><BR>
+<% } %>
+
+<FORM NAME="dummy">
+<INPUT TYPE="hidden" NAME="exportnum" VALUE="<%= $part_export->exportnum %>">
+
+<%= ntable("#cccccc",2) %>
+<TR>
+ <TD ALIGN="right">Export host</TD>
+ <TD>
+ <INPUT TYPE="text" NAME="machine" VALUE="<%= $part_export->machine %>">
+ </TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Export</TD>
+ <TD><%= $widget->html %>
+</BODY>
+</HTML>
+
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi
new file mode 100755
index 0000000..460f68b
--- /dev/null
+++ b/httemplate/edit/part_pkg.cgi
@@ -0,0 +1,627 @@
+<!-- mason kludge -->
+<%
+
+if ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {
+ $cgi->param('clone', $1);
+} else {
+ $cgi->param('clone', '');
+}
+if ( $cgi->param('pkgnum') && $cgi->param('pkgnum') =~ /^(\d+)$/ ) {
+ $cgi->param('pkgnum', $1);
+} else {
+ $cgi->param('pkgnum', '');
+}
+
+my ($query) = $cgi->keywords;
+my $action = '';
+my $part_pkg = '';
+if ( $cgi->param('error') ) {
+ $part_pkg = new FS::part_pkg ( {
+ map { $_, scalar($cgi->param($_)) } fields('part_pkg')
+ } );
+}
+if ( $cgi->param('clone') ) {
+ $action='Custom Pricing';
+ my $old_part_pkg =
+ qsearchs('part_pkg', { 'pkgpart' => $cgi->param('clone') } );
+ $part_pkg ||= $old_part_pkg->clone;
+ $part_pkg->disabled('Y');
+} elsif ( $query && $query =~ /^(\d+)$/ ) {
+ $part_pkg ||= qsearchs('part_pkg',{'pkgpart'=>$1});
+} else {
+ unless ( $part_pkg ) {
+ $part_pkg = new FS::part_pkg {};
+ $part_pkg->plan('flat');
+ }
+}
+unless ( $part_pkg->plan ) { #backwards-compat
+ $part_pkg->plan('flat');
+ $part_pkg->plandata("setup_fee=". $part_pkg->setup. "\n".
+ "recur_fee=". $part_pkg->recur. "\n");
+}
+$action ||= $part_pkg->pkgpart ? 'Edit' : 'Add';
+my $hashref = $part_pkg->hashref;
+
+
+print header("$action Package Definition", menubar(
+ 'Main Menu' => popurl(2),
+ 'View all packages' => popurl(2). 'browse/part_pkg.cgi',
+));
+#), ' onLoad="visualize()"');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+#print '<FORM ACTION="', popurl(1), 'process/part_pkg.cgi" METHOD=POST>';
+print '<FORM NAME="dummy">';
+
+#if ( $cgi->param('clone') ) {
+# print qq!<INPUT TYPE="hidden" NAME="clone" VALUE="!, $cgi->param('clone'), qq!">!;
+#}
+#if ( $cgi->param('pkgnum') ) {
+# print qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="!, $cgi->param('pkgnum'), qq!">!;
+#}
+#
+#print qq!<INPUT TYPE="hidden" NAME="pkgpart" VALUE="$hashref->{pkgpart}">!,
+print "Package Part #", $hashref->{pkgpart} ? $hashref->{pkgpart} : "(NEW)";
+
+#false laziness w/view/cust_main.cgi
+my %freq;
+tie %freq, 'Tie::IxHash',
+ '0' => '(no recurring fee)',
+ '1d' => 'daily',
+ '1w' => 'weekly',
+ '2w' => 'biweekly (every 2 weeks)',
+ '1' => 'monthly',
+ '2' => 'bimonthly (every 2 months)',
+ '3' => 'quarterly (every 3 months)',
+ '6' => 'semiannually (every 6 months)',
+ '12' => 'annually',
+ '24' => 'biannually (every 2 years)',
+;
+if ( $part_pkg->dbdef_table->column('freq')->type =~ /(int)/i ) {
+ delete $freq{$_} foreach grep { ! /^\d+$/ } keys %freq;
+}
+
+%>
+<%= ntable("#cccccc",2) %>
+ <TR>
+ <TD ALIGN="right">Package (customer-visible)</TD>
+ <TD>
+ <INPUT TYPE="text" NAME="pkg" SIZE=32 VALUE="<%= $part_pkg->pkg %>">
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Comment (customer-hidden)</TD>
+ <TD>
+ <INPUT TYPE="text" NAME="comment" SIZE=32 VALUE="<%=$part_pkg->comment%>">
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Recurring fee frequency </TD>
+ <TD>
+ <SELECT NAME="freq">
+ <% foreach my $freq ( keys %freq ) { %>
+ <OPTION VALUE="<%= $freq %>"<%= $freq eq $part_pkg->freq ? ' SELECTED' : '' %>><%= $freq{$freq} %>
+ <% } %>
+ </SELECT>
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Setup fee tax exempt</TD>
+ <TD>
+<%
+
+print '<INPUT TYPE="checkbox" NAME="setuptax" VALUE="Y"';
+print ' CHECKED' if $hashref->{setuptax} eq "Y";
+print '>';
+
+print <<END;
+</TD></TR>
+<TR><TD ALIGN="right">Recurring fee tax exempt</TD><TD>
+END
+
+print '<INPUT TYPE="checkbox" NAME="recurtax" VALUE="Y"';
+print ' CHECKED' if $hashref->{recurtax} eq "Y";
+print '>';
+
+print '</TD></TR>';
+
+my $conf = new FS::Conf;
+#false laziness w/ view/cust_main.cgi quick order
+if ( $conf->exists('enable_taxclasses') ) {
+ print '<TR><TD ALIGN="right">Tax class</TD><TD><SELECT NAME="taxclass">';
+ my $sth = dbh->prepare('SELECT DISTINCT taxclass FROM cust_main_county')
+ or die dbh->errstr;
+ $sth->execute or die $sth->errstr;
+ foreach my $taxclass ( map $_->[0], @{$sth->fetchall_arrayref} ) {
+ print qq!<OPTION VALUE="$taxclass"!;
+ print ' SELECTED' if $taxclass eq $hashref->{taxclass};
+ print qq!>$taxclass</OPTION>!;
+ }
+ print '</SELECT></TD></TR>';
+} else {
+ print
+ '<INPUT TYPE="hidden" NAME="taxclass" VALUE="'. $hashref->{taxclass}. '">';
+}
+
+print '<TR><TD ALIGN="right">Disable new orders</TD><TD>';
+print '<INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"';
+print ' CHECKED' if $hashref->{disabled} eq "Y";
+print '>';
+print '</TD></TR></TABLE>';
+
+my $thead = "\n\n". ntable('#cccccc', 2).
+ '<TR><TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Quan.</FONT></TH>';
+$thead .= '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Primary</FONT></TH>'
+ if dbdef->table('pkg_svc')->column('primary_svc');
+$thead .= '<TH BGCOLOR="#dcdcdc">Service</TH></TR>';
+
+#unless ( $cgi->param('clone') ) {
+#dunno why...
+unless ( 0 ) {
+ #print <<END, $thead;
+ print <<END, itable(), '<TR><TD VALIGN="top">', $thead;
+<BR><BR>Enter the quantity of each service this package includes.<BR><BR>
+END
+}
+
+my @fixups = ();
+my $count = 0;
+my $columns = 3;
+my @part_svc = qsearch( 'part_svc', { 'disabled' => '' } );
+foreach my $part_svc ( @part_svc ) {
+ my $svcpart = $part_svc->svcpart;
+ my $pkgpart = $cgi->param('clone') || $part_pkg->pkgpart;
+ my $pkg_svc = $pkgpart && qsearchs( 'pkg_svc', {
+ 'pkgpart' => $pkgpart,
+ 'svcpart' => $svcpart,
+ } ) || new FS::pkg_svc ( {
+ 'pkgpart' => $pkgpart,
+ 'svcpart' => $svcpart,
+ 'quantity' => 0,
+ 'primary_svc' => '',
+ });
+ #? #next unless $pkg_svc;
+
+ push @fixups, "pkg_svc$svcpart";
+
+ #unless ( defined ($cgi->param('clone')) && $cgi->param('clone') ) {
+ #dunno why...
+ unless ( 0 ) {
+ print '<TR>'; # if $count == 0 ;
+ print qq!<TD><INPUT TYPE="text" NAME="pkg_svc$svcpart" SIZE=4 MAXLENGTH=3 VALUE="!,
+ $cgi->param("pkg_svc$svcpart") || $pkg_svc->quantity || 0,
+ qq!"></TD>!;
+ if ( dbdef->table('pkg_svc')->column('primary_svc') ) {
+ print qq!<TD><INPUT TYPE="radio" NAME="pkg_svc_primary" VALUE="$svcpart"!;
+ print ' CHECKED' if $pkg_svc->primary_svc =~ /^Y/i;
+ print '></TD>';
+ }
+ print qq!<TD><A HREF="part_svc.cgi?!,$part_svc->svcpart,
+ qq!">!, $part_svc->getfield('svc'), "</A></TD></TR>";
+# print "</TABLE></TD><TD>$thead" if ++$count == int(scalar(@part_svc) / 2);
+ $count+=1;
+ foreach ( 1 .. $columns-1 ) {
+ print "</TABLE></TD><TD VALIGN=\"top\">$thead"
+ if $count == int( $_ * scalar(@part_svc) / $columns );
+ }
+ } else {
+ print qq!<INPUT TYPE="hidden" NAME="pkg_svc$svcpart" VALUE="!,
+ $cgi->param("pkg_svc$svcpart") || $pkg_svc->quantity || 0, qq!">\n!;
+ }
+}
+
+#unless ( $cgi->param('clone') ) {
+#dunno why...
+unless ( 0 ) {
+ print "</TR></TABLE></TD></TR></TABLE>";
+ #print "</TR></TABLE>";
+}
+
+foreach my $f ( qw( clone pkgnum ) ) {
+ print qq!<INPUT TYPE="hidden" NAME="$f" VALUE="!. $cgi->param($f). '">';
+}
+print '<INPUT TYPE="hidden" NAME="pkgpart" VALUE="'. $part_pkg->pkgpart. '">';
+
+# prolly should be in database
+tie my %plans, 'Tie::IxHash',
+ 'flat' => {
+ 'name' => 'Flat rate (anniversary billing)',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_fee' => { 'name' => 'Recurring fee for this package',
+ 'default' => 0,
+ },
+ },
+ 'fieldorder' => [ 'setup_fee', 'recur_fee' ],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => 'what.recur_fee.value',
+ },
+
+ 'flat_delayed' => {
+ 'name' => 'Free for X days, then flat rate (anniversary billing)',
+ 'fields' => {
+ 'free_days' => { 'name' => 'Initial free days',
+ 'default' => 0,
+ },
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_fee' => { 'name' => 'Recurring fee for this package',
+ 'default' => 0,
+ },
+ },
+ 'fieldorder' => [ 'free_days', 'setup_fee', 'recur_fee' ],
+ 'setup' => '\'my $d = $cust_pkg->bill || $time; $d += 86400 * \' + what.free_days.value + \'; $cust_pkg->bill($d); $cust_pkg_mod_flag=1; \' + what.setup_fee.value',
+ 'recur' => 'what.recur_fee.value',
+ },
+
+ 'prorate' => {
+ 'name' => 'First partial month pro-rated, then flat-rate (1st of month billing)',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_fee' => { 'name' => 'Recurring fee for this package',
+ 'default' => 0,
+ },
+ },
+ 'fieldorder' => [ 'setup_fee', 'recur_fee' ],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => '\'my $mnow = $sdate; my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate) )[0,1,2,3,4,5]; my $mstart = timelocal(0,0,0,1,$mon,$year); my $mend = timelocal(0,0,0,1, $mon == 11 ? 0 : $mon+1, $year+($mon==11)); $sdate = $mstart; ( $part_pkg->freq - 1 ) * \' + what.recur_fee.value + \' / $part_pkg->freq + \' + what.recur_fee.value + \' / $part_pkg->freq * ($mend-$mnow) / ($mend-$mstart) ; \'',
+ },
+
+ 'subscription' => {
+ 'name' => 'First partial month full charge, then flat-rate (1st of month billing)',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_fee' => { 'name' => 'Recurring fee for this package',
+ 'default' => 0,
+ },
+ },
+ 'fieldorder' => [ 'setup_fee', 'recur_fee' ],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => '\'my $mnow = $sdate; my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate) )[0,1,2,3,4,5]; $sdate = timelocal(0,0,0,1,$mon,$year); \' + what.recur_fee.value',
+ },
+
+ 'flat_comission_cust' => {
+ 'name' => 'Flat rate with recurring commission per active customer',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_fee' => { 'name' => 'Recurring fee for this package',
+ 'default' => 0,
+ },
+ 'comission_amount' => { 'name' => 'Commission amount per month (per active customer)',
+ 'default' => 0,
+ },
+ 'comission_depth' => { 'name' => 'Number of layers',
+ 'default' => 1,
+ },
+ },
+ 'fieldorder' => [ 'setup_fee', 'recur_fee', 'comission_depth', 'comission_amount' ],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => '\'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar($cust_pkg->cust_main->referral_cust_main_ncancelled(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
+ },
+
+ 'flat_comission' => {
+ 'name' => 'Flat rate with recurring commission per (any) active package',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_fee' => { 'name' => 'Recurring fee for this package',
+ 'default' => 0,
+ },
+ 'comission_amount' => { 'name' => 'Commission amount per month (per active package)',
+ 'default' => 0,
+ },
+ 'comission_depth' => { 'name' => 'Number of layers',
+ 'default' => 1,
+ },
+ },
+ 'fieldorder' => [ 'setup_fee', 'recur_fee', 'comission_depth', 'comission_amount' ],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => '\'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar($cust_pkg->cust_main->referral_cust_pkg(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
+ },
+
+ 'flat_comission_pkg' => {
+ 'name' => 'Flat rate with recurring commission per (selected) active package',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_fee' => { 'name' => 'Recurring fee for this package',
+ 'default' => 0,
+ },
+ 'comission_amount' => { 'name' => 'Commission amount per month (per uncancelled package)',
+ 'default' => 0,
+ },
+ 'comission_depth' => { 'name' => 'Number of layers',
+ 'default' => 1,
+ },
+ 'comission_pkgpart' => { 'name' => 'Applicable packages<BR><FONT SIZE="-1">(hold <b>ctrl</b> to select multiple packages)</FONT>',
+ 'type' => 'select_multiple',
+ 'select_table' => 'part_pkg',
+ 'select_hash' => { 'disabled' => '' } ,
+ 'select_key' => 'pkgpart',
+ 'select_label' => 'pkg',
+ },
+ },
+ 'fieldorder' => [ 'setup_fee', 'recur_fee', 'comission_depth', 'comission_amount', 'comission_pkgpart' ],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => '""; var pkgparts = ""; for ( var c=0; c < document.flat_comission_pkg.comission_pkgpart.options.length; c++ ) { if (document.flat_comission_pkg.comission_pkgpart.options[c].selected) { pkgparts = pkgparts + document.flat_comission_pkg.comission_pkgpart.options[c].value + \', \'; } } what.recur.value = \'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar( grep { my $pkgpart = $_->pkgpart; grep { $_ == $pkgpart } ( \' + pkgparts + \' ) } $cust_pkg->cust_main->referral_cust_pkg(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
+ },
+
+
+
+ 'sesmon_hour' => {
+ 'name' => 'Base charge plus charge per-hour from the session monitor',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_flat' => { 'name' => 'Base monthly charge for this package',
+ 'default' => 0,
+ },
+ 'recur_included_hours' => { 'name' => 'Hours included',
+ 'default' => 0,
+ },
+ 'recur_hourly_charge' => { 'name' => 'Additional charge per hour',
+ 'default' => 0,
+ },
+ },
+ 'fieldorder' => [ 'setup_fee', 'recur_flat', 'recur_included_hours', 'recur_hourly_charge' ],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => '\'my $hours = $cust_pkg->seconds_since($cust_pkg->bill || 0) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'',
+ },
+
+ 'sesmon_minute' => {
+ 'name' => 'Base charge plus charge per-minute from the session monitor',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_flat' => { 'name' => 'Base monthly charge for this package',
+ 'default' => 0,
+ },
+ 'recur_included_min' => { 'name' => 'Minutes included',
+ 'default' => 0,
+ },
+ 'recur_minly_charge' => { 'name' => 'Additional charge per minute',
+ 'default' => 0,
+ },
+ },
+ 'fieldorder' => [ 'setup_fee', 'recur_flat', 'recur_included_min', 'recur_minly_charge' ],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => '\'my $min = $cust_pkg->seconds_since($cust_pkg->bill || 0) / 60 - \' + what.recur_included_min.value + \'; $min = 0 if $min < 0; \' + what.recur_flat.value + \' + \' + what.recur_minly_charge.value + \' * $min;\'',
+
+ },
+
+ 'sqlradacct_hour' => {
+ 'name' => 'Base charge plus charge per-hour (and for data) from an external sqlradius radacct table',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_flat' => { 'name' => 'Base monthly charge for this package',
+ 'default' => 0,
+ },
+ 'recur_included_hours' => { 'name' => 'Hours included',
+ 'default' => 0,
+ },
+ 'recur_hourly_charge' => { 'name' => 'Additional charge per hour',
+ 'default' => 0,
+ },
+ 'recur_included_input' => { 'name' => 'Input megabytes included',
+ 'default' => 0,
+ },
+ 'recur_input_charge' => { 'name' =>
+ 'Additional charge per input megabyte',
+ 'default' => 0,
+ },
+ 'recur_included_output' => { 'name' => 'Output megabytes included',
+ 'default' => 0,
+ },
+ 'recur_output_charge' => { 'name' =>
+ 'Additional charge per output megabyte',
+ 'default' => 0,
+ },
+ 'recur_included_total' => { 'name' =>
+ 'Total input+output megabytes included',
+ 'default' => 0,
+ },
+ 'recur_total_charge' => { 'name' =>
+ 'Additional charge per input+output megabyte',
+ 'default' => 0,
+ },
+ },
+ 'fieldorder' => [qw( setup_fee recur_flat recur_included_hours recur_hourly_charge recur_included_input recur_input_charge recur_included_output recur_output_charge recur_included_total recur_total_charge )],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; my $input = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, \"AcctInputOctets\" ) / 1048576; my $output = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, \"AcctOutputOctets\" ) / 1048576; my $total = $input + $output - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; my $totalcharge = sprintf(\"%.2f\", \' + what.recur_total_charge.value + \' * $total); my $inputcharge = sprintf(\"%.2f\", \' + what.recur_input_charge.value + \' * $input); my $outputcharge = sprintf(\"%.2f\", \' + what.recur_output_charge.value + \' * $output); my $hourscharge = sprintf(\"%.2f\", \' + what.recur_hourly_charge.value + \' * $hours); if ( \' + what.recur_total_charge.value + \' > 0 ) { push @details, \"Last month\\\'s data \". sprintf(\"%.1f\", $total). \" megs: \\\$$totalcharge\" } if ( \' + what.recur_input_charge.value + \' > 0 ) { push @details, \"Last month\\\'s download \". sprintf(\"%.1f\", $input). \" megs: \\\$$inputcharge\" } if ( \' + what.recur_output_charge.value + \' > 0 ) { push @details, \"Last month\\\'s upload \". sprintf(\"%.1f\", $output). \" megs: \\\$$outputcharge\" } if ( \' + what.recur_hourly_charge.value + \' > 0 ) { push @details, \"Last month\\\'s time \". sprintf(\"%.1f\", $hours). \" hours: \\\$$hourscharge\"; } \' + what.recur_flat.value + \' + $hourscharge + $inputcharge + $outputcharge + $totalcharge ;\'',
+ },
+
+ 'sql_generic' => {
+ 'name' => 'Base charge plus a metered rate from a configurable SQL query',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_flat' => { 'name' => 'Base monthly charge for this package',
+ 'default' => 0,
+ },
+ 'recur_included' => { 'name' => 'Units included',
+ 'default' => 0,
+ },
+ 'recur_unit_charge' => { 'name' => 'Additional charge per unit',
+ 'default' => 0,
+ },
+ 'datasrc' => { 'name' => 'DBI data source',
+ 'default' => '',
+ },
+ 'db_username' => { 'name' => 'Database username',
+ 'default' => '',
+ },
+ 'db_password' => { 'name' => 'Database username',
+ 'default' => '',
+ },
+ 'query' => { 'name' => 'SQL query',
+ 'default' => '',
+ },
+ },
+ 'fieldorder' => [qw( setup_fee recur_flat recur_included recur_unit_charge datasrc db_username db_password query )],
+ 'setup' => 'what.setup_fee.value',
+ # 'recur' => '\'my $dbh = DBI->connect(\"\' + what.datasrc.value + \'\", \"\' + what.db_username.value + \'\") or die $DBI::errstr; \'',
+ 'recur' => '\'my $dbh = DBI->connect(\"\' + what.datasrc.value + \'\", \"\' + what.db_username.value + \'\", \"\' + what.db_password.value + \'\" ) or die $DBI::errstr; my $sth = $dbh->prepare(\"\' + what.query.value + \'\") or die $dbh->errstr; my $units = 0; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq \"svc_domain\" } $cust_pkg->cust_svc ) { my $domain = $cust_svc->svc_x->domain; $sth->execute($domain) or die $sth->errstr; $units += $sth->fetchrow_arrayref->[0]; } $units -= \' + what.recur_included.value + \'; $units = 0 if $units < 0; \' + what.recur_flat.value + \' + $units * \' + what.recur_unit_charge.value + \';\'',
+ #'recur' => '\'my $dbh = DBI->connect("\' + what.datasrc.value + \'", "\' + what.db_username.value + \'", "\' what.db_password.value + \'" ) or die $DBI::errstr; my $sth = $dbh->prepare("\' + what.query.value + \'") or die $dbh->errstr; my $units = 0; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq "svc_domain" } $cust_pkg->cust_svc ) { my $domain = $cust_svc->svc_x->domain; $sth->execute($domain) or die $sth->errstr; $units += $sth->fetchrow_arrayref->[0]; } $units -= \' + what.recur_included.value + \'; $units = 0 if $units < 0; \' + what.recur_flat.value + \' + $units * \' + what.recur_unit_charge + \';\'',
+ },
+
+
+
+ 'sql_external' => {
+ 'name' => 'Base charge plus additional fees for external services from a configurable SQL query',
+ 'fields' => {
+ 'setup_fee' => { 'name' => 'Setup fee for this package',
+ 'default' => 0,
+ },
+ 'recur_flat' => { 'name' => 'Base monthly charge for this package',
+ 'default' => 0,
+ },
+ 'datasrc' => { 'name' => 'DBI data source',
+ 'default' => '',
+ },
+ 'db_username' => { 'name' => 'Database username',
+ 'default' => '',
+ },
+ 'db_password' => { 'name' => 'Database password',
+ 'default' => '',
+ },
+ 'query' => { 'name' => 'SQL query',
+ 'default' => '',
+ },
+ },
+ 'fieldorder' => [qw( setup_fee recur_flat datasrc db_username db_password query )],
+ 'setup' => 'what.setup_fee.value',
+ 'recur' => q!'my $dbh = DBI->connect("' + what.datasrc.value + '", "' + what.db_username.value + '", "' + what.db_password.value + '" ) or die $DBI::errstr; my $sth = $dbh->prepare("' + what.query.value + '") or die $dbh->errstr; my $price = ' + what.recur_flat.value + '; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq "svc_external" } $cust_pkg->cust_svc ){ my $id = $cust_svc->svc_x->id; $sth->execute($id) or die $sth->errstr; $price += $sth->fetchrow_arrayref->[0]; } $price;'!,
+
+ },
+
+;
+
+my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); }
+ split("\n", $part_pkg->plandata );
+
+tie my %options, 'Tie::IxHash', map { $_=>$plans{$_}->{'name'} } keys %plans;
+
+my @form_select = ();
+if ( $conf->exists('enable_taxclasses') ) {
+ push @form_select, 'taxclass';
+} else {
+ push @fixups, 'taxclass'; #hidden
+}
+
+my @form_radio = ();
+if ( dbdef->table('pkg_svc')->column('primary_svc') ) {
+ push @form_radio, 'pkg_svc_primary';
+}
+
+my $widget = new HTML::Widgets::SelectLayers(
+ 'selected_layer' => $part_pkg->plan,
+ 'options' => \%options,
+ 'form_name' => 'dummy',
+ 'form_action' => 'process/part_pkg.cgi',
+ 'form_text' => [ qw(pkg comment freq clone pkgnum pkgpart), @fixups ],
+ 'form_checkbox' => [ qw(setuptax recurtax disabled) ],
+ 'form_radio' => \@form_radio,
+ 'form_select' => \@form_select,
+ 'fixup_callback' => sub {
+ #my $ = @_;
+ my $html = '';
+ for my $p ( keys %plans ) {
+ $html .= "if ( what.plan.value == \"$p\" ) {
+ what.setup.value = $plans{$p}->{setup} ;
+ what.recur.value = $plans{$p}->{recur} ;
+ }\n";
+ }
+ $html;
+ },
+ 'layer_callback' => sub {
+ my $layer = shift;
+ my $html = qq!<INPUT TYPE="hidden" NAME="plan" VALUE="$layer">!.
+ ntable("#cccccc",2);
+ my $href = $plans{$layer}->{'fields'};
+ foreach my $field ( exists($plans{$layer}->{'fieldorder'})
+ ? @{$plans{$layer}->{'fieldorder'}}
+ : keys %{ $href }
+ ) {
+
+ $html .= '<TR><TD ALIGN="right">'. $href->{$field}{'name'}. '</TD><TD>';
+
+ if ( ! exists($href->{$field}{'type'}) ) {
+ $html .= qq!<INPUT TYPE="text" NAME="$field" VALUE="!.
+ ( exists($plandata{$field})
+ ? $plandata{$field}
+ : $href->{$field}{'default'} ).
+ qq!" onChange="fchanged(this)">!;
+ } elsif ( $href->{$field}{'type'} eq 'select_multiple' ) {
+ $html .= qq!<SELECT MULTIPLE NAME="$field" onChange="fchanged(this)">!;
+ foreach my $record (
+ qsearch( $href->{$field}{'select_table'},
+ $href->{$field}{'select_hash'} )
+ ) {
+ my $value = $record->getfield($href->{$field}{'select_key'});
+ $html .= qq!<OPTION VALUE="$value"!.
+ ( $plandata{$field} =~ /(^|, *)$value *(,|$)/
+ ? ' SELECTED'
+ : '' ).
+ '>'. $record->getfield($href->{$field}{'select_label'})
+ }
+ $html .= '</SELECT>';
+ }
+
+ $html .= '</TD></TR>';
+ }
+ $html .= '</TABLE>';
+
+ $html .= '<INPUT TYPE="hidden" NAME="plandata" VALUE="'.
+ join(',', keys %{ $href } ). '">'.
+ '<BR><BR>';
+
+ $html .= '<INPUT TYPE="submit" VALUE="'.
+ ( $hashref->{pkgpart} ? "Apply changes" : "Add package" ).
+ '" onClick="fchanged(this)">';
+
+ $html .= '<BR><BR>don\'t edit this unless you know what you\'re doing '.
+ '<INPUT TYPE="button" VALUE="refresh expressions" '.
+ 'onClick="fchanged(this)">'.
+ ntable("#cccccc",2).
+ '<TR><TD>'.
+ '<FONT SIZE="1">Setup expression<BR>'.
+ '<INPUT TYPE="text" NAME="setup" SIZE="160" VALUE="'.
+ encode_entities($hashref->{setup}). '" onLoad="fchanged(this)">'.
+ '</FONT><BR>'.
+ '<FONT SIZE="1">Recurring espression<BR>'.
+ '<INPUT TYPE="text" NAME="recur" SIZE="160" VALUE="'.
+ encode_entities($hashref->{recur}). '" onLoad="fchanged(this)">'.
+ '</FONT>'.
+ '</TR></TD>'.
+ '</TABLE>';
+
+ $html;
+
+ },
+);
+
+%>
+
+<BR>
+Price plan <%= $widget->html %>
+ </BODY>
+</HTML>
diff --git a/httemplate/edit/part_referral.cgi b/httemplate/edit/part_referral.cgi
new file mode 100755
index 0000000..f784dfa
--- /dev/null
+++ b/httemplate/edit/part_referral.cgi
@@ -0,0 +1,48 @@
+<!-- mason kludge -->
+<%
+
+my $part_referral;
+if ( $cgi->param('error') ) {
+ $part_referral = new FS::part_referral ( {
+ map { $_, scalar($cgi->param($_)) } fields('part_referral')
+ } );
+} elsif ( $cgi->keywords ) {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $part_referral = qsearchs( 'part_referral', { 'refnum' => $1 } );
+} else { #adding
+ $part_referral = new FS::part_referral {};
+}
+my $action = $part_referral->refnum ? 'Edit' : 'Add';
+my $hashref = $part_referral->hashref;
+
+my $p1 = popurl(1);
+print header("$action Advertising source", menubar(
+ 'Main Menu' => popurl(2),
+ 'View all advertising sources' => popurl(2). "browse/part_referral.cgi",
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print qq!<FORM ACTION="${p1}process/part_referral.cgi" METHOD=POST>!;
+
+print qq!<INPUT TYPE="hidden" NAME="refnum" VALUE="$hashref->{refnum}">!;
+#print "Referral #", $hashref->{refnum} ? $hashref->{refnum} : "(NEW)";
+
+print <<END;
+Advertising source <INPUT TYPE="text" NAME="referral" SIZE=32 VALUE="$hashref->{referral}">
+END
+
+print qq!<BR><INPUT TYPE="submit" VALUE="!,
+ $hashref->{refnum} ? "Apply changes" : "Add advertising source",
+ qq!">!;
+
+print <<END;
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi
new file mode 100755
index 0000000..6868ffd
--- /dev/null
+++ b/httemplate/edit/part_svc.cgi
@@ -0,0 +1,284 @@
+<!-- mason kludge -->
+<%
+ my $part_svc;
+ my $clone = '';
+ if ( $cgi->param('error') ) { #error
+ $part_svc = new FS::part_svc ( {
+ map { $_, scalar($cgi->param($_)) } fields('part_svc')
+ } );
+ } elsif ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {#clone
+ #$cgi->param('clone') =~ /^(\d+)$/ or die "malformed query: $query";
+ $part_svc = qsearchs('part_svc', { 'svcpart'=>$1 } )
+ or die "unknown svcpart: $1";
+ $clone = $part_svc->svcpart;
+ $part_svc->svcpart('');
+ } elsif ( $cgi->keywords ) { #edit
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/ or die "malformed query: $query";
+ $part_svc=qsearchs('part_svc', { 'svcpart'=>$1 } )
+ or die "unknown svcpart: $1";
+ } else { #adding
+ $part_svc = new FS::part_svc {};
+ }
+ my $action = $part_svc->svcpart ? 'Edit' : 'Add';
+ my $hashref = $part_svc->hashref;
+# my $p_svcdb = $part_svc->svcdb || 'svc_acct';
+
+
+ #" onLoad=\"visualize()\""
+%>
+
+<%= header("$action Service Definition",
+ menubar( 'Main Menu' => $p,
+ 'View all service definitions' => "${p}browse/part_svc.cgi"
+ ),
+ )
+%>
+
+<% if ( $cgi->param('error') ) { %>
+<FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT>
+<% } %>
+
+<FORM NAME="dummy">
+
+ Service Part #<%= $part_svc->svcpart ? $part_svc->svcpart : "(NEW)" %>
+<BR><BR>
+Service <INPUT TYPE="text" NAME="svc" VALUE="<%= $hashref->{svc} %>"><BR>
+Disable new orders <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<%= $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>><BR>
+<INPUT TYPE="hidden" NAME="svcpart" VALUE="<%= $hashref->{svcpart} %>">
+<BR>
+Services are items you offer to your customers.
+<UL><LI>svc_acct - Shell accounts, POP mailboxes, SLIP/PPP and ISDN accounts
+ <LI>svc_domain - Domains
+ <LI>svc_forward - mail forwarding
+ <LI>svc_www - Virtual domain website
+ <LI>svc_broadband - Broadband/High-speed Internet service
+ <LI>svc_external - Externally-tracked service
+<!-- <LI>svc_charge - One-time charges (Partially unimplemented)
+ <LI>svc_wo - Work orders (Partially unimplemented)
+-->
+</UL>
+For the selected table, you can give fields default or fixed (unchangable)
+values. For example, a SLIP/PPP account may have a default (or perhaps fixed)
+<B>slipip</B> of <B>0.0.0.0</B>, while a POP mailbox will probably have a fixed
+blank <B>slipip</B> as well as a fixed shell something like <B>/bin/true</B> or
+<B>/usr/bin/passwd</B>.
+<BR><BR>
+
+<%
+
+my %vfields;
+
+#these might belong somewhere else for other user interfaces
+#pry need to eventually create stuff that's shared amount UIs
+my %defs = (
+ 'svc_acct' => {
+ 'dir' => 'Home directory',
+ 'uid' => 'UID (set to fixed and blank for dial-only)',
+ 'slipip' => 'IP address (Set to fixed and blank to disable dialin, or, set a value to be exported to RADIUS Framed-IP-Address. Use the special value <code>0e0</code> [zero e zero] to enable export to RADIUS without a Framed-IP-Address.)',
+# 'popnum' => qq!<A HREF="$p/browse/svc_acct_pop.cgi/">POP number</A>!,
+ 'popnum' => {
+ desc => 'Access number',
+ type => 'select',
+ select_table => 'svc_acct_pop',
+ select_key => 'popnum',
+ select_label => 'city',
+ },
+ 'username' => {
+ desc => 'Username',
+ type => 'disabled',
+ },
+ 'quota' => '',
+ '_password' => 'Password',
+ 'gid' => 'GID (when blank, defaults to UID)',
+ 'shell' => 'Shell (all service definitions should have a default or fixed shell that is present in the <b>shells</b> configuration file)',
+ 'finger' => 'GECOS',
+ 'domsvc' => {
+ desc =>'svcnum from svc_domain',
+ type =>'select',
+ select_table => 'svc_domain',
+ select_key => 'svcnum',
+ select_label => 'domain',
+ },
+ 'usergroup' => {
+ desc =>'ICRADIUS/FreeRADIUS groups',
+ type =>'radius_usergroup_selector',
+ },
+ },
+ 'svc_domain' => {
+ 'domain' => 'Domain',
+ },
+ 'svc_forward' => {
+ 'srcsvc' => 'service from which mail is to be forwarded',
+ 'dstsvc' => 'service to which mail is to be forwarded',
+ 'dst' => 'someone@another.domain.com to use when dstsvc is 0',
+ },
+# 'svc_charge' => {
+# 'amount' => 'amount',
+# },
+# 'svc_wo' => {
+# 'worker' => 'Worker',
+# '_date' => 'Date',
+# },
+ 'svc_www' => {
+ #'recnum' => '',
+ #'usersvc' => '',
+ },
+ 'svc_broadband' => {
+ 'speed_down' => 'Maximum download speed for this service in Kbps. 0 denotes unlimited.',
+ 'speed_up' => 'Maximum upload speed for this service in Kbps. 0 denotes unlimited.',
+ 'ip_addr' => 'IP address. Leave blank for automatic assignment.',
+ 'blocknum' => 'Address block.',
+ },
+ 'svc_external' => {
+ #'id' => '',
+ #'title' => '',
+ },
+);
+
+ foreach my $svcdb (grep dbdef->table($_), keys %defs ) {
+ my $self = "FS::$svcdb"->new;
+ $vfields{$svcdb} = {};
+ foreach my $field ($self->virtual_fields) { # svc_Common::virtual_fields with a null svcpart returns all of them
+ my $pvf = $self->pvf($field);
+ my @list = $pvf->list;
+ if (scalar @list) {
+ $defs{$svcdb}->{$field} = { desc => $pvf->label,
+ type => 'select',
+ select_list => \@list };
+ } else {
+ $defs{$svcdb}->{$field} = $pvf->label;
+ } #endif
+ $vfields{$svcdb}->{$field} = $pvf;
+ warn "\$vfields{$svcdb}->{$field} = $pvf";
+ } #next $field
+ } #next $svcdb
+
+ my @dbs = $hashref->{svcdb}
+ ? ( $hashref->{svcdb} )
+ : qw( svc_acct svc_domain svc_forward svc_www svc_broadband svc_external );
+
+ tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs;
+ my $widget = new HTML::Widgets::SelectLayers(
+ #'selected_layer' => $p_svcdb,
+ 'selected_layer' => $hashref->{svcdb} || 'svc_acct',
+ 'options' => \%svcdb,
+ 'form_name' => 'dummy',
+ 'form_action' => 'process/part_svc.cgi',
+ 'form_text' => [ qw( svc svcpart ) ],
+ 'form_checkbox' => [ 'disabled' ],
+ 'layer_callback' => sub {
+ my $layer = shift;
+ my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!;
+
+ my $columns = 3;
+ my $count = 0;
+ my @part_export =
+ map { qsearch( 'part_export', {exporttype => $_ } ) }
+ keys %{FS::part_export::export_info($layer)};
+ $html .= '<BR><BR>'. table().
+ table(). "<TR><TH COLSPAN=$columns>Exports</TH></TR><TR>";
+ foreach my $part_export ( @part_export ) {
+ $html .= '<TD><INPUT TYPE="checkbox"'.
+ ' NAME="exportnum'. $part_export->exportnum. '" VALUE="1" ';
+ $html .= 'CHECKED'
+ if ( $clone || $part_svc->svcpart ) #null svcpart search causing error
+ && qsearchs( 'export_svc', {
+ exportnum => $part_export->exportnum,
+ svcpart => $clone || $part_svc->svcpart });
+ $html .= '>'. $part_export->exportnum. ': '. $part_export->exporttype.
+ ' to '. $part_export->machine. '</TD>';
+ $count++;
+ $html .= '</TR><TR>' unless $count % $columns;
+ }
+ $html .= '</TR></TABLE><BR><BR>';
+
+ $html .= table(). "<TH>Field</TH><TH COLSPAN=2>Modifier</TH>";
+ #yucky kludge
+ my @fields = defined( $FS::Record::dbdef->table($layer) )
+ ? grep { $_ ne 'svcnum' } fields($layer)
+ : ();
+ push @fields, 'usergroup' if $layer eq 'svc_acct'; #kludge
+ $part_svc->svcpart($clone) if $clone; #haha, undone below
+ foreach my $field (@fields) {
+ my $part_svc_column = $part_svc->part_svc_column($field);
+ my $value = $cgi->param('error')
+ ? $cgi->param("${layer}__${field}")
+ : $part_svc_column->columnvalue;
+ my $flag = $cgi->param('error')
+ ? $cgi->param("${layer}__${field}_flag")
+ : $part_svc_column->columnflag;
+ my $def = $defs{$layer}{$field};
+ my $desc = ref($def) ? $def->{desc} : $def;
+
+ $html .= "<TR><TD>$field";
+ $html .= "- <FONT SIZE=-1>$desc</FONT>" if $desc;
+ $html .= "</TD>";
+ $flag = '' if ref($def) && $def->{type} eq 'disabled';
+ $html .=
+ qq!<TD><INPUT TYPE="radio" NAME="${layer}__${field}_flag" VALUE=""!.
+ ' CHECKED'x($flag eq ''). ">Off</TD>".
+ '<TD>';
+ unless ( ref($def) && $def->{type} eq 'disabled' ) {
+ $html .=
+ qq!<INPUT TYPE="radio" NAME="${layer}__${field}_flag" VALUE="D"!.
+ ' CHECKED'x($flag eq 'D'). ">Default ".
+ qq!<INPUT TYPE="radio" NAME="${layer}__${field}_flag" VALUE="F"!.
+ ' CHECKED'x($flag eq 'F'). ">Fixed ";
+ $html .= '<BR>';
+ }
+ if ( ref($def) ) {
+ if ( $def->{type} eq 'select' ) {
+ $html .= qq!<SELECT NAME="${layer}__${field}">!;
+ $html .= '<OPTION> </OPTION>' unless $value;
+ if ( $def->{select_table} ) {
+ foreach my $record ( qsearch( $def->{select_table}, {} ) ) {
+ my $rvalue = $record->getfield($def->{select_key});
+ $html .= qq!<OPTION VALUE="$rvalue"!.
+ ( $rvalue==$value ? ' SELECTED>' : '>' ).
+ $record->getfield($def->{select_label}). '</OPTION>';
+ } #next $record
+ } else { # select_list
+ foreach my $item ( @{$def->{select_list}} ) {
+ $html .= qq!<OPTION VALUE="$item"!.
+ ( $item eq $value ? ' SELECTED>' : '>' ).
+ $item. '</OPTION>';
+ } #next $item
+ } #endif
+ $html .= '</SELECT>';
+ } elsif ( $def->{type} eq 'radius_usergroup_selector' ) {
+ $html .= FS::svc_acct::radius_usergroup_selector(
+ [ split(',', $value) ], "${layer}__${field}" );
+ } elsif ( $def->{type} eq 'disabled' ) {
+ $html .=
+ qq!<INPUT TYPE="hidden" NAME="${layer}__${field}" VALUE="">!;
+ } else {
+ $html .= '<font color="#ff0000">unknown type'. $def->{type};
+ }
+ } else {
+ $html .=
+ qq!<INPUT TYPE="text" NAME="${layer}__${field}" VALUE="$value">!;
+ }
+
+ if($vfields{$layer}->{$field}) {
+ $html .= qq!<BR><INPUT TYPE="radio" NAME="${layer}__${field}_flag" VALUE="X"!.
+ ' CHECKED'x($flag eq 'X'). ">Excluded ";
+ }
+ $html .= "</TD></TR>\n";
+ }
+ $part_svc->svcpart('') if $clone; #undone
+ $html .= "</TABLE>";
+
+ $html .= '<BR><INPUT TYPE="submit" VALUE="'.
+ ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">';
+
+ $html;
+
+ },
+ );
+
+%>
+Table <%= $widget->html %>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/edit/part_virtual_field.cgi b/httemplate/edit/part_virtual_field.cgi
new file mode 100644
index 0000000..fb10321
--- /dev/null
+++ b/httemplate/edit/part_virtual_field.cgi
@@ -0,0 +1,92 @@
+<!-- mason kludge -->
+<%
+my ($vfieldpart, $part_virtual_field);
+
+if ( $cgi->param('error') ) {
+ $part_virtual_field = new FS::part_virtual_field ( {
+ map { $_, scalar($cgi->param($_)) } fields('part_virtual_field')});
+ $vfieldpart = $part_virtual_field->vfieldpart;
+} else {
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $vfieldpart=$1;
+ $part_virtual_field=qsearchs('part_virtual_field',
+ {'vfieldpart' => $vfieldpart})
+ or die "Unknown vfieldpart!";
+
+ } else { #adding
+ $part_virtual_field = new FS::part_virtual_field({});
+ }
+}
+my $action = $part_virtual_field->vfieldpart ? 'Edit' : 'Add';
+
+my $p1 = popurl(1);
+print header("$action Virtual Field Definition", '');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+%>
+<FORM ACTION="<%=$p1%>process/generic.cgi" METHOD="POST">
+
+<INPUT TYPE="hidden" NAME="table" VALUE="part_virtual_field">
+<INPUT TYPE="hidden" NAME="redirect_ok"
+ VALUE="<%=popurl(2)%>browse/part_virtual_field.cgi">
+<INPUT TYPE="hidden" NAME="vfieldpart" VALUE="<%=
+ $vfieldpart%>">
+Field #<B><%=$vfieldpart or "(NEW)"%></B><BR><BR>
+
+<%=ntable("#cccccc",2)%>
+ <TR>
+ <TD ALIGN="right">Name</TD>
+ <TD><INPUT TYPE="text" NAME="name" MAXLENGTH=15 VALUE="<%=
+ $part_virtual_field->name%>"></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Table</TD>
+ <TD><% if ($action eq 'Add') { %>
+ <SELECT SIZE=1 NAME="dbtable"><%
+ my $dbdef = dbdef; # ick
+ foreach my $dbtable (sort { $a cmp $b } $dbdef->tables) {
+ if ($dbtable !~ /^h_/
+ and $dbdef->table($dbtable)->primary_key) { %>
+ <OPTION VALUE="<%=$dbtable%>"><%=$dbtable%></OPTION><%
+ }
+ }
+ %></SELECT><%
+ } else { # Edit
+ %><%=$part_virtual_field->dbtable%>
+ <INPUT TYPE="hidden" NAME="dbtable" VALUE="<%=$part_virtual_field->dbtable%>">
+ <% } %>
+ </TD>
+ <TR>
+ <TD ALIGN="right">Label</TD>
+ <TD><INPUT TYPE="text" NAME="label" MAXLENGTH="20" VALUE="<%=
+ $part_virtual_field->label%>"></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Length</TD>
+ <TD><INPUT TYPE="text" NAME="length" MAXLENGTH=4 VALUE="<%=
+ $part_virtual_field->length%>"></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Check</TD>
+ <TD><TEXTAREA COLS="20" ROWS="4" NAME="check_block"><%=
+ $part_virtual_field->check_block%></TEXTAREA></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">List source</TD>
+ <TD><TEXTAREA COLS="20" ROWS="4" NAME="list_source"><%=
+ $part_virtual_field->list_source%></TEXTAREA></TD>
+ </TR>
+</TABLE><BR><INPUT TYPE="submit" VALUE="Submit">
+
+</FORM>
+
+<BR><BR>
+<FONT SIZE=-2>If you don't understand what <I>check_block</I> and
+<I>list_source</I> mean, <B>LEAVE THEM BLANK</B>. We mean it.</FONT>
+
+
+</BODY>
+</HTML>
diff --git a/httemplate/edit/process/REAL_cust_pkg.cgi b/httemplate/edit/process/REAL_cust_pkg.cgi
new file mode 100755
index 0000000..3d697dd
--- /dev/null
+++ b/httemplate/edit/process/REAL_cust_pkg.cgi
@@ -0,0 +1,24 @@
+<%
+
+my $pkgnum = $cgi->param('pkgnum') or die;
+my $old = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+my %hash = $old->hash;
+$hash{'setup'} = $cgi->param('setup') ? str2time($cgi->param('setup')) : '';
+$hash{'bill'} = $cgi->param('bill') ? str2time($cgi->param('bill')) : '';
+$hash{'last_bill'} =
+ $cgi->param('last_bill') ? str2time($cgi->param('last_bill')) : '';
+$hash{'expire'} = $cgi->param('expire') ? str2time($cgi->param('expire')) : '';
+my $new = new FS::cust_pkg \%hash;
+
+my $error = $new->replace($old);
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "REAL_cust_pkg.cgi?". $cgi->query_string );
+} else {
+ my $custnum = $new->custnum;
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum".
+ "#cust_pkg$pkgnum" );
+}
+
+%>
diff --git a/httemplate/edit/process/addr_block/add.cgi b/httemplate/edit/process/addr_block/add.cgi
new file mode 100755
index 0000000..34d799c
--- /dev/null
+++ b/httemplate/edit/process/addr_block/add.cgi
@@ -0,0 +1,20 @@
+<%
+
+my $error = '';
+my $ip_gateway = $cgi->param('ip_gateway');
+my $ip_netmask = $cgi->param('ip_netmask');
+
+my $new = new FS::addr_block {
+ ip_gateway => $ip_gateway,
+ ip_netmask => $ip_netmask,
+ routernum => 0 };
+
+$error = $new->insert;
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(4). "browse/addr_block.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(4). "browse/addr_block.cgi");
+}
+%>
diff --git a/httemplate/edit/process/addr_block/allocate.cgi b/httemplate/edit/process/addr_block/allocate.cgi
new file mode 100755
index 0000000..85b0d7a
--- /dev/null
+++ b/httemplate/edit/process/addr_block/allocate.cgi
@@ -0,0 +1,25 @@
+<%
+my $error = '';
+my $blocknum = $cgi->param('blocknum');
+my $routernum = $cgi->param('routernum');
+
+my $addr_block = qsearchs('addr_block', { blocknum => $blocknum });
+my $router = qsearchs('router', { routernum => $routernum });
+
+if($addr_block) {
+ if ($router) {
+ $error = $addr_block->allocate($router);
+ } else {
+ $error = "Cannot find router with routernum $routernum";
+ }
+} else {
+ $error = "Cannot find block with blocknum $blocknum";
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(4). "browse/addr_block.cgi?" . $cgi->query_string);
+} else {
+ print $cgi->redirect(popurl(4). "browse/addr_block.cgi");
+}
+%>
diff --git a/httemplate/edit/process/addr_block/deallocate.cgi b/httemplate/edit/process/addr_block/deallocate.cgi
new file mode 100755
index 0000000..cfb7ed0
--- /dev/null
+++ b/httemplate/edit/process/addr_block/deallocate.cgi
@@ -0,0 +1,24 @@
+<%
+my $error = '';
+my $blocknum = $cgi->param('blocknum');
+
+my $addr_block = qsearchs('addr_block', { blocknum => $blocknum });
+
+if($addr_block) {
+ my $router = $addr_block->router;
+ if ($router) {
+ $error = $addr_block->deallocate($router);
+ } else {
+ $error = "Block is not allocated to a router";
+ }
+} else {
+ $error = "Cannot find block with blocknum $blocknum";
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(4). "browse/addr_block.cgi?" . $cgi->query_string);
+} else {
+ print $cgi->redirect(popurl(4). "browse/addr_block.cgi");
+}
+%>
diff --git a/httemplate/edit/process/addr_block/split.cgi b/httemplate/edit/process/addr_block/split.cgi
new file mode 100755
index 0000000..bb6d4ba
--- /dev/null
+++ b/httemplate/edit/process/addr_block/split.cgi
@@ -0,0 +1,19 @@
+<%
+my $error = '';
+my $blocknum = $cgi->param('blocknum');
+my $addr_block = qsearchs('addr_block', { blocknum => $blocknum });
+
+if ( $addr_block) {
+ $error = $addr_block->split_block;
+} else {
+ $error = "Unknown blocknum: $blocknum";
+}
+
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(4). "browse/addr_block.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(4). "browse/addr_block.cgi");
+}
+%>
diff --git a/httemplate/edit/process/agent.cgi b/httemplate/edit/process/agent.cgi
new file mode 100755
index 0000000..182eeab
--- /dev/null
+++ b/httemplate/edit/process/agent.cgi
@@ -0,0 +1,28 @@
+<%
+
+my $agentnum = $cgi->param('agentnum');
+
+my $old = qsearchs('agent',{'agentnum'=>$agentnum}) if $agentnum;
+
+my $new = new FS::agent ( {
+ map {
+ $_, scalar($cgi->param($_));
+ } fields('agent')
+} );
+
+my $error;
+if ( $agentnum ) {
+ $error=$new->replace($old);
+} else {
+ $error=$new->insert;
+ $agentnum=$new->getfield('agentnum');
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "agent.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "browse/agent.cgi");
+}
+
+%>
diff --git a/httemplate/edit/process/agent_type.cgi b/httemplate/edit/process/agent_type.cgi
new file mode 100755
index 0000000..5165945
--- /dev/null
+++ b/httemplate/edit/process/agent_type.cgi
@@ -0,0 +1,55 @@
+<%
+
+my $typenum = $cgi->param('typenum');
+my $old = qsearchs('agent_type',{'typenum'=>$typenum}) if $typenum;
+
+my $new = new FS::agent_type ( {
+ map {
+ $_, scalar($cgi->param($_));
+ } fields('agent_type')
+} );
+
+my $error;
+if ( $typenum ) {
+ $error=$new->replace($old);
+} else {
+ $error=$new->insert;
+ $typenum=$new->getfield('typenum');
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "agent_type.cgi?". $cgi->query_string );
+} else {
+
+ #false laziness w/ edit/process/part_svc.cgi
+ foreach my $part_pkg (qsearch('part_pkg',{})) {
+ my($pkgpart)=$part_pkg->getfield('pkgpart');
+
+ my($type_pkgs)=qsearchs('type_pkgs',{
+ 'typenum' => $typenum,
+ 'pkgpart' => $pkgpart,
+ });
+ if ( $type_pkgs && ! $cgi->param("pkgpart$pkgpart") ) {
+ my($d_type_pkgs)=$type_pkgs; #need to save $type_pkgs for below.
+ $error=$d_type_pkgs->delete;
+ die $error if $error;
+
+ } elsif ( $cgi->param("pkgpart$pkgpart")
+ && ! $type_pkgs
+ ) {
+ #ok to clobber it now (but bad form nonetheless?)
+ $type_pkgs=new FS::type_pkgs ({
+ 'typenum' => $typenum,
+ 'pkgpart' => $pkgpart,
+ });
+ $error= $type_pkgs->insert;
+ die $error if $error;
+ }
+
+ }
+
+ print $cgi->redirect(popurl(3). "browse/agent_type.cgi");
+}
+
+%>
diff --git a/httemplate/edit/process/cust_bill_pay.cgi b/httemplate/edit/process/cust_bill_pay.cgi
new file mode 100755
index 0000000..0c33506
--- /dev/null
+++ b/httemplate/edit/process/cust_bill_pay.cgi
@@ -0,0 +1,31 @@
+<%
+
+$cgi->param('paynum') =~ /^(\d*)$/ or die "Illegal paynum!";
+my $paynum = $1;
+
+my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } )
+ or die "No such paynum";
+
+my $cust_main = qsearchs('cust_main', { 'custnum' => $cust_pay->custnum } )
+ or die "Bogus credit: not attached to customer";
+
+my $custnum = $cust_main->custnum;
+
+my $new = new FS::cust_bill_pay ( {
+ map {
+ $_, scalar($cgi->param($_));
+ #} qw(custnum _date amount invnum)
+ } fields('cust_bill_pay')
+} );
+
+my $error = $new->insert;
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cust_bill_pay.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum");
+}
+
+
+%>
diff --git a/httemplate/edit/process/cust_credit.cgi b/httemplate/edit/process/cust_credit.cgi
new file mode 100755
index 0000000..ac92631
--- /dev/null
+++ b/httemplate/edit/process/cust_credit.cgi
@@ -0,0 +1,30 @@
+<%
+
+$cgi->param('custnum') =~ /^(\d*)$/ or die "Illegal custnum!";
+my $custnum = $1;
+
+$cgi->param('otaker',getotaker);
+
+my $new = new FS::cust_credit ( {
+ map {
+ $_, scalar($cgi->param($_));
+ #} qw(custnum _date amount otaker reason)
+ } fields('cust_credit')
+} );
+
+my $error = $new->insert;
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cust_credit.cgi?". $cgi->query_string );
+} else {
+ if ( $cgi->param('apply') eq 'yes' ) {
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum })
+ or die "unknown custnum $custnum";
+ $cust_main->apply_credits;
+ }
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum");
+}
+
+
+%>
diff --git a/httemplate/edit/process/cust_credit_bill.cgi b/httemplate/edit/process/cust_credit_bill.cgi
new file mode 100755
index 0000000..23e2e6c
--- /dev/null
+++ b/httemplate/edit/process/cust_credit_bill.cgi
@@ -0,0 +1,43 @@
+<%
+
+$cgi->param('crednum') =~ /^(\d*)$/ or die "Illegal crednum!";
+my $crednum = $1;
+
+my $cust_credit = qsearchs('cust_credit', { 'crednum' => $crednum } )
+ or die "No such crednum";
+
+my $cust_main = qsearchs('cust_main', { 'custnum' => $cust_credit->custnum } )
+ or die "Bogus credit: not attached to customer";
+
+my $custnum = $cust_main->custnum;
+
+my $new;
+if ($cgi->param('invnum') =~ /^Refund$/) {
+ $new = new FS::cust_refund ( {
+ 'reason' => $cust_credit->reason,
+ 'refund' => $cgi->param('amount'),
+ 'payby' => 'BILL',
+ #'_date' => $cgi->param('_date'),
+ 'payinfo' => 'Cash',
+ 'crednum' => $crednum,
+ } );
+} else {
+ $new = new FS::cust_credit_bill ( {
+ map {
+ $_, scalar($cgi->param($_));
+ #} qw(custnum _date amount invnum)
+ } fields('cust_credit_bill')
+ } );
+}
+
+my $error = $new->insert;
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cust_credit_bill.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum");
+}
+
+
+%>
diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi
new file mode 100755
index 0000000..25c346e
--- /dev/null
+++ b/httemplate/edit/process/cust_main.cgi
@@ -0,0 +1,133 @@
+<%
+
+my $error = '';
+
+#unmunge stuff
+
+$cgi->param('tax','') unless defined $cgi->param('tax');
+
+$cgi->param('refnum', (split(/:/, ($cgi->param('refnum'))[0] ))[0] );
+
+my $payby = $cgi->param('payby');
+if ( $payby ) {
+ if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) {
+ $cgi->param('payinfo',
+ $cgi->param($payby. '_payinfo1'). '@'. $cgi->param($payby. '_payinfo2') );
+ } else {
+ $cgi->param('payinfo', $cgi->param( $payby. '_payinfo' ) );
+ }
+ $cgi->param('paydate',
+ $cgi->param( $payby. '_month' ). '-'. $cgi->param( $payby. '_year' ) );
+ $cgi->param('payname', $cgi->param( $payby. '_payname' ) );
+ $cgi->param('paycvv', $cgi->param( $payby. '_paycvv' ) )
+ if defined $cgi->param( $payby. '_paycvv' );
+}
+
+$cgi->param('otaker', &getotaker );
+
+my @invoicing_list = split( /\s*\,\s*/, $cgi->param('invoicing_list') );
+push @invoicing_list, 'POST' if $cgi->param('invoicing_list_POST');
+$cgi->param('invoicing_list', join(',', @invoicing_list) );
+
+
+#create new record object
+
+my $new = new FS::cust_main ( {
+ map {
+ $_, scalar($cgi->param($_))
+# } qw(custnum agentnum last first ss company address1 address2 city county
+# state zip daytime night fax payby payinfo paydate payname tax
+# otaker refnum)
+ } fields('cust_main')
+} );
+
+if ( defined($cgi->param('same')) && $cgi->param('same') eq "Y" ) {
+ $new->setfield("ship_$_", '') foreach qw(
+ last first company address1 address2 city county state zip
+ country daytime night fax
+ );
+}
+
+#perhaps this stuff should go to cust_main.pm
+my $cust_pkg = '';
+my $svc_acct = '';
+if ( $new->custnum eq '' ) {
+
+ if ( $cgi->param('pkgpart_svcpart') ) {
+ my $x = $cgi->param('pkgpart_svcpart');
+ $x =~ /^(\d+)_(\d+)$/ or die "illegal pkgpart_svcpart $x\n";
+ my($pkgpart, $svcpart) = ($1, $2);
+ #false laziness: copied from FS::cust_pkg::order (which should become a
+ #FS::cust_main method)
+ my(%part_pkg);
+ # generate %part_pkg
+ # $part_pkg{$pkgpart} is true iff $custnum may purchase $pkgpart
+ my $agent = qsearchs('agent',{'agentnum'=> $new->agentnum });
+ #my($type_pkgs);
+ #foreach $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) {
+ # my($pkgpart)=$type_pkgs->pkgpart;
+ # $part_pkg{$pkgpart}++;
+ #}
+ # $pkgpart_href->{PKGPART} is true iff $custnum may purchase $pkgpart
+ my $pkgpart_href = $agent->pkgpart_hashref;
+ #eslaf
+
+ # this should wind up in FS::cust_pkg!
+ $error ||= "Agent ". $new->agentnum. " (type ". $agent->typenum. ") can't ".
+ "purchase pkgpart ". $pkgpart
+ #unless $part_pkg{ $pkgpart };
+ unless $pkgpart_href->{ $pkgpart };
+
+ $cust_pkg = new FS::cust_pkg ( {
+ #later 'custnum' => $custnum,
+ 'pkgpart' => $pkgpart,
+ } );
+ $error ||= $cust_pkg->check;
+
+ #$cust_svc = new FS::cust_svc ( { 'svcpart' => $svcpart } );
+
+ #$error ||= $cust_svc->check;
+
+ $svc_acct = new FS::svc_acct ( {
+ 'svcpart' => $svcpart,
+ 'username' => $cgi->param('username'),
+ '_password' => $cgi->param('_password'),
+ 'popnum' => $cgi->param('popnum'),
+ } );
+
+ my $y = $svc_acct->setdefault; # arguably should be in new method
+ $error ||= $y unless ref($y);
+ #and just in case you were silly
+ $svc_acct->svcpart($svcpart);
+ $svc_acct->username($cgi->param('username'));
+ $svc_acct->_password($cgi->param('_password'));
+ $svc_acct->popnum($cgi->param('popnum'));
+
+ $error ||= $svc_acct->check;
+
+ } elsif ( $cgi->param('username') ) { #good thing to catch
+ $error = "Can't assign username without a package!";
+ }
+
+ use Tie::RefHash;
+ tie my %hash, 'Tie::RefHash';
+ %hash = ( $cust_pkg => [ $svc_acct ] ) if $cust_pkg;
+ $error ||= $new->insert( \%hash, \@invoicing_list );
+} else { #create old record object
+ my $old = qsearchs( 'cust_main', { 'custnum' => $new->custnum } );
+ $error ||= "Old record not found!" unless $old;
+ if ( defined dbdef->table('cust_main')->column('paycvv')
+ && length($old->paycvv)
+ && $new->paycvv =~ /^\s*\*+\s*$/ ) {
+ $new->paycvv($old->paycvv);
+ }
+ $error ||= $new->replace($old, \@invoicing_list);
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cust_main.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?". $new->custnum);
+}
+%>
diff --git a/httemplate/edit/process/cust_main_county-collapse.cgi b/httemplate/edit/process/cust_main_county-collapse.cgi
new file mode 100755
index 0000000..5da9dea
--- /dev/null
+++ b/httemplate/edit/process/cust_main_county-collapse.cgi
@@ -0,0 +1,35 @@
+<%
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ or die "Illegal taxnum!";
+my $taxnum = $1;
+my $cust_main_county = qsearchs('cust_main_county', { 'taxnum' => $taxnum } )
+ or die "Unknown taxnum $taxnum";
+
+#really should do this in a .pm & start transaction
+
+foreach my $delete ( qsearch('cust_main_county', {
+ 'country' => $cust_main_county->country,
+ 'state' => $cust_main_county->state
+ } ) ) {
+# unless ( qsearch('cust_main',{
+# 'state' => $cust_main_county->getfield('state'),
+# 'county' => $cust_main_county->getfield('county'),
+# 'country' => $cust_main_county->getfield('country'),
+# } ) ) {
+ my $error = $delete->delete;
+ die $error if $error;
+# } else {
+ #should really fix the $cust_main record
+# }
+
+}
+
+$cust_main_county->taxnum('');
+$cust_main_county->county('');
+my $error = $cust_main_county->insert;
+die $error if $error;
+
+print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi");
+
+%>
diff --git a/httemplate/edit/process/cust_main_county-expand.cgi b/httemplate/edit/process/cust_main_county-expand.cgi
new file mode 100755
index 0000000..a452711
--- /dev/null
+++ b/httemplate/edit/process/cust_main_county-expand.cgi
@@ -0,0 +1,58 @@
+<%
+
+$cgi->param('taxnum') =~ /^(\d+)$/ or die "Illegal taxnum!";
+my $taxnum = $1;
+my $cust_main_county = qsearchs('cust_main_county',{'taxnum'=>$taxnum})
+ or die ("Unknown taxnum!");
+
+my @expansion;
+if ( $cgi->param('delim') eq 'n' ) {
+ @expansion=split(/\n/,$cgi->param('expansion'));
+} elsif ( $cgi->param('delim') eq 's' ) {
+ @expansion=split(' ',$cgi->param('expansion'));
+} else {
+ die "Illegal delim!";
+}
+
+@expansion=map {
+ unless ( /^\s*([\w\- ]+)\s*$/ ) {
+ $cgi->param('error', "Illegal item in expansion");
+ print $cgi->redirect(popurl(2). "cust_main_county-expand.cgi?". $cgi->query_string );
+ myexit();
+ }
+ $1;
+} @expansion;
+
+foreach ( @expansion) {
+ my(%hash)=$cust_main_county->hash;
+ my($new)=new FS::cust_main_county \%hash;
+ $new->setfield('taxnum','');
+ if ( $cgi->param('taxclass') ) {
+ $new->setfield('taxclass', $_);
+ } elsif ( ! $cust_main_county->state ) {
+ $new->setfield('state',$_);
+ } else {
+ $new->setfield('county',$_);
+ }
+ #if (datasrc =~ m/Pg/)
+ #{
+ # $new->setfield('tax',0.0);
+ #}
+ my($error)=$new->insert;
+ die $error if $error;
+}
+
+unless ( qsearch( 'cust_main', {
+ 'state' => $cust_main_county->state,
+ 'county' => $cust_main_county->county,
+ 'country' => $cust_main_county->country,
+ } )
+ || ! @expansion
+) {
+ my($error)=($cust_main_county->delete);
+ die $error if $error;
+}
+
+print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi");
+
+%>
diff --git a/httemplate/edit/process/cust_main_county.cgi b/httemplate/edit/process/cust_main_county.cgi
new file mode 100755
index 0000000..9287ed1
--- /dev/null
+++ b/httemplate/edit/process/cust_main_county.cgi
@@ -0,0 +1,30 @@
+<%
+
+foreach ( grep { /^tax\d+$/ } $cgi->param ) {
+ /^tax(\d+)$/ or die "Illegal form $_!";
+ my $taxnum = $1;
+ my $old = qsearchs('cust_main_county', { 'taxnum' => $taxnum })
+ or die "Couldn't find taxnum $taxnum!";
+ next unless $old->tax != $cgi->param("tax$taxnum")
+ || $old->exempt_amount != $cgi->param("exempt_amount$taxnum")
+ || $old->taxname ne $cgi->param("taxname$taxnum")
+ || $old->setuptax ne $cgi->param("setuptax$taxnum")
+ || $old->recurtax ne $cgi->param("recurtax$taxnum");
+ my %hash = $old->hash;
+ $hash{tax} = $cgi->param("tax$taxnum");
+ $hash{exempt_amount} = $cgi->param("exempt_amount$taxnum");
+ $hash{taxname} = $cgi->param("taxname$taxnum");
+ $hash{setuptax} = $cgi->param("setuptax$taxnum");
+ $hash{recurtax} = $cgi->param("recurtax$taxnum");
+ my $new = new FS::cust_main_county \%hash;
+ my $error = $new->replace($old);
+ if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cust_main_county.cgi?". $cgi->query_string );
+ myexit();
+ }
+}
+
+print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi");
+
+%>
diff --git a/httemplate/edit/process/cust_pay.cgi b/httemplate/edit/process/cust_pay.cgi
new file mode 100755
index 0000000..82442ae
--- /dev/null
+++ b/httemplate/edit/process/cust_pay.cgi
@@ -0,0 +1,39 @@
+<%
+
+$cgi->param('linknum') =~ /^(\d+)$/
+ or die "Illegal linknum: ". $cgi->param('linknum');
+my $linknum = $1;
+
+$cgi->param('link') =~ /^(custnum|invnum)$/
+ or die "Illegal link: ". $cgi->param('link');
+my $link = $1;
+
+my $new = new FS::cust_pay ( {
+ $link => $linknum,
+ map {
+ $_, scalar($cgi->param($_));
+ } qw(paid _date payby payinfo paybatch)
+ #} fields('cust_pay')
+} );
+
+my $error = $new->insert;
+
+if ($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). 'cust_pay.cgi?'. $cgi->query_string );
+} elsif ( $link eq 'invnum' ) {
+ print $cgi->redirect(popurl(3). "view/cust_bill.cgi?$linknum");
+} elsif ( $link eq 'custnum' ) {
+ if ( $cgi->param('apply') eq 'yes' ) {
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $linknum })
+ or die "unknown custnum $linknum";
+ $cust_main->apply_payments;
+ }
+ if ( $cgi->param('quickpay') eq 'yes' ) {
+ print $cgi->redirect(popurl(3). "search/cust_main-quickpay.html");
+ } else {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$linknum");
+ }
+}
+
+%>
diff --git a/httemplate/edit/process/cust_pkg.cgi b/httemplate/edit/process/cust_pkg.cgi
new file mode 100755
index 0000000..df8471c
--- /dev/null
+++ b/httemplate/edit/process/cust_pkg.cgi
@@ -0,0 +1,43 @@
+<%
+
+my $error = '';
+
+#untaint custnum
+$cgi->param('custnum') =~ /^(\d+)$/;
+my $custnum = $1;
+
+my @remove_pkgnums = map {
+ /^(\d+)$/ or die "Illegal remove_pkg value!";
+ $1;
+} $cgi->param('remove_pkg');
+
+my $error_redirect;
+my @pkgparts;
+if ( $cgi->param('new_pkgpart') =~ /^(\d+)$/ ) { #came from misc/change_pkg.cgi
+ $error_redirect = "misc/change_pkg.cgi";
+ @pkgparts = ($1);
+} else { #came from edit/cust_pkg.cgi
+ $error_redirect = "edit/cust_pkg.cgi";
+ foreach my $pkgpart ( map /^pkg(\d+)$/ ? $1 : (), $cgi->param ) {
+ if ( $cgi->param("pkg$pkgpart") =~ /^(\d+)$/ ) {
+ my $num_pkgs = $1;
+ while ( $num_pkgs-- ) {
+ push @pkgparts,$pkgpart;
+ }
+ } else {
+ $error = "Illegal quantity";
+ last;
+ }
+ }
+}
+
+$error ||= FS::cust_pkg::order($custnum,\@pkgparts,\@remove_pkgnums);
+
+if ($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(3). $error_redirect. '?'. $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum");
+}
+
+%>
diff --git a/httemplate/edit/process/domain_record.cgi b/httemplate/edit/process/domain_record.cgi
new file mode 100755
index 0000000..b8c3f62
--- /dev/null
+++ b/httemplate/edit/process/domain_record.cgi
@@ -0,0 +1,34 @@
+<%
+
+my $recnum = $cgi->param('recnum');
+
+my $old = qsearchs('agent',{'recnum'=>$recnum}) if $recnum;
+
+my $new = new FS::domain_record ( {
+ map {
+ $_, scalar($cgi->param($_));
+ } fields('domain_record')
+} );
+
+my $error;
+if ( $recnum ) {
+ $error=$new->replace($old);
+} else {
+ $error=$new->insert;
+ $recnum=$new->getfield('recnum');
+}
+
+if ( $error ) {
+# $cgi->param('error', $error);
+# print $cgi->redirect(popurl(2). "agent.cgi?". $cgi->query_string );
+ #no edit screen to send them back to
+%>
+<!-- mason kludge -->
+<%
+ eidiot($error);
+} else {
+ my $svcnum = $new->svcnum;
+ print $cgi->redirect(popurl(3). "view/svc_domain.cgi?$svcnum");
+}
+
+%>
diff --git a/httemplate/edit/process/generic.cgi b/httemplate/edit/process/generic.cgi
new file mode 100644
index 0000000..9c54feb
--- /dev/null
+++ b/httemplate/edit/process/generic.cgi
@@ -0,0 +1,70 @@
+<%
+
+# Welcome to generic.cgi.
+#
+# This script provides a generic edit/process/ backend for simple table
+# editing. All it knows how to do is take the values entered into
+# the script and insert them into the table specified by $cgi->param('table').
+# If there's an existing record with the same primary key, it will be
+# replaced. (Deletion will be added in the future.)
+#
+# Special cgi params for this script:
+# table: the name of the table to be edited. The script will die horribly
+# if it can't find the table.
+# redirect_ok: URL to be displayed after a successful edit. The value of
+# the record's primary key will be passed as a keyword.
+# Defaults to (freeside root)/view/$table.cgi.
+# redirect_error: URL to be displayed if there's an error. The original
+# query string, plus the error message, will be passed.
+# Defaults to $cgi->referer() (i.e. go back where you
+# came from).
+
+
+use FS::Record qw(qsearchs dbdef);
+use DBIx::DBSchema;
+use DBIx::DBSchema::Table;
+
+
+my $error;
+my $p2 = popurl(2);
+my $p3 = popurl(3);
+my $table = $cgi->param('table');
+my $dbdef = dbdef or die "Cannot fetch dbdef!";
+
+my $dbdef_table = $dbdef->table($table) or die "Cannot fetch schema for $table";
+
+my $pkey = $dbdef_table->primary_key or die "Cannot fetch pkey for $table";
+my $pkey_val = $cgi->param($pkey);
+
+
+#warn "new FS::Record ( $table, (hashref) )";
+my $new = FS::Record::new ( "FS::$table", {
+ map { $_, scalar($cgi->param($_)) } fields($table)
+} );
+
+#warn 'created $new of class '.ref($new);
+
+if($pkey_val and (my $old = qsearchs($table, { $pkey, $pkey_val} ))) {
+ # edit
+ $error = $new->replace($old);
+} else {
+ #add
+ $error = $new->insert;
+ $pkey_val = $new->getfield($pkey);
+ # New records usually don't have their primary keys set until after
+ # they've been checked/inserted, so grab the new $pkey_val so we can
+ # redirect to it.
+}
+
+my $redirect_ok = (($cgi->param('redirect_ok')) ?
+ $cgi->param('redirect_ok') : $p3."browse/generic.cgi?$table");
+my $redirect_error = (($cgi->param('redirect_error')) ?
+ $cgi->param('redirect_error') : $cgi->referer());
+
+if($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect($redirect_error . '?' . $cgi->query_string);
+} else {
+ print $cgi->redirect($redirect_ok);
+}
+%>
diff --git a/httemplate/edit/process/msgcat.cgi b/httemplate/edit/process/msgcat.cgi
new file mode 100644
index 0000000..1f94f66
--- /dev/null
+++ b/httemplate/edit/process/msgcat.cgi
@@ -0,0 +1,20 @@
+<%
+
+my $error;
+foreach my $param ( grep { /^\d+$/ } $cgi->param ) {
+ my $old = qsearchs('msgcat', { msgnum=>$param } );
+ next if $old->msg eq $cgi->param($param); #no need to update identical records
+ my $new = new FS::msgcat { $old->hash };
+ $new->msg($cgi->param($param));
+ $error = $new->replace($old);
+ last if $error;
+}
+
+if ( $error ) {
+ $cgi->param('error',$error);
+ print $cgi->redirect($p. "msgcat.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "browse/msgcat.cgi");
+}
+
+%>
diff --git a/httemplate/edit/process/part_bill_event.cgi b/httemplate/edit/process/part_bill_event.cgi
new file mode 100755
index 0000000..77dcd24
--- /dev/null
+++ b/httemplate/edit/process/part_bill_event.cgi
@@ -0,0 +1,54 @@
+<%
+
+my $eventpart = $cgi->param('eventpart');
+
+my $old = qsearchs('part_bill_event',{'eventpart'=>$eventpart}) if $eventpart;
+
+#s/days/seconds/
+$cgi->param('seconds', int( $cgi->param('days') * 86400 ) );
+
+my $error;
+if ( ! $cgi->param('plan_weight_eventcode') ) {
+ $error = "Must select an action";
+} else {
+
+ $cgi->param('plan_weight_eventcode') =~ /^([\w\-]+):(\d+):(.*)$/s
+ or die "illegal plan_weight_eventcode:".
+ $cgi->param('plan_weight_eventcode');
+ $cgi->param('plan', $1);
+ $cgi->param('weight', $2);
+ my $eventcode = $3;
+ my $plandata = '';
+ while ( $eventcode =~ /%%%(\w+)%%%/ ) {
+ my $field = $1;
+ my $value = join(', ', $cgi->param($field) );
+ $cgi->param($field, $value); #in case it errors out
+ $eventcode =~ s/%%%$field%%%/$value/;
+ $plandata .= "$field $value\n";
+ }
+ $cgi->param('eventcode', $eventcode);
+ $cgi->param('plandata', $plandata);
+
+ my $new = new FS::part_bill_event ( {
+ map {
+ $_, scalar($cgi->param($_));
+ } fields('part_bill_event'),
+ } );
+
+ if ( $eventpart ) {
+ $error = $new->replace($old);
+ } else {
+ $error = $new->insert;
+ $eventpart = $new->getfield('eventpart');
+ }
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "part_bill_event.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3)."browse/part_bill_event.cgi");
+}
+
+%>
+
diff --git a/httemplate/edit/process/part_export.cgi b/httemplate/edit/process/part_export.cgi
new file mode 100644
index 0000000..fa009ed
--- /dev/null
+++ b/httemplate/edit/process/part_export.cgi
@@ -0,0 +1,39 @@
+<%
+
+my $exportnum = $cgi->param('exportnum');
+
+my $old = qsearchs('part_export', { 'exportnum'=>$exportnum } ) if $exportnum;
+
+#fixup options
+#warn join('-', split(',',$cgi->param('options')));
+my %options = map {
+ my $value = $cgi->param($_);
+ $value =~ s/\r\n/\n/g; #browsers? (textarea)
+ $_ => $value;
+} split(',', $cgi->param('options'));
+
+my $new = new FS::part_export ( {
+ map {
+ $_, scalar($cgi->param($_));
+ } fields('part_export')
+} );
+
+my $error;
+if ( $exportnum ) {
+ #warn $old;
+ #warn $exportnum;
+ #warn $new->machine;
+ $error = $new->replace($old,\%options);
+} else {
+ $error = $new->insert(\%options);
+# $exportnum = $new->exportnum;
+}
+
+if ( $error ) {
+ $cgi->param('error', $error );
+ print $cgi->redirect(popurl(2). "part_export.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "browse/part_export.cgi");
+}
+
+%>
diff --git a/httemplate/edit/process/part_pkg.cgi b/httemplate/edit/process/part_pkg.cgi
new file mode 100755
index 0000000..7eada7b
--- /dev/null
+++ b/httemplate/edit/process/part_pkg.cgi
@@ -0,0 +1,117 @@
+<%
+
+my $dbh = dbh;
+
+my $pkgpart = $cgi->param('pkgpart');
+
+my $old = qsearchs('part_pkg',{'pkgpart'=>$pkgpart}) if $pkgpart;
+
+#fixup plandata
+my $plandata = $cgi->param('plandata');
+my @plandata = split(',', $plandata);
+$cgi->param('plandata',
+ join('', map { "$_=". join(', ', $cgi->param($_)). "\n" } @plandata )
+);
+
+foreach (qw( setuptax recurtax disabled )) {
+ $cgi->param($_, '') unless defined $cgi->param($_);
+}
+
+my $new = new FS::part_pkg ( {
+ map {
+ $_, scalar($cgi->param($_));
+ } fields('part_pkg')
+} );
+
+#warn "setuptax: ". $new->setuptax;
+#warn "recurtax: ". $new->recurtax;
+
+#most of the stuff below should move to part_pkg.pm
+
+foreach my $part_svc ( qsearch('part_svc', {} ) ) {
+ my $quantity = $cgi->param('pkg_svc'. $part_svc->svcpart) || 0;
+ unless ( $quantity =~ /^(\d+)$/ ) {
+ $cgi->param('error', "Illegal quantity" );
+ print $cgi->redirect(popurl(2). "part_pkg.cgi?". $cgi->query_string );
+ myexit();
+ }
+}
+
+local $SIG{HUP} = 'IGNORE';
+local $SIG{INT} = 'IGNORE';
+local $SIG{QUIT} = 'IGNORE';
+local $SIG{TERM} = 'IGNORE';
+local $SIG{TSTP} = 'IGNORE';
+local $SIG{PIPE} = 'IGNORE';
+
+local $FS::UID::AutoCommit = 0;
+
+my $error;
+if ( $pkgpart ) {
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+ $pkgpart=$new->pkgpart;
+}
+if ( $error ) {
+ $dbh->rollback;
+ $cgi->param('error', $error );
+ print $cgi->redirect(popurl(2). "part_pkg.cgi?". $cgi->query_string );
+ myexit();
+}
+
+foreach my $part_svc (qsearch('part_svc',{})) {
+ my $quantity = $cgi->param('pkg_svc'. $part_svc->svcpart) || 0;
+ my $primary_svc =
+ $cgi->param('pkg_svc_primary') == $part_svc->svcpart ? 'Y' : '';
+ my $old_pkg_svc = qsearchs('pkg_svc', {
+ 'pkgpart' => $pkgpart,
+ 'svcpart' => $part_svc->svcpart,
+ } );
+ my $old_quantity = $old_pkg_svc ? $old_pkg_svc->quantity : 0;
+ my $old_primary_svc =
+ ( $old_pkg_svc && $old_pkg_svc->dbdef_table->column('primary_svc') )
+ ? $old_pkg_svc->primary_svc
+ : '';
+ next unless $old_quantity != $quantity || $old_primary_svc ne $primary_svc;
+
+ my $new_pkg_svc = new FS::pkg_svc( {
+ 'pkgpart' => $pkgpart,
+ 'svcpart' => $part_svc->svcpart,
+ 'quantity' => $quantity,
+ 'primary_svc' => $primary_svc,
+ } );
+ if ( $old_pkg_svc ) {
+ my $myerror = $new_pkg_svc->replace($old_pkg_svc);
+ if ( $myerror ) {
+ $dbh->rollback;
+ die $myerror;
+ }
+ } else {
+ my $myerror = $new_pkg_svc->insert;
+ if ( $myerror ) {
+ $dbh->rollback;
+ die $myerror;
+ }
+ }
+}
+
+unless ( $cgi->param('pkgnum') && $cgi->param('pkgnum') =~ /^(\d+)$/ ) {
+ $dbh->commit or die $dbh->errstr;
+ print $cgi->redirect(popurl(3). "browse/part_pkg.cgi");
+} else {
+ my($old_cust_pkg) = qsearchs( 'cust_pkg', { 'pkgnum' => $1 } );
+ my %hash = $old_cust_pkg->hash;
+ $hash{'pkgpart'} = $pkgpart;
+ my($new_cust_pkg) = new FS::cust_pkg \%hash;
+ my $myerror = $new_cust_pkg->replace($old_cust_pkg);
+ if ( $myerror ) {
+ $dbh->rollback;
+ die "Error modifying cust_pkg record: $myerror\n";
+ }
+
+ $dbh->commit or die $dbh->errstr;
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?". $new_cust_pkg->custnum);
+}
+
+%>
diff --git a/httemplate/edit/process/part_referral.cgi b/httemplate/edit/process/part_referral.cgi
new file mode 100755
index 0000000..fd2c015
--- /dev/null
+++ b/httemplate/edit/process/part_referral.cgi
@@ -0,0 +1,28 @@
+<%
+
+my $refnum = $cgi->param('refnum');
+
+my $new = new FS::part_referral ( {
+ map {
+ $_, scalar($cgi->param($_));
+ } fields('part_referral')
+} );
+
+my $error;
+if ( $refnum ) {
+ my $old = qsearchs( 'part_referral', { 'refnum' =>$ refnum } );
+ die "(Old) Record not found!" unless $old;
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+}
+$refnum=$new->refnum;
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "part_referral.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "browse/part_referral.cgi");
+}
+
+%>
diff --git a/httemplate/edit/process/part_svc.cgi b/httemplate/edit/process/part_svc.cgi
new file mode 100755
index 0000000..9633fab
--- /dev/null
+++ b/httemplate/edit/process/part_svc.cgi
@@ -0,0 +1,62 @@
+<%
+
+my $svcpart = $cgi->param('svcpart');
+
+my $old = qsearchs('part_svc',{'svcpart'=>$svcpart}) if $svcpart;
+
+$cgi->param( 'svc_acct__usergroup',
+ join(',', $cgi->param('svc_acct__usergroup') ) );
+
+my $new = new FS::part_svc ( {
+ map {
+ $_, scalar($cgi->param($_));
+# } qw(svcpart svc svcdb)
+ } ( fields('part_svc'),
+ map { my $svcdb = $_;
+ my @fields = fields($svcdb);
+ push @fields, 'usergroup' if $svcdb eq 'svc_acct'; #kludge
+ map { ( $svcdb.'__'.$_, $svcdb.'__'.$_.'_flag' ) } @fields;
+ } grep defined( $FS::Record::dbdef->table($_) ),
+ qw( svc_acct svc_domain svc_forward svc_www svc_broadband )
+ )
+} );
+
+my $error;
+if ( $svcpart ) {
+ $error = $new->replace($old, '1.3-COMPAT', [ 'usergroup' ] );
+} else {
+ $error = $new->insert( [ 'usergroup' ] );
+ $svcpart=$new->getfield('svcpart');
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "part_svc.cgi?". $cgi->query_string );
+} else {
+
+ #false laziness w/ edit/process/agent_type.cgi
+ foreach my $part_export (qsearch('part_export',{})) {
+ my $exportnum = $part_export->exportnum;
+ my $export_svc = qsearchs('export_svc', {
+ 'exportnum' => $part_export->exportnum,
+ 'svcpart' => $new->svcpart,
+ } );
+ if ( $export_svc && ! $cgi->param("exportnum". $part_export->exportnum) ) {
+ $error = $export_svc->delete;
+ die $error if $error;
+ } elsif ( $cgi->param("exportnum". $part_export->exportnum)
+ && ! $export_svc ) {
+ $export_svc = new FS::export_svc ( {
+ 'exportnum' => $part_export->exportnum,
+ 'svcpart' => $new->svcpart,
+ } );
+ $error = $export_svc->insert;
+ die $error if $error;
+ }
+
+ }
+
+ print $cgi->redirect(popurl(3)."browse/part_svc.cgi");
+}
+
+%>
diff --git a/httemplate/edit/process/quick-charge.cgi b/httemplate/edit/process/quick-charge.cgi
new file mode 100644
index 0000000..477f585
--- /dev/null
+++ b/httemplate/edit/process/quick-charge.cgi
@@ -0,0 +1,32 @@
+<%
+
+#untaint custnum
+$cgi->param('custnum') =~ /^(\d+)$/
+ or die 'illegal custnum '. $cgi->param('custnum');
+my $custnum = $1;
+
+$cgi->param('amount') =~ /^\s*(\d+(\.\d{1,2})?)\s*$/
+ or die 'illegal amount '. $cgi->param('amount');
+my $amount = $1;
+
+my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or die "unknown custnum $custnum";
+
+my $error = $cust_main->charge(
+ $amount,
+ $cgi->param('pkg'),
+ '$'. sprintf("%.2f",$amount),
+ $cgi->param('taxclass')
+);
+
+if ($error) {
+%>
+<!-- mason kludge -->
+<%
+ eidiot($error);
+} else {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum" );
+}
+
+%>
+
diff --git a/httemplate/edit/process/quick-cust_pkg.cgi b/httemplate/edit/process/quick-cust_pkg.cgi
new file mode 100644
index 0000000..fd9e594
--- /dev/null
+++ b/httemplate/edit/process/quick-cust_pkg.cgi
@@ -0,0 +1,25 @@
+<%
+
+#untaint custnum
+$cgi->param('custnum') =~ /^(\d+)$/
+ or die 'illegal custnum '. $cgi->param('custnum');
+my $custnum = $1;
+$cgi->param('pkgpart') =~ /^(\d+)$/
+ or die 'illegal pkgpart '. $cgi->param('pkgpart');
+my $pkgpart = $1;
+
+my @cust_pkg = ();
+my $error = FS::cust_pkg::order($custnum, [ $pkgpart ], [], \@cust_pkg, );
+
+if ($error) {
+%>
+<!-- mason kludge -->
+<%
+ eidiot($error);
+} else {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum".
+ "#cust_pkg". $cust_pkg[0]->pkgnum );
+}
+
+%>
+
diff --git a/httemplate/edit/process/router.cgi b/httemplate/edit/process/router.cgi
new file mode 100644
index 0000000..a2fa46d
--- /dev/null
+++ b/httemplate/edit/process/router.cgi
@@ -0,0 +1,67 @@
+<%
+
+local $FS::UID::AutoCommit=0;
+
+sub check {
+ my $error = shift;
+ if($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(3) . "edit/router.cgi?". $cgi->query_string);
+ dbh->rollback;
+ exit;
+ }
+}
+
+my $error = '';
+my $routernum = $cgi->param('routernum');
+my $routername = $cgi->param('routername');
+my $old = qsearchs('router', { routernum => $routernum });
+my @old_psr;
+
+my $new = new FS::router {
+ map {
+ ($_, scalar($cgi->param($_)));
+ } fields('router')
+};
+
+if($old) {
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+ $routernum = $new->routernum;
+}
+
+check($error);
+
+if ($old) {
+ @old_psr = $old->part_svc_router;
+ foreach my $psr (@old_psr) {
+ if($cgi->param('svcpart_'.$psr->svcpart) eq 'ON') {
+ # do nothing
+ } else {
+ $error = $psr->delete;
+ }
+ }
+ check($error);
+}
+
+foreach($cgi->param) {
+ if($cgi->param($_) eq 'ON' and /^svcpart_(\d+)$/) {
+ my $svcpart = $1;
+ if(grep {$_->svcpart == $svcpart} @old_psr) {
+ # do nothing
+ } else {
+ my $new_psr = new FS::part_svc_router { svcpart => $svcpart,
+ routernum => $routernum };
+ $error = $new_psr->insert;
+ }
+ check($error);
+ }
+}
+
+
+# Yay, everything worked!
+dbh->commit or die dbh->errstr;
+print $cgi->redirect(popurl(3). "browse/router.cgi");
+
+%>
diff --git a/httemplate/edit/process/svc_acct.cgi b/httemplate/edit/process/svc_acct.cgi
new file mode 100755
index 0000000..950a860
--- /dev/null
+++ b/httemplate/edit/process/svc_acct.cgi
@@ -0,0 +1,49 @@
+<%
+
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+my $svcnum = $1;
+
+my $old;
+if ( $svcnum ) {
+ $old = qsearchs('svc_acct', { 'svcnum' => $svcnum } )
+ or die "fatal: can't find account (svcnum $svcnum)!";
+} else {
+ $old = '';
+}
+
+#unmunge popnum
+$cgi->param('popnum', (split(/:/, $cgi->param('popnum') ))[0] );
+
+#unmunge passwd
+if ( $cgi->param('_password') eq '*HIDDEN*' ) {
+ die "fatal: no previous account to recall hidden password from!" unless $old;
+ $cgi->param('_password',$old->getfield('_password'));
+}
+
+#unmunge usergroup
+$cgi->param('usergroup', [ $cgi->param('radius_usergroup') ] );
+
+my $new = new FS::svc_acct ( {
+ map {
+ $_, scalar($cgi->param($_));
+ #} qw(svcnum pkgnum svcpart username _password popnum uid gid finger dir
+ # shell quota slipip)
+ } ( fields('svc_acct'), qw( pkgnum svcpart usergroup ) )
+} );
+
+my $error;
+if ( $svcnum ) {
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+ $svcnum = $new->svcnum;
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_acct.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/svc_acct.cgi?" . $svcnum );
+}
+
+%>
diff --git a/httemplate/edit/process/svc_acct_pop.cgi b/httemplate/edit/process/svc_acct_pop.cgi
new file mode 100755
index 0000000..46ad74d
--- /dev/null
+++ b/httemplate/edit/process/svc_acct_pop.cgi
@@ -0,0 +1,28 @@
+<%
+
+my $popnum = $cgi->param('popnum');
+
+my $old = qsearchs('svc_acct_pop',{'popnum'=>$popnum}) if $popnum;
+
+my $new = new FS::svc_acct_pop ( {
+ map {
+ $_, scalar($cgi->param($_));
+ } fields('svc_acct_pop')
+} );
+
+my $error = '';
+if ( $popnum ) {
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+ $popnum=$new->getfield('popnum');
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_acct_pop.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "browse/svc_acct_pop.cgi");
+}
+
+%>
diff --git a/httemplate/edit/process/svc_broadband.cgi b/httemplate/edit/process/svc_broadband.cgi
new file mode 100644
index 0000000..4912a3a
--- /dev/null
+++ b/httemplate/edit/process/svc_broadband.cgi
@@ -0,0 +1,45 @@
+<%
+
+# If it's stupid but it works, it's not stupid.
+# -- U.S. Army
+
+local $FS::UID::AutoCommit = 0;
+my $dbh = FS::UID::dbh;
+
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+my $svcnum = $1;
+
+my $old;
+if ( $svcnum ) {
+ $old = qsearchs('svc_broadband', { 'svcnum' => $svcnum } )
+ or die "fatal: can't find broadband service (svcnum $svcnum)!";
+} else {
+ $old = '';
+}
+
+my $new = new FS::svc_broadband ( {
+ map {
+ ($_, scalar($cgi->param($_)));
+ } ( fields('svc_broadband'), qw( pkgnum svcpart ) )
+} );
+
+my $error;
+if ( $svcnum ) {
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+ $svcnum = $new->svcnum;
+}
+
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ $cgi->param('ip_addr', $new->ip_addr);
+ $dbh->rollback;
+ print $cgi->redirect(popurl(2). "svc_broadband.cgi?". $cgi->query_string );
+} else {
+ $dbh->commit or die $dbh->errstr;
+ print $cgi->redirect(popurl(3). "view/svc_broadband.cgi?" . $svcnum );
+}
+
+%>
diff --git a/httemplate/edit/process/svc_domain.cgi b/httemplate/edit/process/svc_domain.cgi
new file mode 100755
index 0000000..19f8eb4
--- /dev/null
+++ b/httemplate/edit/process/svc_domain.cgi
@@ -0,0 +1,31 @@
+<%
+
+#remove this to actually test the domains!
+$FS::svc_domain::whois_hack = 1;
+
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+my $svcnum = $1;
+
+my $new = new FS::svc_domain ( {
+ map {
+ $_, scalar($cgi->param($_));
+ #} qw(svcnum pkgnum svcpart domain action purpose)
+ } ( fields('svc_domain'), qw( pkgnum svcpart action purpose ) )
+} );
+
+my $error = '';
+if ($cgi->param('svcnum')) {
+ $error="Can't modify a domain!";
+} else {
+ $error=$new->insert;
+ $svcnum=$new->svcnum;
+}
+
+if ($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_domain.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/svc_domain.cgi?$svcnum");
+}
+
+%>
diff --git a/httemplate/edit/process/svc_external.cgi b/httemplate/edit/process/svc_external.cgi
new file mode 100755
index 0000000..728cd21
--- /dev/null
+++ b/httemplate/edit/process/svc_external.cgi
@@ -0,0 +1,29 @@
+<%
+
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+my $svcnum =$1;
+
+my $old = qsearchs('svc_external',{'svcnum'=>$svcnum}) if $svcnum;
+
+my $new = new FS::svc_external ( {
+ map {
+ ($_, scalar($cgi->param($_)));
+ } ( fields('svc_external'), qw( pkgnum svcpart ) )
+} );
+
+my $error = '';
+if ( $svcnum ) {
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+ $svcnum = $new->getfield('svcnum');
+}
+
+if ($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_external.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/svc_external.cgi?$svcnum");
+}
+
+%>
diff --git a/httemplate/edit/process/svc_forward.cgi b/httemplate/edit/process/svc_forward.cgi
new file mode 100755
index 0000000..bb066d8
--- /dev/null
+++ b/httemplate/edit/process/svc_forward.cgi
@@ -0,0 +1,29 @@
+<%
+
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+my $svcnum =$1;
+
+my $old = qsearchs('svc_forward',{'svcnum'=>$svcnum}) if $svcnum;
+
+my $new = new FS::svc_forward ( {
+ map {
+ ($_, scalar($cgi->param($_)));
+ } ( fields('svc_forward'), qw( pkgnum svcpart ) )
+} );
+
+my $error = '';
+if ( $svcnum ) {
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+ $svcnum = $new->getfield('svcnum');
+}
+
+if ($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_forward.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/svc_forward.cgi?$svcnum");
+}
+
+%>
diff --git a/httemplate/edit/process/svc_www.cgi b/httemplate/edit/process/svc_www.cgi
new file mode 100644
index 0000000..4091314
--- /dev/null
+++ b/httemplate/edit/process/svc_www.cgi
@@ -0,0 +1,36 @@
+<%
+
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+my $svcnum = $1;
+
+my $old;
+if ( $svcnum ) {
+ $old = qsearchs('svc_www', { 'svcnum' => $svcnum } )
+ or die "fatal: can't find website (svcnum $svcnum)!";
+} else {
+ $old = '';
+}
+
+my $new = new FS::svc_www ( {
+ map {
+ ($_, scalar($cgi->param($_)));
+ #} qw(svcnum pkgnum svcpart recnum usersvc)
+ } ( fields('svc_www'), qw( pkgnum svcpart ) )
+} );
+
+my $error;
+if ( $svcnum ) {
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+ $svcnum = $new->svcnum;
+}
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_www.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/svc_www.cgi?" . $svcnum );
+}
+
+%>
diff --git a/httemplate/edit/router.cgi b/httemplate/edit/router.cgi
new file mode 100755
index 0000000..a573c65
--- /dev/null
+++ b/httemplate/edit/router.cgi
@@ -0,0 +1,77 @@
+<HTML><BODY>
+
+<%
+
+my $router;
+if ( $cgi->keywords ) {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $router = qsearchs('router', { routernum => $1 })
+ or print $cgi->redirect(popurl(2)."browse/router.cgi") ;
+} else {
+ $router = new FS::router ( {
+ map { $_, scalar($cgi->param($_)) } fields('router')
+ } );
+}
+
+my $routernum = $router->routernum;
+my $action = $routernum ? 'Edit' : 'Add';
+
+print header("$action Router", menubar(
+ 'Main Menu' => "$p",
+ 'View all routers' => "${p}browse/router.cgi",
+));
+
+my $p3 = popurl(3);
+
+if($cgi->param('error')) {
+%> <FONT SIZE="+1" COLOR="#ff0000">Error: <%=$cgi->param('error')%></FONT>
+<% } %>
+
+<FORM ACTION="<%=popurl(1)%>process/router.cgi" METHOD=POST>
+ <INPUT TYPE="hidden" NAME="table" VALUE="router">
+ <INPUT TYPE="hidden" NAME="redirect_ok" VALUE="<%=$p3%>/browse/router.cgi">
+ <INPUT TYPE="hidden" NAME="redirect_error" VALUE="<%=$p3%>/edit/router.cgi">
+ <INPUT TYPE="hidden" NAME="routernum" VALUE="<%=$routernum%>">
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%=$router->svcnum%>">
+ Router #<%=$routernum or "(NEW)"%>
+
+<BR><BR>Name <INPUT TYPE="text" NAME="routername" SIZE=32 VALUE="<%=$router->routername%>">
+
+<BR><BR>
+Custom fields:
+<BR>
+<%=table() %>
+
+<%
+foreach my $field ($router->virtual_fields) {
+ print $router->pvf($field)->widget('HTML', 'edit',
+ $router->getfield($field));
+}
+%>
+</TABLE>
+
+
+<%
+unless ($router->svcnum) {
+%>
+<BR><BR>Select the service types available on this router<BR>
+<%
+
+ foreach my $part_svc ( qsearch('part_svc', { svcdb => 'svc_broadband',
+ disabled => '' }) ) {
+ %>
+ <BR>
+ <INPUT TYPE="checkbox" NAME="svcpart_<%=$part_svc->svcpart%>"<%=
+ qsearchs('part_svc_router', { svcpart => $part_svc->svcpart,
+ routernum => $routernum } ) ? ' CHECKED' : ''%> VALUE="ON">
+ <A HREF="<%=${p}%>edit/part_svc.cgi?<%=$part_svc->svcpart%>">
+ <%=$part_svc->svcpart%>: <%=$part_svc->svc%></A>
+ <% } %>
+
+<% } %>
+
+ <BR><BR><INPUT TYPE="submit" VALUE="Apply changes">
+ </FORM>
+</BODY></HTML>
+
diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi
new file mode 100755
index 0000000..f1b8b80
--- /dev/null
+++ b/httemplate/edit/svc_acct.cgi
@@ -0,0 +1,301 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+my @shells = $conf->config('shells');
+
+my($svcnum, $pkgnum, $svcpart, $part_svc, $svc_acct, @groups);
+if ( $cgi->param('error') ) {
+ $svc_acct = new FS::svc_acct ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_acct')
+ } );
+ $svcnum = $svc_acct->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $cgi->param('svcpart');
+ $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } );
+ die "No part_svc entry for svcpart $svcpart!" unless $part_svc;
+ @groups = $cgi->param('radius_usergroup');
+} else {
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_acct=qsearchs('svc_acct',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_acct) svcnum!";
+
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
+
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
+
+ $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } );
+ die "No part_svc entry for svcpart $svcpart!" unless $part_svc;
+
+ @groups = $svc_acct->radius_groups;
+
+ } else { #adding
+
+ foreach $_ (split(/-/,$query)) {
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
+ }
+ $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } );
+ die "No part_svc entry for svcpart $svcpart!" unless $part_svc;
+
+ $svc_acct = new FS::svc_acct({svcpart => $svcpart});
+
+ $svcnum='';
+
+ #set gecos
+ my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+ if ($cust_pkg) {
+ my($cust_main)=qsearchs('cust_main',{'custnum'=> $cust_pkg->custnum } );
+ unless ( $part_svc->part_svc_column('uid')->columnflag eq 'F' ) {
+ $svc_acct->setfield('finger',
+ $cust_main->getfield('first') . " " . $cust_main->getfield('last')
+ );
+ }
+ }
+
+ #set fixed and default fields from part_svc
+ foreach my $part_svc_column (
+ grep { $_->columnflag } $part_svc->all_part_svc_column
+ ) {
+ if ( $part_svc_column->columnname eq 'usergroup' ) {
+ @groups = split(',', $part_svc_column->columnvalue);
+ } else {
+ $svc_acct->setfield( $part_svc_column->columnname,
+ $part_svc_column->columnvalue,
+ );
+ }
+ }
+
+ }
+}
+
+#fixed radius groups always override & display
+if ( $part_svc->part_svc_column('usergroup')->columnflag eq "F" ) {
+ @groups = split(',', $part_svc->part_svc_column('usergroup')->columnvalue);
+}
+
+my $action = $svcnum ? 'Edit' : 'Add';
+
+my $svc = $part_svc->getfield('svc');
+
+my $otaker = getotaker;
+
+my $username = $svc_acct->username;
+my $password;
+if ( $svc_acct->_password ) {
+ if ( $conf->exists('showpasswords') || ! $svcnum ) {
+ $password = $svc_acct->_password;
+ } else {
+ $password = "*HIDDEN*";
+ }
+} else {
+ $password = '';
+}
+
+my $ulen = $conf->config('usernamemax')
+ || $svc_acct->dbdef_table->column('username')->length;
+my $ulen2 = $ulen+2;
+
+my $pmax = $conf->config('passwordmax') || 8;
+my $pmax2 = $pmax+2;
+
+my $p1 = popurl(1);
+print header("$action $svc account");
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT><BR><BR>"
+ if $cgi->param('error');
+
+print 'Service # '. ( $svcnum ? "<B>$svcnum</B>" : " (NEW)" ). '<BR>'.
+ 'Service: <B>'. $part_svc->svc. '</B><BR><BR>'.
+ <<END;
+ <FORM NAME="OneTrueForm" ACTION="${p1}process/svc_acct.cgi" METHOD=POST>
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum">
+ <INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">
+ <INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">
+END
+
+print &ntable("#cccccc",2), <<END;
+<TR><TD ALIGN="right">Username</TD>
+<TD><INPUT TYPE="text" NAME="username" VALUE="$username" SIZE=$ulen2 MAXLENGTH=$ulen></TD></TR>
+<TR><TD ALIGN="right">Password</TD>
+<TD><INPUT TYPE="text" NAME="_password" VALUE="$password" SIZE=$pmax2 MAXLENGTH=$pmax>
+(blank to generate)</TD>
+</TR>
+END
+
+my $sec_phrase = $svc_acct->sec_phrase;
+if ( $conf->exists('security_phrase') ) {
+ print <<END;
+ <TR><TD ALIGN="right">Security phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase" SIZE=32>
+ (for forgotten passwords)</TD>
+ </TD>
+END
+} else {
+ print qq!<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="$sec_phrase">!;
+}
+
+#domain
+my $domsvc = $svc_acct->domsvc || 0;
+if ( $part_svc->part_svc_column('domsvc')->columnflag eq 'F' ) {
+ print qq!<INPUT TYPE="hidden" NAME="domsvc" VALUE="$domsvc">!;
+} else {
+ my %svc_domain = ();
+
+ if ( $domsvc ) {
+ my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $domsvc, } );
+ if ( $svc_domain ) {
+ $svc_domain{$svc_domain->svcnum} = $svc_domain;
+ } else {
+ warn "unknown svc_domain.svcnum for svc_acct.domsvc: $domsvc";
+ }
+ }
+
+ if ( $part_svc->part_svc_column('domsvc')->columnflag eq 'D' ) {
+ my $svc_domain = qsearchs('svc_domain', {
+ 'svcnum' => $part_svc->part_svc_column('domsvc')->columnvalue,
+ } );
+ if ( $svc_domain ) {
+ $svc_domain{$svc_domain->svcnum} = $svc_domain;
+ } else {
+ warn "unknown svc_domain.svcnum for part_svc_column domsvc: ".
+ $part_svc->part_svc_column('domsvc')->columnvalue;
+ }
+ }
+
+ my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $pkgnum } );
+ if ($cust_pkg && !$conf->exists('svc_acct-alldomains') ) {
+ my @cust_svc =
+ map { qsearch('cust_svc', { 'pkgnum' => $_->pkgnum } ) }
+ qsearch('cust_pkg', { 'custnum' => $cust_pkg->custnum } );
+ foreach my $cust_svc ( @cust_svc ) {
+ my $svc_domain =
+ qsearchs('svc_domain', { 'svcnum' => $cust_svc->svcnum } );
+ $svc_domain{$svc_domain->svcnum} = $svc_domain if $svc_domain;
+ }
+ } else {
+ %svc_domain = map { $_->svcnum => $_ } qsearch('svc_domain', {} );
+ }
+ print qq!<TR><TD ALIGN="right">Domain</TD>!.
+ qq!<TD><SELECT NAME="domsvc" SIZE=1>\n!;
+ foreach my $svcnum (
+ sort { $svc_domain{$a}->domain cmp $svc_domain{$b}->domain }
+ keys %svc_domain
+ ) {
+ my $svc_domain = $svc_domain{$svcnum};
+ print qq!<OPTION VALUE="!. $svc_domain->svcnum. qq!"!.
+ ( $svc_domain->svcnum == $domsvc ? ' SELECTED' : '' ).
+ '>'. $svc_domain->domain. "\n" ;
+ }
+ print "</SELECT></TD></TR>";
+}
+
+#pop
+my $popnum = $svc_acct->popnum || 0;
+if ( $part_svc->part_svc_column('popnum')->columnflag eq "F" ) {
+ print qq!<INPUT TYPE="hidden" NAME="popnum" VALUE="$popnum">!;
+} else {
+ print qq!<TR><TD ALIGN="right">Access number</TD>!.
+ qq!<TD>!. FS::svc_acct_pop::popselector($popnum). '</TD></TR>';
+}
+
+my($uid,$gid,$finger,$dir)=(
+ $svc_acct->uid,
+ $svc_acct->gid,
+ $svc_acct->finger,
+ $svc_acct->dir,
+);
+
+print <<END;
+<INPUT TYPE="hidden" NAME="uid" VALUE="$uid">
+<INPUT TYPE="hidden" NAME="gid" VALUE="$gid">
+END
+
+if ( !$finger && $part_svc->part_svc_column('uid')->columnflag eq 'F' ) {
+ print '<INPUT TYPE="hidden" NAME="finger" VALUE="">';
+} else {
+ print '<TR><TD ALIGN="right">GECOS</TD>'.
+ qq!<TD><INPUT TYPE="text" NAME="finger" VALUE="$finger"></TD></TR>!;
+}
+print qq!<INPUT TYPE="hidden" NAME="dir" VALUE="$dir">!;
+
+my $shell = $svc_acct->shell;
+if ( $part_svc->part_svc_column('shell')->columnflag eq "F"
+ || ( !$shell && $part_svc->part_svc_column('uid')->columnflag eq 'F' )
+ ) {
+ print qq!<INPUT TYPE="hidden" NAME="shell" VALUE="$shell">!;
+} else {
+ print qq!<TR><TD ALIGN="right">Shell</TD><TD><SELECT NAME="shell" SIZE=1>!;
+ my($etc_shell);
+ foreach $etc_shell (@shells) {
+ print "<OPTION", $etc_shell eq $shell ? ' SELECTED' : '', ">",
+ $etc_shell, "\n";
+ }
+ print "</SELECT></TD></TR>";
+}
+
+my($quota,$slipip)=(
+ $svc_acct->quota,
+ $svc_acct->slipip,
+);
+
+if ( $part_svc->part_svc_column('quota')->columnflag eq "F" )
+{
+ print qq!<INPUT TYPE="hidden" NAME="quota" VALUE="$quota">!;
+} else {
+ print <<END;
+ <TR><TD ALIGN="right">Quota:</TD>
+ <TD> <INPUT TYPE="text" NAME="quota" VALUE="$quota" ></TD>
+ </TR>
+END
+}
+
+if ( $part_svc->part_svc_column('slipip')->columnflag eq "F" ) {
+ print qq!<INPUT TYPE="hidden" NAME="slipip" VALUE="$slipip">!;
+} else {
+ print qq!<TR><TD ALIGN="right">IP</TD><TD><INPUT TYPE="text" NAME="slipip" VALUE="$slipip"></TD></TR>!;
+}
+
+foreach my $r ( grep { /^r(adius|[cr])_/ } fields('svc_acct') ) {
+ $r =~ /^^r(adius|[cr])_(.+)$/ or next; #?
+ my $a = $2;
+ if ( $part_svc->part_svc_column($r)->columnflag eq 'F' ) {
+ print qq!<INPUT TYPE="hidden" NAME="$r" VALUE="!.
+ $svc_acct->getfield($r). '">';
+ } else {
+ print qq!<TR><TD ALIGN="right">$FS::raddb::attrib{$a}</TD><TD><INPUT TYPE="text" NAME="$r" VALUE="!.
+ $svc_acct->getfield($r). '"></TD></TR>';
+ }
+}
+
+print '<TR><TD ALIGN="right">RADIUS groups</TD>';
+if ( $part_svc->part_svc_column('usergroup')->columnflag eq "F" ) {
+ print '<TD BGCOLOR="#ffffff">'. join('<BR>', @groups);
+} else {
+ print '<TD>'. &FS::svc_acct::radius_usergroup_selector( \@groups );
+}
+print '</TD></TR>';
+
+foreach my $field ($svc_acct->virtual_fields) {
+ if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) {
+ # If the flag is X, it won't even show up in $svc_acct->virtual_fields.
+ print $svc_acct->pvf($field)->widget('HTML', 'edit',
+ $svc_acct->getfield($field));
+ }
+}
+
+#submit
+print qq!</TABLE><BR><INPUT TYPE="submit" VALUE="Submit">!;
+
+print <<END;
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/svc_acct_pop.cgi b/httemplate/edit/svc_acct_pop.cgi
new file mode 100755
index 0000000..399502a
--- /dev/null
+++ b/httemplate/edit/svc_acct_pop.cgi
@@ -0,0 +1,56 @@
+<!-- mason kludge -->
+<%
+
+my $svc_acct_pop;
+if ( $cgi->param('error') ) {
+ $svc_acct_pop = new FS::svc_acct_pop ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_acct_pop')
+ } );
+} elsif ( $cgi->keywords ) { #editing
+ my($query)=$cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $svc_acct_pop=qsearchs('svc_acct_pop',{'popnum'=>$1});
+} else { #adding
+ $svc_acct_pop = new FS::svc_acct_pop {};
+}
+my $action = $svc_acct_pop->popnum ? 'Edit' : 'Add';
+my $hashref = $svc_acct_pop->hashref;
+
+my $p1 = popurl(1);
+print header("$action Access Number", menubar(
+ 'Main Menu' => popurl(2),
+ 'View all Access Numbers' => popurl(2). "browse/svc_acct_pop.cgi",
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print qq!<FORM ACTION="${p1}process/svc_acct_pop.cgi" METHOD=POST>!;
+
+#display
+
+print qq!<INPUT TYPE="hidden" NAME="popnum" VALUE="$hashref->{popnum}">!,
+ "POP #", $hashref->{popnum} ? $hashref->{popnum} : "(NEW)";
+
+print <<END;
+<PRE>
+City <INPUT TYPE="text" NAME="city" SIZE=32 VALUE="$hashref->{city}">
+State <INPUT TYPE="text" NAME="state" SIZE=16 MAXLENGTH=16 VALUE="$hashref->{state}">
+Area Code <INPUT TYPE="text" NAME="ac" SIZE=4 MAXLENGTH=3 VALUE="$hashref->{ac}">
+Exchange <INPUT TYPE="text" NAME="exch" SIZE=4 MAXLENGTH=3 VALUE="$hashref->{exch}">
+Local <INPUT TYPE="text" NAME="loc" SIZE=5 MAXLENGTH=4 VALUE="$hashref->{loc}">
+</PRE>
+END
+
+print qq!<BR><INPUT TYPE="submit" VALUE="!,
+ $hashref->{popnum} ? "Apply changes" : "Add Access Number",
+ qq!">!;
+
+print <<END;
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/svc_broadband.cgi b/httemplate/edit/svc_broadband.cgi
new file mode 100644
index 0000000..9e064c5
--- /dev/null
+++ b/httemplate/edit/svc_broadband.cgi
@@ -0,0 +1,175 @@
+<!-- mason kludge -->
+<%
+
+# If it's stupid but it works, it's still stupid.
+# -Kristian
+
+
+use HTML::Widgets::SelectLayers;
+use Tie::IxHash;
+
+my( $svcnum, $pkgnum, $svcpart, $part_svc, $svc_broadband );
+if ( $cgi->param('error') ) {
+ $svc_broadband = new FS::svc_broadband ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_broadband'), qw(svcpart)
+ } );
+ $svcnum = $svc_broadband->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $svc_broadband->svcpart;
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+} else {
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_broadband=qsearchs('svc_broadband',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_broadband) svcnum!";
+
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
+
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
+
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ } else { #adding
+
+ foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
+ }
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ $svc_broadband = new FS::svc_broadband({ svcpart => $svcpart });
+
+ $svcnum='';
+
+ #set fixed and default fields from part_svc
+ foreach my $part_svc_column (
+ grep { $_->columnflag } $part_svc->all_part_svc_column
+ ) {
+ $svc_broadband->setfield( $part_svc_column->columnname,
+ $part_svc_column->columnvalue,
+ );
+ }
+
+ }
+}
+my $action = $svc_broadband->svcnum ? 'Edit' : 'Add';
+
+if ($pkgnum) {
+
+ #Nothing?
+
+} elsif ( $action eq 'Edit' ) {
+
+ #Nothing?
+
+} else {
+ die "\$action eq Add, but \$pkgnum is null!\n";
+}
+
+my $p1 = popurl(1);
+
+my ($ip_addr, $speed_up, $speed_down, $blocknum) =
+ ($svc_broadband->ip_addr,
+ $svc_broadband->speed_up,
+ $svc_broadband->speed_down,
+ $svc_broadband->blocknum);
+
+%>
+
+<%=header("Broadband Service $action", '')%>
+
+<% if ($cgi->param('error')) { %>
+<FONT SIZE="+1" COLOR="#ff0000">Error: <%=$cgi->param('error')%></FONT><BR>
+<% } %>
+
+Service #<B><%=$svcnum ? $svcnum : "(NEW)"%></B><BR><BR>
+
+<FORM ACTION="<%=${p1}%>process/svc_broadband.cgi" METHOD=POST>
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%=$svcnum%>">
+ <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<%=$pkgnum%>">
+ <INPUT TYPE="hidden" NAME="svcpart" VALUE="<%=$svcpart%>">
+
+ <%=&ntable("#cccccc",2)%>
+ <TR>
+ <TD ALIGN="right">IP Address</TD>
+ <TD BGCOLOR="#ffffff">
+<% if ( $part_svc->part_svc_column('ip_addr')->columnflag eq 'F' ) { %>
+ <INPUT TYPE="hidden" NAME="ip_addr" VALUE="<%=$ip_addr%>"><%=$ip_addr%>
+<% } else { %>
+ <INPUT TYPE="text" NAME="ip_addr" VALUE="<%=$ip_addr%>">
+<% } %>
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Download speed</TD>
+ <TD BGCOLOR="#ffffff">
+<% if ( $part_svc->part_svc_column('speed_down')->columnflag eq 'F' ) { %>
+ <INPUT TYPE="hidden" NAME="speed_down" VALUE="<%=$speed_down%>"><%=$speed_down%>Kbps
+<% } else { %>
+ <INPUT TYPE="text" NAME="speed_down" SIZE=5 VALUE="<%=$speed_down%>">Kbps
+<% } %>
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Upload speed</TD>
+ <TD BGCOLOR="#ffffff">
+<% if ( $part_svc->part_svc_column('speed_up')->columnflag eq 'F' ) { %>
+ <INPUT TYPE="hidden" NAME="speed_up" VALUE="<%=$speed_up%>"><%=$speed_up%>Kbps
+<% } else { %>
+ <INPUT TYPE="text" NAME="speed_up" SIZE=5 VALUE="<%=$speed_up%>">Kbps
+<% } %>
+ </TD>
+ </TR>
+<% if ($action eq 'Add') { %>
+ <TR>
+ <TD ALIGN="right">Router/Block</TD>
+ <TD BGCOLOR="#ffffff">
+ <SELECT NAME="blocknum">
+<%
+ warn $svc_broadband->svcpart;
+ foreach my $router ($svc_broadband->allowed_routers) {
+ warn $router->routername;
+ foreach my $addr_block ($router->addr_block) {
+%>
+ <OPTION VALUE="<%=$addr_block->blocknum%>"<%=($addr_block->blocknum eq $blocknum) ? ' SELECTED' : ''%>>
+ <%=$router->routername%>:<%=$addr_block->ip_gateway%>/<%=$addr_block->ip_netmask%></OPTION>
+<%
+ }
+ }
+%>
+ </SELECT>
+ </TD>
+ </TR>
+<% } else { %>
+
+ <TR>
+ <TD ALIGN="right">Router/Block</TD>
+ <TD BGCOLOR="#ffffff">
+ <%=$svc_broadband->addr_block->router->routername%>:<%=$svc_broadband->addr_block->NetAddr%>
+ <INPUT TYPE="hidden" NAME="blocknum" VALUE="<%=$svc_broadband->blocknum%>">
+ </TD>
+ </TR>
+
+<% } %>
+
+<%
+foreach my $field ($svc_broadband->virtual_fields) {
+ if ( $part_svc->part_svc_column($field)->columnflag ne 'F' &&
+ $part_svc->part_svc_column($field)->columnflag ne 'X') {
+ print $svc_broadband->pvf($field)->widget('HTML', 'edit',
+ $svc_broadband->getfield($field));
+ }
+} %>
+ </TABLE>
+ <BR>
+ <INPUT TYPE="submit" NAME="submit" VALUE="Submit">
+</FORM>
+</BODY>
+</HTML>
+
diff --git a/httemplate/edit/svc_domain.cgi b/httemplate/edit/svc_domain.cgi
new file mode 100755
index 0000000..ca0e339
--- /dev/null
+++ b/httemplate/edit/svc_domain.cgi
@@ -0,0 +1,98 @@
+<!-- mason kludge -->
+<%
+
+my($svcnum, $pkgnum, $svcpart, $kludge_action, $purpose, $part_svc,
+ $svc_domain);
+if ( $cgi->param('error') ) {
+ $svc_domain = new FS::svc_domain ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_domain')
+ } );
+ $svcnum = $svc_domain->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $cgi->param('svcpart');
+ $kludge_action = $cgi->param('action');
+ $purpose = $cgi->param('purpose');
+ $part_svc = qsearchs('part_svc', { 'svcpart' => $svcpart } );
+ die "No part_svc entry!" unless $part_svc;
+} else {
+ $kludge_action = '';
+ $purpose = '';
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_domain=qsearchs('svc_domain',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_domain) svcnum!";
+
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
+
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
+
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ } else { #adding
+
+ $svc_domain = new FS::svc_domain({});
+
+ foreach $_ (split(/-/,$query)) {
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
+ }
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ $svcnum='';
+
+ #set fixed and default fields from part_svc
+ foreach my $part_svc_column (
+ grep { $_->columnflag } $part_svc->all_part_svc_column
+ ) {
+ $svc_domain->setfield( $part_svc_column->columnname,
+ $part_svc_column->columnvalue,
+ );
+ }
+
+ }
+
+}
+my $action = $svcnum ? 'Edit' : 'Add';
+
+my $svc = $part_svc->getfield('svc');
+
+my $otaker = getotaker;
+
+my $domain = $svc_domain->domain;
+
+my $p1 = popurl(1);
+print header("$action $svc", '');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print <<END;
+ <FORM ACTION="${p1}process/svc_domain.cgi" METHOD=POST>
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum">
+ <INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">
+ <INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">
+END
+
+print qq!<INPUT TYPE="radio" NAME="action" VALUE="N"!;
+print ' CHECKED' if $kludge_action eq 'N';
+print qq!>New!;
+print qq!<BR><INPUT TYPE="radio" NAME="action" VALUE="M"!;
+print ' CHECKED' if $kludge_action eq 'M';
+print qq!>Transfer!;
+
+print <<END;
+<P>Domain <INPUT TYPE="text" NAME="domain" VALUE="$domain" SIZE=28 MAXLENGTH=63>
+<BR>Purpose/Description: <INPUT TYPE="text" NAME="purpose" VALUE="$purpose" SIZE=64>
+<P><INPUT TYPE="submit" VALUE="Submit">
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/edit/svc_external.cgi b/httemplate/edit/svc_external.cgi
new file mode 100644
index 0000000..bcfc85e
--- /dev/null
+++ b/httemplate/edit/svc_external.cgi
@@ -0,0 +1,105 @@
+<!-- mason kludge -->
+<%
+
+my( $svcnum, $pkgnum, $svcpart, $part_svc, $svc_external );
+if ( $cgi->param('error') ) {
+ $svc_external = new FS::svc_external ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_external')
+ } );
+ $svcnum = $svc_external->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $cgi->param('svcpart');
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+} else {
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_external=qsearchs('svc_external',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_external) svcnum!";
+
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
+
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
+
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ } else { #adding
+
+ foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
+ }
+ $svc_external = new FS::svc_external { svcpart => $svcpart };
+
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ $svcnum='';
+
+ #set fixed and default fields from part_svc
+ foreach my $part_svc_column (
+ grep { $_->columnflag } $part_svc->all_part_svc_column
+ ) {
+ $svc_external->setfield( $part_svc_column->columnname,
+ $part_svc_column->columnvalue,
+ );
+ }
+
+ }
+}
+my $action = $svc_external->svcnum ? 'Edit' : 'Add';
+
+my $p1 = popurl(1);
+print header("External service $action", '');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print qq!<FORM ACTION="${p1}process/svc_external.cgi" METHOD=POST>!;
+
+#display
+
+
+#svcnum
+print qq!<INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum">!;
+print qq!Service #<B>!, $svcnum ? $svcnum : "(NEW)", "</B><BR><BR>";
+
+#pkgnum
+print qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">!;
+
+#svcpart
+print qq!<INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">!;
+
+my($id,$title)=(
+ $svc_external->id,
+ $svc_external->title,
+);
+
+print &ntable("#cccccc",2),
+ '<TR><TD ALIGN="right">External ID</TD><TD>'.
+ qq!<INPUT TYPE="text" NAME="id" VALUE="$id">!.
+ '</TD></TR>'.
+ '<TR><TD ALIGN="right">Title</TD><TD>'.
+ qq!<INPUT TYPE="text" NAME="title" VALUE="$title">!.
+ '</TD></TR>';
+
+foreach my $field ($svc_external->virtual_fields) {
+ if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) {
+ # If the flag is X, it won't even show up in $svc_acct->virtual_fields.
+ print $svc_external->pvf($field)->widget('HTML', 'edit',
+ $svc_external->getfield($field));
+ }
+}
+
+%>
+
+</TABLE><BR><INPUT TYPE="submit" VALUE="Submit">
+ </FORM>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/edit/svc_forward.cgi b/httemplate/edit/svc_forward.cgi
new file mode 100755
index 0000000..2b9d35a
--- /dev/null
+++ b/httemplate/edit/svc_forward.cgi
@@ -0,0 +1,177 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+
+my($svcnum, $pkgnum, $svcpart, $part_svc, $svc_forward);
+if ( $cgi->param('error') ) {
+ $svc_forward = new FS::svc_forward ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_forward')
+ } );
+ $svcnum = $svc_forward->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $cgi->param('svcpart');
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+} else {
+
+ my($query) = $cgi->keywords;
+
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_forward=qsearchs('svc_forward',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_forward) svcnum!";
+
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
+
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
+
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ } else { #adding
+
+ $svc_forward = new FS::svc_forward({});
+
+ foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
+ }
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ $svcnum='';
+
+ #set fixed and default fields from part_svc
+ foreach my $part_svc_column (
+ grep { $_->columnflag } $part_svc->all_part_svc_column
+ ) {
+ $svc_forward->setfield( $part_svc_column->columnname,
+ $part_svc_column->columnvalue,
+ );
+ }
+ }
+
+}
+my $action = $svc_forward->svcnum ? 'Edit' : 'Add';
+
+my %email;
+
+#starting with those currently attached
+foreach my $method (qw( srcsvc_acct dstsvc_acct )) {
+ my $svc_acct = $svc_forward->$method();
+ $email{$svc_acct->svcnum} = $svc_acct->email if $svc_acct;
+}
+
+if ($pkgnum) {
+
+ #find all possible user svcnums (and emails)
+
+ #and including the rest for this customer
+ my($u_part_svc,@u_acct_svcparts);
+ foreach $u_part_svc ( qsearch('part_svc',{'svcdb'=>'svc_acct'}) ) {
+ push @u_acct_svcparts,$u_part_svc->getfield('svcpart');
+ }
+
+ my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+ my($custnum)=$cust_pkg->getfield('custnum');
+ my($i_cust_pkg);
+ foreach $i_cust_pkg ( qsearch('cust_pkg',{'custnum'=>$custnum}) ) {
+ my($cust_pkgnum)=$i_cust_pkg->getfield('pkgnum');
+ my($acct_svcpart);
+ foreach $acct_svcpart (@u_acct_svcparts) { #now find the corresponding
+ #record(s) in cust_svc ( for this
+ #pkgnum ! )
+ foreach my $i_cust_svc (
+ qsearch( 'cust_svc', { 'pkgnum' => $cust_pkgnum,
+ 'svcpart' => $acct_svcpart } )
+ ) {
+ my $svc_acct =
+ qsearchs( 'svc_acct', { 'svcnum' => $i_cust_svc->svcnum } );
+ $email{$svc_acct->svcnum} = $svc_acct->email;
+ }
+ }
+ }
+
+} elsif ( $action eq 'Add' ) {
+ die "\$action eq Add, but \$pkgnum is null!\n";
+}
+
+my($srcsvc,$dstsvc,$dst)=(
+ $svc_forward->srcsvc,
+ $svc_forward->dstsvc,
+ $svc_forward->dst,
+);
+my $src = $svc_forward->dbdef_table->column('src') ? $svc_forward->src : '';
+
+#display
+
+%>
+
+<%= header("Mail Forward $action") %>
+
+<% if ( $cgi->param('error') ) { %>
+ <FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT>
+ <BR><BR>
+<% } %>
+
+Service #<%= $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR>
+Service: <B><%= $part_svc->svc %></B><BR><BR>
+
+<FORM ACTION="process/svc_forward.cgi" METHOD="POST">
+<INPUT TYPE="hidden" NAME="svcnum" VALUE="<%= $svcnum %>">
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<%= $pkgnum %>">
+<INPUT TYPE="hidden" NAME="svcpart" VALUE="<%= $svcpart %>">
+
+<SCRIPT TYPE="text/javascript">
+function srcchanged(what) {
+ if ( what.options[what.selectedIndex].value == 0 ) {
+ what.form.src.disabled = false;
+ what.form.src.style.backgroundColor = "white";
+ } else {
+ what.form.src.disabled = true;
+ what.form.src.style.backgroundColor = "lightgrey";
+ }
+}
+function dstchanged(what) {
+ if ( what.options[what.selectedIndex].value == 0 ) {
+ what.form.dst.disabled = false;
+ what.form.dst.style.backgroundColor = "white";
+ } else {
+ what.form.dst.disabled = true;
+ what.form.dst.style.backgroundColor = "lightgrey";
+ }
+}
+</SCRIPT>
+
+<%= ntable("#cccccc",2) %>
+<TR><TD ALIGN="right">Email to</TD>
+<TD><SELECT NAME="srcsvc" SIZE=1 onChange="srcchanged(this)">
+<% foreach $_ (keys %email) { %>
+ <OPTION<%= $_ eq $srcsvc ? " SELECTED" : "" %> VALUE="<%= $_ %>"><%= $email{$_} %></OPTION>
+<% } %>
+<% if ( $svc_forward->dbdef_table->column('src') ) { %>
+ <OPTION <%= $src ? 'SELECTED' : '' %> VALUE="0">(other email address)</OPTION>
+<% } %>
+</SELECT>
+<% if ( $svc_forward->dbdef_table->column('src') ) { %>
+<INPUT TYPE="text" NAME="src" VALUE="<%= $src %>" <%= ( $src || !scalar(%email) ) ? '' : 'DISABLED STYLE="background-color: lightgrey"' %>>
+<% } %>
+</TD></TR>
+
+<TR><TD ALIGN="right">Forwards to</TD>
+<TD><SELECT NAME="dstsvc" SIZE=1 onChange="dstchanged(this)">
+<% foreach $_ (keys %email) { %>
+ <OPTION<%= $_ eq $dstsvc ? " SELECTED" : "" %> VALUE="<%= $_ %>"><%= $email{$_} %></OPTION>
+<% } %>
+<OPTION <%= $dst ? 'SELECTED' : '' %> VALUE="0">(other email address)</OPTION>
+</SELECT>
+<INPUT TYPE="text" NAME="dst" VALUE="<%= $dst %>" <%= ( $dst || !scalar(%email) ) ? '' : 'DISABLED STYLE="background-color: lightgrey"' %>>
+</TD></TR>
+ </TABLE>
+<BR><INPUT TYPE="submit" VALUE="Submit">
+</FORM>
+ </BODY>
+</HTML>
diff --git a/httemplate/edit/svc_www.cgi b/httemplate/edit/svc_www.cgi
new file mode 100644
index 0000000..4989bb6
--- /dev/null
+++ b/httemplate/edit/svc_www.cgi
@@ -0,0 +1,221 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+
+my( $svcnum, $pkgnum, $svcpart, $part_svc, $svc_www );
+if ( $cgi->param('error') ) {
+ $svc_www = new FS::svc_www ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_www')
+ } );
+ $svcnum = $svc_www->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $cgi->param('svcpart');
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+} else {
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_www=qsearchs('svc_www',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_www) svcnum!";
+
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
+
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
+
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ } else { #adding
+
+ foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
+ }
+ $svc_www = new FS::svc_www { svcpart => $svcpart };
+
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ $svcnum='';
+
+ #set fixed and default fields from part_svc
+ foreach my $part_svc_column (
+ grep { $_->columnflag } $part_svc->all_part_svc_column
+ ) {
+ $svc_www->setfield( $part_svc_column->columnname,
+ $part_svc_column->columnvalue,
+ );
+ }
+
+ }
+}
+my $action = $svc_www->svcnum ? 'Edit' : 'Add';
+
+my( %svc_acct, %arec );
+if ($pkgnum) {
+
+ my @u_acct_svcparts;
+ foreach my $svcpart (
+ map { $_->svcpart } qsearch( 'part_svc', { 'svcdb' => 'svc_acct' } )
+ ) {
+ next if $conf->exists('svc_www-usersvc_svcpart')
+ && ! grep { $svcpart == $_ }
+ $conf->config('svc_www-usersvc_svcpart');
+ push @u_acct_svcparts, $svcpart;
+ }
+
+ my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+ my($custnum)=$cust_pkg->getfield('custnum');
+ my($i_cust_pkg);
+ foreach $i_cust_pkg ( qsearch('cust_pkg',{'custnum'=>$custnum}) ) {
+ my($cust_pkgnum)=$i_cust_pkg->getfield('pkgnum');
+ my($acct_svcpart);
+ foreach $acct_svcpart (@u_acct_svcparts) { #now find the corresponding
+ #record(s) in cust_svc ( for this
+ #pkgnum ! )
+ my($i_cust_svc);
+ foreach $i_cust_svc ( qsearch('cust_svc',{'pkgnum'=>$cust_pkgnum,'svcpart'=>$acct_svcpart}) ) {
+ my($svc_acct)=qsearchs('svc_acct',{'svcnum'=>$i_cust_svc->getfield('svcnum')});
+ $svc_acct{$svc_acct->getfield('svcnum')}=
+ $svc_acct->cust_svc->part_svc->svc. ': '. $svc_acct->email;
+ }
+ }
+ }
+
+
+ my($d_part_svc,@d_acct_svcparts);
+ foreach $d_part_svc ( qsearch('part_svc',{'svcdb'=>'svc_domain'}) ) {
+ push @d_acct_svcparts,$d_part_svc->getfield('svcpart');
+ }
+
+ foreach $i_cust_pkg ( qsearch( 'cust_pkg', { 'custnum' => $custnum } ) ) {
+ my $cust_pkgnum = $i_cust_pkg->pkgnum;
+
+ foreach my $acct_svcpart (@d_acct_svcparts) {
+
+ foreach my $i_cust_svc (
+ qsearch( 'cust_svc', { 'pkgnum' => $cust_pkgnum,
+ 'svcpart' => $acct_svcpart } )
+ ) {
+ my $svc_domain =
+ qsearchs( 'svc_domain', { 'svcnum' => $i_cust_svc->svcnum } );
+
+ my $extra_sql = "AND ( rectype = 'A' OR rectype = 'CNAME' )";
+ unless ( $conf->exists('svc_www-enable_subdomains') ) {
+ $extra_sql .= " AND ( reczone = '\@' OR reczone = '".
+ $svc_domain->domain. ".' )";
+ }
+
+ foreach my $domain_rec (
+ qsearch( 'domain_record',
+ {
+ 'svcnum' => $svc_domain->svcnum,
+ },
+ '',
+ $extra_sql,
+ )
+ ) {
+ $arec{$domain_rec->recnum} = $domain_rec->zone;
+ }
+
+ if ( $conf->exists('svc_www-enable_subdomains') ) {
+ $arec{'www.'. $svc_domain->domain} = 'www.'. $svc_domain->domain
+ unless qsearchs( 'domain_record', {
+ svcnum => $svc_domain->svcnum,
+ reczone => 'www',
+ } )
+ || qsearchs( 'domain_record', {
+ svcnum => $svc_domain->svcnum,
+ reczone => 'www.'.$svc-domain->domain.'.',
+ } );
+ }
+
+ $arec{'@.'. $svc_domain->domain} = $svc_domain->domain
+ unless qsearchs('domain_record', {
+ svcnum => $svc_domain->svcnum,
+ reczone => '@',
+ } )
+ || qsearchs('domain_record', {
+ svcnum => $svc_domain->svcnum,
+ reczone => $svc_domain->domain.'.',
+ } );
+
+ }
+
+ }
+ }
+
+} elsif ( $action eq 'Edit' ) {
+
+ my($domain_rec) = qsearchs('domain_record', { 'recnum'=>$svc_www->recnum });
+ $arec{$svc_www->recnum} = join '.', $domain_rec->recdata, $domain_rec->reczone;
+
+} else {
+ die "\$action eq Add, but \$pkgnum is null!\n";
+}
+
+
+my $p1 = popurl(1);
+print header("Web Hosting $action", '');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print qq!<FORM ACTION="${p1}process/svc_www.cgi" METHOD=POST>!;
+
+#display
+
+
+
+#svcnum
+print qq!<INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum">!;
+print qq!Service #<B>!, $svcnum ? $svcnum : "(NEW)", "</B><BR><BR>";
+
+#pkgnum
+print qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">!;
+
+#svcpart
+print qq!<INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">!;
+
+my($recnum,$usersvc)=(
+ $svc_www->recnum,
+ $svc_www->usersvc,
+);
+
+print &ntable("#cccccc",2),
+ '<TR><TD ALIGN="right">Zone</TD><TD><SELECT NAME="recnum" SIZE=1>';
+foreach $_ (keys %arec) {
+ print "<OPTION", $_ eq $recnum ? " SELECTED" : "",
+ qq! VALUE="$_">$arec{$_}!;
+}
+print "</SELECT></TD></TR>";
+
+print '<TR><TD ALIGN="right">Username</TD><TD><SELECT NAME="usersvc" SIZE=1>';
+foreach $_ (keys %svc_acct) {
+ print "<OPTION", ($_ eq $usersvc) ? " SELECTED" : "",
+ qq! VALUE="$_">$svc_acct{$_}!;
+}
+print "</SELECT></TD></TR>";
+
+foreach my $field ($svc_www->virtual_fields) {
+ if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) {
+ # If the flag is X, it won't even show up in $svc_acct->virtual_fields.
+ print $svc_www->pvf($field)->widget('HTML', 'edit',
+ $svc_www->getfield($field));
+ }
+}
+
+print '</TABLE><BR><INPUT TYPE="submit" VALUE="Submit">';
+
+print <<END;
+
+ </FORM>
+ </BODY>
+</HTML>
+END
+%>
diff --git a/httemplate/elements/calendar-en.js b/httemplate/elements/calendar-en.js
new file mode 100644
index 0000000..e9291e1
--- /dev/null
+++ b/httemplate/elements/calendar-en.js
@@ -0,0 +1,114 @@
+// ** I18N
+
+// Calendar EN language
+// Author: Mihai Bazon, <mishoo@infoiasi.ro>
+// Encoding: any
+// Distributed under the same terms as the calendar itself.
+
+// For translators: please use UTF-8 if possible. We strongly believe that
+// Unicode is the answer to a real internationalized world. Also please
+// include your contact information in the header, as can be seen above.
+
+// full day names
+Calendar._DN = new Array
+("Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday");
+
+// Please note that the following array of short day names (and the same goes
+// for short month names, _SMN) isn't absolutely necessary. We give it here
+// for exemplification on how one can customize the short day names, but if
+// they are simply the first N letters of the full name you can simply say:
+//
+// Calendar._SDN_len = N; // short day name length
+// Calendar._SMN_len = N; // short month name length
+//
+// If N = 3 then this is not needed either since we assume a value of 3 if not
+// present, to be compatible with translation files that were written before
+// this feature.
+
+// short day names
+Calendar._SDN = new Array
+("Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat",
+ "Sun");
+
+// full month names
+Calendar._MN = new Array
+("January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December");
+
+// short month names
+Calendar._SMN = new Array
+("Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec");
+
+// tooltips
+Calendar._TT = {};
+Calendar._TT["INFO"] = "About the calendar";
+
+Calendar._TT["ABOUT"] =
+"DHTML Date/Time Selector\n" +
+"(c) dynarch.com 2002-2003\n" + // don't translate this this ;-)
+"For latest version visit: http://dynarch.com/mishoo/calendar.epl\n" +
+"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." +
+"\n\n" +
+"Date selection:\n" +
+"- Use the \xab, \xbb buttons to select year\n" +
+"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" +
+"- Hold mouse button on any of the above buttons for faster selection.";
+Calendar._TT["ABOUT_TIME"] = "\n\n" +
+"Time selection:\n" +
+"- Click on any of the time parts to increase it\n" +
+"- or Shift-click to decrease it\n" +
+"- or click and drag for faster selection.";
+
+Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)";
+Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)";
+Calendar._TT["GO_TODAY"] = "Go Today";
+Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)";
+Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)";
+Calendar._TT["SEL_DATE"] = "Select date";
+Calendar._TT["DRAG_TO_MOVE"] = "Drag to move";
+Calendar._TT["PART_TODAY"] = " (today)";
+Calendar._TT["MON_FIRST"] = "Display Monday first";
+Calendar._TT["SUN_FIRST"] = "Display Sunday first";
+Calendar._TT["CLOSE"] = "Close";
+Calendar._TT["TODAY"] = "Today";
+Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value";
+
+// date formats
+Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d";
+Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";
+
+Calendar._TT["WK"] = "wk";
diff --git a/httemplate/elements/calendar-setup.js b/httemplate/elements/calendar-setup.js
new file mode 100644
index 0000000..0dc3caa
--- /dev/null
+++ b/httemplate/elements/calendar-setup.js
@@ -0,0 +1,163 @@
+/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/
+ * ---------------------------------------------------------------------------
+ *
+ * The DHTML Calendar
+ *
+ * Details and latest version at:
+ * http://dynarch.com/mishoo/calendar.epl
+ *
+ * This script is distributed under the GNU Lesser General Public License.
+ * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
+ *
+ * This file defines helper functions for setting up the calendar. They are
+ * intended to help non-programmers get a working calendar on their site
+ * quickly. This script should not be seen as part of the calendar. It just
+ * shows you what one can do with the calendar, while in the same time
+ * providing a quick and simple method for setting it up. If you need
+ * exhaustive customization of the calendar creation process feel free to
+ * modify this code to suit your needs (this is recommended and much better
+ * than modifying calendar.js itself).
+ */
+
+// $Id: calendar-setup.js,v 1.3 2003-11-07 10:53:35 ivan Exp $
+
+/**
+ * This function "patches" an input field (or other element) to use a calendar
+ * widget for date selection.
+ *
+ * The "params" is a single object that can have the following properties:
+ *
+ * prop. name | description
+ * -------------------------------------------------------------------------------------------------
+ * inputField | the ID of an input field to store the date
+ * displayArea | the ID of a DIV or other element to show the date
+ * button | ID of a button or other element that will trigger the calendar
+ * eventName | event that will trigger the calendar, without the "on" prefix (default: "click")
+ * ifFormat | date format that will be stored in the input field
+ * daFormat | the date format that will be used to display the date in displayArea
+ * singleClick | (true/false) wether the calendar is in single click mode or not (default: true)
+ * mondayFirst | (true/false) if true Monday is the first day of week, Sunday otherwise (default: true)
+ * align | alignment (default: "Bl"); if you don't know what's this see the calendar documentation
+ * range | array with 2 elements. Default: [1900, 2999] -- the range of years available
+ * weekNumbers | (true/false) if it's true (default) the calendar will display week numbers
+ * flat | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
+ * flatCallback | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
+ * disableFunc | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
+ * onSelect | function that gets called when a date is selected. You don't _have_ to supply this (the default is generally okay)
+ * onClose | function that gets called when the calendar is closed. [default]
+ * onUpdate | function that gets called after the date is updated in the input field. Receives a reference to the calendar.
+ * date | the date that the calendar will be initially displayed to
+ * showsTime | default: false; if true the calendar will include a time selector
+ * timeFormat | the time format; can be "12" or "24", default is "12"
+ *
+ * None of them is required, they all have default values. However, if you
+ * pass none of "inputField", "displayArea" or "button" you'll get a warning
+ * saying "nothing to setup".
+ */
+Calendar.setup = function (params) {
+ function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };
+
+ param_default("inputField", null);
+ param_default("displayArea", null);
+ param_default("button", null);
+ param_default("eventName", "click");
+ param_default("ifFormat", "%Y/%m/%d");
+ param_default("daFormat", "%Y/%m/%d");
+ param_default("singleClick", true);
+ param_default("disableFunc", null);
+ param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined
+ param_default("mondayFirst", true);
+ param_default("align", "Bl");
+ param_default("range", [1900, 2999]);
+ param_default("weekNumbers", true);
+ param_default("flat", null);
+ param_default("flatCallback", null);
+ param_default("onSelect", null);
+ param_default("onClose", null);
+ param_default("onUpdate", null);
+ param_default("date", null);
+ param_default("showsTime", false);
+ param_default("timeFormat", "24");
+
+ var tmp = ["inputField", "displayArea", "button"];
+ for (var i in tmp) {
+ if (typeof params[tmp[i]] == "string") {
+ params[tmp[i]] = document.getElementById(params[tmp[i]]);
+ }
+ }
+ if (!(params.flat || params.inputField || params.displayArea || params.button)) {
+ alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code");
+ return false;
+ }
+
+ function onSelect(cal) {
+ if (cal.params.flat) {
+ if (typeof cal.params.flatCallback == "function") {
+ cal.params.flatCallback(cal);
+ } else {
+ alert("No flatCallback given -- doing nothing.");
+ }
+ return false;
+ }
+ if (cal.params.inputField) {
+ cal.params.inputField.value = cal.date.print(cal.params.ifFormat);
+ }
+ if (cal.params.displayArea) {
+ cal.params.displayArea.innerHTML = cal.date.print(cal.params.daFormat);
+ }
+ if (cal.params.singleClick && cal.dateClicked) {
+ cal.callCloseHandler();
+ }
+ if (typeof cal.params.onUpdate == "function") {
+ cal.params.onUpdate(cal);
+ }
+ };
+
+ if (params.flat != null) {
+ params.flat = document.getElementById(params.flat);
+ if (!params.flat) {
+ alert("Calendar.setup:\n Flat specified but can't find parent.");
+ return false;
+ }
+ var cal = new Calendar(params.mondayFirst, params.date, params.onSelect || onSelect);
+ cal.showsTime = params.showsTime;
+ cal.time24 = (params.timeFormat == "24");
+ cal.params = params;
+ cal.weekNumbers = params.weekNumbers;
+ cal.setRange(params.range[0], params.range[1]);
+ cal.setDateStatusHandler(params.dateStatusFunc);
+ cal.create(params.flat);
+ cal.show();
+ return false;
+ }
+
+ var triggerEl = params.button || params.displayArea || params.inputField;
+ triggerEl["on" + params.eventName] = function() {
+ var dateEl = params.inputField || params.displayArea;
+ var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
+ var mustCreate = false;
+ var cal = window.calendar;
+ if (!window.calendar) {
+ window.calendar = cal = new Calendar(params.mondayFirst,
+ params.date,
+ params.onSelect || onSelect,
+ params.onClose || function(cal) { cal.hide(); });
+ cal.showsTime = params.showsTime;
+ cal.time24 = (params.timeFormat == "24");
+ cal.weekNumbers = params.weekNumbers;
+ mustCreate = true;
+ } else {
+ cal.hide();
+ }
+ cal.setRange(params.range[0], params.range[1]);
+ cal.params = params;
+ cal.setDateStatusHandler(params.dateStatusFunc);
+ cal.setDateFormat(dateFmt);
+ if (mustCreate)
+ cal.create();
+ cal.parseDate(dateEl.value || dateEl.innerHTML);
+ cal.refresh();
+ cal.showAtElement(params.displayArea || params.inputField, params.align);
+ return false;
+ };
+};
diff --git a/httemplate/elements/calendar-win2k-2.css b/httemplate/elements/calendar-win2k-2.css
new file mode 100644
index 0000000..9727d1b
--- /dev/null
+++ b/httemplate/elements/calendar-win2k-2.css
@@ -0,0 +1,263 @@
+/* The main calendar widget. DIV containing a table. */
+
+.calendar {
+ position: relative;
+ display: none;
+ border-top: 2px solid #fff;
+ border-right: 2px solid #000;
+ border-bottom: 2px solid #000;
+ border-left: 2px solid #fff;
+ font-size: 11px;
+ color: #000;
+ cursor: default;
+ background: #d4c8d0;
+ font-family: tahoma,verdana,sans-serif;
+}
+
+.calendar table {
+ border-top: 1px solid #000;
+ border-right: 1px solid #fff;
+ border-bottom: 1px solid #fff;
+ border-left: 1px solid #000;
+ font-size: 11px;
+ color: #000;
+ cursor: default;
+ background: #d4c8d0;
+ font-family: tahoma,verdana,sans-serif;
+}
+
+/* Header part -- contains navigation buttons and day names. */
+
+.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */
+ text-align: center;
+ padding: 1px;
+ border-top: 1px solid #fff;
+ border-right: 1px solid #000;
+ border-bottom: 1px solid #000;
+ border-left: 1px solid #fff;
+}
+
+.calendar .nav {
+ background: transparent url(menuarrow.gif) no-repeat 100% 100%;
+}
+
+.calendar thead .title { /* This holds the current "month, year" */
+ font-weight: bold;
+ padding: 1px;
+ border: 1px solid #000;
+ background: #847880;
+ color: #fff;
+ text-align: center;
+}
+
+.calendar thead .headrow { /* Row <TR> containing navigation buttons */
+}
+
+.calendar thead .daynames { /* Row <TR> containing the day names */
+}
+
+.calendar thead .name { /* Cells <TD> containing the day names */
+ border-bottom: 1px solid #000;
+ padding: 2px;
+ text-align: center;
+ background: #f4e8f0;
+}
+
+.calendar thead .weekend { /* How a weekend day name shows in header */
+ color: #f00;
+}
+
+.calendar thead .hilite { /* How do the buttons in header appear when hover */
+ border-top: 2px solid #fff;
+ border-right: 2px solid #000;
+ border-bottom: 2px solid #000;
+ border-left: 2px solid #fff;
+ padding: 0px;
+ background-color: #e4d8e0;
+}
+
+.calendar thead .active { /* Active (pressed) buttons in header */
+ padding: 2px 0px 0px 2px;
+ border-top: 1px solid #000;
+ border-right: 1px solid #fff;
+ border-bottom: 1px solid #fff;
+ border-left: 1px solid #000;
+ background-color: #c4b8c0;
+}
+
+/* The body part -- contains all the days in month. */
+
+.calendar tbody .day { /* Cells <TD> containing month days dates */
+ width: 2em;
+ text-align: right;
+ padding: 2px 4px 2px 2px;
+}
+
+.calendar table .wn {
+ padding: 2px 3px 2px 2px;
+ border-right: 1px solid #000;
+ background: #f4e8f0;
+}
+
+.calendar tbody .rowhilite td {
+ background: #e4d8e0;
+}
+
+.calendar tbody .rowhilite td.wn {
+ background: #d4c8d0;
+}
+
+.calendar tbody td.hilite { /* Hovered cells <TD> */
+ padding: 1px 3px 1px 1px;
+ border-top: 1px solid #fff;
+ border-right: 1px solid #000;
+ border-bottom: 1px solid #000;
+ border-left: 1px solid #fff;
+}
+
+.calendar tbody td.active { /* Active (pressed) cells <TD> */
+ padding: 2px 2px 0px 2px;
+ border-top: 1px solid #000;
+ border-right: 1px solid #fff;
+ border-bottom: 1px solid #fff;
+ border-left: 1px solid #000;
+}
+
+.calendar tbody td.selected { /* Cell showing selected date */
+ font-weight: bold;
+ border-top: 1px solid #000;
+ border-right: 1px solid #fff;
+ border-bottom: 1px solid #fff;
+ border-left: 1px solid #000;
+ padding: 2px 2px 0px 2px;
+ background: #e4d8e0;
+}
+
+.calendar tbody td.weekend { /* Cells showing weekend days */
+ color: #f00;
+}
+
+.calendar tbody td.today { /* Cell showing today date */
+ font-weight: bold;
+ color: #00f;
+}
+
+.calendar tbody .disabled { color: #999; }
+
+.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */
+ visibility: hidden;
+}
+
+.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */
+ display: none;
+}
+
+/* The footer part -- status bar and "Close" button */
+
+.calendar tfoot .footrow { /* The <TR> in footer (only one right now) */
+}
+
+.calendar tfoot .ttip { /* Tooltip (status bar) cell <TD> */
+ background: #f4e8f0;
+ padding: 1px;
+ border: 1px solid #000;
+ background: #847880;
+ color: #fff;
+ text-align: center;
+}
+
+.calendar tfoot .hilite { /* Hover style for buttons in footer */
+ border-top: 1px solid #fff;
+ border-right: 1px solid #000;
+ border-bottom: 1px solid #000;
+ border-left: 1px solid #fff;
+ padding: 1px;
+ background: #e4d8e0;
+}
+
+.calendar tfoot .active { /* Active (pressed) style for buttons in footer */
+ padding: 2px 0px 0px 2px;
+ border-top: 1px solid #000;
+ border-right: 1px solid #fff;
+ border-bottom: 1px solid #fff;
+ border-left: 1px solid #000;
+}
+
+/* Combo boxes (menus that display months/years for direct selection) */
+
+.combo {
+ position: absolute;
+ display: none;
+ width: 4em;
+ top: 0px;
+ left: 0px;
+ cursor: default;
+ border-top: 1px solid #fff;
+ border-right: 1px solid #000;
+ border-bottom: 1px solid #000;
+ border-left: 1px solid #fff;
+ background: #e4d8e0;
+ font-size: smaller;
+ padding: 1px;
+}
+
+.combo .label,
+.combo .label-IEfix {
+ text-align: center;
+ padding: 1px;
+}
+
+.combo .label-IEfix {
+ width: 4em;
+}
+
+.combo .active {
+ background: #d4c8d0;
+ padding: 0px;
+ border-top: 1px solid #000;
+ border-right: 1px solid #fff;
+ border-bottom: 1px solid #fff;
+ border-left: 1px solid #000;
+}
+
+.combo .hilite {
+ background: #408;
+ color: #fea;
+}
+
+.calendar td.time {
+ border-top: 1px solid #000;
+ padding: 1px 0px;
+ text-align: center;
+ background-color: #f4f0e8;
+}
+
+.calendar td.time .hour,
+.calendar td.time .minute,
+.calendar td.time .ampm {
+ padding: 0px 3px 0px 4px;
+ border: 1px solid #889;
+ font-weight: bold;
+ background-color: #fff;
+}
+
+.calendar td.time .ampm {
+ text-align: center;
+}
+
+.calendar td.time .colon {
+ padding: 0px 2px 0px 3px;
+ font-weight: bold;
+}
+
+.calendar td.time span.hilite {
+ border-color: #000;
+ background-color: #766;
+ color: #fff;
+}
+
+.calendar td.time span.active {
+ border-color: #f00;
+ background-color: #000;
+ color: #0f0;
+}
diff --git a/httemplate/elements/calendar.js b/httemplate/elements/calendar.js
new file mode 100644
index 0000000..3c028cc
--- /dev/null
+++ b/httemplate/elements/calendar.js
@@ -0,0 +1,1641 @@
+/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/
+ * ------------------------------------------------------------------
+ *
+ * The DHTML Calendar, version 0.9.5 "Your favorite time, bis"
+ *
+ * Details and latest version at:
+ * http://dynarch.com/mishoo/calendar.epl
+ *
+ * This script is distributed under the GNU Lesser General Public License.
+ * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
+ */
+
+// $Id: calendar.js,v 1.3 2003-11-07 10:53:35 ivan Exp $
+
+/** The Calendar object constructor. */
+Calendar = function (mondayFirst, dateStr, onSelected, onClose) {
+ // member variables
+ this.activeDiv = null;
+ this.currentDateEl = null;
+ this.getDateStatus = null;
+ this.timeout = null;
+ this.onSelected = onSelected || null;
+ this.onClose = onClose || null;
+ this.dragging = false;
+ this.hidden = false;
+ this.minYear = 1970;
+ this.maxYear = 2050;
+ this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"];
+ this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"];
+ this.isPopup = true;
+ this.weekNumbers = true;
+ this.mondayFirst = mondayFirst;
+ this.dateStr = dateStr;
+ this.ar_days = null;
+ this.showsTime = false;
+ this.time24 = true;
+ // HTML elements
+ this.table = null;
+ this.element = null;
+ this.tbody = null;
+ this.firstdayname = null;
+ // Combo boxes
+ this.monthsCombo = null;
+ this.yearsCombo = null;
+ this.hilitedMonth = null;
+ this.activeMonth = null;
+ this.hilitedYear = null;
+ this.activeYear = null;
+ // Information
+ this.dateClicked = false;
+
+ // one-time initializations
+ if (typeof Calendar._SDN == "undefined") {
+ // table of short day names
+ if (typeof Calendar._SDN_len == "undefined")
+ Calendar._SDN_len = 3;
+ var ar = new Array();
+ for (var i = 8; i > 0;) {
+ ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len);
+ }
+ Calendar._SDN = ar;
+ // table of short month names
+ if (typeof Calendar._SMN_len == "undefined")
+ Calendar._SMN_len = 3;
+ ar = new Array();
+ for (var i = 12; i > 0;) {
+ ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len);
+ }
+ Calendar._SMN = ar;
+ }
+};
+
+// ** constants
+
+/// "static", needed for event handlers.
+Calendar._C = null;
+
+/// detect a special case of "web browser"
+Calendar.is_ie = ( /msie/i.test(navigator.userAgent) &&
+ !/opera/i.test(navigator.userAgent) );
+
+/// detect Opera browser
+Calendar.is_opera = /opera/i.test(navigator.userAgent);
+
+/// detect KHTML-based browsers
+Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent);
+
+// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate
+// library, at some point.
+
+Calendar.getAbsolutePos = function(el) {
+ var SL = 0, ST = 0;
+ var is_div = /^div$/i.test(el.tagName);
+ if (is_div && el.scrollLeft)
+ SL = el.scrollLeft;
+ if (is_div && el.scrollTop)
+ ST = el.scrollTop;
+ var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
+ if (el.offsetParent) {
+ var tmp = Calendar.getAbsolutePos(el.offsetParent);
+ r.x += tmp.x;
+ r.y += tmp.y;
+ }
+ return r;
+};
+
+Calendar.isRelated = function (el, evt) {
+ var related = evt.relatedTarget;
+ if (!related) {
+ var type = evt.type;
+ if (type == "mouseover") {
+ related = evt.fromElement;
+ } else if (type == "mouseout") {
+ related = evt.toElement;
+ }
+ }
+ while (related) {
+ if (related == el) {
+ return true;
+ }
+ related = related.parentNode;
+ }
+ return false;
+};
+
+Calendar.removeClass = function(el, className) {
+ if (!(el && el.className)) {
+ return;
+ }
+ var cls = el.className.split(" ");
+ var ar = new Array();
+ for (var i = cls.length; i > 0;) {
+ if (cls[--i] != className) {
+ ar[ar.length] = cls[i];
+ }
+ }
+ el.className = ar.join(" ");
+};
+
+Calendar.addClass = function(el, className) {
+ Calendar.removeClass(el, className);
+ el.className += " " + className;
+};
+
+Calendar.getElement = function(ev) {
+ if (Calendar.is_ie) {
+ return window.event.srcElement;
+ } else {
+ return ev.currentTarget;
+ }
+};
+
+Calendar.getTargetElement = function(ev) {
+ if (Calendar.is_ie) {
+ return window.event.srcElement;
+ } else {
+ return ev.target;
+ }
+};
+
+Calendar.stopEvent = function(ev) {
+ ev || (ev = window.event);
+ if (Calendar.is_ie) {
+ ev.cancelBubble = true;
+ ev.returnValue = false;
+ } else {
+ ev.preventDefault();
+ ev.stopPropagation();
+ }
+ return false;
+};
+
+Calendar.addEvent = function(el, evname, func) {
+ if (el.attachEvent) { // IE
+ el.attachEvent("on" + evname, func);
+ } else if (el.addEventListener) { // Gecko / W3C
+ el.addEventListener(evname, func, true);
+ } else {
+ el["on" + evname] = func;
+ }
+};
+
+Calendar.removeEvent = function(el, evname, func) {
+ if (el.detachEvent) { // IE
+ el.detachEvent("on" + evname, func);
+ } else if (el.removeEventListener) { // Gecko / W3C
+ el.removeEventListener(evname, func, true);
+ } else {
+ el["on" + evname] = null;
+ }
+};
+
+Calendar.createElement = function(type, parent) {
+ var el = null;
+ if (document.createElementNS) {
+ // use the XHTML namespace; IE won't normally get here unless
+ // _they_ "fix" the DOM2 implementation.
+ el = document.createElementNS("http://www.w3.org/1999/xhtml", type);
+ } else {
+ el = document.createElement(type);
+ }
+ if (typeof parent != "undefined") {
+ parent.appendChild(el);
+ }
+ return el;
+};
+
+// END: UTILITY FUNCTIONS
+
+// BEGIN: CALENDAR STATIC FUNCTIONS
+
+/** Internal -- adds a set of events to make some element behave like a button. */
+Calendar._add_evs = function(el) {
+ with (Calendar) {
+ addEvent(el, "mouseover", dayMouseOver);
+ addEvent(el, "mousedown", dayMouseDown);
+ addEvent(el, "mouseout", dayMouseOut);
+ if (is_ie) {
+ addEvent(el, "dblclick", dayMouseDblClick);
+ el.setAttribute("unselectable", true);
+ }
+ }
+};
+
+Calendar.findMonth = function(el) {
+ if (typeof el.month != "undefined") {
+ return el;
+ } else if (typeof el.parentNode.month != "undefined") {
+ return el.parentNode;
+ }
+ return null;
+};
+
+Calendar.findYear = function(el) {
+ if (typeof el.year != "undefined") {
+ return el;
+ } else if (typeof el.parentNode.year != "undefined") {
+ return el.parentNode;
+ }
+ return null;
+};
+
+Calendar.showMonthsCombo = function () {
+ var cal = Calendar._C;
+ if (!cal) {
+ return false;
+ }
+ var cal = cal;
+ var cd = cal.activeDiv;
+ var mc = cal.monthsCombo;
+ if (cal.hilitedMonth) {
+ Calendar.removeClass(cal.hilitedMonth, "hilite");
+ }
+ if (cal.activeMonth) {
+ Calendar.removeClass(cal.activeMonth, "active");
+ }
+ var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];
+ Calendar.addClass(mon, "active");
+ cal.activeMonth = mon;
+ var s = mc.style;
+ s.display = "block";
+ if (cd.navtype < 0)
+ s.left = cd.offsetLeft + "px";
+ else
+ s.left = (cd.offsetLeft + cd.offsetWidth - mc.offsetWidth) + "px";
+ s.top = (cd.offsetTop + cd.offsetHeight) + "px";
+};
+
+Calendar.showYearsCombo = function (fwd) {
+ var cal = Calendar._C;
+ if (!cal) {
+ return false;
+ }
+ var cal = cal;
+ var cd = cal.activeDiv;
+ var yc = cal.yearsCombo;
+ if (cal.hilitedYear) {
+ Calendar.removeClass(cal.hilitedYear, "hilite");
+ }
+ if (cal.activeYear) {
+ Calendar.removeClass(cal.activeYear, "active");
+ }
+ cal.activeYear = null;
+ var Y = cal.date.getFullYear() + (fwd ? 1 : -1);
+ var yr = yc.firstChild;
+ var show = false;
+ for (var i = 12; i > 0; --i) {
+ if (Y >= cal.minYear && Y <= cal.maxYear) {
+ yr.firstChild.data = Y;
+ yr.year = Y;
+ yr.style.display = "block";
+ show = true;
+ } else {
+ yr.style.display = "none";
+ }
+ yr = yr.nextSibling;
+ Y += fwd ? 2 : -2;
+ }
+ if (show) {
+ var s = yc.style;
+ s.display = "block";
+ if (cd.navtype < 0)
+ s.left = cd.offsetLeft + "px";
+ else
+ s.left = (cd.offsetLeft + cd.offsetWidth - yc.offsetWidth) + "px";
+ s.top = (cd.offsetTop + cd.offsetHeight) + "px";
+ }
+};
+
+// event handlers
+
+Calendar.tableMouseUp = function(ev) {
+ var cal = Calendar._C;
+ if (!cal) {
+ return false;
+ }
+ if (cal.timeout) {
+ clearTimeout(cal.timeout);
+ }
+ var el = cal.activeDiv;
+ if (!el) {
+ return false;
+ }
+ var target = Calendar.getTargetElement(ev);
+ ev || (ev = window.event);
+ Calendar.removeClass(el, "active");
+ if (target == el || target.parentNode == el) {
+ Calendar.cellClick(el, ev);
+ }
+ var mon = Calendar.findMonth(target);
+ var date = null;
+ if (mon) {
+ date = new Date(cal.date);
+ if (mon.month != date.getMonth()) {
+ date.setMonth(mon.month);
+ cal.setDate(date);
+ cal.dateClicked = false;
+ cal.callHandler();
+ }
+ } else {
+ var year = Calendar.findYear(target);
+ if (year) {
+ date = new Date(cal.date);
+ if (year.year != date.getFullYear()) {
+ date.setFullYear(year.year);
+ cal.setDate(date);
+ cal.dateClicked = false;
+ cal.callHandler();
+ }
+ }
+ }
+ with (Calendar) {
+ removeEvent(document, "mouseup", tableMouseUp);
+ removeEvent(document, "mouseover", tableMouseOver);
+ removeEvent(document, "mousemove", tableMouseOver);
+ cal._hideCombos();
+ _C = null;
+ return stopEvent(ev);
+ }
+};
+
+Calendar.tableMouseOver = function (ev) {
+ var cal = Calendar._C;
+ if (!cal) {
+ return;
+ }
+ var el = cal.activeDiv;
+ var target = Calendar.getTargetElement(ev);
+ if (target == el || target.parentNode == el) {
+ Calendar.addClass(el, "hilite active");
+ Calendar.addClass(el.parentNode, "rowhilite");
+ } else {
+ if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2)))
+ Calendar.removeClass(el, "active");
+ Calendar.removeClass(el, "hilite");
+ Calendar.removeClass(el.parentNode, "rowhilite");
+ }
+ ev || (ev = window.event);
+ if (el.navtype == 50 && target != el) {
+ var pos = Calendar.getAbsolutePos(el);
+ var w = el.offsetWidth;
+ var x = ev.clientX;
+ var dx;
+ var decrease = true;
+ if (x > pos.x + w) {
+ dx = x - pos.x - w;
+ decrease = false;
+ } else
+ dx = pos.x - x;
+
+ if (dx < 0) dx = 0;
+ var range = el._range;
+ var current = el._current;
+ var count = Math.floor(dx / 10) % range.length;
+ for (var i = range.length; --i >= 0;)
+ if (range[i] == current)
+ break;
+ while (count-- > 0)
+ if (decrease) {
+ if (!(--i in range))
+ i = range.length - 1;
+ } else if (!(++i in range))
+ i = 0;
+ var newval = range[i];
+ el.firstChild.data = newval;
+
+ cal.onUpdateTime();
+ }
+ var mon = Calendar.findMonth(target);
+ if (mon) {
+ if (mon.month != cal.date.getMonth()) {
+ if (cal.hilitedMonth) {
+ Calendar.removeClass(cal.hilitedMonth, "hilite");
+ }
+ Calendar.addClass(mon, "hilite");
+ cal.hilitedMonth = mon;
+ } else if (cal.hilitedMonth) {
+ Calendar.removeClass(cal.hilitedMonth, "hilite");
+ }
+ } else {
+ if (cal.hilitedMonth) {
+ Calendar.removeClass(cal.hilitedMonth, "hilite");
+ }
+ var year = Calendar.findYear(target);
+ if (year) {
+ if (year.year != cal.date.getFullYear()) {
+ if (cal.hilitedYear) {
+ Calendar.removeClass(cal.hilitedYear, "hilite");
+ }
+ Calendar.addClass(year, "hilite");
+ cal.hilitedYear = year;
+ } else if (cal.hilitedYear) {
+ Calendar.removeClass(cal.hilitedYear, "hilite");
+ }
+ } else if (cal.hilitedYear) {
+ Calendar.removeClass(cal.hilitedYear, "hilite");
+ }
+ }
+ return Calendar.stopEvent(ev);
+};
+
+Calendar.tableMouseDown = function (ev) {
+ if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) {
+ return Calendar.stopEvent(ev);
+ }
+};
+
+Calendar.calDragIt = function (ev) {
+ var cal = Calendar._C;
+ if (!(cal && cal.dragging)) {
+ return false;
+ }
+ var posX;
+ var posY;
+ if (Calendar.is_ie) {
+ posY = window.event.clientY + document.body.scrollTop;
+ posX = window.event.clientX + document.body.scrollLeft;
+ } else {
+ posX = ev.pageX;
+ posY = ev.pageY;
+ }
+ cal.hideShowCovered();
+ var st = cal.element.style;
+ st.left = (posX - cal.xOffs) + "px";
+ st.top = (posY - cal.yOffs) + "px";
+ return Calendar.stopEvent(ev);
+};
+
+Calendar.calDragEnd = function (ev) {
+ var cal = Calendar._C;
+ if (!cal) {
+ return false;
+ }
+ cal.dragging = false;
+ with (Calendar) {
+ removeEvent(document, "mousemove", calDragIt);
+ removeEvent(document, "mouseover", stopEvent);
+ removeEvent(document, "mouseup", calDragEnd);
+ tableMouseUp(ev);
+ }
+ cal.hideShowCovered();
+};
+
+Calendar.dayMouseDown = function(ev) {
+ var el = Calendar.getElement(ev);
+ if (el.disabled) {
+ return false;
+ }
+ var cal = el.calendar;
+ cal.activeDiv = el;
+ Calendar._C = cal;
+ if (el.navtype != 300) with (Calendar) {
+ if (el.navtype == 50)
+ el._current = el.firstChild.data;
+ addClass(el, "hilite active");
+ addEvent(document, "mouseover", tableMouseOver);
+ addEvent(document, "mousemove", tableMouseOver);
+ addEvent(document, "mouseup", tableMouseUp);
+ } else if (cal.isPopup) {
+ cal._dragStart(ev);
+ }
+ if (el.navtype == -1 || el.navtype == 1) {
+ if (cal.timeout) clearTimeout(cal.timeout);
+ cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250);
+ } else if (el.navtype == -2 || el.navtype == 2) {
+ if (cal.timeout) clearTimeout(cal.timeout);
+ cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250);
+ } else {
+ cal.timeout = null;
+ }
+ return Calendar.stopEvent(ev);
+};
+
+Calendar.dayMouseDblClick = function(ev) {
+ Calendar.cellClick(Calendar.getElement(ev), ev || window.event);
+ if (Calendar.is_ie) {
+ document.selection.empty();
+ }
+};
+
+Calendar.dayMouseOver = function(ev) {
+ var el = Calendar.getElement(ev);
+ if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) {
+ return false;
+ }
+ if (el.ttip) {
+ if (el.ttip.substr(0, 1) == "_") {
+ var date = null;
+ with (el.calendar.date) {
+ date = new Date(getFullYear(), getMonth(), el.caldate);
+ }
+ el.ttip = date.print(el.calendar.ttDateFormat) + el.ttip.substr(1);
+ }
+ el.calendar.tooltips.firstChild.data = el.ttip;
+ }
+ if (el.navtype != 300) {
+ Calendar.addClass(el, "hilite");
+ if (el.caldate) {
+ Calendar.addClass(el.parentNode, "rowhilite");
+ }
+ }
+ return Calendar.stopEvent(ev);
+};
+
+Calendar.dayMouseOut = function(ev) {
+ with (Calendar) {
+ var el = getElement(ev);
+ if (isRelated(el, ev) || _C || el.disabled) {
+ return false;
+ }
+ removeClass(el, "hilite");
+ if (el.caldate) {
+ removeClass(el.parentNode, "rowhilite");
+ }
+ el.calendar.tooltips.firstChild.data = _TT["SEL_DATE"];
+ return stopEvent(ev);
+ }
+};
+
+/**
+ * A generic "click" handler :) handles all types of buttons defined in this
+ * calendar.
+ */
+Calendar.cellClick = function(el, ev) {
+ var cal = el.calendar;
+ var closing = false;
+ var newdate = false;
+ var date = null;
+ if (typeof el.navtype == "undefined") {
+ Calendar.removeClass(cal.currentDateEl, "selected");
+ Calendar.addClass(el, "selected");
+ closing = (cal.currentDateEl == el);
+ if (!closing) {
+ cal.currentDateEl = el;
+ }
+ cal.date.setDate(el.caldate);
+ date = cal.date;
+ newdate = true;
+ // a date was clicked
+ cal.dateClicked = true;
+ } else {
+ if (el.navtype == 200) {
+ Calendar.removeClass(el, "hilite");
+ cal.callCloseHandler();
+ return;
+ }
+ date = (el.navtype == 0) ? new Date() : new Date(cal.date);
+ // unless "today" was clicked, we assume no date was clicked so
+ // the selected handler will know not to close the calenar when
+ // in single-click mode.
+ // cal.dateClicked = (el.navtype == 0);
+ cal.dateClicked = false;
+ var year = date.getFullYear();
+ var mon = date.getMonth();
+ function setMonth(m) {
+ var day = date.getDate();
+ var max = date.getMonthDays(m);
+ if (day > max) {
+ date.setDate(max);
+ }
+ date.setMonth(m);
+ };
+ switch (el.navtype) {
+ case 400:
+ Calendar.removeClass(el, "hilite");
+ var text = Calendar._TT["ABOUT"];
+ if (typeof text != "undefined") {
+ text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : "";
+ } else {
+ // FIXME: this should be removed as soon as lang files get updated!
+ text = "Help and about box text is not translated into this language.\n" +
+ "If you know this language and you feel generous please update\n" +
+ "the corresponding file in \"lang\" subdir to match calendar-en.js\n" +
+ "and send it back to <mishoo@infoiasi.ro> to get it into the distribution ;-)\n\n" +
+ "Thank you!\n" +
+ "http://dynarch.com/mishoo/calendar.epl\n";
+ }
+ alert(text);
+ return;
+ case -2:
+ if (year > cal.minYear) {
+ date.setFullYear(year - 1);
+ }
+ break;
+ case -1:
+ if (mon > 0) {
+ setMonth(mon - 1);
+ } else if (year-- > cal.minYear) {
+ date.setFullYear(year);
+ setMonth(11);
+ }
+ break;
+ case 1:
+ if (mon < 11) {
+ setMonth(mon + 1);
+ } else if (year < cal.maxYear) {
+ date.setFullYear(year + 1);
+ setMonth(0);
+ }
+ break;
+ case 2:
+ if (year < cal.maxYear) {
+ date.setFullYear(year + 1);
+ }
+ break;
+ case 100:
+ cal.setMondayFirst(!cal.mondayFirst);
+ return;
+ case 50:
+ var range = el._range;
+ var current = el.firstChild.data;
+ for (var i = range.length; --i >= 0;)
+ if (range[i] == current)
+ break;
+ if (ev && ev.shiftKey) {
+ if (!(--i in range))
+ i = range.length - 1;
+ } else if (!(++i in range))
+ i = 0;
+ var newval = range[i];
+ el.firstChild.data = newval;
+ cal.onUpdateTime();
+ return;
+ case 0:
+ // TODAY will bring us here
+ if ((typeof cal.getDateStatus == "function") && cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) {
+ // remember, "date" was previously set to new
+ // Date() if TODAY was clicked; thus, it
+ // contains today date.
+ return false;
+ }
+ break;
+ }
+ if (!date.equalsTo(cal.date)) {
+ cal.setDate(date);
+ newdate = true;
+ }
+ }
+ if (newdate) {
+ cal.callHandler();
+ }
+ if (closing) {
+ Calendar.removeClass(el, "hilite");
+ cal.callCloseHandler();
+ }
+};
+
+// END: CALENDAR STATIC FUNCTIONS
+
+// BEGIN: CALENDAR OBJECT FUNCTIONS
+
+/**
+ * This function creates the calendar inside the given parent. If _par is
+ * null than it creates a popup calendar inside the BODY element. If _par is
+ * an element, be it BODY, then it creates a non-popup calendar (still
+ * hidden). Some properties need to be set before calling this function.
+ */
+Calendar.prototype.create = function (_par) {
+ var parent = null;
+ if (! _par) {
+ // default parent is the document body, in which case we create
+ // a popup calendar.
+ parent = document.getElementsByTagName("body")[0];
+ this.isPopup = true;
+ } else {
+ parent = _par;
+ this.isPopup = false;
+ }
+ this.date = this.dateStr ? new Date(this.dateStr) : new Date();
+
+ var table = Calendar.createElement("table");
+ this.table = table;
+ table.cellSpacing = 0;
+ table.cellPadding = 0;
+ table.calendar = this;
+ Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown);
+
+ var div = Calendar.createElement("div");
+ this.element = div;
+ div.className = "calendar";
+ if (this.isPopup) {
+ div.style.position = "absolute";
+ div.style.display = "none";
+ }
+ div.appendChild(table);
+
+ var thead = Calendar.createElement("thead", table);
+ var cell = null;
+ var row = null;
+
+ var cal = this;
+ var hh = function (text, cs, navtype) {
+ cell = Calendar.createElement("td", row);
+ cell.colSpan = cs;
+ cell.className = "button";
+ if (navtype != 0 && Math.abs(navtype) <= 2)
+ cell.className += " nav";
+ Calendar._add_evs(cell);
+ cell.calendar = cal;
+ cell.navtype = navtype;
+ if (text.substr(0, 1) != "&") {
+ cell.appendChild(document.createTextNode(text));
+ }
+ else {
+ // FIXME: dirty hack for entities
+ cell.innerHTML = text;
+ }
+ return cell;
+ };
+
+ row = Calendar.createElement("tr", thead);
+ var title_length = 6;
+ (this.isPopup) && --title_length;
+ (this.weekNumbers) && ++title_length;
+
+ hh("?", 1, 400).ttip = Calendar._TT["INFO"];
+ this.title = hh("", title_length, 300);
+ this.title.className = "title";
+ if (this.isPopup) {
+ this.title.ttip = Calendar._TT["DRAG_TO_MOVE"];
+ this.title.style.cursor = "move";
+ hh("&#x00d7;", 1, 200).ttip = Calendar._TT["CLOSE"];
+ }
+
+ row = Calendar.createElement("tr", thead);
+ row.className = "headrow";
+
+ this._nav_py = hh("&#x00ab;", 1, -2);
+ this._nav_py.ttip = Calendar._TT["PREV_YEAR"];
+
+ this._nav_pm = hh("&#x2039;", 1, -1);
+ this._nav_pm.ttip = Calendar._TT["PREV_MONTH"];
+
+ this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0);
+ this._nav_now.ttip = Calendar._TT["GO_TODAY"];
+
+ this._nav_nm = hh("&#x203a;", 1, 1);
+ this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"];
+
+ this._nav_ny = hh("&#x00bb;", 1, 2);
+ this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"];
+
+ // day names
+ row = Calendar.createElement("tr", thead);
+ row.className = "daynames";
+ if (this.weekNumbers) {
+ cell = Calendar.createElement("td", row);
+ cell.className = "name wn";
+ cell.appendChild(document.createTextNode(Calendar._TT["WK"]));
+ }
+ for (var i = 7; i > 0; --i) {
+ cell = Calendar.createElement("td", row);
+ cell.appendChild(document.createTextNode(""));
+ if (!i) {
+ cell.navtype = 100;
+ cell.calendar = this;
+ Calendar._add_evs(cell);
+ }
+ }
+ this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild;
+ this._displayWeekdays();
+
+ var tbody = Calendar.createElement("tbody", table);
+ this.tbody = tbody;
+
+ for (i = 6; i > 0; --i) {
+ row = Calendar.createElement("tr", tbody);
+ if (this.weekNumbers) {
+ cell = Calendar.createElement("td", row);
+ cell.appendChild(document.createTextNode(""));
+ }
+ for (var j = 7; j > 0; --j) {
+ cell = Calendar.createElement("td", row);
+ cell.appendChild(document.createTextNode(""));
+ cell.calendar = this;
+ Calendar._add_evs(cell);
+ }
+ }
+
+ if (this.showsTime) {
+ row = Calendar.createElement("tr", tbody);
+ row.className = "time";
+
+ cell = Calendar.createElement("td", row);
+ cell.className = "time";
+ cell.colSpan = 2;
+ cell.innerHTML = "&nbsp;";
+
+ cell = Calendar.createElement("td", row);
+ cell.className = "time";
+ cell.colSpan = this.weekNumbers ? 4 : 3;
+
+ (function(){
+ function makeTimePart(className, init, range_start, range_end) {
+ var part = Calendar.createElement("span", cell);
+ part.className = className;
+ part.appendChild(document.createTextNode(init));
+ part.calendar = cal;
+ part.ttip = Calendar._TT["TIME_PART"];
+ part.navtype = 50;
+ part._range = [];
+ if (typeof range_start != "number")
+ part._range = range_start;
+ else {
+ for (var i = range_start; i <= range_end; ++i) {
+ var txt;
+ if (i < 10 && range_end >= 10) txt = '0' + i;
+ else txt = '' + i;
+ part._range[part._range.length] = txt;
+ }
+ }
+ Calendar._add_evs(part);
+ return part;
+ };
+ var hrs = cal.date.getHours();
+ var mins = cal.date.getMinutes();
+ var t12 = !cal.time24;
+ var pm = (hrs > 12);
+ if (t12 && pm) hrs -= 12;
+ var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23);
+ var span = Calendar.createElement("span", cell);
+ span.appendChild(document.createTextNode(":"));
+ span.className = "colon";
+ var M = makeTimePart("minute", mins, 0, 59);
+ var AP = null;
+ cell = Calendar.createElement("td", row);
+ cell.className = "time";
+ cell.colSpan = 2;
+ if (t12)
+ AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]);
+ else
+ cell.innerHTML = "&nbsp;";
+
+ cal.onSetTime = function() {
+ var hrs = this.date.getHours();
+ var mins = this.date.getMinutes();
+ var pm = (hrs > 12);
+ if (pm && t12) hrs -= 12;
+ H.firstChild.data = (hrs < 10) ? ("0" + hrs) : hrs;
+ M.firstChild.data = (mins < 10) ? ("0" + mins) : mins;
+ if (t12)
+ AP.firstChild.data = pm ? "pm" : "am";
+ };
+
+ cal.onUpdateTime = function() {
+ var date = this.date;
+ var h = parseInt(H.firstChild.data, 10);
+ if (t12) {
+ if (/pm/i.test(AP.firstChild.data) && h < 12)
+ h += 12;
+ else if (/am/i.test(AP.firstChild.data) && h == 12)
+ h = 0;
+ }
+ var d = date.getDate();
+ var m = date.getMonth();
+ var y = date.getFullYear();
+ date.setHours(h);
+ date.setMinutes(parseInt(M.firstChild.data, 10));
+ date.setFullYear(y);
+ date.setMonth(m);
+ date.setDate(d);
+ this.dateClicked = false;
+ this.callHandler();
+ };
+ })();
+ } else {
+ this.onSetTime = this.onUpdateTime = function() {};
+ }
+
+ var tfoot = Calendar.createElement("tfoot", table);
+
+ row = Calendar.createElement("tr", tfoot);
+ row.className = "footrow";
+
+ cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300);
+ cell.className = "ttip";
+ if (this.isPopup) {
+ cell.ttip = Calendar._TT["DRAG_TO_MOVE"];
+ cell.style.cursor = "move";
+ }
+ this.tooltips = cell;
+
+ div = Calendar.createElement("div", this.element);
+ this.monthsCombo = div;
+ div.className = "combo";
+ for (i = 0; i < Calendar._MN.length; ++i) {
+ var mn = Calendar.createElement("div");
+ mn.className = Calendar.is_ie ? "label-IEfix" : "label";
+ mn.month = i;
+ mn.appendChild(document.createTextNode(Calendar._SMN[i]));
+ div.appendChild(mn);
+ }
+
+ div = Calendar.createElement("div", this.element);
+ this.yearsCombo = div;
+ div.className = "combo";
+ for (i = 12; i > 0; --i) {
+ var yr = Calendar.createElement("div");
+ yr.className = Calendar.is_ie ? "label-IEfix" : "label";
+ yr.appendChild(document.createTextNode(""));
+ div.appendChild(yr);
+ }
+
+ this._init(this.mondayFirst, this.date);
+ parent.appendChild(this.element);
+};
+
+/** keyboard navigation, only for popup calendars */
+Calendar._keyEvent = function(ev) {
+ if (!window.calendar) {
+ return false;
+ }
+ (Calendar.is_ie) && (ev = window.event);
+ var cal = window.calendar;
+ var act = (Calendar.is_ie || ev.type == "keypress");
+ if (ev.ctrlKey) {
+ switch (ev.keyCode) {
+ case 37: // KEY left
+ act && Calendar.cellClick(cal._nav_pm);
+ break;
+ case 38: // KEY up
+ act && Calendar.cellClick(cal._nav_py);
+ break;
+ case 39: // KEY right
+ act && Calendar.cellClick(cal._nav_nm);
+ break;
+ case 40: // KEY down
+ act && Calendar.cellClick(cal._nav_ny);
+ break;
+ default:
+ return false;
+ }
+ } else switch (ev.keyCode) {
+ case 32: // KEY space (now)
+ Calendar.cellClick(cal._nav_now);
+ break;
+ case 27: // KEY esc
+ act && cal.hide();
+ break;
+ case 37: // KEY left
+ case 38: // KEY up
+ case 39: // KEY right
+ case 40: // KEY down
+ if (act) {
+ var date = cal.date.getDate() - 1;
+ var el = cal.currentDateEl;
+ var ne = null;
+ var prev = (ev.keyCode == 37) || (ev.keyCode == 38);
+ switch (ev.keyCode) {
+ case 37: // KEY left
+ (--date >= 0) && (ne = cal.ar_days[date]);
+ break;
+ case 38: // KEY up
+ date -= 7;
+ (date >= 0) && (ne = cal.ar_days[date]);
+ break;
+ case 39: // KEY right
+ (++date < cal.ar_days.length) && (ne = cal.ar_days[date]);
+ break;
+ case 40: // KEY down
+ date += 7;
+ (date < cal.ar_days.length) && (ne = cal.ar_days[date]);
+ break;
+ }
+ if (!ne) {
+ if (prev) {
+ Calendar.cellClick(cal._nav_pm);
+ } else {
+ Calendar.cellClick(cal._nav_nm);
+ }
+ date = (prev) ? cal.date.getMonthDays() : 1;
+ el = cal.currentDateEl;
+ ne = cal.ar_days[date - 1];
+ }
+ Calendar.removeClass(el, "selected");
+ Calendar.addClass(ne, "selected");
+ cal.date.setDate(ne.caldate);
+ cal.callHandler();
+ cal.currentDateEl = ne;
+ }
+ break;
+ case 13: // KEY enter
+ if (act) {
+ cal.callHandler();
+ cal.hide();
+ }
+ break;
+ default:
+ return false;
+ }
+ return Calendar.stopEvent(ev);
+};
+
+/**
+ * (RE)Initializes the calendar to the given date and style (if mondayFirst is
+ * true it makes Monday the first day of week, otherwise the weeks start on
+ * Sunday.
+ */
+Calendar.prototype._init = function (mondayFirst, date) {
+ var today = new Date();
+ var year = date.getFullYear();
+ if (year < this.minYear) {
+ year = this.minYear;
+ date.setFullYear(year);
+ } else if (year > this.maxYear) {
+ year = this.maxYear;
+ date.setFullYear(year);
+ }
+ this.mondayFirst = mondayFirst;
+ this.date = new Date(date);
+ var month = date.getMonth();
+ var mday = date.getDate();
+ var no_days = date.getMonthDays();
+ date.setDate(1);
+ var wday = date.getDay();
+ var MON = mondayFirst ? 1 : 0;
+ var SAT = mondayFirst ? 5 : 6;
+ var SUN = mondayFirst ? 6 : 0;
+ if (mondayFirst) {
+ wday = (wday > 0) ? (wday - 1) : 6;
+ }
+ var iday = 1;
+ var row = this.tbody.firstChild;
+ var MN = Calendar._SMN[month];
+ var hasToday = ((today.getFullYear() == year) && (today.getMonth() == month));
+ var todayDate = today.getDate();
+ var week_number = date.getWeekNumber();
+ var ar_days = new Array();
+ for (var i = 0; i < 6; ++i) {
+ if (iday > no_days) {
+ row.className = "emptyrow";
+ row = row.nextSibling;
+ continue;
+ }
+ var cell = row.firstChild;
+ if (this.weekNumbers) {
+ cell.className = "day wn";
+ cell.firstChild.data = week_number;
+ cell = cell.nextSibling;
+ }
+ ++week_number;
+ row.className = "daysrow";
+ for (var j = 0; j < 7; ++j) {
+ cell.className = "day";
+ if ((!i && j < wday) || iday > no_days) {
+ // cell.className = "emptycell";
+ cell.innerHTML = "&nbsp;";
+ cell.disabled = true;
+ cell = cell.nextSibling;
+ continue;
+ }
+ cell.disabled = false;
+ cell.firstChild.data = iday;
+ if (typeof this.getDateStatus == "function") {
+ date.setDate(iday);
+ var status = this.getDateStatus(date, year, month, iday);
+ if (status === true) {
+ cell.className += " disabled";
+ cell.disabled = true;
+ } else {
+ if (/disabled/i.test(status))
+ cell.disabled = true;
+ cell.className += " " + status;
+ }
+ }
+ if (!cell.disabled) {
+ ar_days[ar_days.length] = cell;
+ cell.caldate = iday;
+ cell.ttip = "_";
+ if (iday == mday) {
+ cell.className += " selected";
+ this.currentDateEl = cell;
+ }
+ if (hasToday && (iday == todayDate)) {
+ cell.className += " today";
+ cell.ttip += Calendar._TT["PART_TODAY"];
+ }
+ if (wday == SAT || wday == SUN) {
+ cell.className += " weekend";
+ }
+ }
+ ++iday;
+ ((++wday) ^ 7) || (wday = 0);
+ cell = cell.nextSibling;
+ }
+ row = row.nextSibling;
+ }
+ this.ar_days = ar_days;
+ this.title.firstChild.data = Calendar._MN[month] + ", " + year;
+ this.onSetTime();
+ // PROFILE
+ // this.tooltips.firstChild.data = "Generated in " + ((new Date()) - today) + " ms";
+};
+
+/**
+ * Calls _init function above for going to a certain date (but only if the
+ * date is different than the currently selected one).
+ */
+Calendar.prototype.setDate = function (date) {
+ if (!date.equalsTo(this.date)) {
+ this._init(this.mondayFirst, date);
+ }
+};
+
+/**
+ * Refreshes the calendar. Useful if the "disabledHandler" function is
+ * dynamic, meaning that the list of disabled date can change at runtime.
+ * Just * call this function if you think that the list of disabled dates
+ * should * change.
+ */
+Calendar.prototype.refresh = function () {
+ this._init(this.mondayFirst, this.date);
+};
+
+/** Modifies the "mondayFirst" parameter (EU/US style). */
+Calendar.prototype.setMondayFirst = function (mondayFirst) {
+ this._init(mondayFirst, this.date);
+ this._displayWeekdays();
+};
+
+/**
+ * Allows customization of what dates are enabled. The "unaryFunction"
+ * parameter must be a function object that receives the date (as a JS Date
+ * object) and returns a boolean value. If the returned value is true then
+ * the passed date will be marked as disabled.
+ */
+Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) {
+ this.getDateStatus = unaryFunction;
+};
+
+/** Customization of allowed year range for the calendar. */
+Calendar.prototype.setRange = function (a, z) {
+ this.minYear = a;
+ this.maxYear = z;
+};
+
+/** Calls the first user handler (selectedHandler). */
+Calendar.prototype.callHandler = function () {
+ if (this.onSelected) {
+ this.onSelected(this, this.date.print(this.dateFormat));
+ }
+};
+
+/** Calls the second user handler (closeHandler). */
+Calendar.prototype.callCloseHandler = function () {
+ if (this.onClose) {
+ this.onClose(this);
+ }
+ this.hideShowCovered();
+};
+
+/** Removes the calendar object from the DOM tree and destroys it. */
+Calendar.prototype.destroy = function () {
+ var el = this.element.parentNode;
+ el.removeChild(this.element);
+ Calendar._C = null;
+ window.calendar = null;
+};
+
+/**
+ * Moves the calendar element to a different section in the DOM tree (changes
+ * its parent).
+ */
+Calendar.prototype.reparent = function (new_parent) {
+ var el = this.element;
+ el.parentNode.removeChild(el);
+ new_parent.appendChild(el);
+};
+
+// This gets called when the user presses a mouse button anywhere in the
+// document, if the calendar is shown. If the click was outside the open
+// calendar this function closes it.
+Calendar._checkCalendar = function(ev) {
+ if (!window.calendar) {
+ return false;
+ }
+ var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev);
+ for (; el != null && el != calendar.element; el = el.parentNode);
+ if (el == null) {
+ // calls closeHandler which should hide the calendar.
+ window.calendar.callCloseHandler();
+ return Calendar.stopEvent(ev);
+ }
+};
+
+/** Shows the calendar. */
+Calendar.prototype.show = function () {
+ var rows = this.table.getElementsByTagName("tr");
+ for (var i = rows.length; i > 0;) {
+ var row = rows[--i];
+ Calendar.removeClass(row, "rowhilite");
+ var cells = row.getElementsByTagName("td");
+ for (var j = cells.length; j > 0;) {
+ var cell = cells[--j];
+ Calendar.removeClass(cell, "hilite");
+ Calendar.removeClass(cell, "active");
+ }
+ }
+ this.element.style.display = "block";
+ this.hidden = false;
+ if (this.isPopup) {
+ window.calendar = this;
+ Calendar.addEvent(document, "keydown", Calendar._keyEvent);
+ Calendar.addEvent(document, "keypress", Calendar._keyEvent);
+ Calendar.addEvent(document, "mousedown", Calendar._checkCalendar);
+ }
+ this.hideShowCovered();
+};
+
+/**
+ * Hides the calendar. Also removes any "hilite" from the class of any TD
+ * element.
+ */
+Calendar.prototype.hide = function () {
+ if (this.isPopup) {
+ Calendar.removeEvent(document, "keydown", Calendar._keyEvent);
+ Calendar.removeEvent(document, "keypress", Calendar._keyEvent);
+ Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar);
+ }
+ this.element.style.display = "none";
+ this.hidden = true;
+ this.hideShowCovered();
+};
+
+/**
+ * Shows the calendar at a given absolute position (beware that, depending on
+ * the calendar element style -- position property -- this might be relative
+ * to the parent's containing rectangle).
+ */
+Calendar.prototype.showAt = function (x, y) {
+ var s = this.element.style;
+ s.left = x + "px";
+ s.top = y + "px";
+ this.show();
+};
+
+/** Shows the calendar near a given element. */
+Calendar.prototype.showAtElement = function (el, opts) {
+ var self = this;
+ var p = Calendar.getAbsolutePos(el);
+ if (!opts || typeof opts != "string") {
+ this.showAt(p.x, p.y + el.offsetHeight);
+ return true;
+ }
+ this.element.style.display = "block";
+ Calendar.continuation_for_the_fucking_khtml_browser = function() {
+ var w = self.element.offsetWidth;
+ var h = self.element.offsetHeight;
+ self.element.style.display = "none";
+ var valign = opts.substr(0, 1);
+ var halign = "l";
+ if (opts.length > 1) {
+ halign = opts.substr(1, 1);
+ }
+ // vertical alignment
+ switch (valign) {
+ case "T": p.y -= h; break;
+ case "B": p.y += el.offsetHeight; break;
+ case "C": p.y += (el.offsetHeight - h) / 2; break;
+ case "t": p.y += el.offsetHeight - h; break;
+ case "b": break; // already there
+ }
+ // horizontal alignment
+ switch (halign) {
+ case "L": p.x -= w; break;
+ case "R": p.x += el.offsetWidth; break;
+ case "C": p.x += (el.offsetWidth - w) / 2; break;
+ case "r": p.x += el.offsetWidth - w; break;
+ case "l": break; // already there
+ }
+ self.showAt(p.x, p.y);
+ };
+ if (Calendar.is_khtml)
+ setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
+ else
+ Calendar.continuation_for_the_fucking_khtml_browser();
+};
+
+/** Customizes the date format. */
+Calendar.prototype.setDateFormat = function (str) {
+ this.dateFormat = str;
+};
+
+/** Customizes the tooltip date format. */
+Calendar.prototype.setTtDateFormat = function (str) {
+ this.ttDateFormat = str;
+};
+
+/**
+ * Tries to identify the date represented in a string. If successful it also
+ * calls this.setDate which moves the calendar to the given date.
+ */
+Calendar.prototype.parseDate = function (str, fmt) {
+ var y = 0;
+ var m = -1;
+ var d = 0;
+ var a = str.split(/\W+/);
+ if (!fmt) {
+ fmt = this.dateFormat;
+ }
+ var b = [];
+ fmt.replace(/(%.)/g, function(str, par) {
+ return b[b.length] = par;
+ });
+ var i = 0, j = 0;
+ var hr = 0;
+ var min = 0;
+ for (i = 0; i < a.length; ++i) {
+ if (b[i] == "%a" || b[i] == "%A") {
+ continue;
+ }
+ if (b[i] == "%d" || b[i] == "%e") {
+ d = parseInt(a[i], 10);
+ }
+ if (b[i] == "%m") {
+ m = parseInt(a[i], 10) - 1;
+ }
+ if (b[i] == "%Y" || b[i] == "%y") {
+ y = parseInt(a[i], 10);
+ (y < 100) && (y += (y > 29) ? 1900 : 2000);
+ }
+ if (b[i] == "%b" || b[i] == "%B") {
+ for (j = 0; j < 12; ++j) {
+ if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; }
+ }
+ } else if (/%[HIkl]/.test(b[i])) {
+ hr = parseInt(a[i], 10);
+ } else if (/%[pP]/.test(b[i])) {
+ if (/pm/i.test(a[i]) && hr < 12)
+ hr += 12;
+ } else if (b[i] == "%M") {
+ min = parseInt(a[i], 10);
+ }
+ }
+ if (y != 0 && m != -1 && d != 0) {
+ this.setDate(new Date(y, m, d, hr, min, 0));
+ return;
+ }
+ y = 0; m = -1; d = 0;
+ for (i = 0; i < a.length; ++i) {
+ if (a[i].search(/[a-zA-Z]+/) != -1) {
+ var t = -1;
+ for (j = 0; j < 12; ++j) {
+ if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
+ }
+ if (t != -1) {
+ if (m != -1) {
+ d = m+1;
+ }
+ m = t;
+ }
+ } else if (parseInt(a[i], 10) <= 12 && m == -1) {
+ m = a[i]-1;
+ } else if (parseInt(a[i], 10) > 31 && y == 0) {
+ y = parseInt(a[i], 10);
+ (y < 100) && (y += (y > 29) ? 1900 : 2000);
+ } else if (d == 0) {
+ d = a[i];
+ }
+ }
+ if (y == 0) {
+ var today = new Date();
+ y = today.getFullYear();
+ }
+ if (m != -1 && d != 0) {
+ this.setDate(new Date(y, m, d, hr, min, 0));
+ }
+};
+
+Calendar.prototype.hideShowCovered = function () {
+ var self = this;
+ Calendar.continuation_for_the_fucking_khtml_browser = function() {
+ function getVisib(obj){
+ var value = obj.style.visibility;
+ if (!value) {
+ if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
+ if (!Calendar.is_khtml)
+ value = document.defaultView.
+ getComputedStyle(obj, "").getPropertyValue("visibility");
+ else
+ value = '';
+ } else if (obj.currentStyle) { // IE
+ value = obj.currentStyle.visibility;
+ } else
+ value = '';
+ }
+ return value;
+ };
+
+ var tags = new Array("applet", "iframe", "select");
+ var el = self.element;
+
+ var p = Calendar.getAbsolutePos(el);
+ var EX1 = p.x;
+ var EX2 = el.offsetWidth + EX1;
+ var EY1 = p.y;
+ var EY2 = el.offsetHeight + EY1;
+
+ for (var k = tags.length; k > 0; ) {
+ var ar = document.getElementsByTagName(tags[--k]);
+ var cc = null;
+
+ for (var i = ar.length; i > 0;) {
+ cc = ar[--i];
+
+ p = Calendar.getAbsolutePos(cc);
+ var CX1 = p.x;
+ var CX2 = cc.offsetWidth + CX1;
+ var CY1 = p.y;
+ var CY2 = cc.offsetHeight + CY1;
+
+ if (self.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
+ if (!cc.__msh_save_visibility) {
+ cc.__msh_save_visibility = getVisib(cc);
+ }
+ cc.style.visibility = cc.__msh_save_visibility;
+ } else {
+ if (!cc.__msh_save_visibility) {
+ cc.__msh_save_visibility = getVisib(cc);
+ }
+ cc.style.visibility = "hidden";
+ }
+ }
+ }
+ };
+ if (Calendar.is_khtml)
+ setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
+ else
+ Calendar.continuation_for_the_fucking_khtml_browser();
+};
+
+/** Internal function; it displays the bar with the names of the weekday. */
+Calendar.prototype._displayWeekdays = function () {
+ var MON = this.mondayFirst ? 0 : 1;
+ var SUN = this.mondayFirst ? 6 : 0;
+ var SAT = this.mondayFirst ? 5 : 6;
+ var cell = this.firstdayname;
+ for (var i = 0; i < 7; ++i) {
+ cell.className = "day name";
+ if (!i) {
+ cell.ttip = this.mondayFirst ? Calendar._TT["SUN_FIRST"] : Calendar._TT["MON_FIRST"];
+ cell.navtype = 100;
+ cell.calendar = this;
+ Calendar._add_evs(cell);
+ }
+ if (i == SUN || i == SAT) {
+ Calendar.addClass(cell, "weekend");
+ }
+ cell.firstChild.data = Calendar._SDN[i + 1 - MON];
+ cell = cell.nextSibling;
+ }
+};
+
+/** Internal function. Hides all combo boxes that might be displayed. */
+Calendar.prototype._hideCombos = function () {
+ this.monthsCombo.style.display = "none";
+ this.yearsCombo.style.display = "none";
+};
+
+/** Internal function. Starts dragging the element. */
+Calendar.prototype._dragStart = function (ev) {
+ if (this.dragging) {
+ return;
+ }
+ this.dragging = true;
+ var posX;
+ var posY;
+ if (Calendar.is_ie) {
+ posY = window.event.clientY + document.body.scrollTop;
+ posX = window.event.clientX + document.body.scrollLeft;
+ } else {
+ posY = ev.clientY + window.scrollY;
+ posX = ev.clientX + window.scrollX;
+ }
+ var st = this.element.style;
+ this.xOffs = posX - parseInt(st.left);
+ this.yOffs = posY - parseInt(st.top);
+ with (Calendar) {
+ addEvent(document, "mousemove", calDragIt);
+ addEvent(document, "mouseover", stopEvent);
+ addEvent(document, "mouseup", calDragEnd);
+ }
+};
+
+// BEGIN: DATE OBJECT PATCHES
+
+/** Adds the number of days array to the Date object. */
+Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
+
+/** Constants used for time computations */
+Date.SECOND = 1000 /* milliseconds */;
+Date.MINUTE = 60 * Date.SECOND;
+Date.HOUR = 60 * Date.MINUTE;
+Date.DAY = 24 * Date.HOUR;
+Date.WEEK = 7 * Date.DAY;
+
+/** Returns the number of days in the current month */
+Date.prototype.getMonthDays = function(month) {
+ var year = this.getFullYear();
+ if (typeof month == "undefined") {
+ month = this.getMonth();
+ }
+ if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) {
+ return 29;
+ } else {
+ return Date._MD[month];
+ }
+};
+
+/** Returns the number of day in the year. */
+Date.prototype.getDayOfYear = function() {
+ var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
+ var then = new Date(this.getFullYear(), 0, 1, 0, 0, 0);
+ var time = now - then;
+ return Math.floor(time / Date.DAY);
+};
+
+/** Returns the number of the week in year, as defined in ISO 8601. */
+Date.prototype.getWeekNumber = function() {
+ var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
+ var then = new Date(this.getFullYear(), 0, 1, 0, 0, 0);
+ var time = now - then;
+ var day = then.getDay(); // 0 means Sunday
+ if (day == 0) day = 7;
+ (day > 4) && (day -= 4) || (day += 3);
+ return Math.round(((time / Date.DAY) + day) / 7);
+};
+
+/** Checks dates equality (ignores time) */
+Date.prototype.equalsTo = function(date) {
+ return ((this.getFullYear() == date.getFullYear()) &&
+ (this.getMonth() == date.getMonth()) &&
+ (this.getDate() == date.getDate()) &&
+ (this.getHours() == date.getHours()) &&
+ (this.getMinutes() == date.getMinutes()));
+};
+
+/** Prints the date in a string according to the given format. */
+Date.prototype.print = function (str) {
+ var m = this.getMonth();
+ var d = this.getDate();
+ var y = this.getFullYear();
+ var wn = this.getWeekNumber();
+ var w = this.getDay();
+ var s = {};
+ var hr = this.getHours();
+ var pm = (hr >= 12);
+ var ir = (pm) ? (hr - 12) : hr;
+ var dy = this.getDayOfYear();
+ if (ir == 0)
+ ir = 12;
+ var min = this.getMinutes();
+ var sec = this.getSeconds();
+ s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N]
+ s["%A"] = Calendar._DN[w]; // full weekday name
+ s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N]
+ s["%B"] = Calendar._MN[m]; // full month name
+ // FIXME: %c : preferred date and time representation for the current locale
+ s["%C"] = 1 + Math.floor(y / 100); // the century number
+ s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
+ s["%e"] = d; // the day of the month (range 1 to 31)
+ // FIXME: %D : american date style: %m/%d/%y
+ // FIXME: %E, %F, %G, %g, %h (man strftime)
+ s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
+ s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
+ s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
+ s["%k"] = hr; // hour, range 0 to 23 (24h format)
+ s["%l"] = ir; // hour, range 1 to 12 (12h format)
+ s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
+ s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
+ s["%n"] = "\n"; // a newline character
+ s["%p"] = pm ? "PM" : "AM";
+ s["%P"] = pm ? "pm" : "am";
+ // FIXME: %r : the time in am/pm notation %I:%M:%S %p
+ // FIXME: %R : the time in 24-hour notation %H:%M
+ s["%s"] = Math.floor(this.getTime() / 1000);
+ s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
+ s["%t"] = "\t"; // a tab character
+ // FIXME: %T : the time in 24-hour notation (%H:%M:%S)
+ s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
+ s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON)
+ s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN)
+ // FIXME: %x : preferred date representation for the current locale without the time
+ // FIXME: %X : preferred time representation for the current locale without the date
+ s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
+ s["%Y"] = y; // year with the century
+ s["%%"] = "%"; // a literal '%' character
+ var re = Date._msh_formatRegexp;
+ if (typeof re == "undefined") {
+ var tmp = "";
+ for (var i in s)
+ tmp += tmp ? ("|" + i) : i;
+ Date._msh_formatRegexp = re = new RegExp("(" + tmp + ")", 'g');
+ }
+ return str.replace(re, function(match, par) { return s[par]; });
+};
+
+// END: DATE OBJECT PATCHES
+
+// global object that remembers the calendar
+window.calendar = null;
diff --git a/httemplate/elements/calendar_stripped.js b/httemplate/elements/calendar_stripped.js
new file mode 100644
index 0000000..029496a
--- /dev/null
+++ b/httemplate/elements/calendar_stripped.js
@@ -0,0 +1,12 @@
+/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/
+ * ------------------------------------------------------------------
+ *
+ * The DHTML Calendar, version 0.9.5 "Your favorite time, bis"
+ *
+ * Details and latest version at:
+ * http://dynarch.com/mishoo/calendar.epl
+ *
+ * This script is distributed under the GNU Lesser General Public License.
+ * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
+ */
+ Calendar=function(mondayFirst,dateStr,onSelected,onClose){this.activeDiv=null;this.currentDateEl=null;this.getDateStatus=null;this.timeout=null;this.onSelected=onSelected||null;this.onClose=onClose||null;this.dragging=false;this.hidden=false;this.minYear=1970;this.maxYear=2050;this.dateFormat=Calendar._TT["DEF_DATE_FORMAT"];this.ttDateFormat=Calendar._TT["TT_DATE_FORMAT"];this.isPopup=true;this.weekNumbers=true;this.mondayFirst=mondayFirst;this.dateStr=dateStr;this.ar_days=null;this.showsTime=false;this.time24=true;this.table=null;this.element=null;this.tbody=null;this.firstdayname=null;this.monthsCombo=null;this.yearsCombo=null;this.hilitedMonth=null;this.activeMonth=null;this.hilitedYear=null;this.activeYear=null;this.dateClicked=false;if(typeof Calendar._SDN=="undefined"){if(typeof Calendar._SDN_len=="undefined")Calendar._SDN_len=3;var ar=new Array();for(var i=8;i>0;){ar[--i]=Calendar._DN[i].substr(0,Calendar._SDN_len);}Calendar._SDN=ar;if(typeof Calendar._SMN_len=="undefined")Calendar._SMN_len=3;ar=new Array();for(var i=12;i>0;){ar[--i]=Calendar._MN[i].substr(0,Calendar._SMN_len);}Calendar._SMN=ar;}};Calendar._C=null;Calendar.is_ie=(/msie/i.test(navigator.userAgent)&&!/opera/i.test(navigator.userAgent));Calendar.is_opera=/opera/i.test(navigator.userAgent);Calendar.is_khtml=/Konqueror|Safari|KHTML/i.test(navigator.userAgent);Calendar.getAbsolutePos=function(el){var SL=0,ST=0;var is_div=/^div$/i.test(el.tagName);if(is_div&&el.scrollLeft)SL=el.scrollLeft;if(is_div&&el.scrollTop)ST=el.scrollTop;var r={x:el.offsetLeft-SL,y:el.offsetTop-ST};if(el.offsetParent){var tmp=Calendar.getAbsolutePos(el.offsetParent);r.x+=tmp.x;r.y+=tmp.y;}return r;};Calendar.isRelated=function(el,evt){var related=evt.relatedTarget;if(!related){var type=evt.type;if(type=="mouseover"){related=evt.fromElement;}else if(type=="mouseout"){related=evt.toElement;}}while(related){if(related==el){return true;}related=related.parentNode;}return false;};Calendar.removeClass=function(el,className){if(!(el&&el.className)){return;}var cls=el.className.split(" ");var ar=new Array();for(var i=cls.length;i>0;){if(cls[--i]!=className){ar[ar.length]=cls[i];}}el.className=ar.join(" ");};Calendar.addClass=function(el,className){Calendar.removeClass(el,className);el.className+=" "+className;};Calendar.getElement=function(ev){if(Calendar.is_ie){return window.event.srcElement;}else{return ev.currentTarget;}};Calendar.getTargetElement=function(ev){if(Calendar.is_ie){return window.event.srcElement;}else{return ev.target;}};Calendar.stopEvent=function(ev){ev||(ev=window.event);if(Calendar.is_ie){ev.cancelBubble=true;ev.returnValue=false;}else{ev.preventDefault();ev.stopPropagation();}return false;};Calendar.addEvent=function(el,evname,func){if(el.attachEvent){el.attachEvent("on"+evname,func);}else if(el.addEventListener){el.addEventListener(evname,func,true);}else{el["on"+evname]=func;}};Calendar.removeEvent=function(el,evname,func){if(el.detachEvent){el.detachEvent("on"+evname,func);}else if(el.removeEventListener){el.removeEventListener(evname,func,true);}else{el["on"+evname]=null;}};Calendar.createElement=function(type,parent){var el=null;if(document.createElementNS){el=document.createElementNS("http://www.w3.org/1999/xhtml",type);}else{el=document.createElement(type);}if(typeof parent!="undefined"){parent.appendChild(el);}return el;};Calendar._add_evs=function(el){with(Calendar){addEvent(el,"mouseover",dayMouseOver);addEvent(el,"mousedown",dayMouseDown);addEvent(el,"mouseout",dayMouseOut);if(is_ie){addEvent(el,"dblclick",dayMouseDblClick);el.setAttribute("unselectable",true);}}};Calendar.findMonth=function(el){if(typeof el.month!="undefined"){return el;}else if(typeof el.parentNode.month!="undefined"){return el.parentNode;}return null;};Calendar.findYear=function(el){if(typeof el.year!="undefined"){return el;}else if(typeof el.parentNode.year!="undefined"){return el.parentNode;}return null;};Calendar.showMonthsCombo=function(){var cal=Calendar._C;if(!cal){return false;}var cal=cal;var cd=cal.activeDiv;var mc=cal.monthsCombo;if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}if(cal.activeMonth){Calendar.removeClass(cal.activeMonth,"active");}var mon=cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];Calendar.addClass(mon,"active");cal.activeMonth=mon;var s=mc.style;s.display="block";if(cd.navtype<0)s.left=cd.offsetLeft+"px";else s.left=(cd.offsetLeft+cd.offsetWidth-mc.offsetWidth)+"px";s.top=(cd.offsetTop+cd.offsetHeight)+"px";};Calendar.showYearsCombo=function(fwd){var cal=Calendar._C;if(!cal){return false;}var cal=cal;var cd=cal.activeDiv;var yc=cal.yearsCombo;if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}if(cal.activeYear){Calendar.removeClass(cal.activeYear,"active");}cal.activeYear=null;var Y=cal.date.getFullYear()+(fwd?1:-1);var yr=yc.firstChild;var show=false;for(var i=12;i>0;--i){if(Y>=cal.minYear&&Y<=cal.maxYear){yr.firstChild.data=Y;yr.year=Y;yr.style.display="block";show=true;}else{yr.style.display="none";}yr=yr.nextSibling;Y+=fwd?2:-2;}if(show){var s=yc.style;s.display="block";if(cd.navtype<0)s.left=cd.offsetLeft+"px";else s.left=(cd.offsetLeft+cd.offsetWidth-yc.offsetWidth)+"px";s.top=(cd.offsetTop+cd.offsetHeight)+"px";}};Calendar.tableMouseUp=function(ev){var cal=Calendar._C;if(!cal){return false;}if(cal.timeout){clearTimeout(cal.timeout);}var el=cal.activeDiv;if(!el){return false;}var target=Calendar.getTargetElement(ev);ev||(ev=window.event);Calendar.removeClass(el,"active");if(target==el||target.parentNode==el){Calendar.cellClick(el,ev);}var mon=Calendar.findMonth(target);var date=null;if(mon){date=new Date(cal.date);if(mon.month!=date.getMonth()){date.setMonth(mon.month);cal.setDate(date);cal.dateClicked=false;cal.callHandler();}}else{var year=Calendar.findYear(target);if(year){date=new Date(cal.date);if(year.year!=date.getFullYear()){date.setFullYear(year.year);cal.setDate(date);cal.dateClicked=false;cal.callHandler();}}}with(Calendar){removeEvent(document,"mouseup",tableMouseUp);removeEvent(document,"mouseover",tableMouseOver);removeEvent(document,"mousemove",tableMouseOver);cal._hideCombos();_C=null;return stopEvent(ev);}};Calendar.tableMouseOver=function(ev){var cal=Calendar._C;if(!cal){return;}var el=cal.activeDiv;var target=Calendar.getTargetElement(ev);if(target==el||target.parentNode==el){Calendar.addClass(el,"hilite active");Calendar.addClass(el.parentNode,"rowhilite");}else{if(typeof el.navtype=="undefined"||(el.navtype!=50&&(el.navtype==0||Math.abs(el.navtype)>2)))Calendar.removeClass(el,"active");Calendar.removeClass(el,"hilite");Calendar.removeClass(el.parentNode,"rowhilite");}ev||(ev=window.event);if(el.navtype==50&&target!=el){var pos=Calendar.getAbsolutePos(el);var w=el.offsetWidth;var x=ev.clientX;var dx;var decrease=true;if(x>pos.x+w){dx=x-pos.x-w;decrease=false;}else dx=pos.x-x;if(dx<0)dx=0;var range=el._range;var current=el._current;var count=Math.floor(dx/10)%range.length;for(var i=range.length;--i>=0;)if(range[i]==current)break;while(count-->0)if(decrease){if(!(--i in range))i=range.length-1;}else if(!(++i in range))i=0;var newval=range[i];el.firstChild.data=newval;cal.onUpdateTime();}var mon=Calendar.findMonth(target);if(mon){if(mon.month!=cal.date.getMonth()){if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}Calendar.addClass(mon,"hilite");cal.hilitedMonth=mon;}else if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}}else{if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}var year=Calendar.findYear(target);if(year){if(year.year!=cal.date.getFullYear()){if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}Calendar.addClass(year,"hilite");cal.hilitedYear=year;}else if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}}else if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}}return Calendar.stopEvent(ev);};Calendar.tableMouseDown=function(ev){if(Calendar.getTargetElement(ev)==Calendar.getElement(ev)){return Calendar.stopEvent(ev);}};Calendar.calDragIt=function(ev){var cal=Calendar._C;if(!(cal&&cal.dragging)){return false;}var posX;var posY;if(Calendar.is_ie){posY=window.event.clientY+document.body.scrollTop;posX=window.event.clientX+document.body.scrollLeft;}else{posX=ev.pageX;posY=ev.pageY;}cal.hideShowCovered();var st=cal.element.style;st.left=(posX-cal.xOffs)+"px";st.top=(posY-cal.yOffs)+"px";return Calendar.stopEvent(ev);};Calendar.calDragEnd=function(ev){var cal=Calendar._C;if(!cal){return false;}cal.dragging=false;with(Calendar){removeEvent(document,"mousemove",calDragIt);removeEvent(document,"mouseover",stopEvent);removeEvent(document,"mouseup",calDragEnd);tableMouseUp(ev);}cal.hideShowCovered();};Calendar.dayMouseDown=function(ev){var el=Calendar.getElement(ev);if(el.disabled){return false;}var cal=el.calendar;cal.activeDiv=el;Calendar._C=cal;if(el.navtype!=300)with(Calendar){if(el.navtype==50)el._current=el.firstChild.data;addClass(el,"hilite active");addEvent(document,"mouseover",tableMouseOver);addEvent(document,"mousemove",tableMouseOver);addEvent(document,"mouseup",tableMouseUp);}else if(cal.isPopup){cal._dragStart(ev);}if(el.navtype==-1||el.navtype==1){if(cal.timeout)clearTimeout(cal.timeout);cal.timeout=setTimeout("Calendar.showMonthsCombo()",250);}else if(el.navtype==-2||el.navtype==2){if(cal.timeout)clearTimeout(cal.timeout);cal.timeout=setTimeout((el.navtype>0)?"Calendar.showYearsCombo(true)":"Calendar.showYearsCombo(false)",250);}else{cal.timeout=null;}return Calendar.stopEvent(ev);};Calendar.dayMouseDblClick=function(ev){Calendar.cellClick(Calendar.getElement(ev),ev||window.event);if(Calendar.is_ie){document.selection.empty();}};Calendar.dayMouseOver=function(ev){var el=Calendar.getElement(ev);if(Calendar.isRelated(el,ev)||Calendar._C||el.disabled){return false;}if(el.ttip){if(el.ttip.substr(0,1)=="_"){var date=null;with(el.calendar.date){date=new Date(getFullYear(),getMonth(),el.caldate);}el.ttip=date.print(el.calendar.ttDateFormat)+el.ttip.substr(1);}el.calendar.tooltips.firstChild.data=el.ttip;}if(el.navtype!=300){Calendar.addClass(el,"hilite");if(el.caldate){Calendar.addClass(el.parentNode,"rowhilite");}}return Calendar.stopEvent(ev);};Calendar.dayMouseOut=function(ev){with(Calendar){var el=getElement(ev);if(isRelated(el,ev)||_C||el.disabled){return false;}removeClass(el,"hilite");if(el.caldate){removeClass(el.parentNode,"rowhilite");}el.calendar.tooltips.firstChild.data=_TT["SEL_DATE"];return stopEvent(ev);}};Calendar.cellClick=function(el,ev){var cal=el.calendar;var closing=false;var newdate=false;var date=null;if(typeof el.navtype=="undefined"){Calendar.removeClass(cal.currentDateEl,"selected");Calendar.addClass(el,"selected");closing=(cal.currentDateEl==el);if(!closing){cal.currentDateEl=el;}cal.date.setDate(el.caldate);date=cal.date;newdate=true;cal.dateClicked=true;}else{if(el.navtype==200){Calendar.removeClass(el,"hilite");cal.callCloseHandler();return;}date=(el.navtype==0)?new Date():new Date(cal.date);cal.dateClicked=false;var year=date.getFullYear();var mon=date.getMonth();function setMonth(m){var day=date.getDate();var max=date.getMonthDays(m);if(day>max){date.setDate(max);}date.setMonth(m);};switch(el.navtype){case 400:Calendar.removeClass(el,"hilite");var text=Calendar._TT["ABOUT"];if(typeof text!="undefined"){text+=cal.showsTime?Calendar._TT["ABOUT_TIME"]:"";}else{text="Help and about box text is not translated into this language.\n"+"If you know this language and you feel generous please update\n"+"the corresponding file in \"lang\" subdir to match calendar-en.js\n"+"and send it back to <mishoo@infoiasi.ro> to get it into the distribution ;-)\n\n"+"Thank you!\n"+"http://dynarch.com/mishoo/calendar.epl\n";}alert(text);return;case-2:if(year>cal.minYear){date.setFullYear(year-1);}break;case-1:if(mon>0){setMonth(mon-1);}else if(year-->cal.minYear){date.setFullYear(year);setMonth(11);}break;case 1:if(mon<11){setMonth(mon+1);}else if(year<cal.maxYear){date.setFullYear(year+1);setMonth(0);}break;case 2:if(year<cal.maxYear){date.setFullYear(year+1);}break;case 100:cal.setMondayFirst(!cal.mondayFirst);return;case 50:var range=el._range;var current=el.firstChild.data;for(var i=range.length;--i>=0;)if(range[i]==current)break;if(ev&&ev.shiftKey){if(!(--i in range))i=range.length-1;}else if(!(++i in range))i=0;var newval=range[i];el.firstChild.data=newval;cal.onUpdateTime();return;case 0:if((typeof cal.getDateStatus=="function")&&cal.getDateStatus(date,date.getFullYear(),date.getMonth(),date.getDate())){return false;}break;}if(!date.equalsTo(cal.date)){cal.setDate(date);newdate=true;}}if(newdate){cal.callHandler();}if(closing){Calendar.removeClass(el,"hilite");cal.callCloseHandler();}};Calendar.prototype.create=function(_par){var parent=null;if(!_par){parent=document.getElementsByTagName("body")[0];this.isPopup=true;}else{parent=_par;this.isPopup=false;}this.date=this.dateStr?new Date(this.dateStr):new Date();var table=Calendar.createElement("table");this.table=table;table.cellSpacing=0;table.cellPadding=0;table.calendar=this;Calendar.addEvent(table,"mousedown",Calendar.tableMouseDown);var div=Calendar.createElement("div");this.element=div;div.className="calendar";if(this.isPopup){div.style.position="absolute";div.style.display="none";}div.appendChild(table);var thead=Calendar.createElement("thead",table);var cell=null;var row=null;var cal=this;var hh=function(text,cs,navtype){cell=Calendar.createElement("td",row);cell.colSpan=cs;cell.className="button";if(navtype!=0&&Math.abs(navtype)<=2)cell.className+=" nav";Calendar._add_evs(cell);cell.calendar=cal;cell.navtype=navtype;if(text.substr(0,1)!="&"){cell.appendChild(document.createTextNode(text));}else{cell.innerHTML=text;}return cell;};row=Calendar.createElement("tr",thead);var title_length=6;(this.isPopup)&&--title_length;(this.weekNumbers)&&++title_length;hh("?",1,400).ttip=Calendar._TT["INFO"];this.title=hh("",title_length,300);this.title.className="title";if(this.isPopup){this.title.ttip=Calendar._TT["DRAG_TO_MOVE"];this.title.style.cursor="move";hh("&#x00d7;",1,200).ttip=Calendar._TT["CLOSE"];}row=Calendar.createElement("tr",thead);row.className="headrow";this._nav_py=hh("&#x00ab;",1,-2);this._nav_py.ttip=Calendar._TT["PREV_YEAR"];this._nav_pm=hh("&#x2039;",1,-1);this._nav_pm.ttip=Calendar._TT["PREV_MONTH"];this._nav_now=hh(Calendar._TT["TODAY"],this.weekNumbers?4:3,0);this._nav_now.ttip=Calendar._TT["GO_TODAY"];this._nav_nm=hh("&#x203a;",1,1);this._nav_nm.ttip=Calendar._TT["NEXT_MONTH"];this._nav_ny=hh("&#x00bb;",1,2);this._nav_ny.ttip=Calendar._TT["NEXT_YEAR"];row=Calendar.createElement("tr",thead);row.className="daynames";if(this.weekNumbers){cell=Calendar.createElement("td",row);cell.className="name wn";cell.appendChild(document.createTextNode(Calendar._TT["WK"]));}for(var i=7;i>0;--i){cell=Calendar.createElement("td",row);cell.appendChild(document.createTextNode(""));if(!i){cell.navtype=100;cell.calendar=this;Calendar._add_evs(cell);}}this.firstdayname=(this.weekNumbers)?row.firstChild.nextSibling:row.firstChild;this._displayWeekdays();var tbody=Calendar.createElement("tbody",table);this.tbody=tbody;for(i=6;i>0;--i){row=Calendar.createElement("tr",tbody);if(this.weekNumbers){cell=Calendar.createElement("td",row);cell.appendChild(document.createTextNode(""));}for(var j=7;j>0;--j){cell=Calendar.createElement("td",row);cell.appendChild(document.createTextNode(""));cell.calendar=this;Calendar._add_evs(cell);}}if(this.showsTime){row=Calendar.createElement("tr",tbody);row.className="time";cell=Calendar.createElement("td",row);cell.className="time";cell.colSpan=2;cell.innerHTML="&nbsp;";cell=Calendar.createElement("td",row);cell.className="time";cell.colSpan=this.weekNumbers?4:3;(function(){function makeTimePart(className,init,range_start,range_end){var part=Calendar.createElement("span",cell);part.className=className;part.appendChild(document.createTextNode(init));part.calendar=cal;part.ttip=Calendar._TT["TIME_PART"];part.navtype=50;part._range=[];if(typeof range_start!="number")part._range=range_start;else{for(var i=range_start;i<=range_end;++i){var txt;if(i<10&&range_end>=10)txt='0'+i;else txt=''+i;part._range[part._range.length]=txt;}}Calendar._add_evs(part);return part;};var hrs=cal.date.getHours();var mins=cal.date.getMinutes();var t12=!cal.time24;var pm=(hrs>12);if(t12&&pm)hrs-=12;var H=makeTimePart("hour",hrs,t12?1:0,t12?12:23);var span=Calendar.createElement("span",cell);span.appendChild(document.createTextNode(":"));span.className="colon";var M=makeTimePart("minute",mins,0,59);var AP=null;cell=Calendar.createElement("td",row);cell.className="time";cell.colSpan=2;if(t12)AP=makeTimePart("ampm",pm?"pm":"am",["am","pm"]);else cell.innerHTML="&nbsp;";cal.onSetTime=function(){var hrs=this.date.getHours();var mins=this.date.getMinutes();var pm=(hrs>12);if(pm&&t12)hrs-=12;H.firstChild.data=(hrs<10)?("0"+hrs):hrs;M.firstChild.data=(mins<10)?("0"+mins):mins;if(t12)AP.firstChild.data=pm?"pm":"am";};cal.onUpdateTime=function(){var date=this.date;var h=parseInt(H.firstChild.data,10);if(t12){if(/pm/i.test(AP.firstChild.data)&&h<12)h+=12;else if(/am/i.test(AP.firstChild.data)&&h==12)h=0;}var d=date.getDate();var m=date.getMonth();var y=date.getFullYear();date.setHours(h);date.setMinutes(parseInt(M.firstChild.data,10));date.setFullYear(y);date.setMonth(m);date.setDate(d);this.dateClicked=false;this.callHandler();};})();}else{this.onSetTime=this.onUpdateTime=function(){};}var tfoot=Calendar.createElement("tfoot",table);row=Calendar.createElement("tr",tfoot);row.className="footrow";cell=hh(Calendar._TT["SEL_DATE"],this.weekNumbers?8:7,300);cell.className="ttip";if(this.isPopup){cell.ttip=Calendar._TT["DRAG_TO_MOVE"];cell.style.cursor="move";}this.tooltips=cell;div=Calendar.createElement("div",this.element);this.monthsCombo=div;div.className="combo";for(i=0;i<Calendar._MN.length;++i){var mn=Calendar.createElement("div");mn.className=Calendar.is_ie?"label-IEfix":"label";mn.month=i;mn.appendChild(document.createTextNode(Calendar._SMN[i]));div.appendChild(mn);}div=Calendar.createElement("div",this.element);this.yearsCombo=div;div.className="combo";for(i=12;i>0;--i){var yr=Calendar.createElement("div");yr.className=Calendar.is_ie?"label-IEfix":"label";yr.appendChild(document.createTextNode(""));div.appendChild(yr);}this._init(this.mondayFirst,this.date);parent.appendChild(this.element);};Calendar._keyEvent=function(ev){if(!window.calendar){return false;}(Calendar.is_ie)&&(ev=window.event);var cal=window.calendar;var act=(Calendar.is_ie||ev.type=="keypress");if(ev.ctrlKey){switch(ev.keyCode){case 37:act&&Calendar.cellClick(cal._nav_pm);break;case 38:act&&Calendar.cellClick(cal._nav_py);break;case 39:act&&Calendar.cellClick(cal._nav_nm);break;case 40:act&&Calendar.cellClick(cal._nav_ny);break;default:return false;}}else switch(ev.keyCode){case 32:Calendar.cellClick(cal._nav_now);break;case 27:act&&cal.hide();break;case 37:case 38:case 39:case 40:if(act){var date=cal.date.getDate()-1;var el=cal.currentDateEl;var ne=null;var prev=(ev.keyCode==37)||(ev.keyCode==38);switch(ev.keyCode){case 37:(--date>=0)&&(ne=cal.ar_days[date]);break;case 38:date-=7;(date>=0)&&(ne=cal.ar_days[date]);break;case 39:(++date<cal.ar_days.length)&&(ne=cal.ar_days[date]);break;case 40:date+=7;(date<cal.ar_days.length)&&(ne=cal.ar_days[date]);break;}if(!ne){if(prev){Calendar.cellClick(cal._nav_pm);}else{Calendar.cellClick(cal._nav_nm);}date=(prev)?cal.date.getMonthDays():1;el=cal.currentDateEl;ne=cal.ar_days[date-1];}Calendar.removeClass(el,"selected");Calendar.addClass(ne,"selected");cal.date.setDate(ne.caldate);cal.callHandler();cal.currentDateEl=ne;}break;case 13:if(act){cal.callHandler();cal.hide();}break;default:return false;}return Calendar.stopEvent(ev);};Calendar.prototype._init=function(mondayFirst,date){var today=new Date();var year=date.getFullYear();if(year<this.minYear){year=this.minYear;date.setFullYear(year);}else if(year>this.maxYear){year=this.maxYear;date.setFullYear(year);}this.mondayFirst=mondayFirst;this.date=new Date(date);var month=date.getMonth();var mday=date.getDate();var no_days=date.getMonthDays();date.setDate(1);var wday=date.getDay();var MON=mondayFirst?1:0;var SAT=mondayFirst?5:6;var SUN=mondayFirst?6:0;if(mondayFirst){wday=(wday>0)?(wday-1):6;}var iday=1;var row=this.tbody.firstChild;var MN=Calendar._SMN[month];var hasToday=((today.getFullYear()==year)&&(today.getMonth()==month));var todayDate=today.getDate();var week_number=date.getWeekNumber();var ar_days=new Array();for(var i=0;i<6;++i){if(iday>no_days){row.className="emptyrow";row=row.nextSibling;continue;}var cell=row.firstChild;if(this.weekNumbers){cell.className="day wn";cell.firstChild.data=week_number;cell=cell.nextSibling;}++week_number;row.className="daysrow";for(var j=0;j<7;++j){cell.className="day";if((!i&&j<wday)||iday>no_days){cell.innerHTML="&nbsp;";cell.disabled=true;cell=cell.nextSibling;continue;}cell.disabled=false;cell.firstChild.data=iday;if(typeof this.getDateStatus=="function"){date.setDate(iday);var status=this.getDateStatus(date,year,month,iday);if(status===true){cell.className+=" disabled";cell.disabled=true;}else{if(/disabled/i.test(status))cell.disabled=true;cell.className+=" "+status;}}if(!cell.disabled){ar_days[ar_days.length]=cell;cell.caldate=iday;cell.ttip="_";if(iday==mday){cell.className+=" selected";this.currentDateEl=cell;}if(hasToday&&(iday==todayDate)){cell.className+=" today";cell.ttip+=Calendar._TT["PART_TODAY"];}if(wday==SAT||wday==SUN){cell.className+=" weekend";}}++iday;((++wday)^ 7)||(wday=0);cell=cell.nextSibling;}row=row.nextSibling;}this.ar_days=ar_days;this.title.firstChild.data=Calendar._MN[month]+", "+year;this.onSetTime();};Calendar.prototype.setDate=function(date){if(!date.equalsTo(this.date)){this._init(this.mondayFirst,date);}};Calendar.prototype.refresh=function(){this._init(this.mondayFirst,this.date);};Calendar.prototype.setMondayFirst=function(mondayFirst){this._init(mondayFirst,this.date);this._displayWeekdays();};Calendar.prototype.setDateStatusHandler=Calendar.prototype.setDisabledHandler=function(unaryFunction){this.getDateStatus=unaryFunction;};Calendar.prototype.setRange=function(a,z){this.minYear=a;this.maxYear=z;};Calendar.prototype.callHandler=function(){if(this.onSelected){this.onSelected(this,this.date.print(this.dateFormat));}};Calendar.prototype.callCloseHandler=function(){if(this.onClose){this.onClose(this);}this.hideShowCovered();};Calendar.prototype.destroy=function(){var el=this.element.parentNode;el.removeChild(this.element);Calendar._C=null;window.calendar=null;};Calendar.prototype.reparent=function(new_parent){var el=this.element;el.parentNode.removeChild(el);new_parent.appendChild(el);};Calendar._checkCalendar=function(ev){if(!window.calendar){return false;}var el=Calendar.is_ie?Calendar.getElement(ev):Calendar.getTargetElement(ev);for(;el!=null&&el!=calendar.element;el=el.parentNode);if(el==null){window.calendar.callCloseHandler();return Calendar.stopEvent(ev);}};Calendar.prototype.show=function(){var rows=this.table.getElementsByTagName("tr");for(var i=rows.length;i>0;){var row=rows[--i];Calendar.removeClass(row,"rowhilite");var cells=row.getElementsByTagName("td");for(var j=cells.length;j>0;){var cell=cells[--j];Calendar.removeClass(cell,"hilite");Calendar.removeClass(cell,"active");}}this.element.style.display="block";this.hidden=false;if(this.isPopup){window.calendar=this;Calendar.addEvent(document,"keydown",Calendar._keyEvent);Calendar.addEvent(document,"keypress",Calendar._keyEvent);Calendar.addEvent(document,"mousedown",Calendar._checkCalendar);}this.hideShowCovered();};Calendar.prototype.hide=function(){if(this.isPopup){Calendar.removeEvent(document,"keydown",Calendar._keyEvent);Calendar.removeEvent(document,"keypress",Calendar._keyEvent);Calendar.removeEvent(document,"mousedown",Calendar._checkCalendar);}this.element.style.display="none";this.hidden=true;this.hideShowCovered();};Calendar.prototype.showAt=function(x,y){var s=this.element.style;s.left=x+"px";s.top=y+"px";this.show();};Calendar.prototype.showAtElement=function(el,opts){var self=this;var p=Calendar.getAbsolutePos(el);if(!opts||typeof opts!="string"){this.showAt(p.x,p.y+el.offsetHeight);return true;}this.element.style.display="block";Calendar.continuation_for_the_fucking_khtml_browser=function(){var w=self.element.offsetWidth;var h=self.element.offsetHeight;self.element.style.display="none";var valign=opts.substr(0,1);var halign="l";if(opts.length>1){halign=opts.substr(1,1);}switch(valign){case "T":p.y-=h;break;case "B":p.y+=el.offsetHeight;break;case "C":p.y+=(el.offsetHeight-h)/2;break;case "t":p.y+=el.offsetHeight-h;break;case "b":break;}switch(halign){case "L":p.x-=w;break;case "R":p.x+=el.offsetWidth;break;case "C":p.x+=(el.offsetWidth-w)/2;break;case "r":p.x+=el.offsetWidth-w;break;case "l":break;}self.showAt(p.x,p.y);};if(Calendar.is_khtml)setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()",10);else Calendar.continuation_for_the_fucking_khtml_browser();};Calendar.prototype.setDateFormat=function(str){this.dateFormat=str;};Calendar.prototype.setTtDateFormat=function(str){this.ttDateFormat=str;};Calendar.prototype.parseDate=function(str,fmt){var y=0;var m=-1;var d=0;var a=str.split(/\W+/);if(!fmt){fmt=this.dateFormat;}var b=[];fmt.replace(/(%.)/g,function(str,par){return b[b.length]=par;});var i=0,j=0;var hr=0;var min=0;for(i=0;i<a.length;++i){if(b[i]=="%a"||b[i]=="%A"){continue;}if(b[i]=="%d"||b[i]=="%e"){d=parseInt(a[i],10);}if(b[i]=="%m"){m=parseInt(a[i],10)-1;}if(b[i]=="%Y"||b[i]=="%y"){y=parseInt(a[i],10);(y<100)&&(y+=(y>29)?1900:2000);}if(b[i]=="%b"||b[i]=="%B"){for(j=0;j<12;++j){if(Calendar._MN[j].substr(0,a[i].length).toLowerCase()==a[i].toLowerCase()){m=j;break;}}}else if(/%[HIkl]/.test(b[i])){hr=parseInt(a[i],10);}else if(/%[pP]/.test(b[i])){if(/pm/i.test(a[i])&&hr<12)hr+=12;}else if(b[i]=="%M"){min=parseInt(a[i],10);}}if(y!=0&&m!=-1&&d!=0){this.setDate(new Date(y,m,d,hr,min,0));return;}y=0;m=-1;d=0;for(i=0;i<a.length;++i){if(a[i].search(/[a-zA-Z]+/)!=-1){var t=-1;for(j=0;j<12;++j){if(Calendar._MN[j].substr(0,a[i].length).toLowerCase()==a[i].toLowerCase()){t=j;break;}}if(t!=-1){if(m!=-1){d=m+1;}m=t;}}else if(parseInt(a[i],10)<=12&&m==-1){m=a[i]-1;}else if(parseInt(a[i],10)>31&&y==0){y=parseInt(a[i],10);(y<100)&&(y+=(y>29)?1900:2000);}else if(d==0){d=a[i];}}if(y==0){var today=new Date();y=today.getFullYear();}if(m!=-1&&d!=0){this.setDate(new Date(y,m,d,hr,min,0));}};Calendar.prototype.hideShowCovered=function(){var self=this;Calendar.continuation_for_the_fucking_khtml_browser=function(){function getVisib(obj){var value=obj.style.visibility;if(!value){if(document.defaultView&&typeof(document.defaultView.getComputedStyle)=="function"){if(!Calendar.is_khtml)value=document.defaultView. getComputedStyle(obj,"").getPropertyValue("visibility");else value='';}else if(obj.currentStyle){value=obj.currentStyle.visibility;}else value='';}return value;};var tags=new Array("applet","iframe","select");var el=self.element;var p=Calendar.getAbsolutePos(el);var EX1=p.x;var EX2=el.offsetWidth+EX1;var EY1=p.y;var EY2=el.offsetHeight+EY1;for(var k=tags.length;k>0;){var ar=document.getElementsByTagName(tags[--k]);var cc=null;for(var i=ar.length;i>0;){cc=ar[--i];p=Calendar.getAbsolutePos(cc);var CX1=p.x;var CX2=cc.offsetWidth+CX1;var CY1=p.y;var CY2=cc.offsetHeight+CY1;if(self.hidden||(CX1>EX2)||(CX2<EX1)||(CY1>EY2)||(CY2<EY1)){if(!cc.__msh_save_visibility){cc.__msh_save_visibility=getVisib(cc);}cc.style.visibility=cc.__msh_save_visibility;}else{if(!cc.__msh_save_visibility){cc.__msh_save_visibility=getVisib(cc);}cc.style.visibility="hidden";}}}};if(Calendar.is_khtml)setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()",10);else Calendar.continuation_for_the_fucking_khtml_browser();};Calendar.prototype._displayWeekdays=function(){var MON=this.mondayFirst?0:1;var SUN=this.mondayFirst?6:0;var SAT=this.mondayFirst?5:6;var cell=this.firstdayname;for(var i=0;i<7;++i){cell.className="day name";if(!i){cell.ttip=this.mondayFirst?Calendar._TT["SUN_FIRST"]:Calendar._TT["MON_FIRST"];cell.navtype=100;cell.calendar=this;Calendar._add_evs(cell);}if(i==SUN||i==SAT){Calendar.addClass(cell,"weekend");}cell.firstChild.data=Calendar._SDN[i+1-MON];cell=cell.nextSibling;}};Calendar.prototype._hideCombos=function(){this.monthsCombo.style.display="none";this.yearsCombo.style.display="none";};Calendar.prototype._dragStart=function(ev){if(this.dragging){return;}this.dragging=true;var posX;var posY;if(Calendar.is_ie){posY=window.event.clientY+document.body.scrollTop;posX=window.event.clientX+document.body.scrollLeft;}else{posY=ev.clientY+window.scrollY;posX=ev.clientX+window.scrollX;}var st=this.element.style;this.xOffs=posX-parseInt(st.left);this.yOffs=posY-parseInt(st.top);with(Calendar){addEvent(document,"mousemove",calDragIt);addEvent(document,"mouseover",stopEvent);addEvent(document,"mouseup",calDragEnd);}};Date._MD=new Array(31,28,31,30,31,30,31,31,30,31,30,31);Date.SECOND=1000;Date.MINUTE=60*Date.SECOND;Date.HOUR=60*Date.MINUTE;Date.DAY=24*Date.HOUR;Date.WEEK=7*Date.DAY;Date.prototype.getMonthDays=function(month){var year=this.getFullYear();if(typeof month=="undefined"){month=this.getMonth();}if(((0==(year%4))&&((0!=(year%100))||(0==(year%400))))&&month==1){return 29;}else{return Date._MD[month];}};Date.prototype.getDayOfYear=function(){var now=new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0);var then=new Date(this.getFullYear(),0,1,0,0,0);var time=now-then;return Math.floor(time/Date.DAY);};Date.prototype.getWeekNumber=function(){var now=new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0);var then=new Date(this.getFullYear(),0,1,0,0,0);var time=now-then;var day=then.getDay();if(day==0)day=7;(day>4)&&(day-=4)||(day+=3);return Math.round(((time/Date.DAY)+day)/7);};Date.prototype.equalsTo=function(date){return((this.getFullYear()==date.getFullYear())&&(this.getMonth()==date.getMonth())&&(this.getDate()==date.getDate())&&(this.getHours()==date.getHours())&&(this.getMinutes()==date.getMinutes()));};Date.prototype.print=function(str){var m=this.getMonth();var d=this.getDate();var y=this.getFullYear();var wn=this.getWeekNumber();var w=this.getDay();var s={};var hr=this.getHours();var pm=(hr>=12);var ir=(pm)?(hr-12):hr;var dy=this.getDayOfYear();if(ir==0)ir=12;var min=this.getMinutes();var sec=this.getSeconds();s["%a"]=Calendar._SDN[w];s["%A"]=Calendar._DN[w];s["%b"]=Calendar._SMN[m];s["%B"]=Calendar._MN[m];s["%C"]=1+Math.floor(y/100);s["%d"]=(d<10)?("0"+d):d;s["%e"]=d;s["%H"]=(hr<10)?("0"+hr):hr;s["%I"]=(ir<10)?("0"+ir):ir;s["%j"]=(dy<100)?((dy<10)?("00"+dy):("0"+dy)):dy;s["%k"]=hr;s["%l"]=ir;s["%m"]=(m<9)?("0"+(1+m)):(1+m);s["%M"]=(min<10)?("0"+min):min;s["%n"]="\n";s["%p"]=pm?"PM":"AM";s["%P"]=pm?"pm":"am";s["%s"]=Math.floor(this.getTime()/1000);s["%S"]=(sec<10)?("0"+sec):sec;s["%t"]="\t";s["%U"]=s["%W"]=s["%V"]=(wn<10)?("0"+wn):wn;s["%u"]=w+1;s["%w"]=w;s["%y"]=(''+y).substr(2,2);s["%Y"]=y;s["%%"]="%";var re=Date._msh_formatRegexp;if(typeof re=="undefined"){var tmp="";for(var i in s)tmp+=tmp?("|"+i):i;Date._msh_formatRegexp=re=new RegExp("("+tmp+")",'g');}return str.replace(re,function(match,par){return s[par];});};window.calendar=null; \ No newline at end of file
diff --git a/httemplate/elements/header.html b/httemplate/elements/header.html
new file mode 100644
index 0000000..1d7bf09
--- /dev/null
+++ b/httemplate/elements/header.html
@@ -0,0 +1,19 @@
+<%
+ my($title, $menubar) = @_;
+ my $etc = @_ ? shift : ''; #$etc is for things like onLoad= etc.
+%>
+ <HTML>
+ <HEAD>
+ <TITLE>
+ <%= $title %>
+ </TITLE>
+ <META HTTP-Equiv="Cache-Control" Content="no-cache">
+ <META HTTP-Equiv="Pragma" Content="no-cache">
+ <META HTTP-Equiv="Expires" Content="0">
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8"<%= $etc %>>
+ <FONT SIZE=6>
+ <%= $title %>
+ </FONT>
+ <BR><BR>
+ <%= $menubar ? "$menubar<BR><BR>" : '' %>
diff --git a/httemplate/elements/menubar.html b/httemplate/elements/menubar.html
new file mode 100644
index 0000000..87a5031
--- /dev/null
+++ b/httemplate/elements/menubar.html
@@ -0,0 +1,8 @@
+<%
+ my($item, $url, @html);
+ while (@_) {
+ ($item, $url) = splice(@_,0,2);
+ push @html, qq!<A HREF="$url">$item</A>!;
+ }
+%>
+<%= join(' | ', @html) %>
diff --git a/httemplate/elements/pager.html b/httemplate/elements/pager.html
new file mode 100644
index 0000000..0510d32
--- /dev/null
+++ b/httemplate/elements/pager.html
@@ -0,0 +1,42 @@
+<%
+
+ my %opt = @_;
+
+ my $pager = '';
+ if ( $opt{'total'} != $opt{'num_rows'} && $opt{'maxrecords'} ) {
+ unless ( $opt{'offset'} == 0 ) {
+ $cgi->param('offset', $opt{'offset'} - $opt{'maxrecords'});
+%>
+
+ <A HREF="<%= $cgi->self_url %>"><B><FONT SIZE="+1">Previous</FONT></B></A>
+
+<%
+ }
+ my $page = 0;
+ for ( my $poff = 0; $poff < $opt{'total'}; $poff += $opt{'maxrecords'} ) {
+ $page++;
+ if ( $opt{'offset'} == $poff ) {
+%>
+
+ <FONT SIZE="+2"><%= $page %></FONT>
+
+<%
+ } else {
+ $cgi->param('offset', $poff);
+%>
+
+ <A HREF="<%= $cgi->self_url %>"><%= $page %></A>
+
+<%
+ }
+ }
+ unless ( $opt{'offset'} + $opt{'maxrecords'} > $opt{'total'} ) {
+ $cgi->param('offset', $opt{'offset'} + $opt{'maxrecords'});
+%>
+
+ <A HREF="<%= $cgi->self_url %>"><B><FONT SIZE="+1">Next</FONT></B></A>
+
+<%
+ }
+ }
+%>
diff --git a/httemplate/elements/small_custview.html b/httemplate/elements/small_custview.html
new file mode 100644
index 0000000..1e8ae73
--- /dev/null
+++ b/httemplate/elements/small_custview.html
@@ -0,0 +1,2 @@
+<% my $conf = new FS::Conf; %>
+<%= small_custview( shift, shift || $conf->config('countrydefault') ) %>
diff --git a/httemplate/elements/table.html b/httemplate/elements/table.html
new file mode 100644
index 0000000..3b61087
--- /dev/null
+++ b/httemplate/elements/table.html
@@ -0,0 +1,8 @@
+<%
+ my $color = shift;
+ if ( $color ) {
+%>
+ <TABLE BGCOLOR="<%= $color %>" BORDER=1 WIDTH="100%" CELLSPACING=0 CELLPADDING=2 BORDERCOLOR="#999999">
+<% } else { %>
+ <TABLE BORDER=1 CELLSPACING=0 CELLPADDING=2 BORDERCOLOR="#999999">
+<% } %>
diff --git a/httemplate/graph/money_time-graph.cgi b/httemplate/graph/money_time-graph.cgi
new file mode 100755
index 0000000..bb3d23a
--- /dev/null
+++ b/httemplate/graph/money_time-graph.cgi
@@ -0,0 +1,68 @@
+<%
+
+#my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+my ($curmon,$curyear) = (localtime(time))[4,5];
+
+#find first month
+my $syear = $cgi->param('syear') || 1899+$curyear;
+my $smonth = $cgi->param('smonth') || $curmon+1;
+
+#find last month
+my $eyear = $cgi->param('eyear') || 1900+$curyear;
+my $emonth = $cgi->param('emonth') || $curmon+1;
+#if ( $emonth++>12 ) { $emonth-=12; $eyear++; }
+
+#my @labels;
+#my %data;
+
+my @items = qw( invoiced netsales credits payments receipts );
+my %label = (
+ 'invoiced' => 'Gross Sales (invoiced)',
+ 'netsales' => 'Net Sales (invoiced - applied credits)',
+ 'credits' => 'Credits',
+ 'payments' => 'Gross Receipts (payments)',
+ 'receipts' => 'Net Receipts/Cashflow (payments - refunds)',
+);
+my %color = (
+ 'invoiced' => [ 153, 153, 255 ], #light blue
+ 'netsales' => [ 0, 0, 204 ], #blue
+ 'credits' => [ 204, 0, 0 ], #red
+ 'payments' => [ 153, 204, 153 ], #light green
+ 'receipts' => [ 0, 204, 0 ], #green
+);
+
+my $report = new FS::Report::Table::Monthly (
+ 'items' => \@items,
+ 'start_month' => $smonth,
+ 'start_year' => $syear,
+ 'end_month' => $emonth,
+ 'end_year' => $eyear,
+);
+my %data = %{$report->data};
+
+#my $chart = Chart::LinesPoints->new(1024,480);
+#my $chart = Chart::LinesPoints->new(768,480);
+my $chart = Chart::LinesPoints->new(976,384);
+
+my $d = 0;
+$chart->set(
+ #'min_val' => 0,
+ 'legend' => 'bottom',
+ 'colors' => { ( map { 'dataset'.$d++ => $color{$_} } @items ),
+ #'grey_background' => [ 211, 211, 211 ],
+ 'grey_background' => 'white',
+ 'background' => [ 0xe8, 0xe8, 0xe8 ], #grey
+ },
+ #'grey_background' => 'false',
+ 'legend_labels' => [ map { $label{$_} } @items ],
+ 'brush_size' => 4,
+ #'pt_size' => 12,
+);
+
+my @data = map { $data{$_} } ( 'label', @items );
+
+http_header('Content-Type' => 'image/png' );
+
+$chart->_set_colors();
+
+%><%= $chart->scalar_png(\@data) %>
diff --git a/httemplate/graph/money_time.cgi b/httemplate/graph/money_time.cgi
new file mode 100644
index 0000000..1c7d542
--- /dev/null
+++ b/httemplate/graph/money_time.cgi
@@ -0,0 +1,125 @@
+<!-- mason kludge -->
+<%
+
+#my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+my ($curmon,$curyear) = (localtime(time))[4,5];
+
+#find first month
+my $syear = $cgi->param('syear') || 1899+$curyear;
+my $smonth = $cgi->param('smonth') || $curmon+1;
+
+#find last month
+my $eyear = $cgi->param('eyear') || 1900+$curyear;
+my $emonth = $cgi->param('emonth') || $curmon+1;
+
+%>
+
+<HTML>
+ <HEAD>
+ <TITLE>Sales, Credits and Receipts Summary</TITLE>
+ </HEAD>
+<BODY BGCOLOR="#e8e8e8">
+<IMG SRC="money_time-graph.cgi?<%= $cgi->query_string %>" WIDTH="976" HEIGHT="384">
+<BR>
+
+<%= table('e8e8e8') %>
+<%
+
+my @items = qw( invoiced netsales credits payments receipts );
+my %label = (
+ 'invoiced' => 'Gross Sales',
+ 'netsales' => 'Net Sales',
+ 'credits' => 'Credits',
+ 'payments' => 'Gross Receipts',
+ 'receipts' => 'Net Receipts',
+);
+my %color = (
+ 'invoiced' => '9999ff', #light blue
+ 'netsales' => '0000cc', #blue
+ 'credits' => 'cc0000', #red
+ 'payments' => '99cc99', #light green
+ 'receipts' => '00cc00', #green
+);
+my %link = (
+ 'invoiced' => "${p}search/cust_bill.html?",
+ 'credits' => "${p}search/cust_credit.html?",
+ 'payments' => "${p}search/cust_pay.cgi?magic=_date;",
+);
+
+my $report = new FS::Report::Table::Monthly (
+ 'items' => \@items,
+ 'start_month' => $smonth,
+ 'start_year' => $syear,
+ 'end_month' => $emonth,
+ 'end_year' => $eyear,
+);
+my $data = $report->data;
+
+my @mon = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+
+%>
+
+<TR><TD></TD>
+<% foreach my $column ( @{$data->{label}} ) {
+ #$column =~ s/^(\d+)\//$mon[$1-1]<BR>/e;
+ $column =~ s/^(\d+)\//$mon[$1-1]<BR>/;
+ %>
+ <TH><%= $column %></TH>
+<% } %>
+</TR>
+
+<% foreach my $row (@items) { %>
+ <TR><TH><FONT COLOR="#<%= $color{$row} %>"><%= $label{$row} %></FONT></TH>
+ <% my $link = exists($link{$row})
+ ? qq(<A HREF="$link{$row})
+ : '';
+ my @speriod = @{$data->{speriod}};
+ my @eperiod = @{$data->{eperiod}};
+ %>
+ <% foreach my $column ( @{$data->{$row}} ) { %>
+ <TD ALIGN="right" BGCOLOR="#ffffff">
+ <%= $link ? $link. 'begin='. shift(@speriod). ';end='. shift(@eperiod). '">' : '' %><FONT COLOR="#<%= $color{$row} %>">$<%= sprintf("%.2f", $column) %></FONT><%= $link ? '</A>' : '' %>
+ </TD>
+ <% } %>
+ </TR>
+<% } %>
+</TABLE>
+
+<BR>
+<FORM METHOD="POST">
+<!--
+<INPUT TYPE="checkbox" NAME="ar">
+ Accounts receivable (invoices - applied credits)<BR>
+<INPUT TYPE="checkbox" NAME="charged">
+ Just Invoices<BR>
+<INPUT TYPE="checkbox" NAME="defer">
+ Accounts receivable, with deferred revenue (invoices - applied credits, with charges for annual/semi-annual/quarterly/etc. services deferred over applicable time period) (there has got to be a shorter description for this)<BR>
+<INPUT TYPE="checkbox" NAME="cash">
+ Cashflow (payments - refunds)<BR>
+<BR>
+-->
+From <SELECT NAME="smonth">
+<% foreach my $mon ( 1..12 ) { %>
+<OPTION VALUE="<%= $mon %>"<%= $mon == $smonth ? ' SELECTED' : '' %>><%= $mon[$mon-1] %>
+<% } %>
+</SELECT>
+<SELECT NAME="syear">
+<% foreach my $y ( 1999 .. 2010 ) { %>
+<OPTION VALUE="<%= $y %>"<%= $y == $syear ? ' SELECTED' : '' %>><%= $y %>
+<% } %>
+</SELECT>
+ to <SELECT NAME="emonth">
+<% foreach my $mon ( 1..12 ) { %>
+<OPTION VALUE="<%= $mon %>"<%= $mon == $emonth ? ' SELECTED' : '' %>><%= $mon[$mon-1] %>
+<% } %>
+</SELECT>
+<SELECT NAME="eyear">
+<% foreach my $y ( 1999 .. 2010 ) { %>
+<OPTION VALUE="<%= $y %>"<%= $y == $eyear ? ' SELECTED' : '' %>><%= $y %>
+<% } %>
+</SELECT>
+
+<INPUT TYPE="submit" VALUE="Redisplay">
+</FORM>
+</BODY>
+</HTML>
diff --git a/httemplate/images/ach.png b/httemplate/images/ach.png
new file mode 100644
index 0000000..fdcd5e6
--- /dev/null
+++ b/httemplate/images/ach.png
Binary files differ
diff --git a/httemplate/images/calendar.png b/httemplate/images/calendar.png
new file mode 100644
index 0000000..1632661
--- /dev/null
+++ b/httemplate/images/calendar.png
Binary files differ
diff --git a/httemplate/images/cvv2.png b/httemplate/images/cvv2.png
new file mode 100644
index 0000000..4610dcb
--- /dev/null
+++ b/httemplate/images/cvv2.png
Binary files differ
diff --git a/httemplate/images/cvv2_amex.png b/httemplate/images/cvv2_amex.png
new file mode 100644
index 0000000..21c36a0
--- /dev/null
+++ b/httemplate/images/cvv2_amex.png
Binary files differ
diff --git a/httemplate/images/mid-logo.png b/httemplate/images/mid-logo.png
new file mode 100644
index 0000000..d993419
--- /dev/null
+++ b/httemplate/images/mid-logo.png
Binary files differ
diff --git a/httemplate/images/small-logo.png b/httemplate/images/small-logo.png
new file mode 100644
index 0000000..406a369
--- /dev/null
+++ b/httemplate/images/small-logo.png
Binary files differ
diff --git a/httemplate/index.html b/httemplate/index.html
new file mode 100644
index 0000000..d894cb5
--- /dev/null
+++ b/httemplate/index.html
@@ -0,0 +1,206 @@
+<HTML>
+ <HEAD>
+ <TITLE>
+ Freeside Main Menu
+ </TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#FFFFFF">
+ <table width="100%">
+ <tr><td>
+ <IMG BORDER=0 ALT="Silicon Interactive Software Design" SRC="images/small-logo.png">
+ </td><td>
+ <font color="#ff0000" size=7>freeside main menu</font>
+ </td><td align=right valign=bottom>
+ version %%%VERSION%%%
+ <BR><A HREF="http://www.sisd.com/freeside">Freeside&nbsp;home&nbsp;page</A>
+ <BR><A HREF="docs/">Documentation</A>
+ </td></tr>
+ </table>
+
+<BR>
+[<A NAME="customer_service" style="background-color: #cccccc"> Sales / Customer service </A>]
+[ <A HREF="#bookkeeping">Bookkeeping / Collections</A> ]
+[ <A HREF="#reports">Reports</A> ]
+[ <A HREF="#sysadmin">Sysadmin</A> ]
+ <TABLE CELLSPACING=2 CELLPADDING=0 BORDER=0" WIDTH="100%" BGCOLOR="#eeeeee">
+ <TR><TH BGCOLOR="#cccccc">Sales / Customer service</TH></TR>
+ <TR><TD>
+ <BR><FONT SIZE="+1"><A HREF="edit/cust_main.cgi">New Customer</A></FONT>
+ <BR>
+ <BR><FORM ACTION="search/cust_main.cgi" METHOD="POST"><INPUT TYPE="hidden" NAME="custnum_on" VALUE="1">Customer # <INPUT TYPE="text" NAME="custnum_text"><INPUT TYPE="submit" VALUE="Search"> or <A HREF="search/cust_main.cgi?browse=custnum">all customers by customer number</A></FORM>
+ <FORM ACTION="search/cust_main.cgi" METHOD="POST"><INPUT TYPE="hidden" NAME="last_on" VALUE="1">Last name <INPUT TYPE="text" NAME="last_text"><SELECT NAME="last_type"><OPTION SELECTED VALUE="All">(all)</OPTION><OPTION>Fuzzy<OPTION>Substring</OPTION><OPTION>Exact</OPTION></SELECT><INPUT TYPE="submit" VALUE="Search"> or <A HREF="search/cust_main.cgi?browse=last">all customers by last name</A></FORM>
+ <FORM ACTION="search/cust_main.cgi" METHOD="POST"><INPUT TYPE="hidden" NAME="company_on" VALUE="1">Company <INPUT TYPE="text" NAME="company_text"><SELECT NAME="company_type"><OPTION SELECTED VALUE="All">(all)</OPTION><OPTION>Fuzzy<OPTION>Substring</OPTION><OPTION>Exact</OPTION></SELECT><INPUT TYPE="submit" VALUE="Search"> or <A HREF="search/cust_main.cgi?browse=company">all customers by company</A></FORM>
+<!-- <FORM ACTION="search/cust_main.cgi" METHOD="POST"><INPUT TYPE="hidden" NAME="address2_on" VALUE="1">Unit <INPUT TYPE="text" NAME="address2_text"><INPUT TYPE="submit" VALUE="Search"></FORM>-->
+ <FORM ACTION="search/cust_main.cgi" METHOD="POST"><INPUT TYPE="hidden" NAME="phone_on" VALUE="1">Phone # <INPUT TYPE="text" NAME="phone_text"><INPUT TYPE="submit" VALUE="Search"></FORM>
+ <BR><FORM ACTION="search/svc_acct.cgi" METHOD="POST">Username <INPUT TYPE="text" NAME="username"><SELECT NAME="username_type"><OPTION VALUE="All">(all)</OPTION><OPTION>Fuzzy</OPTION><OPTION>Substring</OPTION><OPTION SELECTED>Exact</OPTION></SELECT><INPUT TYPE="submit" VALUE="Search"> or <A HREF="search/svc_acct.cgi?username">all accounts by username</A> or <A HREF="search/svc_acct.cgi?uid">uid</A></FORM>
+ <BR><FORM ACTION="search/svc_domain.cgi" METHOD="POST">Domain <INPUT TYPE="text" NAME="domain"><INPUT TYPE="submit" VALUE="Search"> or <A HREF="search/svc_domain.cgi?domain">all domains</A></FORM>
+ <BR><A HREF="search/svc_forward.cgi?svcnum">all mail forwards by svcnum</A><BR>
+ <BR><A HREF="search/svc_www?svcnum">all virtual hosts by svcnum</A><BR>
+ <BR>
+ </TD></TR>
+ </TABLE>
+
+
+
+ <BR><BR><BR>
+
+
+[ <A HREF="#customer_service">Sales / Customer service</A> ]
+[<A NAME="bookkeeping" style="background-color: #cccccc"> Bookkeeping / Collections </A>]
+[ <A HREF="#reports">Reports</A> ]
+[ <A HREF="#sysadmin">Sysadmin</A> ]
+ <TABLE CELLSPACING=2 CELLPADDING=0 BORDER=0 WIDTH="100%" BGCOLOR="#eeeeee">
+ <TR><TH BGCOLOR="#cccccc">Bookkeeping / Collections</TH></TR>
+ <TR><TD>
+ <BR><A HREF="search/cust_main-quickpay.html">Quick payment entry</A>
+ <BR>
+ <BR><FORM ACTION="search/cust_main.cgi" METHOD="POST">Credit card # <INPUT TYPE="hidden" NAME="card_on" VALUE="1"><INPUT TYPE="text" NAME="card"><INPUT TYPE="submit" VALUE="Search"></FORM>
+ <FORM ACTION="search/cust_bill.html" METHOD="POST">Invoice # <INPUT TYPE="text" NAME="invnum" SIZE="8"><INPUT TYPE="submit" VALUE="Search"></FORM>
+ <FORM ACTION="search/cust_pay.cgi" METHOD="POST">Check # <INPUT TYPE="text" NAME="payinfo" SIZE="8"><INPUT TYPE="hidden" NAME="payby" VALUE="BILL"><INPUT TYPE="submit" VALUE="Search"></FORM>
+ <BR><A HREF="browse/cust_pay_batch.cgi">View pending credit card batch</A> <BR><BR><A HREF="search/cust_pkg_report.cgi">Packages (by next bill date range)</A>
+ <BR><BR>Invoice reports
+ <UL>
+ <LI><a href="search/cust_bill_event.html">Invoice event errors (failed credit cards)</a>
+ <LI>open invoices (<A HREF="search/cust_bill.html?OPEN_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN_custnum">by customer number</A>)
+ <LI>15 day open invoices (<A HREF="search/cust_bill.html?OPEN15_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN15_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN15_custnum">by customer number</A>)
+ <LI>30 day open invoices (<A HREF="search/cust_bill.html?OPEN30_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN30_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN30_custnum">by customer number</A>)
+ <LI>60 day open invoices (<A HREF="search/cust_bill.html?OPEN60_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN60_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN60_custnum">by customer number</A>)
+ <LI>90 day open invoices (<A HREF="search/cust_bill.html?OPEN90_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN90_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN90_custnum">by customer number</A>)
+ <LI>120 day open invoices (<A HREF="search/cust_bill.html?OPEN120_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN120_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN120_custnum">by customer number</A>)
+ <LI>all invoices (<A HREF="search/cust_bill.html?invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?date">by date</A>) (<A HREF="search/cust_bill.html?custnum">by customer number</A>)
+ </UL>
+ <A HREF="search/report_cust_pay.html">Payment report (by type and/or date range)</A>
+ <BR><BR><A HREF="search/report_cust_credit.html">Credit report (by employee and/or date range)</A>
+ <BR><BR><A HREF="graph/money_time.cgi">Sales, Credits and Receipts Summary</A>
+ <BR><BR><A HREF="search/report_receivables.cgi">Accounts Receivable Aging Summary</A>
+ <BR><BR><A HREF="search/report_prepaid_income.html">Prepaid Income (Unearned Revenue) Report</A>
+ <BR><BR><A HREF="search/report_tax.html">Sales Tax Liability Report</A>
+ <BR><BR>
+ <CENTER><HR WIDTH="94%" NOSHADE></CENTER><BR>
+ <A NAME="admin">Administration</a>
+ <ul>
+ <LI><A HREF="browse/part_pkg.cgi">View/Edit package definitions</A>
+ - One or more services are grouped together into a package and
+ given pricing information. Customers purchase packages, not
+ services.
+<!-- <LI><A HREF="browse/agent_type.cgi">View/Edit agent types</A>
+ - Agent types define groups of package definitions that you can
+ then assign to particular agents.
+ <LI><A HREF="browse/agent.cgi">View/Edit agents</A>
+ - Agents are resellers of your service. Agents may be limited
+ to a subset of your full offerings (via their type).
+-->
+ <LI><A HREF="browse/cust_main_county.cgi">View/Edit locales and tax rates</A>
+ - Change tax rates, or break down a country into states, or a state
+ into counties and assign different tax rates to each.
+ <LI><A HREF="browse/part_bill_event.cgi">View/Edit invoice events</A> - Actions for overdue invoices
+ </ul>
+ <BR>
+ </TD></TR>
+ </TABLE>
+
+
+
+ <BR><BR><BR>
+
+
+
+[ <A HREF="#customer_service">Sales / Customer service</A> ]
+[ <A HREF="#bookkeeping">Bookkeeping / Collections</A> ]
+[<A NAME="reports" style="background-color: #cccccc"> Reports </A>]
+[ <A HREF="#sysadmin">Sysadmin</A> ]
+ <TABLE CELLSPACING=2 CELLPADDING=0 BORDER=0 WIDTH="100%" BGCOLOR="#eeeeee">
+ <TR><TH BGCOLOR="#cccccc">Reports</TH></TR>
+ <TR><TD>
+ <BR>
+ Auditing pre-Freeside services with no customer record
+ <UL>
+ <LI>unlinked accounts (<A HREF="search/svc_acct.cgi?UN_svcnum">by service number</A>) (<A HREF="search/svc_acct.cgi?UN_username">by username</A>) (<A HREF="search/svc_acct.cgi?UN_uid">by uid</A>)
+<!-- <LI>unlinked mail forwards (<A HREF="search/svc_forward.cgi?UN_svcnum">by service number</A>) (by ?)) -->
+ <LI>unlinked domains (<A HREF="search/svc_domain.cgi?UN_svcnum">by service number</A>) (<A HREF="search/svc_domain.cgi?UN_domain">by domain</A>)
+ </UL>
+ Packages
+ <UL>
+ <LI><A HREF="search/cust_pkg.cgi?pkgnum">all packages (by package number)</A>
+ <LI><A HREF="search/cust_pkg.cgi?magic=suspended">suspended packages (by package number)</A>
+ <LI><A HREF="search/cust_pkg.cgi?APKG_pkgnum">packages with unconfigured services (by package number)</A>
+ <LI><A HREF="search/cust_pkg_report.cgi">packages (by next bill date range)</A>
+ </UL>
+ <A HREF="browse/part_pkg.cgi?active=1">Package definitions (by number of active packages)</A><BR><BR>
+ <A HREF="browse/part_svc.cgi?active=1">Service definitions (by number of active services)</A><BR><BR>
+ Customers
+ <UL>
+ <LI><A HREF="search/cust_main-otaker.cgi">Search customers by ordering employee</A>
+ </UL>
+ <FORM ACTION="search/sql.html" METHOD="POST">SQL query: <TT>SELECT </TT><INPUT TYPE="text" NAME="sql" SIZE=32><INPUT TYPE="submit" VALUE="Query"></FORM>
+
+ <BR>
+ </TD></TR>
+ </TABLE>
+
+
+
+ <BR><BR><BR>
+
+
+[ <A HREF="#customer_service">Sales / Customer service</A> ]
+[ <A HREF="#bookkeeping">Bookkeeping / Collections</A> ]
+[ <A HREF="#reports">Reports</A> ]
+[<A NAME="sysadmin" style="background-color: #cccccc"> Sysadmin </A>]
+ <TABLE CELLSPACING=2 CELLPADDING=0 BORDER=0 WIDTH="100%" BGCOLOR="#eeeeee">
+ <TR><TH BGCOLOR="#cccccc">Sysadmin</TH></TR>
+ <TR><TD>
+ <BR>
+ <A HREF="browse/nas.cgi">View active NAS ports</A>
+ <BR><A HREF="browse/queue.cgi">View pending job queue</A>
+ <BR><A HREF="misc/cust_main-import.cgi">Batch import customers from CSV file</A>
+ <BR><A HREF="misc/cust_main-import_charges.cgi">Batch import charges from CSV file</A>
+ <BR><A HREF="misc/dump.cgi">Download database dump</A>
+ <BR><BR><CENTER><HR WIDTH="94%" NOSHADE></CENTER><BR>
+ <A NAME="config" HREF="config/config-view.cgi">Configuration</a><!-- - <font size="+2" color="#ff0000">start here</font> -->
+ <BR><BR><A NAME="admin">Administration</a>
+ <ul>
+ <LI><A HREF="browse/part_export.cgi">View/Edit exports</A>
+ - Provisioning services to external machines, databases and APIs.
+ <LI><A HREF="browse/part_svc.cgi">View/Edit service definitions</A>
+ - Services are items you offer to your customers.
+ <LI><A HREF="browse/part_pkg.cgi">View/Edit package definitions</A>
+ - One or more services are grouped together into a package and
+ given pricing information. Customers purchase packages, not
+ services.
+ <LI><A HREF="browse/agent_type.cgi">View/Edit agent types</A>
+ - Agent types define groups of package definitions that you can
+ then assign to particular agents.
+ <LI><A HREF="browse/agent.cgi">View/Edit agents</A>
+ - Agents are resellers of your service. Agents may be limited
+ to a subset of your full offerings (via their type).
+ <LI><A HREF="browse/part_referral.cgi">View/Edit advertising sources</A>
+ - Where a customer heard about your service. Tracked for
+ informational purposes.
+ <LI><A HREF="browse/cust_main_county.cgi">View/Edit locales and tax rates</A>
+ - Change tax rates, or break down a country into states, or a state
+ into counties and assign different tax rates to each.
+ <LI><A HREF="browse/svc_acct_pop.cgi">View/Edit access numbers</A>
+ - Points of Presence
+ <LI><A HREF="browse/part_bill_event.cgi">View/Edit invoice events</A> - Actions for overdue invoices
+ <LI><A HREF="browse/msgcat.cgi">View/Edit message catalog</A> - Change error messages and other customizable labels.
+ <LI><A HREF="browse/part_virtual_field.cgi">View/Edit virtual fields</A>
+ - Locally defined fields
+ <LI><A HREF="browse/router.cgi">View/Edit routers</A>
+ - Broadband access routers
+ <LI><A HREF="browse/addr_block.cgi">View/Edit address blocks</A>
+ - Manage address blocks and block assignments to broadband routers.
+ </ul>
+ <BR>
+ </TD></TR>
+ </TABLE>
+ <BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>
+ <BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>
+ <BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>
+ <BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>
+ <BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>
+ <BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>
+ <BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>
+ <BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>
+ </BODY>
+</HTML>
diff --git a/httemplate/misc/bill.cgi b/httemplate/misc/bill.cgi
new file mode 100755
index 0000000..44d85b8
--- /dev/null
+++ b/httemplate/misc/bill.cgi
@@ -0,0 +1,38 @@
+<%
+
+#untaint custnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d*)$/;
+my $custnum = $1;
+my $cust_main = qsearchs('cust_main',{'custnum'=>$custnum});
+die "Can't find customer!\n" unless $cust_main;
+
+my $error = $cust_main->bill(
+# 'time'=>$time
+ );
+#&eidiot($error) if $error;
+
+unless ( $error ) {
+ $cust_main->apply_payments;
+ $cust_main->apply_credits;
+
+ $error = $cust_main->collect(
+ # 'invoice-time'=>$time,
+ #'batch_card'=> 'yes',
+ #'batch_card'=> 'no',
+ #'report_badcard'=> 'yes',
+ #'retry_card' => 'yes',
+ 'retry' => 'yes',
+ );
+}
+#&eidiot($error) if $error;
+
+if ( $error ) {
+%>
+<!-- mason kludge -->
+<%
+ &idiot($error);
+} else {
+ print $cgi->redirect(popurl(2). "view/cust_main.cgi?$custnum");
+}
+%>
diff --git a/httemplate/misc/cancel-unaudited.cgi b/httemplate/misc/cancel-unaudited.cgi
new file mode 100755
index 0000000..43e439b
--- /dev/null
+++ b/httemplate/misc/cancel-unaudited.cgi
@@ -0,0 +1,34 @@
+<%
+
+my $dbh = dbh;
+
+#untaint svcnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $svcnum = $1;
+
+#my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum});
+#die "Unknown svcnum!" unless $svc_acct;
+
+my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum});
+die "Unknown svcnum!" unless $cust_svc;
+my $cust_pkg = $cust_svc->cust_pkg;
+if ( $cust_pkg ) {
+ &eidiot( 'This account has already been audited. Cancel the '.
+ qq!<A HREF="${p}view/cust_main.cgi?!. $cust_pkg->custnum.
+ '#cust_pkg'. $cust_pkg->pkgnum. '">'.
+ 'package</A> instead.');
+}
+
+my $error = $cust_svc->cancel;
+
+if ( $error ) {
+ %>
+<!-- mason kludge -->
+<%
+ &eidiot($error);
+} else {
+ print $cgi->redirect(popurl(2));
+}
+
+%>
diff --git a/httemplate/misc/cancel_pkg.cgi b/httemplate/misc/cancel_pkg.cgi
new file mode 100755
index 0000000..0487677
--- /dev/null
+++ b/httemplate/misc/cancel_pkg.cgi
@@ -0,0 +1,15 @@
+<%
+
+#untaint pkgnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal pkgnum";
+my $pkgnum = $1;
+
+my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+
+my $error = $cust_pkg->cancel;
+eidiot($error) if $error;
+
+print $cgi->redirect($p. "view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
+
+%>
diff --git a/httemplate/misc/catchall.cgi b/httemplate/misc/catchall.cgi
new file mode 100755
index 0000000..3402b61
--- /dev/null
+++ b/httemplate/misc/catchall.cgi
@@ -0,0 +1,133 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+
+my($svc_domain, $svcnum, $pkgnum, $svcpart, $part_svc);
+if ( $cgi->param('error') ) {
+ $svc_domain = new FS::svc_domain ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_domain')
+ } );
+ $svcnum = $svc_domain->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $cgi->param('svcpart');
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+} else {
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_domain=qsearchs('svc_domain',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_domain) svcnum!";
+
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
+
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
+
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ } else {
+
+ die "Invalid (svc_domain) svcnum!";
+
+ }
+}
+
+my %email;
+if ($pkgnum) {
+
+ #find all possible user svcnums (and emails)
+
+ #starting with that currently attached
+ if ($svc_domain->catchall) {
+ my($svc_acct)=qsearchs('svc_acct',{'svcnum'=>$svc_domain->catchall});
+ $email{$svc_domain->catchall} = $svc_acct->email;
+ }
+
+ #and including the rest for this customer
+ my($u_part_svc,@u_acct_svcparts);
+ foreach $u_part_svc ( qsearch('part_svc',{'svcdb'=>'svc_acct'}) ) {
+ push @u_acct_svcparts,$u_part_svc->getfield('svcpart');
+ }
+
+ my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+ my($custnum)=$cust_pkg->getfield('custnum');
+ my($i_cust_pkg);
+ foreach $i_cust_pkg ( qsearch('cust_pkg',{'custnum'=>$custnum}) ) {
+ my($cust_pkgnum)=$i_cust_pkg->getfield('pkgnum');
+ my($acct_svcpart);
+ foreach $acct_svcpart (@u_acct_svcparts) { #now find the corresponding
+ #record(s) in cust_svc ( for this
+ #pkgnum ! )
+ my($i_cust_svc);
+ foreach $i_cust_svc ( qsearch('cust_svc',{'pkgnum'=>$cust_pkgnum,'svcpart'=>$acct_svcpart}) ) {
+ my($svc_acct)=qsearchs('svc_acct',{'svcnum'=>$i_cust_svc->getfield('svcnum')});
+ $email{$svc_acct->getfield('svcnum')}=$svc_acct->email;
+ }
+ }
+ }
+
+} else {
+
+ my($svc_acct)=qsearchs('svc_acct',{'svcnum'=>$svc_domain->catchall});
+ $email{$svc_domain->catchall} = $svc_acct->email;
+}
+
+# add an absence of a catchall
+$email{''} = "(none)";
+
+my $p1 = popurl(1);
+print header("Domain Catchall Edit", '');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print qq!<FORM ACTION="${p1}process/catchall.cgi" METHOD=POST>!;
+
+#display
+
+ #formatting
+ print "<PRE>";
+
+#svcnum
+print qq!<INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum">!;
+print qq!Service #<FONT SIZE=+1><B>!, $svcnum ? $svcnum : " (NEW)", "</B></FONT>";
+
+#pkgnum
+print qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">!;
+
+#svcpart
+print qq!<INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">!;
+
+my($domain,$catchall)=(
+ $svc_domain->domain,
+ $svc_domain->catchall,
+);
+
+print qq!<INPUT TYPE="hidden" NAME="domain" VALUE="$domain">!;
+
+#catchall
+print qq!\n\nMail to <I>(anything)</I>@<B>$domain</B> forwards to <SELECT NAME="catchall" SIZE=1>!;
+foreach $_ (keys %email) {
+ print "<OPTION", $_ eq $catchall ? " SELECTED" : "",
+ qq! VALUE="$_">$email{$_}!;
+}
+print "</SELECT>";
+
+ #formatting
+ print "</PRE>\n";
+
+print qq!<CENTER><INPUT TYPE="submit" VALUE="Submit"></CENTER>!;
+
+print <<END;
+
+ </FORM>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi
new file mode 100755
index 0000000..5346fd9
--- /dev/null
+++ b/httemplate/misc/change_pkg.cgi
@@ -0,0 +1,66 @@
+<!-- mason kludge -->
+<%
+
+my $pkgnum;
+if ( $cgi->param('error') ) {
+ #$custnum = $cgi->param('custnum');
+ #%remove_pkg = map { $_ => 1 } $cgi->param('remove_pkg');
+ $pkgnum = ($cgi->param('remove_pkg'))[0];
+} else {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ #$custnum = $1;
+ $pkgnum = $1;
+ #%remove_pkg = ();
+}
+
+my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } )
+ or die "unknown pkgnum $pkgnum";
+my $custnum = $cust_pkg->custnum;
+
+my $conf = new FS::Conf;
+
+my $p1 = popurl(1);
+
+my $cust_main = $cust_pkg->cust_main
+ or die "can't get cust_main record for custnum ". $cust_pkg->custnum.
+ " ( pkgnum ". cust_pkg->pkgnum. ")";
+my $agent = $cust_main->agent;
+
+print header("Change Package", menubar(
+ "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ 'Main Menu' => $p,
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT><BR><BR>"
+ if $cgi->param('error');
+
+my $part_pkg = $cust_pkg->part_pkg;
+
+print small_custview( $cust_main, $conf->config('countrydefault') ).
+ qq!<FORM ACTION="${p}edit/process/cust_pkg.cgi" METHOD=POST>!.
+ qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!.
+ qq!<INPUT TYPE="hidden" NAME="remove_pkg" VALUE="$pkgnum">!.
+ '<BR>Current package: '. $part_pkg->pkg. ' - '. $part_pkg->comment.
+ qq!<BR>New package: <SELECT NAME="new_pkgpart"><OPTION VALUE=0></OPTION>!;
+
+foreach my $part_pkg (
+ grep { ! $_->disabled && $_->pkgpart != $cust_pkg->pkgpart }
+ map { $_->part_pkg } $agent->agent_type->type_pkgs
+) {
+ my $pkgpart = $part_pkg->pkgpart;
+ print qq!<OPTION VALUE="$pkgpart"!;
+ print ' SELECTED' if $cgi->param('error')
+ && $cgi->param('new_pkgpart') == $pkgpart;
+ print qq!>$pkgpart: !. $part_pkg->pkg. ' - '. $part_pkg->comment. '</OPTION>';
+}
+
+print <<END;
+</SELECT>
+<BR><BR><INPUT TYPE="submit" VALUE="Change package">
+ </FORM>
+ </BODY>
+</HTML>
+END
+%>
diff --git a/httemplate/misc/cust_main-cancel.cgi b/httemplate/misc/cust_main-cancel.cgi
new file mode 100755
index 0000000..257c338
--- /dev/null
+++ b/httemplate/misc/cust_main-cancel.cgi
@@ -0,0 +1,16 @@
+<%
+
+#untaint custnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal custnum";
+my $custnum = $1;
+
+my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
+
+my @errors = $cust_main->cancel;
+eidiot(join(' / ', @errors)) if scalar(@errors);
+
+#print $cgi->redirect($p. "view/cust_main.cgi?". $cust_main->custnum);
+print $cgi->redirect($p);
+
+%>
diff --git a/httemplate/misc/cust_main-import.cgi b/httemplate/misc/cust_main-import.cgi
new file mode 100644
index 0000000..6b36f47
--- /dev/null
+++ b/httemplate/misc/cust_main-import.cgi
@@ -0,0 +1,51 @@
+<!-- mason kludge -->
+<%= header('Batch Customer Import') %>
+<FORM ACTION="process/cust_main-import.cgi" METHOD="post" ENCTYPE="multipart/form-data">
+Import a CSV file containing customer records.<BR><BR>
+Default file format is CSV, with the following field order: <i>cust_pkg.setup, dayphone, first, last, address1, address2, city, state, zip, comments</i><BR><BR>
+
+<%
+ #false laziness with edit/cust_main.cgi
+ my @agents = qsearch( 'agent', {} );
+ die "No agents created!" unless @agents;
+ my $agentnum = $agents[0]->agentnum; #default to first
+
+ if ( scalar(@agents) == 1 ) {
+%>
+ <INPUT TYPE="hidden" NAME="agentnum" VALUE="<%= $agentnum %>">
+<% } else { %>
+ <BR><BR>Agent <SELECT NAME="agentnum" SIZE="1">
+ <% foreach my $agent (sort { $a->agent cmp $b->agent } @agents) { %>
+ <OPTION VALUE="<%= $agent->agentnum %>" <%= " SELECTED"x($agent->agentnum==$agentnum) %>><%= $agent->agent %></OPTION>
+ <% } %>
+ </SELECT><BR><BR>
+<% } %>
+
+<%
+ my @referrals = qsearch('part_referral',{});
+ die "No advertising sources created!" unless @referrals;
+ my $refnum = $referrals[0]->refnum; #default to first
+
+ if ( scalar(@referrals) == 1 ) {
+%>
+ <INPUT TYPE="hidden" NAME="refnum" VALUE="<%= $refnum %>">
+<% } else { %>
+ <BR><BR>Advertising source <SELECT NAME="refnum" SIZE="1">
+ <% foreach my $referral ( sort { $a->referral <=> $b->referral } @referrals) { %>
+ <OPTION VALUE="<%= $referral->refnum %>" <%= " SELECTED"x($referral->refnum==$refnum) %>><%= $referral->refnum %>: <%= $referral->referral %></OPTION>
+ <% } %>
+ </SELECT><BR><BR>
+<% } %>
+
+ First package: <SELECT NAME="pkgpart"><OPTION VALUE="">(none)</OPTION>
+<% foreach my $part_pkg ( qsearch('part_pkg',{'disabled'=>'' }) ) { %>
+ <OPTION VALUE="<%= $part_pkg->pkgpart %>"><%= $part_pkg->pkg. ' - '. $part_pkg->comment %></OPTION>
+<% } %>
+</SELECT><BR><BR>
+
+ CSV Filename: <INPUT TYPE="file" NAME="csvfile"><BR><BR>
+ <INPUT TYPE="submit" VALUE="Import">
+ </FORM>
+ </BODY>
+<HTML>
+
diff --git a/httemplate/misc/cust_main-import_charges.cgi b/httemplate/misc/cust_main-import_charges.cgi
new file mode 100644
index 0000000..0822b9e
--- /dev/null
+++ b/httemplate/misc/cust_main-import_charges.cgi
@@ -0,0 +1,14 @@
+<!-- mason kludge -->
+<%= header('Batch Customer Charge') %>
+<FORM ACTION="process/cust_main-import_charges.cgi" METHOD="post" ENCTYPE="multipart/form-data">
+Import a CSV file containing customer charges.<BR><BR>
+Default file format is CSV, with the following field order: <i>custnum, amount, description</i><BR><BR>
+If <i>amount</i> is negative, a credit will be applied instead.<BR><BR>
+<BR><BR>
+
+ CSV Filename: <INPUT TYPE="file" NAME="csvfile"><BR><BR>
+ <INPUT TYPE="submit" VALUE="Import">
+ </FORM>
+ </BODY>
+<HTML>
+
diff --git a/httemplate/misc/delete-cust_credit.cgi b/httemplate/misc/delete-cust_credit.cgi
new file mode 100755
index 0000000..30de04d
--- /dev/null
+++ b/httemplate/misc/delete-cust_credit.cgi
@@ -0,0 +1,16 @@
+<%
+
+#untaint crednum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal crednum";
+my $crednum = $1;
+
+my $cust_credit = qsearchs('cust_credit',{'crednum'=>$crednum});
+my $custnum = $cust_credit->custnum;
+
+my $error = $cust_credit->delete;
+eidiot($error) if $error;
+
+print $cgi->redirect($p. "view/cust_main.cgi?". $custnum);
+
+%>
diff --git a/httemplate/misc/delete-cust_pay.cgi b/httemplate/misc/delete-cust_pay.cgi
new file mode 100755
index 0000000..3efd918
--- /dev/null
+++ b/httemplate/misc/delete-cust_pay.cgi
@@ -0,0 +1,16 @@
+<%
+
+#untaint paynum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal paynum";
+my $paynum = $1;
+
+my $cust_pay = qsearchs('cust_pay',{'paynum'=>$paynum});
+my $custnum = $cust_pay->custnum;
+
+my $error = $cust_pay->delete;
+eidiot($error) if $error;
+
+print $cgi->redirect($p. "view/cust_main.cgi?". $custnum);
+
+%>
diff --git a/httemplate/misc/delete-customer.cgi b/httemplate/misc/delete-customer.cgi
new file mode 100755
index 0000000..4302317
--- /dev/null
+++ b/httemplate/misc/delete-customer.cgi
@@ -0,0 +1,60 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+die "Customer deletions not enabled" unless $conf->exists('deletecustomers');
+
+my($custnum, $new_custnum);
+if ( $cgi->param('error') ) {
+ $custnum = $cgi->param('custnum');
+ $new_custnum = $cgi->param('new_custnum');
+} else {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/ or die "Illegal query: $query";
+ $custnum = $1;
+ $new_custnum = '';
+}
+my $cust_main = qsearchs( 'cust_main', { 'custnum' => $custnum } )
+ or die "Customer not found: $custnum";
+
+print header('Delete customer');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print
+ qq!<form action="!, popurl(1), qq!process/delete-customer.cgi" method=post>!,
+ qq!<input type="hidden" name="custnum" value="$custnum">!;
+
+if ( qsearch('cust_pkg', { 'custnum' => $custnum, 'cancel' => '' } ) ) {
+ print "Move uncancelled packages to customer number ",
+ qq!<input type="text" name="new_custnum" value="$new_custnum"><br><br>!;
+}
+
+print <<END;
+This will <b>completely remove</b> all traces of this customer record. This
+is <B>not</B> what you want if this is a real customer who has simply
+canceled service with you. For that, cancel all of the customer's packages.
+(you can optionally hide cancelled customers with the <a href="../config/config-view.cgi#hidecancelledcustomers">hidecancelledcustomers</a> configuration option)
+<br>
+<br>Are you <b>absolutely sure</b> you want to delete this customer?
+<br><input type="submit" value="Yes">
+</form></body></html>
+END
+
+#Deleting a customer you have financial records on (i.e. credits) is
+#typically considered fraudulant bookkeeping. Remember, deleting
+#customers should ONLY be used for completely bogus records. You should
+#NOT delete real customers who simply discontinue service.
+#
+#For real customers who simply discontinue service, cancel all of the
+#customer's packages. Customers with all cancelled packages are not
+#billed. There is no need to take further action to prevent billing on
+#customers with all cancelled packages.
+#
+#Also see the "hidecancelledcustomers" and "hidecancelledpackages"
+#configuration options, which will allow you to surpress the display of
+#cancelled customers and packages, respectively.
+
+%>
diff --git a/httemplate/misc/delete-domain_record.cgi b/httemplate/misc/delete-domain_record.cgi
new file mode 100755
index 0000000..dcc2d50
--- /dev/null
+++ b/httemplate/misc/delete-domain_record.cgi
@@ -0,0 +1,15 @@
+<%
+
+#untaint recnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal recnum";
+my $recnum = $1;
+
+my $domain_record = qsearchs('domain_record',{'recnum'=>$recnum});
+
+my $error = $domain_record->delete;
+eidiot($error) if $error;
+
+print $cgi->redirect($p. "view/svc_domain.cgi?". $domain_record->svcnum);
+
+%>
diff --git a/httemplate/misc/delete-part_export.cgi b/httemplate/misc/delete-part_export.cgi
new file mode 100755
index 0000000..7c4ab8b
--- /dev/null
+++ b/httemplate/misc/delete-part_export.cgi
@@ -0,0 +1,15 @@
+<%
+
+#untaint exportnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal exportnum";
+my $exportnum = $1;
+
+my $part_export = qsearchs('part_export',{'exportnum'=>$exportnum});
+
+my $error = $part_export->delete;
+eidiot($error) if $error;
+
+print $cgi->redirect($p. "browse/part_export.cgi");
+
+%>
diff --git a/httemplate/misc/download-batch.cgi b/httemplate/misc/download-batch.cgi
new file mode 100644
index 0000000..306ef5d
--- /dev/null
+++ b/httemplate/misc/download-batch.cgi
@@ -0,0 +1,16 @@
+<%
+
+#http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes
+http_header('Content-Type' => 'text/plain' );
+
+for my $cust_pay_batch ( sort { $a->paybatchnum <=> $b->paybatchnum }
+ qsearch('cust_pay_batch', {} )
+) {
+
+$cust_pay_batch->exp =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
+my( $mon, $y ) = ( $2, $1 );
+$mon = "0$mon" if $mon < 10;
+my $exp = "$mon$y";
+
+%>,,,,<%= $cust_pay_batch->cardnum %>,<%= $exp %>,<%= $cust_pay_batch->amount %>,<%= $cust_pay_batch->paybatchnum %>
+<% } %>
diff --git a/httemplate/misc/dump.cgi b/httemplate/misc/dump.cgi
new file mode 100644
index 0000000..dc1323b
--- /dev/null
+++ b/httemplate/misc/dump.cgi
@@ -0,0 +1,19 @@
+<%
+ if ( driver_name =~ /^Pg$/ ) {
+ my $dbname = (split(':', datasrc))[2];
+ if ( $dbname =~ /[;=]/ ) {
+ my %elements = map { /^(\w+)=(.*)$/; $1=>$2 } split(';', $dbname);
+ $dbname = $elements{'dbname'};
+ }
+ open(DUMP,"pg_dump $dbname |");
+ } else {
+ eidiot "don't (yet) know how to dump ". driver_name. " databases\n";
+ }
+
+ http_header('Content-Type' => 'text/plain' );
+
+ while (<DUMP>) {
+ print $_;
+ }
+ close DUMP;
+%>
diff --git a/httemplate/misc/email-invoice.cgi b/httemplate/misc/email-invoice.cgi
new file mode 100755
index 0000000..a560a18
--- /dev/null
+++ b/httemplate/misc/email-invoice.cgi
@@ -0,0 +1,23 @@
+<%
+
+my $conf = new FS::Conf;
+
+#untaint invnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d*)$/;
+my $invnum = $1;
+my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
+die "Can't find invoice!\n" unless $cust_bill;
+
+my $error = send_email(
+ 'from' => $cust_bill->_agent_invoice_from || $conf->config('invoice_from'),
+ 'to' => [ grep { $_ ne 'POST' } $cust_bill->cust_main->invoicing_list ],
+ 'subject' => 'Invoice',
+ 'body' => [ $cust_bill->print_text ],
+);
+eidiot($error) if $error;
+
+my $custnum = $cust_bill->getfield('custnum');
+print $cgi->redirect("${p}view/cust_main.cgi?$custnum");
+
+%>
diff --git a/httemplate/misc/expire_pkg.cgi b/httemplate/misc/expire_pkg.cgi
new file mode 100755
index 0000000..b59674a
--- /dev/null
+++ b/httemplate/misc/expire_pkg.cgi
@@ -0,0 +1,55 @@
+<!-- mason kludge -->
+<%
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $pkgnum = $1;
+
+#get package record
+my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+die "Unknown pkgnum $pkgnum" unless $cust_pkg;
+my $part_pkg = $cust_pkg->part_pkg;
+
+my $custnum = $cust_pkg->getfield('custnum');
+
+my $date = $cust_pkg->expire ? time2str('%D', $cust_pkg->expire) : '';
+
+%>
+
+<%= header('Expire package', menubar(
+ "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ 'Main Menu' => popurl(2)
+)) %>
+
+<LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+<SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
+
+<%= $pkgnum %>: <%= $part_pkg->pkg. ' - '. $part_pkg->comment %>
+
+<FORM NAME="formname" ACTION="process/expire_pkg.cgi" METHOD="post">
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<%= $pkgnum %>">
+<TABLE>
+ <TR>
+ <TD>Cancel package on </TD>
+ <TD><INPUT TYPE="text" NAME="date" ID="expire_date" VALUE="<%= $date %>">
+ <IMG SRC="<%= $p %>images/calendar.png" ID="expire_button" STYLE="cursor:pointer" TITLE="Select date">
+ <BR><I>m/d/y</I>
+ </TD>
+ </TR>
+</TABLE>
+
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "expire_date",
+ ifFormat: "%m/%d/%Y",
+ button: "expire_button",
+ align: "BR"
+ });
+</SCRIPT>
+
+<INPUT TYPE="submit" VALUE="Cancel later">
+</FORM>
+</BODY>
+</HTML>
diff --git a/httemplate/misc/link.cgi b/httemplate/misc/link.cgi
new file mode 100755
index 0000000..18cd378
--- /dev/null
+++ b/httemplate/misc/link.cgi
@@ -0,0 +1,74 @@
+<!-- mason kludge -->
+<%
+
+my %link_field = (
+ 'svc_acct' => 'username',
+ 'svc_domain' => 'domain',
+);
+
+my %link_field2 = (
+ 'svc_acct' => { label => 'Domain',
+ field => 'domsvc',
+ type => 'select',
+ select_table => 'svc_domain',
+ select_key => 'svcnum',
+ select_label => 'domain'
+ },
+);
+
+my($query) = $cgi->keywords;
+my($pkgnum, $svcpart) = ('', '');
+foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
+}
+
+my $part_svc = qsearchs('part_svc',{'svcpart'=>$svcpart});
+my $svc = $part_svc->getfield('svc');
+my $svcdb = $part_svc->getfield('svcdb');
+my $link_field = $link_field{$svcdb};
+my $link_field2 = $link_field2{$svcdb};
+
+%>
+
+<%= header("Link to existing $svc") %>
+<FORM ACTION="<%= popurl(1) %>process/link.cgi" METHOD=POST>
+
+<% if ( $link_field ) { %>
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="">
+ <INPUT TYPE="hidden" NAME="link_field" VALUE="<%= $link_field %>">
+ <%= $link_field %> of existing service: <INPUT TYPE="text" NAME="link_value">
+ <BR>
+ <% if ( $link_field2 ) { %>
+ <INPUT TYPE="hidden" NAME="link_field2" VALUE="<%= $link_field2->{field} %>">
+ <%= $link_field2->{'label'} %> of existing service:
+ <% if ( $link_field2->{'type'} eq 'select' ) { %>
+ <% if ( $link_field2->{'select_table'} ) { %>
+ <SELECT NAME="link_value2">
+ <OPTION> </OPTION>
+ <% foreach my $r ( qsearch( $link_field2->{'select_table'}, {})) { %>
+ <% my $key = $link_field2->{'select_key'}; %>
+ <% my $label = $link_field2->{'select_label'}; %>
+ <OPTION VALUE="<%= $r->$key() %>"><%= $r->$label() %></OPTION>
+ <% } %>
+ </SELECT>
+ <% } else { %>
+ Don't know how to process secondary link field for <%= $svcdb %>
+ (type=>select but no select_table)
+ <% } %>
+ <% } else { %>
+ Don't know how to process secondary link field for <%= $svcdb %>
+ (unknown type <%= $link_field2->{'type'} %>)
+ <% } %>
+ <BR>
+ <% } %>
+<% } else { %>
+ Service # of existing service: <INPUT TYPE="text" NAME="svcnum" VALUE="">
+<% } %>
+
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<%= $pkgnum %>">
+<INPUT TYPE="hidden" NAME="svcpart" VALUE="<%= $svcpart %>">
+<BR><INPUT TYPE="submit" VALUE="Link">
+ </FORM>
+ </BODY>
+</HTML>
diff --git a/httemplate/misc/meta-import.cgi b/httemplate/misc/meta-import.cgi
new file mode 100644
index 0000000..2f3b738
--- /dev/null
+++ b/httemplate/misc/meta-import.cgi
@@ -0,0 +1,64 @@
+<!-- mason kludge -->
+<%= header('Import') %>
+<FORM ACTION="process/meta-import.cgi" METHOD="post" ENCTYPE="multipart/form-data">
+Import data from a DBI data source<BR><BR>
+
+<%
+ #false laziness with edit/cust_main.cgi
+ my @agents = qsearch( 'agent', {} );
+ die "No agents created!" unless @agents;
+ my $agentnum = $agents[0]->agentnum; #default to first
+
+ if ( scalar(@agents) == 1 ) {
+%>
+ <INPUT TYPE="hidden" NAME="agentnum" VALUE="<%= $agentnum %>">
+<% } else { %>
+ <BR><BR>Agent <SELECT NAME="agentnum" SIZE="1">
+ <% foreach my $agent (sort { $a->agent cmp $b->agent } @agents) { %>
+ <OPTION VALUE="<%= $agent->agentnum %>" <%= " SELECTED"x($agent->agentnum==$agentnum) %>><%= $agent->agent %></OPTION>
+ <% } %>
+ </SELECT><BR><BR>
+<% } %>
+
+<%
+ my @referrals = qsearch('part_referral',{});
+ die "No advertising sources created!" unless @referrals;
+ my $refnum = $referrals[0]->refnum; #default to first
+
+ if ( scalar(@referrals) == 1 ) {
+%>
+ <INPUT TYPE="hidden" NAME="refnum" VALUE="<%= $refnum %>">
+<% } else { %>
+ <BR><BR>Advertising source <SELECT NAME="refnum" SIZE="1">
+ <% foreach my $referral ( sort { $a->referral <=> $b->referral } @referrals) { %>
+ <OPTION VALUE="<%= $referral->refnum %>" <%= " SELECTED"x($referral->refnum==$refnum) %>><%= $referral->refnum %>: <%= $referral->referral %></OPTION>
+ <% } %>
+ </SELECT><BR><BR>
+<% } %>
+
+ First package: <SELECT NAME="pkgpart"><OPTION VALUE="">(none)</OPTION>
+<% foreach my $part_pkg ( qsearch('part_pkg',{'disabled'=>'' }) ) { %>
+ <OPTION VALUE="<%= $part_pkg->pkgpart %>"><%= $part_pkg->pkg. ' - '. $part_pkg->comment %></OPTION>
+<% } %>
+</SELECT><BR><BR>
+
+ <table>
+ <tr>
+ <td align="right">DBI data source: </td>
+ <td><INPUT TYPE="text" NAME="data_source"></td>
+ </tr>
+ <tr>
+ <td align="right">DBI username: </td>
+ <td><INPUT TYPE="text" NAME="username"></td>
+ </tr>
+ <tr>
+ <td align="right">DBI password: </td>
+ <td><INPUT TYPE="text" NAME="password"></td>
+ </tr>
+ </table>
+ <INPUT TYPE="submit" VALUE="Import">
+
+ </FORM>
+ </BODY>
+<HTML>
+
diff --git a/httemplate/misc/payment.cgi b/httemplate/misc/payment.cgi
new file mode 100644
index 0000000..bf89a3d
--- /dev/null
+++ b/httemplate/misc/payment.cgi
@@ -0,0 +1,209 @@
+<%
+ my %type = ( 'CARD' => 'credit card',
+ 'CHEK' => 'electronic check (ACH)',
+ );
+
+ $cgi->param('payby') =~ /^(CARD|CHEK)$/
+ or die "unknown payby ". $cgi->param('payby');
+ my $payby = $1;
+
+ $cgi->param('custnum') =~ /^(\d+)$/
+ or die "illegal custnum ". $cgi->param('custnum');
+ my $custnum = $1;
+
+ my $cust_main = qsearchs( 'cust_main', { 'custnum'=>$custnum } );
+ die "unknown custnum $custnum" unless $cust_main;
+
+ my $balance = $cust_main->balance;
+
+ my $payinfo = '';
+
+ #false laziness w/selfservice make_payment.html shortcut for one-country
+ my $conf = new FS::Conf;
+ my %states = map { $_->state => 1 }
+ qsearch('cust_main_county', {
+ 'country' => $conf->config('defaultcountry') || 'US'
+ } );
+ my @states = sort { $a cmp $b } keys %states;
+
+ my $paybatch = "webui-payment-". time. "-$$-". rand() * 2**32;
+
+%>
+<%= include( '/elements/header.html', "Process $type{$payby} payment" ) %>
+<%= include( '/elements/small_custview.html', $cust_main ) %>
+<FORM NAME="OneTrueForm" ACTION="process/payment.cgi" METHOD="POST" onSubmit="document.OneTrueForm.process.disabled=true">
+<INPUT TYPE="hidden" NAME="custnum" VALUE="<%= $custnum %>">
+<INPUT TYPE="hidden" NAME="payby" VALUE="<%= $payby %>">
+<INPUT TYPE="hidden" NAME="paybatch" VALUE="<%= $paybatch %>">
+<SCRIPT>
+var mywindow = -1;
+function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+}
+function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1;
+}
+var achwindow = -1;
+function achopen(filename,windowname,properties) {
+ achclose();
+ achwindow = window.open(filename,windowname,properties);
+}
+function achclose() {
+ if ( achwindow != -1 )
+ achwindow.close();
+ achwindow = -1;
+}
+</SCRIPT>
+<% #include( '/elements/table.html', '#cccccc' ) %>
+<%= ntable('#cccccc') %>
+ <TR>
+ <TD ALIGN="right">Payment amount</TD>
+ <TD>
+ <TABLE><TR><TD BGCOLOR="#ffffff">
+ $<INPUT TYPE="text" NAME="amount" SIZE=8 VALUE="<%= $balance > 0 ? sprintf("%.2f", $balance) : '' %>">
+ </TD></TR></TABLE>
+ </TD>
+ </TR>
+<% if ( $payby eq 'CARD' ) {
+ my( $payinfo, $paycvv, $month, $year ) = ( '', '', '', '' );
+ my $payname = $cust_main->first. ' '. $cust_main->getfield('last');
+ my $address1 = $cust_main->address1;
+ my $address2 = $cust_main->address2;
+ my $city = $cust_main->city;
+ my $state = $cust_main->state;
+ my $zip = $cust_main->zip;
+ if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
+ $payinfo = $cust_main->payinfo;
+ $paycvv = $cust_main->paycvv;
+ ( $month, $year ) = $cust_main->paydate_monthyear;
+ $payname = $cust_main->payname if $cust_main->payname;
+ }
+%>
+ <TR>
+ <TD ALIGN="right">Card&nbsp;number</TD>
+ <TD>
+ <TABLE>
+ <TR>
+ <TD>
+ <INPUT TYPE="text" NAME="payinfo" SIZE=20 MAXLENGTH=19 VALUE="<%=$payinfo%>"> </TD>
+ <TD>Exp.</TD>
+ <TD>
+ <SELECT NAME="month">
+ <% for ( ( map "0$_", 1 .. 9 ), 11, 12 ) { %>
+ <OPTION<%= $_ eq $month ? ' SELECTED' : '' %>><%= $_ %>
+ <% } %>
+ </SELECT>
+ </TD>
+ <TD> / </TD>
+ <TD>
+ <SELECT NAME="year">
+ <% my @a = localtime; for ( $a[5]+1900 .. $a[5]+1915 ) { %>
+ <OPTION<%= $_ eq $year ? ' SELECTED' : '' %>><%= $_ %>
+ <% } %>
+ </SELECT>
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">CVV2</TD>
+ <TD><INPUT TYPE="text" NAME="paycvv" VALUE="<%= $paycvv %>" SIZE=4 MAXLENGTH=4>
+ (<A HREF="javascript:myopen('../docs/cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Exact&nbsp;name&nbsp;on&nbsp;card</TD>
+ <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%=$payname%>"></TD>
+ </TR><TR>
+ <TD ALIGN="right">Card&nbsp;billing&nbsp;address</TD>
+ <TD>
+ <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address1" VALUE="<%=$address1%>">
+ </TD>
+ </TR><TR>
+ <TD ALIGN="right">Address&nbsp;line&nbsp;2</TD>
+ <TD>
+ <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address2" VALUE="<%=$address2%>">
+ </TD>
+ </TR><TR>
+ <TD ALIGN="right">City</TD>
+ <TD>
+ <TABLE>
+ <TR>
+ <TD>
+ <INPUT TYPE="text" NAME="city" SIZE="12" MAXLENGTH=80 VALUE="<%=$city%>">
+ </TD>
+ <TD>State</TD>
+ <TD>
+ <SELECT NAME="state">
+ <% for ( @states ) { %>
+ <OPTION<%= $_ eq $state ? ' SELECTED' : '' %>><%= $_ %>
+ <% } %>
+ </SELECT>
+ </TD>
+ <TD>Zip</TD>
+ <TD>
+ <INPUT TYPE="text" NAME="zip" SIZE=11 MAXLENGTH=10 VALUE="<%=$zip%>">
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+
+<% } elsif ( $payby eq 'CHEK' ) {
+ my( $payinfo1, $payinfo2, $payname, $ss ) = ( '', '', '', '' );
+ if ( $cust_main->payby =~ /^(CHEK|DCHK)$/ ) {
+ $cust_main->payinfo =~ /^(\d+)\@(\d+)$/
+ or die "unparsable payinfo ". $cust_main->payinfo;
+ ($payinfo1, $payinfo2) = ($1, $2);
+ $payname = $cust_main->payname;
+ $ss = $cust_main->ss;
+ }
+%>
+ <INPUT TYPE="hidden" NAME="month" VALUE="12">
+ <INPUT TYPE="hidden" NAME="year" VALUE="2037">
+ <TR>
+ <TD ALIGN="right">Account&nbsp;number</TD>
+ <TD><INPUT TYPE="text" SIZE=10 NAME="payinfo1" VALUE="<%=$payinfo1%>"></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">ABA/Routing&nbsp;number</TD>
+ <TD>
+ <INPUT TYPE="text" SIZE=10 MAXLENGTH=9 NAME="payinfo2" VALUE="<%=$payinfo2%>">
+ (<A HREF="javascript:achopen('../docs/ach.html','ach','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=384,height=256')">help</A>)
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Bank&nbsp;name</TD>
+ <TD><INPUT TYPE="text" NAME="payname" VALUE="<%=$payname%>"></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">
+ Account&nbsp;holder<BR>
+ Social&nbsp;security&nbsp;or&nbsp;tax&nbspID&nbsp;#
+ </TD>
+ <TD><INPUT TYPE="text" NAME="ss" VALUE="<%=$ss%>"></TD>
+ </TR>
+
+<% } %>
+
+<TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox" CHECKED NAME="save" VALUE="1">
+ Remember this information
+ </TD>
+</TR><TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox"<%= $payby eq 'CARD' ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }">
+ Charge future payments to this <%= $type{$payby} %> automatically
+ </TD>
+</TR>
+</TABLE>
+<BR>
+<INPUT TYPE="submit" NAME="process" VALUE="Process payment">
+</FORM>
+</BODY>
+</HTML>
diff --git a/httemplate/misc/print-invoice.cgi b/httemplate/misc/print-invoice.cgi
new file mode 100755
index 0000000..144f615
--- /dev/null
+++ b/httemplate/misc/print-invoice.cgi
@@ -0,0 +1,29 @@
+<%
+
+my $conf = new FS::Conf;
+my $lpr = $conf->config('lpr');
+
+#untaint invnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d*)$/;
+my $invnum = $1;
+my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
+die "Can't find invoice!\n" unless $cust_bill;
+
+ open(LPR,"|$lpr") or die "Can't open $lpr: $!";
+
+ if ( $conf->exists('invoice_latex') ) {
+ print LPR $cust_bill->print_ps; #( date )
+ } else {
+ print LPR $cust_bill->print_text; #( date )
+ }
+
+ close LPR
+ or die $! ? "Error closing $lpr: $!"
+ : "Exit status $? from $lpr";
+
+my $custnum = $cust_bill->getfield('custnum');
+
+print $cgi->redirect("${p}view/cust_main.cgi?$custnum");
+
+%>
diff --git a/httemplate/misc/process/catchall.cgi b/httemplate/misc/process/catchall.cgi
new file mode 100755
index 0000000..44a63f9
--- /dev/null
+++ b/httemplate/misc/process/catchall.cgi
@@ -0,0 +1,33 @@
+<%
+
+$FS::svc_domain::whois_hack=1;
+
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+my $svcnum =$1;
+
+my $old = qsearchs('svc_domain',{'svcnum'=>$svcnum}) if $svcnum;
+
+my $new = new FS::svc_domain ( {
+ map {
+ ($_, scalar($cgi->param($_)));
+ } ( fields('svc_domain'), qw( pkgnum svcpart ) )
+} );
+
+$new->setfield('action' => 'M');
+
+my $error;
+if ( $svcnum ) {
+ $error = $new->replace($old);
+} else {
+ $error = $new->insert;
+ $svcnum = $new->getfield('svcnum');
+}
+
+if ($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "catchall.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/svc_domain.cgi?$svcnum");
+}
+
+%>
diff --git a/httemplate/misc/process/cust_main-import.cgi b/httemplate/misc/process/cust_main-import.cgi
new file mode 100644
index 0000000..9e1adce
--- /dev/null
+++ b/httemplate/misc/process/cust_main-import.cgi
@@ -0,0 +1,30 @@
+<%
+
+ my $fh = $cgi->upload('csvfile');
+ #warn $cgi;
+ #warn $fh;
+
+ my $error = defined($fh)
+ ? FS::cust_main::batch_import( {
+ filehandle => $fh,
+ agentnum => scalar($cgi->param('agentnum')),
+ refnum => scalar($cgi->param('refnum')),
+ pkgpart => scalar($cgi->param('pkgpart')),
+ 'fields' => [qw( cust_pkg.setup dayphone first last address1 address2
+ city state zip comments )],
+ } )
+ : 'No file';
+
+ if ( $error ) {
+ %>
+ <!-- mason kludge -->
+ <%
+ eidiot($error);
+# $cgi->param('error', $error);
+# print $cgi->redirect( "${p}cust_main-import.cgi
+ } else {
+ %>
+ <!-- mason kludge -->
+ <%= header('Import sucessful') %> <%
+ }
+%>
diff --git a/httemplate/misc/process/cust_main-import_charges.cgi b/httemplate/misc/process/cust_main-import_charges.cgi
new file mode 100644
index 0000000..14df1bd
--- /dev/null
+++ b/httemplate/misc/process/cust_main-import_charges.cgi
@@ -0,0 +1,26 @@
+<%
+
+ my $fh = $cgi->upload('csvfile');
+ #warn $cgi;
+ #warn $fh;
+
+ my $error = defined($fh)
+ ? FS::cust_main::batch_charge( {
+ filehandle => $fh,
+ 'fields' => [qw( custnum amount pkg )],
+ } )
+ : 'No file';
+
+ if ( $error ) {
+ %>
+ <!-- mason kludge -->
+ <%
+ eidiot($error);
+# $cgi->param('error', $error);
+# print $cgi->redirect( "${p}cust_main-import_charges.cgi
+ } else {
+ %>
+ <!-- mason kludge -->
+ <%= header('Import sucessful') %> <%
+ }
+%>
diff --git a/httemplate/misc/process/delete-customer.cgi b/httemplate/misc/process/delete-customer.cgi
new file mode 100755
index 0000000..16bdbae
--- /dev/null
+++ b/httemplate/misc/process/delete-customer.cgi
@@ -0,0 +1,29 @@
+<%
+
+my $conf = new FS::Conf;
+die "Customer deletions not enabled" unless $conf->exists('deletecustomers');
+
+$cgi->param('custnum') =~ /^(\d+)$/;
+my $custnum = $1;
+my $new_custnum;
+if ( $cgi->param('new_custnum') ) {
+ $cgi->param('new_custnum') =~ /^(\d+)$/
+ or die "Illegal new customer number: ". $cgi->param('new_custnum');
+ $new_custnum = $1;
+} else {
+ $new_custnum = '';
+}
+my $cust_main = qsearchs( 'cust_main', { 'custnum' => $custnum } )
+ or die "Customer not found: $custnum";
+
+my $error = $cust_main->delete($new_custnum);
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "delete-customer.cgi?". $cgi->query_string );
+} elsif ( $new_custnum ) {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$new_custnum");
+} else {
+ print $cgi->redirect(popurl(3));
+}
+%>
diff --git a/httemplate/misc/process/expire_pkg.cgi b/httemplate/misc/process/expire_pkg.cgi
new file mode 100755
index 0000000..dc35592
--- /dev/null
+++ b/httemplate/misc/process/expire_pkg.cgi
@@ -0,0 +1,25 @@
+<%
+
+#untaint date & pkgnum
+
+my $date;
+if ( $cgi->param('date') ) {
+ str2time($cgi->param('date')) =~ /^(\d+)$/ or die "Illegal date";
+ $date=$1;
+} else {
+ $date='';
+}
+
+$cgi->param('pkgnum') =~ /^(\d+)$/ or die "Illegal pkgnum";
+my $pkgnum = $1;
+
+my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+my %hash = $cust_pkg->hash;
+$hash{expire}=$date;
+my $new = new FS::cust_pkg ( \%hash );
+my $error = $new->replace($cust_pkg);
+&eidiot($error) if $error;
+
+print $cgi->redirect(popurl(3). "view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
+
+%>
diff --git a/httemplate/misc/process/link.cgi b/httemplate/misc/process/link.cgi
new file mode 100755
index 0000000..32a5360
--- /dev/null
+++ b/httemplate/misc/process/link.cgi
@@ -0,0 +1,54 @@
+<%
+
+$cgi->param('pkgnum') =~ /^(\d+)$/;
+my $pkgnum = $1;
+$cgi->param('svcpart') =~ /^(\d+)$/;
+my $svcpart = $1;
+$cgi->param('svcnum') =~ /^(\d*)$/;
+my $svcnum = $1;
+
+unless ( $svcnum ) {
+ my $part_svc = qsearchs('part_svc',{'svcpart'=>$svcpart});
+ my $svcdb = $part_svc->getfield('svcdb');
+ $cgi->param('link_field') =~ /^(\w+)$/;
+ my $link_field = $1;
+ my %search = ( $link_field => $cgi->param('link_value') );
+ if ( $cgi->param('link_field2') =~ /^(\w+)$/ ) {
+ $search{$1} = $cgi->param('link_value2');
+ }
+ my $svc_x = ( grep { $_->cust_svc->svcpart == $svcpart }
+ qsearch( $svcdb, \%search )
+ )[0];
+ eidiot("$link_field not found!") unless $svc_x;
+ $svcnum = $svc_x->svcnum;
+}
+
+my $old = qsearchs('cust_svc',{'svcnum'=>$svcnum});
+die "svcnum not found!" unless $old;
+my $conf = new FS::Conf;
+my($error, $new);
+if ( $old->pkgnum && ! $conf->exists('legacy_link-steal') ) {
+ $error = "svcnum $svcnum already linked to package ". $old->pkgnum;
+} else {
+ $new = new FS::cust_svc ({
+ 'svcnum' => $svcnum,
+ 'pkgnum' => $pkgnum,
+ 'svcpart' => $svcpart,
+ });
+
+ $error = $new->replace($old);
+}
+
+unless ($error) {
+ #no errors, so let's view this customer.
+ my $custnum = $new->cust_pkg->custnum;
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum".
+ "#cust_pkg$pkgnum" );
+} else {
+%>
+<!-- mason kludge -->
+<%
+ idiot($error);
+}
+
+%>
diff --git a/httemplate/misc/process/meta-import.cgi b/httemplate/misc/process/meta-import.cgi
new file mode 100644
index 0000000..59d236f
--- /dev/null
+++ b/httemplate/misc/process/meta-import.cgi
@@ -0,0 +1,178 @@
+<!-- mason kludge -->
+<%= header('Map tables') %>
+
+<SCRIPT>
+var gSafeOnload = new Array();
+var gSafeOnsubmit = new Array();
+window.onload = SafeOnload;
+function SafeAddOnLoad(f) {
+ gSafeOnload[gSafeOnload.length] = f;
+}
+function SafeOnload() {
+ for (var i=0;i<gSafeOnload.length;i++)
+ gSafeOnload[i]();
+}
+function SafeAddOnSubmit(f) {
+ gSafeOnsubmit[gSafeOnsubmit.length] = f;
+}
+function SafeOnsubmit() {
+ for (var i=0;i<gSafeOnsubmit.length;i++)
+ gSafeOnsubmit[i]();
+}
+</SCRIPT>
+
+<FORM NAME="OneTrueForm" METHOD="POST" ACTION="meta-import.cgi">
+
+<%
+ #use DBIx::DBSchema;
+ my $schema = new_native DBIx::DBSchema
+ map { $cgi->param($_) } qw( data_source username password );
+ foreach my $field (qw( data_source username password )) { %>
+ <INPUT TYPE="hidden" NAME=<%= $field %> VALUE="<%= $cgi->param($field) %>">
+ <% }
+
+ my %schema;
+ use Tie::DxHash;
+ tie %schema, 'Tie::DxHash';
+ if ( $cgi->param('schema') ) {
+ my $schema_string = $cgi->param('schema');
+ %> <INPUT TYPE="hidden" NAME="schema" VALUE="<%=$schema_string%>"> <%
+ %schema = map { /^\s*(\w+)\s*=>\s*(\w+)\s*$/
+ or die "guru meditation #420: $_";
+ ( $1 => $2 );
+ }
+ split( /\n/, $schema_string );
+ }
+
+ #first page
+ unless ( $cgi->param('magic') ) { %>
+
+ <INPUT TYPE="hidden" NAME="magic" VALUE="process">
+ <%= hashmaker('schema', [ $schema->tables ],
+ [ grep !/^h_/, dbdef->tables ], ) %>
+ <br><INPUT TYPE="submit" VALUE="done">
+ <%
+
+ #second page
+ } elsif ( $cgi->param('magic') eq 'process' ) { %>
+
+ <INPUT TYPE="hidden" NAME="magic" VALUE="process2">
+ <%
+
+ my %unique;
+ foreach my $table ( keys %schema ) {
+
+ my @from_columns = $schema->table($table)->columns;
+ my @fs_columns = dbdef->table($schema{$table})->columns;
+
+ %>
+ <%= hashmaker( $table.'__'.$unique{$table}++,
+ \@from_columns => \@fs_columns,
+ $table => $schema{$table}, ) %>
+ <br><hr><br>
+ <%
+
+ }
+
+ %>
+ <br><INPUT TYPE="submit" VALUE="done">
+ <%
+
+ #third (results)
+ } elsif ( $cgi->param('magic') eq 'process2' ) {
+
+ print "<pre>\n";
+
+ my %unique;
+ foreach my $table ( keys %schema ) {
+ ( my $spaces = $table ) =~ s/./ /g;
+ print "'$table' => { 'table' => '$schema{$table}',\n".
+ #(length($table) x ' '). " 'map' => {\n";
+ "$spaces 'map' => {\n";
+ my %map = map { /^\s*(\w+)\s*=>\s*(\w+)\s*$/
+ or die "guru meditation #420: $_";
+ ( $1 => $2 );
+ }
+ split( /\n/, $cgi->param($table.'__'.$unique{$table}++) );
+ foreach ( keys %map ) {
+ print "$spaces '$_' => '$map{$_}',\n";
+ }
+ print "$spaces },\n";
+ print "$spaces },\n";
+
+ }
+ print "\n</pre>";
+
+ } else {
+ warn "unrecognized magic: ". $cgi->param('magic');
+ }
+
+ %>
+</FORM>
+</BODY>
+</HTML>
+
+ <%
+ #hashmaker widget
+ sub hashmaker {
+ my($name, $from, $to, $labelfrom, $labelto) = @_;
+ my $fromsize = scalar(@$from);
+ my $tosize = scalar(@$to);
+ "<TABLE><TR><TH>$labelfrom</TH><TH>$labelto</TH></TR><TR><TD>".
+ qq!<SELECT NAME="${name}_from" SIZE=$fromsize>\n!.
+ join("\n", map { qq!<OPTION VALUE="$_">$_</OPTION>! } sort { $a cmp $b } @$from ).
+ "</SELECT>\n<BR>".
+ qq!<INPUT TYPE="button" VALUE="refill" onClick="repack_${name}_from()">!.
+ '</TD><TD>'.
+ qq!<SELECT NAME="${name}_to" SIZE=$tosize>\n!.
+ join("\n", map { qq!<OPTION VALUE="$_">$_</OPTION>! } sort { $a cmp $b } @$to ).
+ "</SELECT>\n<BR>".
+ qq!<INPUT TYPE="button" VALUE="refill" onClick="repack_${name}_to()">!.
+ '</TD></TR>'.
+ '<TR><TD COLSPAN=2>'.
+ qq!<INPUT TYPE="button" VALUE="map" onClick="toke_$name(this.form)">!.
+ '</TD></TR><TR><TD COLSPAN=2>'.
+ qq!<TEXTAREA NAME="$name" COLS=80 ROWS=8></TEXTAREA>!.
+ '</TD></TR></TABLE>'.
+ "<script>
+ function toke_$name() {
+ fromObject = document.OneTrueForm.${name}_from;
+ for (var i=fromObject.options.length-1;i>-1;i--) {
+ if (fromObject.options[i].selected)
+ fromname = deleteOption_$name(fromObject,i);
+ }
+ toObject = document.OneTrueForm.${name}_to;
+ for (var i=toObject.options.length-1;i>-1;i--) {
+ if (toObject.options[i].selected)
+ toname = deleteOption_$name(toObject,i);
+ }
+ document.OneTrueForm.$name.value = document.OneTrueForm.$name.value + fromname + ' => ' + toname + '\\n';
+ }
+ function deleteOption_$name(object,index) {
+ value = object.options[index].value;
+ object.options[index] = null;
+ return value;
+ }
+ function repack_${name}_from() {
+ var object = document.OneTrueForm.${name}_from;
+ object.options.length = 0;
+ ". join("\n",
+ map { "addOption_$name(object, '$_');\n" }
+ ( sort { $a cmp $b } @$from ) ). "
+ }
+ function repack_${name}_to() {
+ var object = document.OneTrueForm.${name}_to;
+ object.options.length = 0;
+ ". join("\n",
+ map { "addOption_$name(object, '$_');\n" }
+ ( sort { $a cmp $b } @$to ) ). "
+ }
+ function addOption_$name(object,value) {
+ var length = object.length;
+ object.options[length] = new Option(value, value, false, false);
+ }
+ </script>".
+ '';
+ }
+
+%>
diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi
new file mode 100644
index 0000000..fa0ede8
--- /dev/null
+++ b/httemplate/misc/process/payment.cgi
@@ -0,0 +1,148 @@
+<%
+
+#some false laziness w/MyAccount::process_payment
+
+$cgi->param('custnum') =~ /^(\d+)$/
+ or die "illegal custnum ". $cgi->param('custnum');
+my $custnum = $1;
+
+my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
+die "unknown custnum $custnum" unless $cust_main;
+
+$cgi->param('amount') =~ /^\s*(\d*(\.\d\d)?)\s*$/
+ or eidiot "illegal amount ". $cgi->param('amount');
+my $amount = $1;
+eidiot "amount <= 0" unless $amount > 0;
+
+$cgi->param('year') =~ /^(\d+)$/
+ or die "illegal year ". $cgi->param('year');
+my $year = $1;
+
+$cgi->param('month') =~ /^(\d+)$/
+ or die "illegal month ". $cgi->param('month');
+my $month = $1;
+
+$cgi->param('payby') =~ /^(CARD|CHEK)$/
+ or die "illegal payby ". $cgi->param('payby');
+my $payby = $1;
+my %payby2bop = (
+ 'CARD' => 'CC',
+ 'CHEK' => 'ECHECK',
+);
+my %payby2fields = (
+ 'CARD' => [ qw( address1 address2 city state zip ) ],
+ 'CHEK' => [ qw( ss ) ],
+);
+my %type = ( 'CARD' => 'credit card',
+ 'CHEK' => 'electronic check (ACH)',
+ );
+
+$cgi->param('payname') =~ /^([\w \,\.\-\']+)$/
+ or eidiot gettext('illegal_name'). " payname: ". $cgi->param('payname');
+my $payname = $1;
+
+$cgi->param('paybatch') =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
+ or eidiot gettext('illegal_text'). " paybatch: ". $cgi->param('paybatch');
+my $paybatch = $1;
+
+my $payinfo;
+my $paycvv = '';
+if ( $payby eq 'CHEK' ) {
+
+ $cgi->param('payinfo1') =~ /^(\d+)$/
+ or eidiot "illegal account number ". $cgi->param('payinfo1');
+ my $payinfo1 = $1;
+ $cgi->param('payinfo2') =~ /^(\d+)$/
+ or eidiot "illegal ABA/routing number ". $cgi->param('payinfo2');
+ my $payinfo2 = $1;
+ $payinfo = $payinfo1. '@'. $payinfo2;
+
+} elsif ( $payby eq 'CARD' ) {
+
+ $payinfo = $cgi->param('payinfo');
+ $payinfo =~ s/\D//g;
+ $payinfo =~ /^(\d{13,16})$/
+ or eidiot gettext('invalid_card'); # . ": ". $self->payinfo;
+ $payinfo = $1;
+ validate($payinfo)
+ or eidiot gettext('invalid_card'); # . ": ". $self->payinfo;
+ eidiot gettext('unknown_card_type')
+ if cardtype($payinfo) eq "Unknown";
+
+ if ( defined $cust_main->dbdef_table->column('paycvv') ) {
+ if ( length($cgi->param('paycvv') ) ) {
+ if ( cardtype($payinfo) eq 'American Express card' ) {
+ $cgi->param('paycvv') =~ /^(\d{4})$/
+ or eidiot "CVV2 (CID) for American Express cards is four digits.";
+ $paycvv = $1;
+ } else {
+ $cgi->param('paycvv') =~ /^(\d{3})$/
+ or eidiot "CVV2 (CVC2/CID) is three digits.";
+ $paycvv = $1;
+ }
+ }
+ }
+
+} else {
+ die "unknown payby $payby";
+}
+
+my $error = $cust_main->realtime_bop( $payby2bop{$payby}, $amount,
+ 'quiet' => 1,
+ 'payinfo' => $payinfo,
+ 'paydate' => "$year-$month-01",
+ 'payname' => $payname,
+ 'paybatch' => $paybatch,
+ 'paycvv' => $paycvv,
+ map { $_ => $cgi->param($_) } @{$payby2fields{$payby}}
+);
+eidiot($error) if $error;
+
+$cust_main->apply_payments;
+
+if ( $cgi->param('save') ) {
+ my $new = new FS::cust_main { $cust_main->hash };
+ if ( $payby eq 'CARD' ) {
+ $new->set( 'payby' => ( $cgi->param('auto') ? 'CARD' : 'DCRD' ) );
+ } elsif ( $payby eq 'CHEK' ) {
+ $new->set( 'payby' => ( $cgi->param('auto') ? 'CHEK' : 'DCHK' ) );
+ } else {
+ die "unknown payby $payby";
+ }
+ $new->set( 'payinfo' => $payinfo );
+ $new->set( 'paydate' => "$year-$month-01" );
+ $new->set( 'payname' => $payname );
+
+ #false laziness w/FS:;cust_main::realtime_bop - check both to make sure
+ # working correctly
+ my $conf = new FS::Conf;
+ if ( $payby eq 'CARD' &&
+ grep { $_ eq cardtype($payinfo) } $conf->config('cvv-save') ) {
+ $new->set( 'paycvv' => $paycvv );
+ } else {
+ $new->set( 'paycvv' => '');
+ }
+
+ $new->set( $_ => $cgi->param($_) ) foreach @{$payby2fields{$payby}};
+
+ my $error = $new->replace($cust_main);
+ eidiot "payment processed sucessfully, but error saving info: $error"
+ if $error;
+ $cust_main = $new;
+}
+
+#success!
+
+%>
+<%= include( '/elements/header.html', ucfirst($type{$payby}). ' processing sucessful',
+ include('/elements/menubar.html',
+ 'Main menu' => popurl(3),
+ "View this customer (#$custnum)" =>
+ popurl(3). "view/cust_main.cgi?$custnum",
+ ),
+
+ )
+%>
+<%= include( '/elements/small_custview.html', $cust_main ) %>
+</BODY>
+</HTML>
diff --git a/httemplate/misc/queue.cgi b/httemplate/misc/queue.cgi
new file mode 100644
index 0000000..ce9c8fb
--- /dev/null
+++ b/httemplate/misc/queue.cgi
@@ -0,0 +1,47 @@
+<%
+
+$cgi->param('action') =~ /^(new|del|(retry|remove) selected)$/
+ or die "Illegal action";
+my $action = $1;
+
+my $job;
+if ( $action eq 'new' || $action eq 'del' ) {
+ $cgi->param('jobnum') =~ /^(\d+)$/ or die "Illegal jobnum";
+ my $jobnum = $1;
+ $job = qsearchs('queue', { 'jobnum' => $1 })
+ or die "unknown jobnum $jobnum - ".
+ "it probably completed normally or was removed by another user";
+}
+
+if ( $action eq 'new' ) {
+ my %hash = $job->hash;
+ $hash{'status'} = 'new';
+ $hash{'statustext'} = '';
+ my $new = new FS::queue \%hash;
+ my $error = $new->replace($job);
+ die $error if $error;
+} elsif ( $action eq 'del' ) {
+ my $error = $job->delete;
+ die $error if $error;
+} elsif ( $action =~ /^(retry|remove) selected$/ ) {
+ foreach my $jobnum (
+ map { /^jobnum(\d+)$/; $1; } grep /^jobnum\d+$/, $cgi->param
+ ) {
+ my $job = qsearchs('queue', { 'jobnum' => $jobnum });
+ if ( $action eq 'retry selected' && $job ) { #new
+ my %hash = $job->hash;
+ $hash{'status'} = 'new';
+ $hash{'statustext'} = '';
+ my $new = new FS::queue \%hash;
+ my $error = $new->replace($job);
+ die $error if $error;
+ } elsif ( $action eq 'remove selected' && $job ) { #del
+ my $error = $job->delete;
+ die $error if $error;
+ }
+ }
+}
+
+print $cgi->redirect(popurl(2). "browse/queue.cgi");
+
+%>
diff --git a/httemplate/misc/susp_pkg.cgi b/httemplate/misc/susp_pkg.cgi
new file mode 100755
index 0000000..4a19fa8
--- /dev/null
+++ b/httemplate/misc/susp_pkg.cgi
@@ -0,0 +1,15 @@
+<%
+
+#untaint pkgnum
+my ($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal pkgnum";
+my $pkgnum = $1;
+
+my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+
+my $error = $cust_pkg->suspend;
+&eidiot($error) if $error;
+
+print $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
+
+%>
diff --git a/httemplate/misc/unapply-cust_credit.cgi b/httemplate/misc/unapply-cust_credit.cgi
new file mode 100755
index 0000000..c658d2a
--- /dev/null
+++ b/httemplate/misc/unapply-cust_credit.cgi
@@ -0,0 +1,18 @@
+<%
+
+#untaint crednum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal crednum";
+my $crednum = $1;
+
+my $cust_credit = qsearchs('cust_credit', { 'crednum' => $crednum } );
+my $custnum = $cust_credit->custnum;
+
+foreach my $cust_credit_bill ( $cust_credit->cust_credit_bill ) {
+ my $error = $cust_credit_bill->delete;
+ eidiot($error) if $error;
+}
+
+print $cgi->redirect($p. "view/cust_main.cgi?". $custnum);
+
+%>
diff --git a/httemplate/misc/unapply-cust_pay.cgi b/httemplate/misc/unapply-cust_pay.cgi
new file mode 100755
index 0000000..28643ef
--- /dev/null
+++ b/httemplate/misc/unapply-cust_pay.cgi
@@ -0,0 +1,18 @@
+<%
+
+#untaint paynum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal paynum";
+my $paynum = $1;
+
+my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } );
+my $custnum = $cust_pay->custnum;
+
+foreach my $cust_bill_pay ( $cust_pay->cust_bill_pay ) {
+ my $error = $cust_bill_pay->delete;
+ eidiot($error) if $error;
+}
+
+print $cgi->redirect($p. "view/cust_main.cgi?". $custnum);
+
+%>
diff --git a/httemplate/misc/unprovision.cgi b/httemplate/misc/unprovision.cgi
new file mode 100755
index 0000000..3c92a4e
--- /dev/null
+++ b/httemplate/misc/unprovision.cgi
@@ -0,0 +1,29 @@
+<%
+
+my $dbh = dbh;
+
+#untaint svcnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $svcnum = $1;
+
+#my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum});
+#die "Unknown svcnum!" unless $svc_acct;
+
+my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum});
+die "Unknown svcnum!" unless $cust_svc;
+
+my $custnum = $cust_svc->cust_pkg->custnum;
+
+my $error = $cust_svc->cancel;
+
+if ( $error ) {
+ %>
+<!-- mason kludge -->
+<%
+ &eidiot($error);
+} else {
+ print $cgi->redirect(popurl(2)."view/cust_main.cgi?$custnum");
+}
+
+%>
diff --git a/httemplate/misc/unsusp_pkg.cgi b/httemplate/misc/unsusp_pkg.cgi
new file mode 100755
index 0000000..5008729
--- /dev/null
+++ b/httemplate/misc/unsusp_pkg.cgi
@@ -0,0 +1,15 @@
+<%
+
+#untaint pkgnum
+my ($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal pkgnum";
+my $pkgnum = $1;
+
+my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+
+my $error = $cust_pkg->unsuspend;
+&eidiot($error) if $error;
+
+print $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
+
+%>
diff --git a/httemplate/misc/upload-batch.cgi b/httemplate/misc/upload-batch.cgi
new file mode 100644
index 0000000..5d01501
--- /dev/null
+++ b/httemplate/misc/upload-batch.cgi
@@ -0,0 +1,30 @@
+<%
+
+ my $fh = $cgi->upload('batch_results');
+ my $filename = $cgi->param('batch_results');
+ $filename =~ /^(.*[\/\\])?([^\/\\]+)$/
+ or die "unparsable filename: $filename\n";
+ my $paybatch = $2;
+
+ my $error = defined($fh)
+ ? FS::cust_pay_batch::import_results( {
+ 'filehandle' => $fh,
+ 'format' => $cgi->param('format'),
+ 'paybatch' => $paybatch,
+ } )
+ : 'No file';
+
+ if ( $error ) {
+ %>
+ <!-- mason kludge -->
+ <%
+ eidiot($error);
+# $cgi->param('error', $error);
+# print $cgi->redirect( "${p}cust_main-import.cgi
+ } else {
+ %>
+ <!-- mason kludge -->
+ <%= header('Batch results upload sucessful') %> <%
+ }
+%>
+
diff --git a/httemplate/misc/whois.cgi b/httemplate/misc/whois.cgi
new file mode 100644
index 0000000..dd7851d
--- /dev/null
+++ b/httemplate/misc/whois.cgi
@@ -0,0 +1,25 @@
+<%
+ my $svcnum = $cgi->param('svcnum');
+ my $custnum = $cgi->param('custnum');
+ my $domain = $cgi->param('domain');
+
+%>
+<%= header("Whois $domain", menubar(
+ ( $custnum
+ ? ( "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ()
+ ),
+ "View this domain (#$svcnum)" => "${p}view/svc_domain.cgi?$svcnum",
+ "Main menu" => $p,
+)) %>
+<% my $whois = eval { whois($domain) };
+ if ( $@ ) {
+ ( $whois = $@ ) =~ s/ at \/.*Net\/Whois\/Raw\.pm line \d+.*$//s;
+ } else {
+ $whois =~ s/^\n+//;
+ }
+%>
+<PRE><%= $whois %></PRE>
+</BODY>
+</HTML>
diff --git a/httemplate/search/cust_bill.cgi b/httemplate/search/cust_bill.cgi
new file mode 100755
index 0000000..5b0538c
--- /dev/null
+++ b/httemplate/search/cust_bill.cgi
@@ -0,0 +1,165 @@
+<%
+
+my $conf = new FS::Conf;
+my $maxrecords = $conf->config('maxsearchrecordsperpage');
+
+my $orderby = ''; #removeme
+
+my $limit = '';
+$limit .= "LIMIT $maxrecords" if $maxrecords;
+
+my $offset = $cgi->param('offset') || 0;
+$limit .= " OFFSET $offset" if $offset;
+
+my($total, $tot_amount, $tot_balance);
+
+my(@cust_bill);
+if ( $cgi->keywords ) {
+ my($query) = $cgi->keywords;
+ my $owed = "charged - ( select coalesce(sum(amount),0) from cust_bill_pay
+ where cust_bill_pay.invnum = cust_bill.invnum )
+ - ( select coalesce(sum(amount),0) from cust_credit_bill
+ where cust_credit_bill.invnum = cust_bill.invnum )";
+ my @where;
+ if ( $query =~ /^(OPEN(\d*)_)?(invnum|date|custnum)$/ ) {
+ my($open, $days, $field) = ($1, $2, $3);
+ $field = "_date" if $field eq 'date';
+ $orderby = "ORDER BY cust_bill.$field";
+ push @where, "0 != $owed" if $open;
+ push @where, "cust_bill._date < ". (time-86400*$days) if $days;
+ } else {
+ die "unknown query string $query";
+ }
+
+ my $extra_sql = scalar(@where) ? 'WHERE '. join(' AND ', @where) : '';
+
+ my $statement = "SELECT COUNT(*), sum(charged), sum($owed)
+ FROM cust_bill $extra_sql";
+ my $sth = dbh->prepare($statement) or die dbh->errstr. " doing $statement";
+ $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
+
+ ( $total, $tot_amount, $tot_balance ) = @{$sth->fetchrow_arrayref};
+
+ @cust_bill = qsearch(
+ 'cust_bill',
+ {},
+ "cust_bill.*, $owed as owed",
+ "$extra_sql $orderby $limit"
+ );
+} else {
+ $cgi->param('invnum') =~ /^\s*(FS-)?(\d+)\s*$/;
+ my $invnum = $2;
+ @cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum } );
+ $total = scalar(@cust_bill);
+}
+
+#if ( scalar(@cust_bill) == 1 ) {
+if ( $total == 1 ) {
+ my $invnum = $cust_bill[0]->invnum;
+ print $cgi->redirect(popurl(2). "view/cust_bill.cgi?$invnum"); #redirect
+} elsif ( scalar(@cust_bill) == 0 ) {
+%>
+<!-- mason kludge -->
+<%
+ eidiot("Invoice not found.");
+} else {
+%>
+<!-- mason kludge -->
+<%
+
+ #begin pager
+ my $pager = '';
+ if ( $total != scalar(@cust_bill) && $maxrecords ) {
+ unless ( $offset == 0 ) {
+ $cgi->param('offset', $offset - $maxrecords);
+ $pager .= '<A HREF="'. $cgi->self_url.
+ '"><B><FONT SIZE="+1">Previous</FONT></B></A> ';
+ }
+ my $poff;
+ my $page;
+ for ( $poff = 0; $poff < $total; $poff += $maxrecords ) {
+ $page++;
+ if ( $offset == $poff ) {
+ $pager .= qq!<FONT SIZE="+2">$page</FONT> !;
+ } else {
+ $cgi->param('offset', $poff);
+ $pager .= qq!<A HREF="!. $cgi->self_url. qq!">$page</A> !;
+ }
+ }
+ unless ( $offset + $maxrecords > $total ) {
+ $cgi->param('offset', $offset + $maxrecords);
+ $pager .= '<A HREF="'. $cgi->self_url.
+ '"><B><FONT SIZE="+1">Next</FONT></B></A> ';
+ }
+ }
+ #end pager
+
+ print header("Invoice Search Results", menubar(
+ 'Main Menu', popurl(2)
+ )).
+ "$total matching invoices found<BR>".
+ "\$$tot_balance total balance<BR>".
+ "\$$tot_amount total amount<BR>".
+ "<BR>$pager". table(). <<END;
+ <TR>
+ <TH></TH>
+ <TH>Balance</TH>
+ <TH>Amount</TH>
+ <TH>Date</TH>
+ <TH>Contact name</TH>
+ <TH>Company</TH>
+ </TR>
+END
+
+ foreach my $cust_bill ( @cust_bill ) {
+ my($invnum, $owed, $charged, $date ) = (
+ $cust_bill->invnum,
+ sprintf("%.2f", $cust_bill->getfield('owed')),
+ sprintf("%.2f", $cust_bill->charged),
+ $cust_bill->_date,
+ );
+ my $pdate = time2str("%b %d %Y", $date);
+
+ my $rowspan = 1;
+
+ my $view = popurl(2). "view/cust_bill.cgi?$invnum";
+ print <<END;
+ <TR>
+ <TD ROWSPAN=$rowspan><A HREF="$view">$invnum</A></TD>
+ <TD ROWSPAN=$rowspan ALIGN="right"><A HREF="$view">\$$owed</A></TD>
+ <TD ROWSPAN=$rowspan ALIGN="right"><A HREF="$view">\$$charged</A></TD>
+ <TD ROWSPAN=$rowspan><A HREF="$view">$pdate</A></TD>
+END
+ my $custnum = $cust_bill->custnum;
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
+ if ( $cust_main ) {
+ my $cview = popurl(2). "view/cust_main.cgi?". $cust_main->custnum;
+ my ( $name, $company ) = (
+ $cust_main->last. ', '. $cust_main->first,
+ $cust_main->company,
+ );
+ print <<END;
+ <TD ROWSPAN=$rowspan><A HREF="$cview">$name</A></TD>
+ <TD ROWSPAN=$rowspan><A HREF="$cview">$company</A></TD>
+END
+ } else {
+ print <<END
+ <TD ROWSPAN=$rowspan COLSPAN=2>WARNING: couldn't find cust_main.custnum $custnum (cust_bill.invnum $invnum)</TD>
+END
+ }
+
+ print "</TR>";
+ }
+ $tot_balance = sprintf("%.2f", $tot_balance);
+ $tot_amount = sprintf("%.2f", $tot_amount);
+ print "</TABLE>$pager<BR>". table(). <<END;
+ <TR><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TH>Total<BR>Balance</TH><TH>Total<BR>Amount</TH></TR>
+ <TR><TD></TD><TD ALIGN="right">\$$tot_balance</TD><TD ALIGN="right">\$$tot_amount</TD></TD></TR>
+ </TABLE>
+ </BODY>
+</HTML>
+END
+
+}
+
+%>
diff --git a/httemplate/search/cust_bill.html b/httemplate/search/cust_bill.html
new file mode 100755
index 0000000..3ae624a
--- /dev/null
+++ b/httemplate/search/cust_bill.html
@@ -0,0 +1,101 @@
+<%
+ my( $count_query, $sql_query );
+ if ( $cgi->param('begin') || $cgi->param('end') || $cgi->keywords ) {
+
+ my $owed =
+ "charged - ( SELECT COALESCE(SUM(amount),0) FROM cust_bill_pay
+ WHERE cust_bill_pay.invnum = cust_bill.invnum )
+ - ( SELECT COALESCE(SUM(amount),0) FROM cust_credit_bill
+ WHERE cust_credit_bill.invnum = cust_bill.invnum )";
+
+ my @where;
+ my $orderby = 'ORDER BY cust_bill._date';
+
+ if ( $cgi->param('begin') =~ /^(\d+)$/ ) {
+ push @where, "cust_bill._date >= $1",
+ }
+ if ( $cgi->param('end') =~ /^(\d+)$/ ) {
+ push @where, "cust_bill._date < $1",
+ }
+
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(OPEN(\d*)_)?(invnum|date|custnum)$/ ) {
+ my($open, $days, $field) = ($1, $2, $3);
+ $field = "_date" if $field eq 'date';
+ $orderby = "ORDER BY cust_bill.$field";
+ push @where, "0 != $owed" if $open;
+ push @where, "cust_bill._date < ". (time-86400*$days) if $days;
+ }
+
+ my $extra_sql = scalar(@where) ? 'WHERE '. join(' AND ', @where) : '';
+
+ $count_query = "SELECT COUNT(*), sum(charged), sum($owed)
+ FROM cust_bill $extra_sql";
+
+ $sql_query = {
+ 'table' => 'cust_bill',
+ 'hashref' => {},
+ 'select' => "cust_bill.*, $owed as owed",
+ 'extra_sql' => "$extra_sql $orderby"
+ };
+
+ } else {
+ $cgi->param('invnum') =~ /^\s*(FS-)?(\d+)\s*$/;
+ $count_query = "SELECT COUNT(*) FROM cust_bill WHERE invnum = $2";
+ $sql_query = {
+ 'table' => 'cust_bill',
+ 'hashref' => { 'invnum' => $2 },
+ #'select' => '*',
+ };
+ }
+
+ my $link = [ "${p}view/cust_bill.cgi?", 'invnum', ];
+ my $clink = sub {
+ my $cust_bill = shift;
+ my $cust_main = $cust_bill->cust_main;
+ $cust_main
+ ? [ "${p}view/cust_main.cgi?", 'custnum' ]
+ : '';
+ };
+
+%>
+<%= include( 'elements/search.html',
+ 'title' => 'Invoice Search Results',
+ 'name' => 'invoices',
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'count_addl' => [ '$%.2f total invoiced',
+ '$%.2f total outstanding balance',
+ ],
+ 'redirect' => $link,
+ 'header' =>
+ [ 'Invoice #', qw(Balance Amount Date), 'Contact name',
+ 'Company' ],
+ 'fields' => [
+ 'invnum',
+ sub { sprintf('$%.2f', shift->get('owed') ) },
+ sub { sprintf('$%.2f', shift->charged ) },
+ sub { time2str('%b %d %Y', shift->_date ) },
+ sub { my $cust_bill = shift;
+ my $cust_main = $cust_bill->cust_main;
+ $cust_main
+ ? $cust_main->get('last'). ', '. $cust_main->first
+ : "WARNING: can't find cust_main.custnum ".
+ $cust_bill->custnum. ' (cust_bill.invnum '.
+ $cust_bill->invnum. ')';
+ },
+ sub { my $cust_main = shift->cust_main;
+ $cust_main ? $cust_main->company : '';
+ },
+ ],
+ 'links' => [
+ $link,
+ $link,
+ $link,
+ $link,
+ $clink,
+ $clink,
+ ],
+
+ )
+%>
diff --git a/httemplate/search/cust_bill_event.cgi b/httemplate/search/cust_bill_event.cgi
new file mode 100644
index 0000000..ec952ea
--- /dev/null
+++ b/httemplate/search/cust_bill_event.cgi
@@ -0,0 +1,62 @@
+<!-- mason kludge -->
+<%
+
+#false laziness with view/cust_bill.cgi
+
+$cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/;
+my $beginning = str2time($1) || 0;
+
+$cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/;
+my $ending = str2time($1) + 86399;
+
+my @cust_bill_event =
+ sort { $a->_date <=> $b->_date }
+ qsearch('cust_bill_event', {
+ _date => { op=> '>=', value=>$beginning },
+ statustext => { op=> '!=', value=>'' },
+# i wish...
+# _date => { op=> '<=', value=>$ending },
+ }, '', "AND _date <= $ending");
+
+%>
+
+<%= header('Failed billing events') %>
+
+<%= table() %>
+<TR>
+ <TH>Event</TH>
+ <TH>Date</TH>
+ <TH>Status</TH>
+ <TH>Invoice</TH>
+ <TH>(bill) name</TH>
+ <TH>company</TH>
+<% if ( defined dbdef->table('cust_main')->column('ship_last') ) { %>
+ <TH>(service) name</TH>
+ <TH>company</TH>
+<% } %>
+</TR>
+
+<% foreach my $cust_bill_event ( @cust_bill_event ) {
+ my $status = $cust_bill_event->status;
+ $status .= ': '.$cust_bill_event->statustext if $cust_bill_event->statustext;
+ my $cust_bill = $cust_bill_event->cust_bill;
+ my $cust_main = $cust_bill->cust_main;
+ my $invlink = "${p}view/cust_bill.cgi?". $cust_bill->invnum;
+ my $custlink = "${p}view/cust_main.cgi?". $cust_main->custnum;
+%>
+<TR>
+ <TD><%= $cust_bill_event->part_bill_event->event %></TD>
+ <TD><%= time2str("%a %b %e %T %Y", $cust_bill_event->_date) %></TD>
+ <TD><%= $status %></TD>
+ <TD><A HREF="<%=$invlink%>">Invoice #<%= $cust_bill->invnum %> (<%= time2str("%D", $cust_bill->_date ) %>)</A></TD>
+ <TD><A HREF="<%=$custlink%>"><%= $cust_main->last. ', '. $cust_main->first %></A></TD>
+ <TD><A HREF="<%=$custlink%>"><%= $cust_main->company %></A></TD>
+ <% if ( defined dbdef->table('cust_main')->column('ship_last') ) { %>
+ <TD><A HREF="<%=$custlink%>"><%= $cust_main->ship_last. ', '. $cust_main->ship_first %></A></TD>
+ <TD><A HREF="<%=$custlink%>"><%= $cust_main->ship_company %></A></TD>
+ <% } %>
+</TR>
+<% } %>
+</TABLE>
+
+</BODY></HTML>
diff --git a/httemplate/search/cust_bill_event.html b/httemplate/search/cust_bill_event.html
new file mode 100755
index 0000000..d76ce3c
--- /dev/null
+++ b/httemplate/search/cust_bill_event.html
@@ -0,0 +1,23 @@
+<HTML>
+ <HEAD>
+ <TITLE>Failed billing events</TITLE>
+ </HEAD>
+ <BODY>
+ <CENTER>
+ <H1>Failed billing events</H1>
+ </CENTER>
+ <HR>
+ <FORM ACTION="cust_bill_event.cgi" METHOD="post">
+ Return <B>failed billing events</B> for period:
+ from <INPUT TYPE="text" NAME="beginning"> <i>m/d/y</i>
+ to <INPUT TYPE="text" NAME="ending"> <i>m/d/y</i>
+
+ <P><INPUT TYPE="submit" VALUE="Get Report">
+
+ </FORM>
+
+ <HR>
+
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/cust_credit.html b/httemplate/search/cust_credit.html
new file mode 100755
index 0000000..c46caba
--- /dev/null
+++ b/httemplate/search/cust_credit.html
@@ -0,0 +1,76 @@
+<%
+ #my( $count_query, $sql_query );
+
+ my @search = ();
+
+ if ( $cgi->param('otaker') && $cgi->param('otaker') =~ /^([\w\.\-]+)$/ ) {
+ push @search, "otaker = '$1'";
+ }
+
+ #false laziness with cust_pkg.cgi and cust_pay.cgi
+ if ( $cgi->param('beginning')
+ && $cgi->param('beginning') =~ /^([ 0-9\-\/]{1,10})$/ ) {
+ my $beginning = str2time($1);
+ push @search, "_date >= $beginning ";
+ }
+ if ( $cgi->param('ending')
+ && $cgi->param('ending') =~ /^([ 0-9\-\/]{1,10})$/ ) {
+ my $ending = str2time($1) + 86399;
+ push @search, " _date <= $ending ";
+ }
+
+ if ( $cgi->param('begin')
+ && $cgi->param('begin') =~ /^(\d+)$/ ) {
+ push @search, "_date >= $1 ";
+ }
+ if ( $cgi->param('end')
+ && $cgi->param('end') =~ /^(\d+)$/ ) {
+ push @search, " _date < $1 ";
+ }
+
+ my $where = scalar(@search)
+ ? 'WHERE '. join(' AND ', @search)
+ : '';
+
+ my $count_query = "SELECT COUNT(*), SUM(amount) FROM cust_credit $where";
+ my $sql_query = {
+ 'table' => 'cust_credit',
+ 'hashref' => {},
+ 'extra_sql' => $where,
+ };
+
+ my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
+
+%>
+<%= include( 'elements/search.html',
+ 'title' => 'Credit Search Results',
+ 'name' => 'credits',
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'count_addl' => [ '$%.2f total credited', ],
+ #'redirect' => $link,
+ 'header' =>
+ [ qw(Amount Date), 'Contact name', qw(Company By Reason) ],
+ 'fields' => [
+ #'crednum',
+ sub { sprintf('$%.2f', shift->amount ) },
+ sub { time2str('%b %d %Y', shift->_date ) },
+ sub { my $cust_main = shift->cust_main;
+ $cust_main->get('last'). ', '. $cust_main->first;
+ },
+ sub { my $cust_main = shift->cust_main;
+ $cust_main->company;
+ },
+ 'otaker',
+ 'reason',
+ ],
+ 'links' => [
+ '',
+ '',
+ $clink,
+ $clink,
+ '',
+ '',
+ ],
+ )
+%>
diff --git a/httemplate/search/cust_main-otaker.cgi b/httemplate/search/cust_main-otaker.cgi
new file mode 100755
index 0000000..4421436
--- /dev/null
+++ b/httemplate/search/cust_main-otaker.cgi
@@ -0,0 +1,28 @@
+<HTML>
+ <HEAD>
+ <TITLE>Customer Search</TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <FONT SIZE=7>
+ Customer Search
+ </FONT>
+ <BR>
+ <FORM ACTION="cust_main.cgi" METHOD="post">
+ Search for <B>Order taker</B>:
+ <INPUT TYPE="hidden" NAME="otaker_on" VALUE="TRUE">
+ <% my $sth = dbh->prepare("SELECT DISTINCT otaker FROM cust_main")
+ or die dbh->errstr;
+ $sth->execute() or die $sth->errstr;
+# my @otakers = map { $_->[0] } @{$sth->selectall_arrayref};
+ %>
+ <SELECT NAME="otaker">
+ <% my $otaker; while ( $otaker = $sth->fetchrow_arrayref ) { %>
+ <OPTION><%= $otaker->[0] %></OTAKER>
+ <% } %>
+ </SELECT>
+ <P><INPUT TYPE="submit" VALUE="Search">
+
+ </FORM>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/cust_main-payinfo.html b/httemplate/search/cust_main-payinfo.html
new file mode 100755
index 0000000..671b5ef
--- /dev/null
+++ b/httemplate/search/cust_main-payinfo.html
@@ -0,0 +1,20 @@
+<HTML>
+ <HEAD>
+ <TITLE>Customer Search</TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <FONT SIZE=7>
+ Customer Search
+ </FONT>
+ <BR>
+ <FORM ACTION="cust_main.cgi" METHOD="post">
+ Search for <B>Credit card #</B>:
+ <INPUT TYPE="hidden" NAME="card_on" VALUE="TRUE">
+ <INPUT TYPE="text" NAME="card">
+
+ <P><INPUT TYPE="submit" VALUE="Search">
+
+ </FORM>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/cust_main-quickpay.html b/httemplate/search/cust_main-quickpay.html
new file mode 100755
index 0000000..d48f1d0
--- /dev/null
+++ b/httemplate/search/cust_main-quickpay.html
@@ -0,0 +1,44 @@
+<HTML>
+ <HEAD>
+ <TITLE>Quick payment entry</TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <FONT SIZE=7>
+ Quick payment entry
+ </FONT>
+ <BR><BR>
+ <A HREF="../">Main Menu</A><BR><BR>
+ <FORM ACTION="cust_main.cgi" METHOD="post">
+ <INPUT TYPE="hidden" NAME="quickpay" VALUE="yes">
+ <INPUT TYPE="checkbox" NAME="last_on" CHECKED> Search for <B>last name</B>:
+ <INPUT TYPE="text" NAME="last_text">
+ using search method: <SELECT NAME="last_type">
+ <OPTION>All
+ <OPTION>Fuzzy
+ <OPTION>Substring
+ <OPTION SELECTED>Exact
+ </SELECT>
+
+ <P><INPUT TYPE="checkbox" NAME="company_on" CHECKED> Search for <B>company</B>:
+ <INPUT TYPE="text" NAME="company_text">
+ using search methods: <SELECT NAME="company_type">
+ <OPTION>All
+ <OPTION>Fuzzy
+ <OPTION>Substring
+ <OPTION SELECTED>Exact
+ </SELECT>
+
+ <P><INPUT TYPE="submit" VALUE="Search">
+
+ </FORM>
+
+ <HR>Explanation of search methods:
+ <UL>
+ <LI><B>All</B> - Try all search methods.
+ <LI><B>Fuzzy</B> - Searches for matches that are close to your text.
+ <LI><B>Substring</B> - Searches for matches that contain your text.
+ <LI><B>Exact</B> - Finds exact matches only, but much faster than the other search methods.
+ </UL>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/cust_main.cgi b/httemplate/search/cust_main.cgi
new file mode 100755
index 0000000..632d68d
--- /dev/null
+++ b/httemplate/search/cust_main.cgi
@@ -0,0 +1,640 @@
+<%
+
+my $conf = new FS::Conf;
+my $maxrecords = $conf->config('maxsearchrecordsperpage');
+
+#my $cache;
+
+#my $monsterjoin = <<END;
+#cust_main left outer join (
+# ( cust_pkg left outer join part_pkg using(pkgpart)
+# ) left outer join (
+# (
+# (
+# ( cust_svc left outer join part_svc using (svcpart)
+# ) left outer join svc_acct using (svcnum)
+# ) left outer join svc_domain using(svcnum)
+# ) left outer join svc_forward using(svcnum)
+# ) using (pkgnum)
+#) using (custnum)
+#END
+
+#my $monsterjoin = <<END;
+#cust_main left outer join (
+# ( cust_pkg left outer join part_pkg using(pkgpart)
+# ) left outer join (
+# (
+# (
+# ( cust_svc left outer join part_svc using (svcpart)
+# ) left outer join (
+# svc_acct left outer join (
+# select svcnum, domain, catchall from svc_domain
+# ) as svc_acct_domsvc (
+# svc_acct_svcnum, svc_acct_domain, svc_acct_catchall
+# ) on svc_acct.domsvc = svc_acct_domsvc.svc_acct_svcnum
+# ) using (svcnum)
+# ) left outer join svc_domain using(svcnum)
+# ) left outer join svc_forward using(svcnum)
+# ) using (pkgnum)
+#) using (custnum)
+#END
+
+my $limit = '';
+$limit .= "LIMIT $maxrecords" if $maxrecords;
+
+my $offset = $cgi->param('offset') || 0;
+$limit .= " OFFSET $offset" if $offset;
+
+my $total = 0;
+
+my(@cust_main, $sortby, $orderby);
+if ( $cgi->param('browse')
+ || $cgi->param('otaker_on')
+ || $cgi->param('agentnum_on')
+) {
+
+ my %search = ();
+ if ( $cgi->param('browse') ) {
+ my $query = $cgi->param('browse');
+ if ( $query eq 'custnum' ) {
+ $sortby=\*custnum_sort;
+ $orderby = "ORDER BY custnum";
+ } elsif ( $query eq 'last' ) {
+ $sortby=\*last_sort;
+ $orderby = "ORDER BY LOWER(last || ' ' || first)";
+ } elsif ( $query eq 'company' ) {
+ $sortby=\*company_sort;
+ $orderby = "ORDER BY LOWER(company || ' ' || last || ' ' || first )";
+ } else {
+ die "unknown browse field $query";
+ }
+ } else {
+ $sortby = \*last_sort; #??
+ $orderby = "ORDER BY LOWER(last || ' ' || first)"; #??
+ if ( $cgi->param('otaker_on') ) {
+ $cgi->param('otaker') =~ /^(\w{1,32})$/ or eidiot "Illegal otaker\n";
+ $search{otaker} = $1;
+ } elsif ( $cgi->param('agentnum_on') ) {
+ $cgi->param('agentnum') =~ /^(\d+)$/ or eidiot "Illegal agentnum\n";
+ $search{agentnum} = $1;
+ } else {
+ die "unknown query...";
+ }
+ }
+
+ my @qual = ();
+
+ my $ncancelled = '';
+
+ if ( $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me
+ || ( $conf->exists('hidecancelledcustomers')
+ && ! $cgi->param('showcancelledcustomers') )
+ ) {
+ #grep { $_->ncancelled_pkgs || ! $_->all_pkgs }
+ push @qual, "
+ ( 0 < ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ AND ( cust_pkg.cancel IS NULL
+ OR cust_pkg.cancel = 0
+ )
+ )
+ OR 0 = ( SELECT COUNT(*) FROM cust_pkg
+ WHERE cust_pkg.custnum = cust_main.custnum
+ )
+ )
+ ";
+ }
+
+ push @qual, FS::cust_main->cancel_sql if $cgi->param('cancelled');
+ push @qual, FS::cust_main->prospect_sql if $cgi->param('prospect');
+ push @qual, FS::cust_main->active_sql if $cgi->param('active');
+ push @qual, FS::cust_main->susp_sql if $cgi->param('suspended');
+
+ #EWWWWWW
+ my $qual = join(' AND ',
+ map { "$_ = ". dbh->quote($search{$_}) } keys %search );
+
+ my $addl_qual = join(' AND ', @qual);
+
+ if ( $addl_qual ) {
+ $qual .= ' AND ' if $qual;
+ $qual .= $addl_qual;
+ }
+
+ $qual = " WHERE $qual" if $qual;
+ my $statement = "SELECT COUNT(*) FROM cust_main $qual";
+ my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement";
+ $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
+
+ $total = $sth->fetchrow_arrayref->[0];
+
+ if ( $addl_qual ) {
+ if ( %search ) {
+ $addl_qual = " AND $addl_qual";
+ } else {
+ $addl_qual = " WHERE $addl_qual";
+ }
+ }
+
+ @cust_main = qsearch('cust_main', \%search, '',
+ "$addl_qual $orderby $limit" );
+
+# foreach my $cust_main ( @just_cust_main ) {
+#
+# my @one_cust_main;
+# $FS::Record::DEBUG=1;
+# ( $cache, @one_cust_main ) = jsearch(
+# "$monsterjoin",
+# { 'custnum' => $cust_main->custnum },
+# '',
+# '',
+# 'cust_main',
+# 'custnum',
+# );
+# push @cust_main, @one_cust_main;
+# }
+
+} else {
+ @cust_main=();
+ $sortby = \*last_sort;
+
+ push @cust_main, @{&custnumsearch}
+ if $cgi->param('custnum_on') && $cgi->param('custnum_text');
+ push @cust_main, @{&cardsearch}
+ if $cgi->param('card_on') && $cgi->param('card');
+ push @cust_main, @{&lastsearch}
+ if $cgi->param('last_on') && $cgi->param('last_text');
+ push @cust_main, @{&companysearch}
+ if $cgi->param('company_on') && $cgi->param('company_text');
+ push @cust_main, @{&address2search}
+ if $cgi->param('address2_on') && $cgi->param('address2_text');
+ push @cust_main, @{&phonesearch}
+ if $cgi->param('phone_on') && $cgi->param('phone_text');
+ push @cust_main, @{&referralsearch}
+ if $cgi->param('referral_custnum');
+
+ if ( $cgi->param('company_on') && $cgi->param('company_text') ) {
+ $sortby = \*company_sort;
+ push @cust_main, @{&companysearch};
+ }
+
+ @cust_main = grep { $_->ncancelled_pkgs || ! $_->all_pkgs } @cust_main
+ if ! $cgi->param('cancelled')
+ && (
+ $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me
+ || ( $conf->exists('hidecancelledcustomers')
+ && ! $cgi->param('showcancelledcustomers') )
+ );
+
+ my %saw = ();
+ @cust_main = grep { !$saw{$_->custnum}++ } @cust_main;
+}
+
+my %all_pkgs;
+if ( $conf->exists('hidecancelledpackages' ) ) {
+ %all_pkgs = map { $_->custnum => [ $_->ncancelled_pkgs ] } @cust_main;
+} else {
+ %all_pkgs = map { $_->custnum => [ $_->all_pkgs ] } @cust_main;
+}
+#%all_pkgs = ();
+
+if ( scalar(@cust_main) == 1 && ! $cgi->param('referral_custnum') ) {
+ if ( $cgi->param('quickpay') eq 'yes' ) {
+ print $cgi->redirect(popurl(2). "edit/cust_pay.cgi?quickpay=yes;custnum=". $cust_main[0]->custnum);
+ } else {
+ print $cgi->redirect(popurl(2). "view/cust_main.cgi?". $cust_main[0]->custnum);
+ }
+ #exit;
+} elsif ( scalar(@cust_main) == 0 ) {
+%>
+<!-- mason kludge -->
+<%
+ eidiot "No matching customers found!\n";
+} else {
+%>
+<!-- mason kludge -->
+<%
+
+ $total ||= scalar(@cust_main);
+ print header("Customer Search Results",menubar(
+ 'Main Menu', popurl(2)
+ )), "$total matching customers found ";
+
+ #begin pager
+ my $pager = '';
+ if ( $total != scalar(@cust_main) && $maxrecords ) {
+ unless ( $offset == 0 ) {
+ $cgi->param('offset', $offset - $maxrecords);
+ $pager .= '<A HREF="'. $cgi->self_url.
+ '"><B><FONT SIZE="+1">Previous</FONT></B></A> ';
+ }
+ my $poff;
+ my $page;
+ for ( $poff = 0; $poff < $total; $poff += $maxrecords ) {
+ $page++;
+ if ( $offset == $poff ) {
+ $pager .= qq!<FONT SIZE="+2">$page</FONT> !;
+ } else {
+ $cgi->param('offset', $poff);
+ $pager .= qq!<A HREF="!. $cgi->self_url. qq!">$page</A> !;
+ }
+ }
+ unless ( $offset + $maxrecords > $total ) {
+ $cgi->param('offset', $offset + $maxrecords);
+ $pager .= '<A HREF="'. $cgi->self_url.
+ '"><B><FONT SIZE="+1">Next</FONT></B></A> ';
+ }
+ }
+ #end pager
+
+ unless ( $cgi->param('cancelled') ) {
+ if ( $cgi->param('showcancelledcustomers') eq '0' #see if it was set by me
+ || ( $conf->exists('hidecancelledcustomers')
+ && ! $cgi->param('showcancelledcustomers')
+ )
+ ) {
+ $cgi->param('showcancelledcustomers', 1);
+ $cgi->param('offset', 0);
+ print qq!( <a href="!. $cgi->self_url. qq!">show!;
+ } else {
+ $cgi->param('showcancelledcustomers', 0);
+ $cgi->param('offset', 0);
+ print qq!( <a href="!. $cgi->self_url. qq!">hide!;
+ }
+ print ' cancelled customers</a> )';
+ }
+ if ( $cgi->param('referral_custnum') ) {
+ $cgi->param('referral_custnum') =~ /^(\d+)$/
+ or eidiot "Illegal referral_custnum\n";
+ my $referral_custnum = $1;
+ my $cust_main = qsearchs('cust_main', { custnum => $referral_custnum } );
+ print '<FORM METHOD=POST>'.
+ qq!<INPUT TYPE="hidden" NAME="referral_custnum" VALUE="$referral_custnum">!.
+ 'referrals of <A HREF="'. popurl(2).
+ "view/cust_main.cgi?$referral_custnum\">$referral_custnum: ".
+ ( $cust_main->company
+ || $cust_main->last. ', '. $cust_main->first ).
+ '</A>';
+ print "\n",<<END;
+ <SCRIPT>
+ function changed(what) {
+ what.form.submit();
+ }
+ </SCRIPT>
+END
+ print ' <SELECT NAME="referral_depth" SIZE="1" onChange="changed(this)">';
+ my $max = 8; #config file
+ $cgi->param('referral_depth') =~ /^(\d*)$/
+ or eidiot "Illegal referral_depth";
+ my $referral_depth = $1;
+
+ foreach my $depth ( 1 .. $max ) {
+ print '<OPTION',
+ ' SELECTED'x($depth == $referral_depth),
+ ">$depth";
+ }
+ print "</SELECT> levels deep".
+ '<NOSCRIPT> <INPUT TYPE="submit" VALUE="change"></NOSCRIPT>'.
+ '</FORM>';
+ }
+
+ print "<BR><BR>". $pager. &table(). <<END;
+ <TR>
+ <TH></TH>
+ <TH>(bill) name</TH>
+ <TH>company</TH>
+END
+
+if ( defined dbdef->table('cust_main')->column('ship_last') ) {
+ print <<END;
+ <TH>(service) name</TH>
+ <TH>company</TH>
+END
+}
+
+print <<END;
+ <TH>Packages</TH>
+ <TH COLSPAN=2>Services</TH>
+ </TR>
+END
+
+ my(%saw,$cust_main);
+ my $p = popurl(2);
+ foreach $cust_main (
+ sort $sortby grep(!$saw{$_->custnum}++, @cust_main)
+ ) {
+ my($custnum,$last,$first,$company)=(
+ $cust_main->custnum,
+ $cust_main->getfield('last'),
+ $cust_main->getfield('first'),
+ $cust_main->company,
+ );
+
+ my(@lol_cust_svc);
+ my($rowspan)=0;#scalar( @{$all_pkgs{$custnum}} );
+ foreach ( @{$all_pkgs{$custnum}} ) {
+ #my(@cust_svc) = qsearch( 'cust_svc', { 'pkgnum' => $_->pkgnum } );
+ my @cust_svc = $_->cust_svc;
+ push @lol_cust_svc, \@cust_svc;
+ $rowspan += scalar(@cust_svc) || 1;
+ }
+
+ #my($rowspan) = scalar(@{$all_pkgs{$custnum}});
+ my $view;
+ if ( defined $cgi->param('quickpay') && $cgi->param('quickpay') eq 'yes' ) {
+ $view = $p. 'edit/cust_pay.cgi?quickpay=yes;custnum='. $custnum;
+ } else {
+ $view = $p. 'view/cust_main.cgi?'. $custnum;
+ }
+ my $pcompany = $company
+ ? qq!<A HREF="$view"><FONT SIZE=-1>$company</FONT></A>!
+ : '<FONT SIZE=-1>&nbsp;</FONT>';
+ print <<END;
+ <TR>
+ <TD ROWSPAN=$rowspan><A HREF="$view"><FONT SIZE=-1>$custnum</FONT></A></TD>
+ <TD ROWSPAN=$rowspan><A HREF="$view"><FONT SIZE=-1>$last, $first</FONT></A></TD>
+ <TD ROWSPAN=$rowspan>$pcompany</TD>
+END
+ if ( defined dbdef->table('cust_main')->column('ship_last') ) {
+ my($ship_last,$ship_first,$ship_company)=(
+ $cust_main->ship_last || $cust_main->getfield('last'),
+ $cust_main->ship_last ? $cust_main->ship_first : $cust_main->first,
+ $cust_main->ship_last ? $cust_main->ship_company : $cust_main->company,
+ );
+ my $pship_company = $ship_company
+ ? qq!<A HREF="$view"><FONT SIZE=-1>$ship_company</FONT></A>!
+ : '<FONT SIZE=-1>&nbsp;</FONT>';
+ print <<END;
+ <TD ROWSPAN=$rowspan><A HREF="$view"><FONT SIZE=-1>$ship_last, $ship_first</FONT></A></TD>
+ <TD ROWSPAN=$rowspan>$pship_company</A></TD>
+END
+ }
+
+ my($n1)='';
+ foreach ( @{$all_pkgs{$custnum}} ) {
+ my $pkgnum = $_->pkgnum;
+# my $part_pkg = qsearchs( 'part_pkg', { pkgpart => $_->pkgpart } );
+ my $part_pkg = $_->part_pkg;
+
+ my $pkg = $part_pkg->pkg;
+ my $comment = $part_pkg->comment;
+ my $pkgview = "${p}view/cust_main.cgi?$custnum#cust_pkg$pkgnum";
+ my @cust_svc = @{shift @lol_cust_svc};
+ #my(@cust_svc) = qsearch( 'cust_svc', { 'pkgnum' => $_->pkgnum } );
+ my $rowspan = scalar(@cust_svc) || 1;
+
+ print $n1, qq!<TD ROWSPAN=$rowspan><A HREF="$pkgview"><FONT SIZE=-1>$pkg - $comment</FONT></A></TD>!;
+ my($n2)='';
+ foreach my $cust_svc ( @cust_svc ) {
+ my($label, $value, $svcdb) = $cust_svc->label;
+ my($svcnum) = $cust_svc->svcnum;
+ my($sview) = $p.'view';
+ print $n2,qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$label</FONT></A></TD>!,
+ qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$value</FONT></A></TD>!;
+ $n2="</TR><TR>";
+ }
+ #print qq!</TR><TR>\n!;
+ $n1="</TR><TR>";
+ }
+ print "</TR>";
+ }
+
+ print "</TABLE>$pager</BODY></HTML>";
+
+}
+
+#undef $cache; #does this help?
+
+#
+
+sub last_sort {
+ lc($a->getfield('last')) cmp lc($b->getfield('last'))
+ || lc($a->first) cmp lc($b->first);
+}
+
+sub company_sort {
+ return -1 if $a->company && ! $b->company;
+ return 1 if ! $a->company && $b->company;
+ lc($a->company) cmp lc($b->company)
+ || lc($a->getfield('last')) cmp lc($b->getfield('last'))
+ || lc($a->first) cmp lc($b->first);;
+}
+
+sub custnum_sort {
+ $a->getfield('custnum') <=> $b->getfield('custnum');
+}
+
+sub custnumsearch {
+
+ my $custnum = $cgi->param('custnum_text');
+ $custnum =~ s/\D//g;
+ $custnum =~ /^(\d{1,23})$/ or eidiot "Illegal customer number\n";
+ $custnum = $1;
+
+ [ qsearchs('cust_main', { 'custnum' => $custnum } ) ];
+}
+
+sub cardsearch {
+
+ my($card)=$cgi->param('card');
+ $card =~ s/\D//g;
+ $card =~ /^(\d{13,16})$/ or eidiot "Illegal card number\n";
+ my($payinfo)=$1;
+
+ [ qsearch('cust_main',{'payinfo'=>$payinfo, 'payby'=>'CARD'}),
+ qsearch('cust_main',{'payinfo'=>$payinfo, 'payby'=>'DCRD'})
+ ];
+}
+
+sub referralsearch {
+ $cgi->param('referral_custnum') =~ /^(\d+)$/
+ or eidiot "Illegal referral_custnum";
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $1 } )
+ or eidiot "Customer $1 not found";
+ my $depth;
+ if ( $cgi->param('referral_depth') ) {
+ $cgi->param('referral_depth') =~ /^(\d+)$/
+ or eidiot "Illegal referral_depth";
+ $depth = $1;
+ } else {
+ $depth = 1;
+ }
+ [ $cust_main->referral_cust_main($depth) ];
+}
+
+sub lastsearch {
+ my(%last_type);
+ my @cust_main;
+ foreach ( $cgi->param('last_type') ) {
+ $last_type{$_}++;
+ }
+
+ $cgi->param('last_text') =~ /^([\w \,\.\-\']*)$/
+ or eidiot "Illegal last name";
+ my($last)=$1;
+
+ if ( $last_type{'Exact'} || $last_type{'Fuzzy'} ) {
+ push @cust_main, qsearch( 'cust_main',
+ { 'last' => { 'op' => 'ILIKE',
+ 'value' => $last } } );
+
+ push @cust_main, qsearch( 'cust_main',
+ { 'ship_last' => { 'op' => 'ILIKE',
+ 'value' => $last } } )
+ if defined dbdef->table('cust_main')->column('ship_last');
+ }
+
+ if ( $last_type{'Substring'} || $last_type{'All'} ) {
+
+ push @cust_main, qsearch( 'cust_main',
+ { 'last' => { 'op' => 'ILIKE',
+ 'value' => "%$last%" } } );
+
+ push @cust_main, qsearch( 'cust_main',
+ { 'ship_last' => { 'op' => 'ILIKE',
+ 'value' => "%$last%" } } )
+ if defined dbdef->table('cust_main')->column('ship_last');
+
+ }
+
+ if ( $last_type{'Fuzzy'} || $last_type{'All'} ) {
+
+ &FS::cust_main::check_and_rebuild_fuzzyfiles;
+ my $all_last = &FS::cust_main::all_last;
+
+ my %last;
+ if ( $last_type{'Fuzzy'} || $last_type{'All'} ) {
+ foreach ( amatch($last, [ qw(i) ], @$all_last) ) {
+ $last{$_}++;
+ }
+ }
+
+ #if ($last_type{'Sound-alike'}) {
+ #}
+
+ foreach ( keys %last ) {
+ push @cust_main, qsearch('cust_main',{'last'=>$_});
+ push @cust_main, qsearch('cust_main',{'ship_last'=>$_})
+ if defined dbdef->table('cust_main')->column('ship_last');
+ }
+
+ }
+
+ \@cust_main;
+}
+
+sub companysearch {
+
+ my(%company_type);
+ my @cust_main;
+ foreach ( $cgi->param('company_type') ) {
+ $company_type{$_}++
+ };
+
+ $cgi->param('company_text') =~
+ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
+ or eidiot "Illegal company";
+ my $company = $1;
+
+ if ( $company_type{'Exact'} || $company_type{'Fuzzy'} ) {
+ push @cust_main, qsearch( 'cust_main',
+ { 'company' => { 'op' => 'ILIKE',
+ 'value' => $company } } );
+
+ push @cust_main, qsearch( 'cust_main',
+ { 'ship_company' => { 'op' => 'ILIKE',
+ 'value' => $company } } )
+ if defined dbdef->table('cust_main')->column('ship_last');
+ }
+
+ if ( $company_type{'Substring'} || $company_type{'All'} ) {
+
+ push @cust_main, qsearch( 'cust_main',
+ { 'company' => { 'op' => 'ILIKE',
+ 'value' => "%$company%" } } );
+
+ push @cust_main, qsearch( 'cust_main',
+ { 'ship_company' => { 'op' => 'ILIKE',
+ 'value' => "%$company%" } })
+ if defined dbdef->table('cust_main')->column('ship_last');
+
+ }
+
+ if ( $company_type{'Fuzzy'} || $company_type{'All'} ) {
+
+ &FS::cust_main::check_and_rebuild_fuzzyfiles;
+ my $all_company = &FS::cust_main::all_company;
+
+ my %company;
+ if ( $company_type{'Fuzzy'} || $company_type{'All'} ) {
+ foreach ( amatch($company, [ qw(i) ], @$all_company ) ) {
+ $company{$_}++;
+ }
+ }
+
+ #if ($company_type{'Sound-alike'}) {
+ #}
+
+ foreach ( keys %company ) {
+ push @cust_main, qsearch('cust_main',{'company'=>$_});
+ push @cust_main, qsearch('cust_main',{'ship_company'=>$_})
+ if defined dbdef->table('cust_main')->column('ship_last');
+ }
+
+ }
+
+ \@cust_main;
+}
+
+sub address2search {
+ my @cust_main;
+
+ $cgi->param('address2_text') =~
+ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/
+ or eidiot "Illegal address2";
+ my $address2 = $1;
+
+ push @cust_main, qsearch( 'cust_main',
+ { 'address2' => { 'op' => 'ILIKE',
+ 'value' => $address2 } } );
+ push @cust_main, qsearch( 'cust_main',
+ { 'address2' => { 'op' => 'ILIKE',
+ 'value' => $address2 } } )
+ if defined dbdef->table('cust_main')->column('ship_last');
+
+ \@cust_main;
+}
+
+sub phonesearch {
+ my @cust_main;
+
+ my $phone = $cgi->param('phone_text');
+
+ #(no longer really) false laziness with Record::ut_phonen
+ #only works with US/CA numbers...
+ $phone =~ s/\D//g;
+ if ( $phone =~ /^(\d{3})(\d{3})(\d{4})(\d*)$/ ) {
+ $phone = "$1-$2-$3";
+ $phone .= " x$4" if $4;
+ } elsif ( $phone =~ /^(\d{3})(\d{4})$/ ) {
+ $phone = "$1-$2";
+ } elsif ( $phone =~ /^(\d{3,4})$/ ) {
+ $phone = $1;
+ } else {
+ eidiot gettext('illegal_phone'). ": $phone";
+ }
+
+ my @fields = qw(daytime night fax);
+ push @fields, qw(ship_daytime ship_night ship_fax)
+ if defined dbdef->table('cust_main')->column('ship_last');
+
+ for my $field ( @fields ) {
+ push @cust_main, qsearch ( 'cust_main',
+ { $field => { 'op' => 'LIKE',
+ 'value' => "%$phone%" } } );
+ }
+
+ \@cust_main;
+}
+
+%>
diff --git a/httemplate/search/cust_main.html b/httemplate/search/cust_main.html
new file mode 100755
index 0000000..5a066e4
--- /dev/null
+++ b/httemplate/search/cust_main.html
@@ -0,0 +1,42 @@
+<HTML>
+ <HEAD>
+ <TITLE>Customer Search</TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <FONT SIZE=7>
+ Customer Search
+ </FONT>
+ <BR><BR>
+ <FORM ACTION="cust_main.cgi" METHOD="post">
+ <INPUT TYPE="checkbox" NAME="last_on" CHECKED> Search for <B>last name</B>:
+ <INPUT TYPE="text" NAME="last_text">
+ using search method: <SELECT NAME="last_type">
+ <OPTION SELECTED>All
+ <OPTION>Fuzzy
+ <OPTION>Substring
+ <OPTION>Exact
+ </SELECT>
+
+ <P><INPUT TYPE="checkbox" NAME="company_on" CHECKED> Search for <B>company</B>:
+ <INPUT TYPE="text" NAME="company_text">
+ using search methods: <SELECT NAME="company_type">
+ <OPTION SELECTED>All
+ <OPTION>Fuzzy
+ <OPTION>Substring
+ <OPTION>Exact
+ </SELECT>
+
+ <P><INPUT TYPE="submit" VALUE="Search"> Note: Fuzzy searching can take a while. Please be patient.
+
+ </FORM>
+
+ <HR>Explanation of search methods:
+ <UL>
+ <LI><B>All</B> - Try all search methods.
+ <LI><B>Fuzzy</B> - Searches for matches that are close to your text.
+ <LI><B>Substring</B> - Searches for matches that contain your text.
+ <LI><B>Exact</B> - Finds exact matches only, but much faster than the other search methods.
+ </UL>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/cust_pay.cgi b/httemplate/search/cust_pay.cgi
new file mode 100755
index 0000000..ba2bc63
--- /dev/null
+++ b/httemplate/search/cust_pay.cgi
@@ -0,0 +1,133 @@
+<%
+ my( $count_query, $sql_query );
+ if ( $cgi->param('magic') && $cgi->param('magic') eq '_date' ) {
+
+ my %search;
+ my @search;
+
+ if ( $cgi->param('payby') ) {
+ $cgi->param('payby') =~ /^(CARD|CHEK|BILL)(-(VisaMC|Amex|Discover))?$/
+ or die "illegal payby ". $cgi->param('payby');
+ $search{'payby'} = $1;
+ if ( $3 ) {
+ if ( $3 eq 'VisaMC' ) {
+ #avoid posix regexes for portability
+ push @search, " ( substring(payinfo from 1 for 1) = '4' ".
+ " OR substring(payinfo from 1 for 2) = '51' ".
+ " OR substring(payinfo from 1 for 2) = '52' ".
+ " OR substring(payinfo from 1 for 2) = '53' ".
+ " OR substring(payinfo from 1 for 2) = '54' ".
+ " OR substring(payinfo from 1 for 2) = '54' ".
+ " OR substring(payinfo from 1 for 2) = '55' ".
+ " ) ";
+ } elsif ( $3 eq 'Amex' ) {
+ push @search, " ( substring(payinfo from 1 for 2 ) = '34' ".
+ " OR substring(payinfo from 1 for 2 ) = '37' ".
+ " ) ";
+ } elsif ( $3 eq 'Discover' ) {
+ push @search, " substring(payinfo from 1 for 4 ) = '6011' ";
+ } else {
+ die "unknown card type $3";
+ }
+ }
+ }
+
+ #false laziness with cust_pkg.cgi
+ if ( $cgi->param('beginning')
+ && $cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/ ) {
+ my $beginning = str2time($1);
+ push @search, "_date >= $beginning ";
+ }
+ if ( $cgi->param('ending')
+ && $cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/ ) {
+ my $ending = str2time($1) + 86399;
+ push @search, " _date <= $ending ";
+ }
+ if ( $cgi->param('begin')
+ && $cgi->param('begin') =~ /^(\d+)$/ ) {
+ push @search, "_date >= $1 ";
+ }
+ if ( $cgi->param('end')
+ && $cgi->param('end') =~ /^(\d+)$/ ) {
+ push @search, " _date < $1 ";
+ }
+
+ my $search;
+ if ( @search ) {
+ $search = ( scalar(keys %search) ? ' AND ' : ' WHERE ' ).
+ join(' AND ', @search);
+ }
+
+ my $hsearch = join(' AND ', map { "$_ = '$search{$_}'" } keys %search );
+ $count_query = "SELECT COUNT(*), SUM(paid) FROM cust_pay ".
+ ( $hsearch ? " WHERE $hsearch " : '' ).
+ $search;
+
+ $sql_query = {
+ 'table' => 'cust_pay',
+ 'hashref' => \%search,
+ 'extra_sql' => "$search ORDER BY _date",
+ };
+
+ } else {
+
+ $cgi->param('payinfo') =~ /^\s*(\d+)\s*$/ or die "illegal payinfo";
+ my $payinfo = $1;
+
+ $cgi->param('payby') =~ /^(\w+)$/ or die "illegal payby";
+ my $payby = $1;
+
+ $count_query = "SELECT COUNT(*), SUM(paid) FROM cust_pay ".
+ "WHERE payinfo = '$payinfo' AND payby = '$payby'";
+
+ $sql_query = {
+ 'table' => 'cust_pay',
+ 'hashref' => { 'payinfo' => $payinfo,
+ 'payby' => $payby },
+ 'extra_sql' => "ORDER BY _date",
+ };
+
+ }
+
+ my $link = [ "${p}view/cust_main.cgi?", 'custnum' ];
+
+%>
+<%= include( 'elements/search.html',
+ 'title' => 'Payment Search Results',
+ 'name' => 'payments',
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'count_addl' => [ '$%.2f total paid', ],
+ 'header' =>
+ [ qw(Payment Amount Date), 'Contact name', 'Company', ],
+ 'fields' => [
+ sub {
+ my $cust_pay = shift;
+ if ( $cust_pay->payby eq 'CARD' ) {
+ 'Card #'. $cust_pay->payinfo_masked;
+ } elsif ( $cust_pay->payby eq 'CHEK' ) {
+ 'E-check acct#'. $cust_pay->payinfo;
+ } elsif ( $cust_pay->payby eq 'BILL' ) {
+ 'Check #'. $cust_pay->payinfo;
+ } else {
+ $cust_pay->payby. ' '. $cust_pay->payinfo;
+ }
+ },
+ sub { sprintf('$%.2f', shift->paid ) },
+ sub { time2str('%b %d %Y', shift->_date ) },
+ sub { my $cust_main = shift->cust_main;
+ $cust_main->get('last'). ', '. $cust_main->first;
+ },
+ sub { my $cust_main = shift->cust_main;
+ $cust_main->company;
+ },
+ ],
+ 'links' => [
+ '',
+ '',
+ '',
+ $link,
+ $link,
+ ],
+ )
+%>
diff --git a/httemplate/search/cust_pay.html b/httemplate/search/cust_pay.html
new file mode 100755
index 0000000..3848d66
--- /dev/null
+++ b/httemplate/search/cust_pay.html
@@ -0,0 +1,18 @@
+<HTML>
+ <HEAD>
+ <TITLE>Check # Search</TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <FONT SIZE=7>
+ Check # Search
+ </FONT>
+ <BR><BR>
+ <FORM ACTION="cust_pay.cgi" METHOD="post">
+ Search for <B>check #</B>:
+ <INPUT TYPE="text" NAME="payinfo">
+ <INPUT TYPE="hidden" NAME="payby" VALUE="BILL">
+ <BR><BR><INPUT TYPE="submit" VALUE="Search">
+ </FORM>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi
new file mode 100755
index 0000000..6d26317
--- /dev/null
+++ b/httemplate/search/cust_pkg.cgi
@@ -0,0 +1,363 @@
+<%
+
+my $conf = new FS::Conf;
+my $maxrecords = $conf->config('maxsearchrecordsperpage');
+
+my %part_pkg = map { $_->pkgpart => $_ } qsearch('part_pkg', {});
+
+my $limit = '';
+$limit .= "LIMIT $maxrecords" if $maxrecords;
+
+my $offset = $cgi->param('offset') || 0;
+$limit .= " OFFSET $offset" if $offset;
+
+my $total;
+
+my($query) = $cgi->keywords;
+my $sortby;
+my @cust_pkg;
+
+if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) {
+ $sortby=\*bill_sort;
+
+ #false laziness with cust_pay.cgi
+ my $range = '';
+ if ( $cgi->param('beginning')
+ && $cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/ ) {
+ my $beginning = str2time($1);
+ $range = " WHERE bill >= $beginning ";
+ }
+ if ( $cgi->param('ending')
+ && $cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/ ) {
+ my $ending = str2time($1) + 86399;
+ $range .= ( $range ? ' AND ' : ' WHERE ' ). " bill <= $ending ";
+ }
+
+ $range .= ( $range ? 'AND ' : ' WHERE ' ). '( cancel IS NULL OR cancel = 0 )';
+
+ if ( $cgi->param('agentnum') =~ /^(\d+)$/ and $1 ) {
+ $range .= ( $range ? 'AND ' : ' WHERE ' ).
+ "$1 = ( SELECT agentnum FROM cust_main".
+ " WHERE cust_main.custnum = cust_pkg.custnum )";
+ }
+
+ #false laziness with below
+ my $statement = "SELECT COUNT(*) FROM cust_pkg $range";
+ warn $statement;
+ my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement";
+ $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
+
+ $total = $sth->fetchrow_arrayref->[0];
+
+ @cust_pkg = qsearch('cust_pkg',{}, '', " $range ORDER BY bill $limit" );
+
+} else {
+
+ my $qual = '';
+ if ( $cgi->param('magic') &&
+ $cgi->param('magic') =~ /^(active|suspended|canceled)$/
+ ) {
+
+ if ( $cgi->param('magic') eq 'active' ) {
+ $qual = 'WHERE ( susp IS NULL OR susp = 0 )'.
+ ' AND ( cancel IS NULL OR cancel = 0)';
+ } elsif ( $cgi->param('magic') eq 'suspended' ) {
+ $qual = 'WHERE susp IS NOT NULL AND susp != 0'.
+ ' AND ( cancel IS NULL OR cancel = 0)';
+ } elsif ( $cgi->param('magic') eq 'canceled' ) {
+ $qual = 'WHERE cancel IS NOT NULL AND cancel != 0';
+ } else {
+ die "guru meditation #420";
+ }
+
+ $sortby = \*pkgnum_sort;
+
+ if ( $cgi->param('pkgpart') =~ /^(\d+)$/ ) {
+ $qual .= " AND pkgpart = $1";
+ }
+
+ } elsif ( $query eq 'pkgnum' ) {
+
+ $sortby=\*pkgnum_sort;
+
+ } elsif ( $query eq 'APKG_pkgnum' ) {
+
+ $sortby=\*pkgnum_sort;
+
+ #@cust_pkg=();
+ ##perhaps this should go in cust_pkg as a qsearch-like constructor?
+ #my($cust_pkg);
+ #foreach $cust_pkg (
+ # qsearch('cust_pkg',{}, '', "ORDER BY pkgnum $limit" )
+ #) {
+ # my($flag)=0;
+ # my($pkg_svc);
+ # PKG_SVC:
+ # foreach $pkg_svc (qsearch('pkg_svc',{ 'pkgpart' => $cust_pkg->pkgpart })) {
+ # if ( $pkg_svc->quantity
+ # > scalar(qsearch('cust_svc',{
+ # 'pkgnum' => $cust_pkg->pkgnum,
+ # 'svcpart' => $pkg_svc->svcpart,
+ # }))
+ # )
+ # {
+ # $flag=1;
+ # last PKG_SVC;
+ # }
+ # }
+ # push @cust_pkg, $cust_pkg if $flag;
+ #}
+
+ if ( driver_name eq 'mysql' ) {
+ #$query = "DROP TABLE temp1_$$,temp2_$$;";
+ #my $sth = dbh->prepare($query);
+ #$sth->execute;
+
+ $query = "CREATE TEMPORARY TABLE temp1_$$ TYPE=MYISAM
+ SELECT cust_svc.pkgnum,cust_svc.svcpart,COUNT(*) as count
+ FROM cust_pkg,cust_svc,pkg_svc
+ WHERE cust_pkg.pkgnum = cust_svc.pkgnum
+ AND cust_svc.svcpart = pkg_svc.svcpart
+ AND cust_pkg.pkgpart = pkg_svc.pkgpart
+ GROUP BY cust_svc.pkgnum,cust_svc.svcpart";
+ my $sth = dbh->prepare($query) or die dbh->errstr. " preparing $query";
+
+ $sth->execute or die "Error executing \"$query\": ". $sth->errstr;
+
+ $query = "CREATE TEMPORARY TABLE temp2_$$ TYPE=MYISAM
+ SELECT cust_pkg.pkgnum FROM cust_pkg
+ LEFT JOIN pkg_svc ON (cust_pkg.pkgpart=pkg_svc.pkgpart)
+ LEFT JOIN temp1_$$ ON (cust_pkg.pkgnum = temp1_$$.pkgnum
+ AND pkg_svc.svcpart=temp1_$$.svcpart)
+ WHERE ( pkg_svc.quantity > temp1_$$.count
+ OR temp1_$$.pkgnum IS NULL )
+ AND pkg_svc.quantity != 0;";
+ $sth = dbh->prepare($query) or die dbh->errstr. " preparing $query";
+ $sth->execute or die "Error executing \"$query\": ". $sth->errstr;
+ $qual = " LEFT JOIN temp2_$$ ON cust_pkg.pkgnum = temp2_$$.pkgnum
+ WHERE temp2_$$.pkgnum IS NOT NULL";
+
+ } else {
+
+ $qual = "
+ WHERE 0 <
+ ( SELECT count(*) FROM pkg_svc
+ WHERE pkg_svc.pkgpart = cust_pkg.pkgpart
+ AND pkg_svc.quantity > ( SELECT count(*) FROM cust_svc
+ WHERE cust_svc.pkgnum = cust_pkg.pkgnum
+ AND cust_svc.svcpart = pkg_svc.svcpart
+ )
+ )
+ ";
+
+ }
+
+ } else {
+ die "Empty or unknown QUERY_STRING!";
+ }
+
+ my $statement = "SELECT COUNT(*) FROM cust_pkg $qual";
+ my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement";
+ $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
+
+ $total = $sth->fetchrow_arrayref->[0];
+
+ my $tblname = driver_name eq 'mysql' ? 'cust_pkg.' : '';
+ @cust_pkg =
+ qsearch('cust_pkg',{}, '', "$qual ORDER BY ${tblname}pkgnum $limit" );
+
+ if ( driver_name eq 'mysql' ) {
+ $query = "DROP TABLE temp1_$$,temp2_$$;";
+ my $sth = dbh->prepare($query) or die dbh->errstr. " doing $query";
+ $sth->execute; # or die "Error executing \"$query\": ". $sth->errstr;
+ }
+
+}
+
+if ( scalar(@cust_pkg) == 1 ) {
+ print $cgi->redirect("${p}view/cust_main.cgi?". $cust_pkg[0]->custnum.
+ "#cust_pkg". $cust_pkg[0]->pkgnum );
+ #exit;
+} elsif ( scalar(@cust_pkg) == 0 ) { #error
+%>
+<!-- mason kludge -->
+<%
+ eidiot("No packages found");
+} else {
+%>
+<!-- mason kludge -->
+<%
+ $total ||= scalar(@cust_pkg);
+
+ #begin pager
+ my $pager = '';
+ if ( $total != scalar(@cust_pkg) && $maxrecords ) {
+ unless ( $offset == 0 ) {
+ $cgi->param('offset', $offset - $maxrecords);
+ $pager .= '<A HREF="'. $cgi->self_url.
+ '"><B><FONT SIZE="+1">Previous</FONT></B></A> ';
+ }
+ my $poff;
+ my $page;
+ for ( $poff = 0; $poff < $total; $poff += $maxrecords ) {
+ $page++;
+ if ( $offset == $poff ) {
+ $pager .= qq!<FONT SIZE="+2">$page</FONT> !;
+ } else {
+ $cgi->param('offset', $poff);
+ $pager .= qq!<A HREF="!. $cgi->self_url. qq!">$page</A> !;
+ }
+ }
+ unless ( $offset + $maxrecords > $total ) {
+ $cgi->param('offset', $offset + $maxrecords);
+ $pager .= '<A HREF="'. $cgi->self_url.
+ '"><B><FONT SIZE="+1">Next</FONT></B></A> ';
+ }
+ }
+ #end pager
+
+ print header('Package Search Results',''),
+ "$total matching packages found<BR><BR>$pager", &table(), <<END;
+ <TR>
+ <TH>Package</TH>
+ <TH><FONT SIZE=-1>Setup</FONT></TH>
+END
+
+ print '<TH><FONT SIZE=-1>Last<BR>bill</FONT></TH>'
+ if defined dbdef->table('cust_pkg')->column('last_bill');
+
+ print <<END;
+ <TH><FONT SIZE=-1>Next<BR>bill</FONT></TH>
+ <TH><FONT SIZE=-1>Susp.</FONT></TH>
+ <TH><FONT SIZE=-1>Expire</FONT></TH>
+ <TH><FONT SIZE=-1>Cancel</FONT></TH>
+ <TH><FONT SIZE=-1>Cust#</FONT></TH>
+ <TH>(bill) name</TH>
+ <TH>company</TH>
+END
+
+ print '<TH>(service) name</TH><TH>company</TH>'
+ if defined dbdef->table('cust_main')->column('ship_last');
+
+ print '<TH COLSPAN=2>Services</TH></TR>';
+
+ my $n1 = '<TR>';
+ my(%saw,$cust_pkg);
+ foreach $cust_pkg (
+ sort $sortby grep(!$saw{$_->pkgnum}++, @cust_pkg)
+ ) {
+ my($cust_main)=qsearchs('cust_main',{'custnum'=>$cust_pkg->custnum});
+ my($pkgnum, $setup, $bill, $susp, $expire, $cancel,
+ $custnum, $last, $first, $company ) = (
+ $cust_pkg->pkgnum,
+ $cust_pkg->getfield('setup')
+ ? time2str("%D", $cust_pkg->getfield('setup') )
+ : '',
+ $cust_pkg->getfield('bill')
+ ? time2str("%D", $cust_pkg->getfield('bill') )
+ : '',
+ $cust_pkg->getfield('susp')
+ ? time2str("%D", $cust_pkg->getfield('susp') )
+ : '',
+ $cust_pkg->getfield('expire')
+ ? time2str("%D", $cust_pkg->getfield('expire') )
+ : '',
+ $cust_pkg->getfield('cancel')
+ ? time2str("%D", $cust_pkg->getfield('cancel') )
+ : '',
+ $cust_pkg->custnum,
+ $cust_main ? $cust_main->last : '',
+ $cust_main ? $cust_main->first : '',
+ $cust_main ? $cust_main->company : '',
+ );
+
+ my $last_bill = $cust_pkg->getfield('last_bill')
+ ? time2str("%D", $cust_pkg->getfield('last_bill') )
+ : ''
+ if defined dbdef->table('cust_pkg')->column('last_bill');
+
+ my($ship_last, $ship_first, $ship_company);
+ if ( defined dbdef->table('cust_main')->column('ship_last') ) {
+ ($ship_last, $ship_first, $ship_company) = (
+ $cust_main
+ ? ( $cust_main->ship_last || $cust_main->getfield('last') )
+ : '',
+ $cust_main
+ ? ( $cust_main->ship_last
+ ? $cust_main->ship_first
+ : $cust_main->first )
+ : '',
+ $cust_main
+ ? ( $cust_main->ship_last
+ ? $cust_main->ship_company
+ : $cust_main->company )
+ : '',
+ );
+ }
+ my $pkg = $part_pkg{$cust_pkg->pkgpart}->pkg;
+ #$pkg .= ' - '. $part_pkg{$cust_pkg->pkgpart}->comment;
+ my @cust_svc = qsearch( 'cust_svc', { 'pkgnum' => $pkgnum } );
+ my $rowspan = scalar(@cust_svc) || 1;
+ my $p = popurl(2);
+ print $n1, <<END;
+ <TD ROWSPAN=$rowspan><A HREF="${p}view/cust_main.cgi?$custnum#cust_pkg$pkgnum"><FONT SIZE=-1>$pkgnum - $pkg</FONT></A></TD>
+ <TD ROWSPAN=$rowspan>$setup</TD>
+END
+
+ print "<TD ROWSPAN=$rowspan>$last_bill</TD>"
+ if defined dbdef->table('cust_pkg')->column('last_bill');
+
+ print <<END;
+ <TD ROWSPAN=$rowspan>$bill</TD>
+ <TD ROWSPAN=$rowspan>$susp</TD>
+ <TD ROWSPAN=$rowspan>$expire</TD>
+ <TD ROWSPAN=$rowspan>$cancel</TD>
+END
+ if ( $cust_main ) {
+ print <<END;
+ <TD ROWSPAN=$rowspan><FONT SIZE=-1><A HREF="${p}view/cust_main.cgi?$custnum">$custnum</A></FONT></TD>
+ <TD ROWSPAN=$rowspan><FONT SIZE=-1><A HREF="${p}view/cust_main.cgi?$custnum">$last, $first</A></FONT></TD>
+ <TD ROWSPAN=$rowspan><FONT SIZE=-1><A HREF="${p}view/cust_main.cgi?$custnum">$company</A></FONT></TD>
+END
+ if ( defined dbdef->table('cust_main')->column('ship_last') ) {
+ print <<END;
+ <TD ROWSPAN=$rowspan><FONT SIZE=-1><A HREF="${p}view/cust_main.cgi?$custnum">$ship_last, $ship_first</A></FONT></TD>
+ <TD ROWSPAN=$rowspan><FONT SIZE=-1><A HREF="${p}view/cust_main.cgi?$custnum">$ship_company</A></FONT></TD>
+END
+ }
+ } else {
+ my $colspan = defined dbdef->table('cust_main')->column('ship_last')
+ ? 5 : 3;
+ print <<END;
+ <TD ROWSPAN=$rowspan COLSPAN=$colspan>WARNING: couldn't find cust_main.custnum $custnum (cust_pkg.pkgnum $pkgnum)</TD>
+END
+ }
+
+ my $n2 = '';
+ foreach my $cust_svc ( @cust_svc ) {
+ my($label, $value, $svcdb) = $cust_svc->label;
+ my $svcnum = $cust_svc->svcnum;
+ my $sview = $p. "view";
+ print $n2,qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$label</FONT></A></TD>!,
+ qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$value</FONT></A></TD>!;
+ $n2="</TR><TR>";
+ }
+
+ $n1 = "</TR><TR>";
+
+ }
+ print '</TR>';
+
+ print "</TABLE>$pager</BODY></HTML>";
+
+}
+
+sub pkgnum_sort {
+ $a->getfield('pkgnum') <=> $b->getfield('pkgnum');
+}
+
+sub bill_sort {
+ $a->getfield('bill') <=> $b->getfield('bill');
+}
+
+%>
diff --git a/httemplate/search/cust_pkg_report.cgi b/httemplate/search/cust_pkg_report.cgi
new file mode 100755
index 0000000..b316745
--- /dev/null
+++ b/httemplate/search/cust_pkg_report.cgi
@@ -0,0 +1,63 @@
+<HTML>
+ <HEAD>
+ <TITLE>Packages</TITLE>
+ <LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <H1>Packages</H1>
+ <FORM ACTION="cust_pkg.cgi" METHOD="post">
+ <INPUT TYPE="hidden" NAME="magic" VALUE="bill">
+ Return packages with next bill date:<BR><BR>
+ <TABLE>
+ <TR>
+ <TD ALIGN="right">From: </TD>
+ <TD><INPUT TYPE="text" NAME="beginning" ID="beginning_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="beginning_button" STYLE="cursor: pointer" TITLE="Select date"><BR><I>m/d/y</I></TD>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "beginning_text",
+ ifFormat: "%m/%d/%Y",
+ button: "beginning_button",
+ align: "BR"
+ });
+</SCRIPT>
+ </TR>
+ <TR>
+ <TD ALIGN="right">To: </TD>
+ <TD><INPUT TYPE="text" NAME="ending" ID="ending_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="ending_button" STYLE="cursor: pointer" TITLE="Select date"><BR><I>m/d/y</I></TD>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "ending_text",
+ ifFormat: "%m/%d/%Y",
+ button: "ending_button",
+ align: "BR"
+ });
+</SCRIPT>
+ </TR>
+<% my %agent_search = dbdef->table('agent')->column('disabled')
+ ? ( 'disabled' => '' ) : ();
+ my @agents = qsearch( 'agent', \%agent_search );
+ if ( scalar(@agents) == 1 ) {
+%>
+ <INPUT TYPE="hidden" NAME="agentnum" VALUE="<%= $agents[0]->agentnum %>">
+<% } else { %>
+
+ <TR>
+ <TD ALIGN="right">Agent: </TD>
+ <TD><SELECT NAME="agentnum"><OPTION VALUE="">(all)
+ <% foreach my $agent ( sort { $a->agent cmp $b->agent; } @agents) { %>
+ <OPTION VALUE="<%= $agent->agentnum %>"><%= $agent->agent %>
+ <% } %>
+ </TD>
+ </TR>
+<% } %>
+ </TABLE>
+ <BR><INPUT TYPE="submit" VALUE="Get Report">
+
+ </FORM>
+
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/elements/search.html b/httemplate/search/elements/search.html
new file mode 100644
index 0000000..12ab83b
--- /dev/null
+++ b/httemplate/search/elements/search.html
@@ -0,0 +1,126 @@
+<%
+
+ my(%opt) = @_;
+
+ if ( ref($opt{'query'}) ) {
+
+ }
+
+ unless (exists($opt{'count_query'}) && length($opt{'count_query'})) {
+ ( $opt{'count_query'} = $opt{'query'} ) =~
+ s/^\s*SELECT\s*(.*?)\s+FROM\s/SELECT COUNT(*) FROM /i;
+ }
+
+ my $conf = new FS::Conf;
+ my $maxrecords = $conf->config('maxsearchrecordsperpage');
+
+ my $limit = $maxrecords ? "LIMIT $maxrecords" : '';
+
+ my $offset = $cgi->param('offset') || 0;
+ $limit .= " OFFSET $offset" if $offset;
+
+ my $count_sth = dbh->prepare($opt{'count_query'})
+ or die "Error preparing $opt{'count_query'}: ". dbh->errstr;
+ $count_sth->execute
+ or die "Error executing $opt{'count_query'}: ". $count_sth->errstr;
+ my $count_arrayref = $count_sth->fetchrow_arrayref;
+ my $total = $count_arrayref->[0];
+
+ #warn join(' / ', map { "$_ => $opt{$_}" } keys %opt ). "\n";
+
+ my $header = $opt{'header'};
+ my $rows;
+ if ( ref($opt{'query'}) ) {
+ #eval "use FS::$opt{'query'};";
+ $rows = [ qsearch(
+ $opt{'query'}->{'table'},
+ $opt{'query'}->{'hashref'} || {},
+ $opt{'query'}->{'select'},
+ $opt{'query'}->{'extra_sql'}. " $limit",
+ ) ];
+ } else {
+ my $sth = dbh->prepare("$opt{'query'} $limit")
+ or die "Error preparing $opt{'query'}: ". dbh->errstr;
+ $sth->execute
+ or die "Error executing $opt{'query'}: ". $sth->errstr;
+
+ #can get # of rows without fetching them all?
+ $rows = $sth->fetchall_arrayref;
+
+ $header ||= $sth->{NAME};
+ }
+
+ if ( exists($opt{'redirect'}) && scalar(@$rows) == 1 && $total == 1 ) {
+ my( $url, $method ) = @{$opt{'redirect'}};
+ redirect( $url. $rows->[0]->$method() );
+ } else {
+ $opt{'name'} =~ s/s$// if $total == 1;
+%>
+<%= include( '/elements/header.html', $opt{'title'},
+ include( '/elements/menubar.html', 'Main menu' => $p )
+ )
+%>
+<% my $pager = include ( '/elements/pager.html',
+ 'offset' => $offset,
+ 'num_rows' => scalar(@$rows),
+ 'total' => $total,
+ 'maxrecords' => $maxrecords,
+ );
+%>
+<% unless ( $total ) { %>
+ No matching <%= $opt{'name'} %> found.<BR>
+<% } else { %>
+ <%= $total %> total <%= $opt{'name'} %><BR>
+ <% if ( $opt{'count_addl'} ) { %>
+ <% my $n=0; foreach my $count ( @{$opt{'count_addl'}} ) { %>
+ <%= sprintf( $count, $count_arrayref->[++$n] ) %><BR>
+ <% } %>
+ <% } %>
+ <BR><%= $pager %>
+ <%= include( '/elements/table.html' ) %>
+ <TR>
+ <% foreach my $header ( @$header ) { %>
+ <TH><%= $header %></TH>
+ <% } %>
+ </TR>
+ <% foreach my $row ( @$rows ) { %>
+ <TR>
+ <% if ( $opt{'fields'} ) { %>
+ <% my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : ''; %>
+ <% foreach my $field ( @{$opt{'fields'}} ) { %>
+ <% my $a = ''; %>
+ <% if ( $links ) {
+ my $link = shift @$links;
+ $link = &{$link}($row) if ref($link) eq 'CODE';
+ if ( $link ) {
+ my( $url, $method ) = @{$link};
+ if ( ref($method) eq 'CODE' ) {
+ $a = $url. &{$method}($row);
+ } else {
+ $a = $url. $row->$method();
+ }
+ $a = qq(<A HREF="$a">);
+ }
+ }
+ %>
+ <% if ( ref($field) eq 'CODE' ) { %>
+ <TD><%= $a %><%= &{$field}($row) %><%= $a ? '</A>' : '' %></TD>
+ <% } else { %>
+ <TD><%= $a %><%= $row->$field() %><%= $a ? '</A>' : '' %></TD>
+ <% } %>
+ <% } %>
+ <% } else { %>
+ <% foreach ( @$row ) { %>
+ <TD><%= $_ %></TD>
+ <% } %>
+ <% } %>
+ </TR>
+ <% } %>
+
+ </TABLE>
+ <%= $pager %>
+<% } %>
+</BODY>
+</HTML>
+<% } %>
+
diff --git a/httemplate/search/report_cust_credit.html b/httemplate/search/report_cust_credit.html
new file mode 100644
index 0000000..8a0f0ed
--- /dev/null
+++ b/httemplate/search/report_cust_credit.html
@@ -0,0 +1,57 @@
+<HTML>
+ <HEAD>
+ <TITLE>Credit report criteria</TITLE>
+ <LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <H1>Credit report criteria</H1>
+ <FORM ACTION="cust_credit.html" METHOD="post">
+ <INPUT TYPE="hidden" NAME="magic" VALUE="_date">
+ <TABLE>
+ <TR>
+ <TD ALIGN="right">Credits by employee: </TD>
+<%
+ my $sth = dbh->prepare("SELECT DISTINCT otaker FROM cust_credit")
+ or die dbh->errstr;
+ $sth->execute or die $sth->errstr;
+ my @otakers = map { $_->[0] } @{$sth->fetchall_arrayref};
+%>
+ <TD><SELECT NAME="otaker">
+ <OPTION VALUE="">all</OPTION>
+ <% foreach my $otaker ( @otakers ) { %>
+ <OPTION VALUE="<%= $otaker %>"><%= $otaker %></OPTION>
+ <% } %>
+ </SELECT>
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">From: </TD>
+ <TD><INPUT TYPE="text" NAME="beginning" ID="beginning_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="beginning_button" STYLE="cursor: pointer" TITLE="Select date"><BR><i>m/d/y</i></TD>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "beginning_text",
+ ifFormat: "%m/%d/%Y",
+ button: "beginning_button",
+ align: "BR"
+ });
+</SCRIPT>
+ </TR>
+ <TD ALIGN="right">To: </TD>
+ <TD><INPUT TYPE="text" NAME="ending" ID="ending_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="ending_button" STYLE="cursor: pointer" TITLE="Select date"><BR><i>m/d/y</i></TD>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "ending_text",
+ ifFormat: "%m/%d/%Y",
+ button: "ending_button",
+ align: "BR"
+ });
+</SCRIPT>
+ </TR>
+ </TABLE>
+ <BR><INPUT TYPE="submit" VALUE="Get Report">
+ </FORM>
+ </BODY>
+</HTML>
diff --git a/httemplate/search/report_cust_pay.html b/httemplate/search/report_cust_pay.html
new file mode 100644
index 0000000..1b30685
--- /dev/null
+++ b/httemplate/search/report_cust_pay.html
@@ -0,0 +1,54 @@
+<HTML>
+ <HEAD>
+ <TITLE>Payment report criteria</TITLE>
+ <LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <H1>Payment report criteria</H1>
+ <FORM ACTION="cust_pay.cgi" METHOD="post">
+ <INPUT TYPE="hidden" NAME="magic" VALUE="_date">
+ <TABLE>
+ <TR>
+ <TD ALIGN="right">Payments of type: </TD>
+ <TD><SELECT NAME="payby">
+ <OPTION VALUE="">all</OPTION>
+ <OPTION VALUE="CARD">credit card (all)</OPTION>
+ <OPTION VALUE="CARD-VisaMC">credit card (Visa/MasterCard)</OPTION>
+ <OPTION VALUE="CARD-Amex">credit card (American Express)</OPTION>
+ <OPTION VALUE="CARD-Discover">credit card (Discover)</OPTION>
+ <OPTION VALUE="CHEK">electronic check / ACH</OPTION>
+ <OPTION VALUE="BILL">check / cash</OPTION>
+ </SELECT>
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">From: </TD>
+ <TD><INPUT TYPE="text" NAME="beginning" ID="beginning_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="beginning_button" STYLE="cursor: pointer" TITLE="Select date"><BR><i>m/d/y</i></TD>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "beginning_text",
+ ifFormat: "%m/%d/%Y",
+ button: "beginning_button",
+ align: "BR"
+ });
+</SCRIPT>
+ </TR>
+ <TD ALIGN="right">To: </TD>
+ <TD><INPUT TYPE="text" NAME="ending" ID="ending_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="ending_button" STYLE="cursor: pointer" TITLE="Select date"><BR><i>m/d/y</i></TD>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "ending_text",
+ ifFormat: "%m/%d/%Y",
+ button: "ending_button",
+ align: "BR"
+ });
+</SCRIPT>
+ </TR>
+ </TABLE>
+ <BR><INPUT TYPE="submit" VALUE="Get Report">
+ </FORM>
+ </BODY>
+</HTML>
diff --git a/httemplate/search/report_prepaid_income.cgi b/httemplate/search/report_prepaid_income.cgi
new file mode 100644
index 0000000..1677591
--- /dev/null
+++ b/httemplate/search/report_prepaid_income.cgi
@@ -0,0 +1,86 @@
+<!-- mason kludge -->
+<%
+
+ #doesn't yet deal with daily/weekly packages
+
+ #needs to be re-written in sql for efficiency
+
+ my $time = time;
+
+ my $now = $cgi->param('date') && str2time($cgi->param('date')) || $time;
+ $now =~ /^(\d+)$/ or die "unparsable date?";
+ $now = $1;
+
+ my( $total, $total_legacy ) = ( 0, 0 );
+
+ my @cust_bill_pkg =
+ grep { $_->cust_pkg && $_->cust_pkg->part_pkg->freq !~ /^([01]|\d+[dw])$/ }
+ qsearch( 'cust_bill_pkg', {
+ 'recur' => { op=>'!=', value=>0 },
+ 'edate' => { op=>'>', value=>$now },
+ }, );
+
+ my @cust_pkg =
+ grep { $_->part_pkg->recur != 0
+ && $_->part_pkg->freq !~ /^([01]|\d+[dw])$/
+ }
+ qsearch ( 'cust_pkg', {
+ 'bill' => { op=>'>', value=>$now }
+ } );
+
+ foreach my $cust_bill_pkg ( @cust_bill_pkg) {
+ my $period = $cust_bill_pkg->edate - $cust_bill_pkg->sdate;
+
+ my $elapsed = $now - $cust_bill_pkg->sdate;
+ $elapsed = 0 if $elapsed < 0;
+
+ my $remaining = 1 - $elapsed/$period;
+
+ my $unearned = $remaining * $cust_bill_pkg->recur;
+ $total += $unearned;
+
+ }
+
+ foreach my $cust_pkg ( @cust_pkg ) {
+ my $period = $cust_pkg->bill - $cust_pkg->last_bill;
+
+ my $elapsed = $now - $cust_pkg->last_bill;
+ $elapsed = 0 if $elapsed < 0;
+
+ my $remaining = 1 - $elapsed/$period;
+
+ my $unearned = $remaining * $cust_pkg->part_pkg->recur; #!! only works for flat/legacy
+ $total_legacy += $unearned;
+
+ }
+
+ $total = sprintf('%.2f', $total);
+ $total_legacy = sprintf('%.2f', $total_legacy);
+
+%>
+
+<%= header( 'Prepaid Income (Unearned Revenue) Report',
+ menubar( 'Main Menu'=>$p, ) ) %>
+<%= table() %>
+ <TR>
+ <TH>Actual Unearned Revenue</TH>
+ <TH>Legacy Unearned Revenue</TH>
+ </TR>
+ <TR>
+ <TD ALIGN="right">$<%= $total %>
+ <TD ALIGN="right">
+ <%= $now == $time ? "\$$total_legacy" : '<i>N/A</i>'%>
+ </TD>
+ </TR>
+
+</TABLE>
+<BR>
+Actual unearned revenue is the amount of unearned revenue Freeside has
+actually invoiced for packages with longer-than monthly terms.
+<BR><BR>
+Legacy unearned revenue is the amount of unearned revenue represented by
+customer packages. This number may be larger than actual unearned
+revenue if you have imported longer-than monthly customer packages from
+a previous billing system.
+</BODY>
+</HTML>
diff --git a/httemplate/search/report_prepaid_income.html b/httemplate/search/report_prepaid_income.html
new file mode 100644
index 0000000..e8b6ac4
--- /dev/null
+++ b/httemplate/search/report_prepaid_income.html
@@ -0,0 +1,39 @@
+<HTML>
+ <HEAD>
+ <TITLE>Prepaid Income (Unearned Revenue) Report</TITLE>
+ <LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <H1>Prepaid Income (Unearned Revenue) Report</H1>
+ <FORM ACTION="report_prepaid_income.cgi" METHOD="post">
+ <TABLE>
+ <TR>
+ <TD>Prepaid income (unearned revenue) as of </TD>
+ <TD>
+ <INPUT TYPE="text" NAME="date" ID="date_text" VALUE="now">
+ <IMG SRC="../images/calendar.png" ID="date_button" STYLE="cursor: pointer" TITLE="Select date">
+ </TD>
+ </TR>
+ <TR>
+ <TD>
+ </TD>
+ <TD><i>m/d/y</i></TD>
+ </TR>
+ </TABLE>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "date_text",
+ ifFormat: "%m/%d/%Y",
+ button: "date_button",
+ align: "BR"
+ });
+</SCRIPT>
+
+ <INPUT TYPE="submit" VALUE="Generate report">
+ </BODY>
+</HTML>
+ <TABLE>
+
diff --git a/httemplate/search/report_receivables.cgi b/httemplate/search/report_receivables.cgi
new file mode 100755
index 0000000..0e95ad7
--- /dev/null
+++ b/httemplate/search/report_receivables.cgi
@@ -0,0 +1,158 @@
+<!-- mason kludge -->
+<%
+
+ my $charged = <<END;
+ sum( charged
+ - coalesce(
+ ( select sum(amount) from cust_bill_pay
+ where cust_bill.invnum = cust_bill_pay.invnum )
+ ,0
+ )
+ - coalesce(
+ ( select sum(amount) from cust_credit_bill
+ where cust_bill.invnum = cust_credit_bill.invnum )
+ ,0
+ )
+
+ )
+END
+
+ my $owed_cols = <<END;
+ coalesce(
+ ( select $charged from cust_bill
+ where cust_bill._date > extract(epoch from now())-2592000
+ and cust_main.custnum = cust_bill.custnum
+ )
+ ,0
+ ) as owed_0_30,
+
+ coalesce(
+ ( select $charged from cust_bill
+ where cust_bill._date > extract(epoch from now())-5184000
+ and cust_bill._date <= extract(epoch from now())-2592000
+ and cust_main.custnum = cust_bill.custnum
+ )
+ ,0
+ ) as owed_30_60,
+
+ coalesce(
+ ( select $charged from cust_bill
+ where cust_bill._date > extract(epoch from now())-7776000
+ and cust_bill._date <= extract(epoch from now())-5184000
+ and cust_main.custnum = cust_bill.custnum
+ )
+ ,0
+ ) as owed_60_90,
+
+ coalesce(
+ ( select $charged from cust_bill
+ where cust_bill._date <= extract(epoch from now())-7776000
+ and cust_main.custnum = cust_bill.custnum
+ )
+ ,0
+ ) as owed_90_plus,
+
+ coalesce(
+ ( select $charged from cust_bill
+ where cust_main.custnum = cust_bill.custnum
+ )
+ ,0
+ ) as owed_total
+END
+
+ my $recurring = <<END;
+ 0 < ( select freq from part_pkg
+ where cust_pkg.pkgpart = part_pkg.pkgpart )
+END
+
+ my $packages_cols = <<END;
+
+ ( select count(*) from cust_pkg
+ where cust_main.custnum = cust_pkg.custnum
+ and $recurring
+ and ( cancel = 0 or cancel is null )
+ ) as uncancelled_pkgs,
+
+ ( select count(*) from cust_pkg
+ where cust_main.custnum = cust_pkg.custnum
+ and $recurring
+ and ( cancel = 0 or cancel is null )
+ and ( susp = 0 or susp is null )
+ ) as active_pkgs
+
+END
+
+ my $sql = <<END;
+
+select *, $owed_cols, $packages_cols from cust_main
+where 0 <
+ coalesce(
+ ( select $charged from cust_bill
+ where cust_main.custnum = cust_bill.custnum
+ )
+ ,0
+ )
+
+order by coalesce(lower(company), ''), lower(last)
+
+END
+
+ my $total_sql = "select $owed_cols";
+
+ my $sth = dbh->prepare($sql) or die dbh->errstr;
+ $sth->execute or die $sth->errstr;
+
+ my $total_sth = dbh->prepare($total_sql) or die dbh->errstr;
+ $total_sth->execute or die $total_sth->errstr;
+
+%>
+<%= header('Accounts Receivable Aging Summary', menubar( 'Main Menu'=>$p, ) ) %>
+<%= table() %>
+ <TR>
+ <TH>Customer</TH>
+ <TH>Status</TH>
+ <TH>0-30</TH>
+ <TH>30-60</TH>
+ <TH>60-90</TH>
+ <TH>90+</TH>
+ <TH>Total</TH>
+ </TR>
+<% while ( my $row = $sth->fetchrow_hashref() ) {
+ my $status = 'Cancelled';
+ my $statuscol = 'FF0000';
+ if ( $row->{uncancelled_pkgs} ) {
+ $status = 'Suspended';
+ $statuscol = 'FF9900';
+ if ( $row->{active_pkgs} ) {
+ $status = 'Active';
+ $statuscol = '00CC00';
+ }
+ }
+%>
+ <TR>
+ <TD><A HREF="<%= $p %>view/cust_main.cgi?<%= $row->{'custnum'} %>"><%= $row->{'custnum'} %>:
+ <%= $row->{'company'} ? $row->{'company'}. ' (' : '' %><%= $row->{'last'}. ', '. $row->{'first'} %><%= $row->{'company'} ? ')' : '' %></A>
+ </TD>
+ <TD><B><FONT SIZE=-1 COLOR="#<%= $statuscol %>"><%= $status %></FONT></B></TD>
+ <TD ALIGN="right">$<%= sprintf("%.2f", $row->{'owed_0_30'} ) %></TD>
+ <TD ALIGN="right">$<%= sprintf("%.2f", $row->{'owed_30_60'} ) %></TD>
+ <TD ALIGN="right">$<%= sprintf("%.2f", $row->{'owed_60_90'} ) %></TD>
+ <TD ALIGN="right">$<%= sprintf("%.2f", $row->{'owed_90_plus'} ) %></TD>
+ <TD ALIGN="right"><B>$<%= sprintf("%.2f", $row->{'owed_total'} ) %></B></TD>
+ </TR>
+<% } %>
+<% my $row = $total_sth->fetchrow_hashref(); %>
+ <TR>
+ <TD COLSPAN=6>&nbsp;</TD>
+ </TR>
+ <TR>
+ <TD COLSPAN=2><I>Total</I></TD>
+ <TD ALIGN="right"><I>$<%= sprintf("%.2f", $row->{'owed_0_30'} ) %></TD>
+ <TD ALIGN="right"><I>$<%= sprintf("%.2f", $row->{'owed_30_60'} ) %></TD>
+ <TD ALIGN="right"><I>$<%= sprintf("%.2f", $row->{'owed_60_90'} ) %></TD>
+ <TD ALIGN="right"><I>$<%= sprintf("%.2f", $row->{'owed_90_plus'} ) %></TD>
+ <TD ALIGN="right"><I><B>$<%= sprintf("%.2f", $row->{'owed_total'} ) %></B></I></TD>
+ </TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi
new file mode 100755
index 0000000..a98d36f
--- /dev/null
+++ b/httemplate/search/report_tax.cgi
@@ -0,0 +1,168 @@
+<!-- mason kludge -->
+<%
+
+my $user = getotaker;
+
+$cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/;
+my $pbeginning = $1;
+my $beginning = $1 ? str2time($1) : 0;
+
+$cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/;
+my $pending = $1;
+my $ending = ( $1 ? str2time($1) : 4294880896 ) + 86399;
+
+my($total, $exempt, $taxable, $tax) = ( 0, 0, 0, 0 );
+my $out = 'Out of taxable region(s)';
+my %regions;
+foreach my $r (
+ qsearch('cust_main_county', {}, '',
+ "WHERE 0 < ( SELECT COUNT(*) FROM cust_main
+ WHERE ( cust_main.county = cust_main_county.county
+ OR cust_main_county.county = ''
+ OR cust_main_county.county IS NULL )
+ AND ( cust_main.state = cust_main_county.state
+ OR cust_main_county.state = ''
+ OR cust_main_county.state IS NULL )
+ AND ( cust_main.country = cust_main_county.country )
+ LIMIT 1
+ )"
+ )
+) {
+ #warn $r->county. ' '. $r->state. ' '. $r->country. "\n";
+ my $label;
+ if ( $r->tax == 0 ) {
+ $label = $out;
+ } elsif ( $r->taxname ) {
+ $label = $r->taxname;
+ } else {
+ $label = $r->country;
+ $label = $r->state.", $label" if $r->state;
+ $label = $r->county." county, $label" if $r->county;
+ }
+
+ my $fromwhere = "
+ FROM cust_bill_pkg
+ JOIN cust_bill USING ( invnum )
+ JOIN cust_main USING ( custnum )
+ JOIN cust_pkg USING ( pkgnum )
+ JOIN part_pkg USING ( pkgpart )
+ WHERE _date >= $beginning AND _date <= $ending
+ AND ( county = ? OR ? = '' )
+ AND ( state = ? OR ? = '' )
+ AND ( country = ? )
+ AND ( taxclass = ? OR ? = '' )
+ AND payby != 'COMP'
+ ";
+ my $nottax = 'pkgnum != 0';
+
+ my $a = scalar_sql($r,
+ "SELECT SUM(cust_bill_pkg.setup+cust_bill_pkg.recur) $fromwhere AND $nottax"
+ );
+ $total += $a;
+ $regions{$label}->{'total'} += $a;
+
+ foreach my $e ( grep { $r->get($_.'tax') =~ /^Y/i }
+ qw( cust_bill_pkg.setup cust_bill_pkg.recur ) ) {
+ my $x = scalar_sql($r,
+ "SELECT SUM($e) $fromwhere AND $nottax"
+ );
+ $exempt += $x;
+ $regions{$label}->{'exempt'} += $x;
+ }
+
+ foreach my $e ( grep { $r->get($_.'tax') !~ /^Y/i }
+ qw( cust_bill_pkg.setup cust_bill_pkg.recur ) ) {
+ my $t = scalar_sql($r,
+ "SELECT SUM($e) $fromwhere AND $nottax AND ( tax != 'Y' OR tax IS NULL )"
+ );
+ $taxable += $t;
+ $regions{$label}->{'taxable'} += $t;
+
+ my $x = scalar_sql($r,
+ "SELECT SUM($e) $fromwhere AND $nottax AND tax = 'Y'"
+ );
+ $exempt += $x;
+ $regions{$label}->{'exempt'} += $x;
+ }
+
+ if ( defined($regions{$label}->{'rate'})
+ && $regions{$label}->{'rate'} != $r->tax.'%' ) {
+ $regions{$label}->{'rate'} = 'variable';
+ } else {
+ $regions{$label}->{'rate'} = $r->tax.'%';
+ }
+
+ #match itemdesc if necessary!
+ my $named_tax = $r->taxname ? 'AND itemdesc = '. dbh->quote($r->taxname) : '';
+ my $x = scalar_sql($r,
+ "SELECT SUM(cust_bill_pkg.setup+cust_bill_pkg.recur) $fromwhere ".
+ "AND pkgnum = 0 $named_tax",
+ );
+ $tax += $x;
+ $regions{$label}->{'tax'} += $x;
+
+ $regions{$label}->{'label'} = $label;
+
+}
+
+#ordering
+my @regions = map $regions{$_},
+ sort { ( ($a eq $out) cmp ($b eq $out) ) || ($b cmp $a) }
+ keys %regions;
+
+push @regions, {
+ 'label' => 'Total',
+ 'total' => $total,
+ 'exempt' => $exempt,
+ 'taxable' => $taxable,
+ 'rate' => '',
+ 'tax' => $tax,
+};
+
+#--
+
+#false laziness w/FS::Report::Table::Monthly (sub should probably be moved up
+#to FS::Report or FS::Record or who the fuck knows where)
+sub scalar_sql {
+ my( $r, $sql ) = @_;
+ #warn "$sql\n";
+ my $sth = dbh->prepare($sql) or die dbh->errstr;
+ $sth->execute( map $r->$_(),
+ qw( county county state state country taxclass taxclass ) )
+ or die "Unexpected error executing statement $sql: ". $sth->errstr;
+ $sth->fetchrow_arrayref->[0] || 0;
+}
+
+%>
+
+<%= header( "Sales Tax Report - $pbeginning through ".($pending||'now'),
+ menubar( 'Main Menu'=>$p, ) ) %>
+<%= table() %>
+ <TR>
+ <TH ROWSPAN=2></TH>
+ <TH COLSPAN=3>Sales</TH>
+ <TH ROWSPAN=2>Rate</TH>
+ <TH ROWSPAN=2>Tax</TH>
+ </TR>
+ <TR>
+ <TH>Total</TH>
+ <TH>Non-taxable</TH>
+ <TH>Taxable</TH>
+ </TR>
+ <% foreach my $region ( @regions ) { %>
+ <TR>
+ <TD><%= $region->{'label'} %></TD>
+ <TD ALIGN="right">$<%= sprintf('%.2f', $region->{'total'} ) %></TD>
+ <TD ALIGN="right">$<%= sprintf('%.2f', $region->{'exempt'} ) %></TD>
+ <TD ALIGN="right">$<%= sprintf('%.2f', $region->{'taxable'} ) %></TD>
+ <TD ALIGN="right"><%= $region->{'rate'} %></TD>
+ <TD ALIGN="right">$<%= sprintf('%.2f', $region->{'tax'} ) %></TD>
+ </TR>
+ <% } %>
+
+</TABLE>
+
+</BODY>
+</HTML>
+
+
diff --git a/httemplate/search/report_tax.html b/httemplate/search/report_tax.html
new file mode 100755
index 0000000..7bc35e3
--- /dev/null
+++ b/httemplate/search/report_tax.html
@@ -0,0 +1,43 @@
+<HTML>
+ <HEAD>
+ <TITLE>Tax Report Criteria</TITLE>
+ <LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT> </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <H1>Tax Report Criteria</H1>
+ <FORM ACTION="report_tax.cgi" METHOD="post">
+ Return <B>tax report</B> for period:
+ <TABLE>
+ <TR>
+ <TD ALIGN="right">From: </TD>
+ <TD><INPUT TYPE="text" NAME="beginning" ID="beginning_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="beginning_button" STYLE="cursor: pointer" TITLE="Select date"><BR><i>m/d/y</i></TD>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "beginning_text",
+ ifFormat: "%m/%d/%Y",
+ button: "beginning_button",
+ align: "BR"
+ });
+</SCRIPT>
+ </TR>
+ <TD ALIGN="right">To: </TD>
+ <TD><INPUT TYPE="text" NAME="ending" ID="ending_text" VALUE="" SIZE=11 MAXLENGTH=10> <IMG SRC="../images/calendar.png" ID="ending_button" STYLE="cursor: pointer" TITLE="Select date"><BR><i>m/d/y</i></TD>
+<SCRIPT TYPE="text/javascript">
+ Calendar.setup({
+ inputField: "ending_text",
+ ifFormat: "%m/%d/%Y",
+ button: "ending_button",
+ align: "BR"
+ });
+</SCRIPT>
+ </TR>
+ </TABLE>
+
+ <BR><INPUT TYPE="submit" VALUE="Get Report">
+
+ </FORM>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/sql.html b/httemplate/search/sql.html
new file mode 100644
index 0000000..b28c045
--- /dev/null
+++ b/httemplate/search/sql.html
@@ -0,0 +1,7 @@
+<%= include( 'elements/search.html',
+ 'title' => 'Query Results',
+ 'name' => 'rows',
+ 'query' => 'SELECT '. ( $cgi->param('sql')
+ || eidiot('Empty query') ),
+ )
+%>
diff --git a/httemplate/search/svc_acct.cgi b/httemplate/search/svc_acct.cgi
new file mode 100755
index 0000000..1e4a03d
--- /dev/null
+++ b/httemplate/search/svc_acct.cgi
@@ -0,0 +1,294 @@
+<%
+
+my $conf = new FS::Conf;
+my $maxrecords = $conf->config('maxsearchrecordsperpage');
+
+my $orderby = ''; #removeme
+
+my $limit = '';
+$limit .= "LIMIT $maxrecords" if $maxrecords;
+
+my $offset = $cgi->param('offset') || 0;
+$limit .= " OFFSET $offset" if $offset;
+
+my $total;
+
+my($query)=$cgi->keywords;
+$query ||= ''; #to avoid use of unitialized value errors
+
+my $unlinked = '';
+if ( $query =~ /^UN_(.*)$/ ) {
+ $query = $1;
+ my $empty = driver_name eq 'Pg' ? qq('') : qq("");
+ if ( driver_name eq 'mysql' ) {
+ $unlinked = "LEFT JOIN cust_svc ON cust_svc.svcnum = svc_acct.svcnum
+ WHERE cust_svc.pkgnum IS NULL
+ OR cust_svc.pkgnum = 0
+ OR cust_svc.pkgnum = $empty";
+ } else {
+ $unlinked = "
+ WHERE 0 <
+ ( SELECT count(*) FROM cust_svc
+ WHERE cust_svc.svcnum = svc_acct.svcnum
+ AND ( pkgnum IS NULL OR pkgnum = 0 )
+ )
+ ";
+ }
+}
+
+my $tblname = driver_name eq 'mysql' ? 'svc_acct.' : '';
+my(@svc_acct, $sortby);
+if ( $query eq 'svcnum' ) {
+ $sortby=\*svcnum_sort;
+ $orderby = "ORDER BY ${tblname}svcnum";
+} elsif ( $query eq 'username' ) {
+ $sortby=\*username_sort;
+ $orderby = "ORDER BY ${tblname}username";
+} elsif ( $query eq 'uid' ) {
+ $sortby=\*uid_sort;
+ $orderby = ( $unlinked ? ' AND' : ' WHERE' ).
+ " ${tblname}uid IS NOT NULL ORDER BY ${tblname}uid";
+} elsif ( $cgi->param('popnum') =~ /^(\d+)$/ ) {
+ $unlinked .= ( $unlinked ? 'AND' : 'WHERE' ).
+ " popnum = $1";
+ $sortby=\*username_sort;
+ $orderby = "ORDER BY ${tblname}username";
+} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
+ $unlinked .= ( $unlinked ? ' AND' : ' WHERE' ).
+ " $1 = ( SELECT svcpart FROM cust_svc ".
+ " WHERE cust_svc.svcnum = svc_acct.svcnum ) ";
+ $sortby=\*uid_sort;
+ #$sortby=\*svcnum_sort;
+} else {
+ $sortby=\*uid_sort;
+ @svc_acct = @{&usernamesearch};
+}
+
+
+if ( $query eq 'svcnum'
+ || $query eq 'username'
+ || $query eq 'uid'
+ || $cgi->param('popnum') =~ /^(\d+)$/
+ || $cgi->param('svcpart') =~ /^(\d+)$/
+ ) {
+
+ my $statement = "SELECT COUNT(*) FROM svc_acct $unlinked";
+ my $sth = dbh->prepare($statement)
+ or die dbh->errstr. " doing $statement";
+ $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
+
+ $total = $sth->fetchrow_arrayref->[0];
+
+ @svc_acct = qsearch('svc_acct', {}, '', "$unlinked $orderby $limit");
+
+}
+
+if ( scalar(@svc_acct) == 1 ) {
+ my($svcnum)=$svc_acct[0]->svcnum;
+ print $cgi->redirect(popurl(2). "view/svc_acct.cgi?$svcnum"); #redirect
+ #exit;
+} elsif ( scalar(@svc_acct) == 0 ) { #error
+%>
+<!-- mason kludge -->
+<%
+ idiot("Account not found");
+} else {
+%>
+<!-- mason kludge -->
+<%
+ $total ||= scalar(@svc_acct);
+
+ #begin pager
+ my $pager = '';
+ if ( $total != scalar(@svc_acct) && $maxrecords ) {
+ unless ( $offset == 0 ) {
+ $cgi->param('offset', $offset - $maxrecords);
+ $pager .= '<A HREF="'. $cgi->self_url.
+ '"><B><FONT SIZE="+1">Previous</FONT></B></A> ';
+ }
+ my $poff;
+ my $page;
+ for ( $poff = 0; $poff < $total; $poff += $maxrecords ) {
+ $page++;
+ if ( $offset == $poff ) {
+ $pager .= qq!<FONT SIZE="+2">$page</FONT> !;
+ } else {
+ $cgi->param('offset', $poff);
+ $pager .= qq!<A HREF="!. $cgi->self_url. qq!">$page</A> !;
+ }
+ }
+ unless ( $offset + $maxrecords > $total ) {
+ $cgi->param('offset', $offset + $maxrecords);
+ $pager .= '<A HREF="'. $cgi->self_url.
+ '"><B><FONT SIZE="+1">Next</FONT></B></A> ';
+ }
+ }
+ #end pager
+
+ print header("Account Search Results",menubar('Main Menu'=>popurl(2))),
+ "$total matching accounts found<BR><BR>$pager",
+ &table(), <<END;
+ <TR>
+ <TH><FONT SIZE=-1>#</FONT></TH>
+ <TH><FONT SIZE=-1>Username</FONT></TH>
+ <TH><FONT SIZE=-1>Domain</FONT></TH>
+ <TH><FONT SIZE=-1>UID</FONT></TH>
+ <TH><FONT SIZE=-1>Service</FONT></TH>
+ <TH><FONT SIZE=-1>Cust#</FONT></TH>
+ <TH><FONT SIZE=-1>(bill) name</FONT></TH>
+ <TH><FONT SIZE=-1>company</FONT></TH>
+END
+ if ( defined dbdef->table('cust_main')->column('ship_last') ) {
+ print <<END;
+ <TH><FONT SIZE=-1>(service) name</FONT></TH>
+ <TH><FONT SIZE=-1>company</FONT></TH>
+END
+ }
+ print "</TR>";
+
+ my(%saw,$svc_acct);
+ my $p = popurl(2);
+ foreach $svc_acct (
+ sort $sortby grep(!$saw{$_->svcnum}++, @svc_acct)
+ ) {
+ my $cust_svc = qsearchs('cust_svc', { 'svcnum' => $svc_acct->svcnum })
+ or die "No cust_svc record for svcnum ". $svc_acct->svcnum;
+ my $part_svc = qsearchs('part_svc', { 'svcpart' => $cust_svc->svcpart })
+ or die "No part_svc record for svcpart ". $cust_svc->svcpart;
+
+ my $domain;
+ my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $svc_acct->domsvc });
+ if ( $svc_domain ) {
+ $domain = "<A HREF=\"${p}view/svc_domain.cgi?". $svc_domain->svcnum.
+ "\">". $svc_domain->domain. "</A>";
+ } else {
+ die "No svc_domain.svcnum record for svc_acct.domsvc: ".
+ $svc_acct->domsvc;
+ }
+ my($cust_pkg,$cust_main);
+ if ( $cust_svc->pkgnum ) {
+ $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_svc->pkgnum })
+ or die "No cust_pkg record for pkgnum ". $cust_svc->pkgnum;
+ $cust_main = qsearchs('cust_main', { 'custnum' => $cust_pkg->custnum })
+ or die "No cust_main record for custnum ". $cust_pkg->custnum;
+ }
+ my($svcnum, $username, $uid, $svc, $custnum, $last, $first, $company) = (
+ $svc_acct->svcnum,
+ $svc_acct->getfield('username'),
+ $svc_acct->getfield('uid'),
+ $part_svc->svc,
+ $cust_svc->pkgnum ? $cust_main->custnum : '',
+ $cust_svc->pkgnum ? $cust_main->getfield('last') : '',
+ $cust_svc->pkgnum ? $cust_main->getfield('first') : '',
+ $cust_svc->pkgnum ? $cust_main->company : '',
+ );
+ my($pcustnum) = $custnum
+ ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\"><FONT SIZE=-1>$custnum</FONT></A>"
+ : "<I>(unlinked)</I>"
+ ;
+ my $pname = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$last, $first</A>" : '';
+ my $pcompany = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$company</A>" : '';
+ my($pship_name, $pship_company);
+ if ( defined dbdef->table('cust_main')->column('ship_last') ) {
+ my($ship_last, $ship_first, $ship_company) = (
+ $cust_svc->pkgnum ? ( $cust_main->ship_last || $last ) : '',
+ $cust_svc->pkgnum ? ( $cust_main->ship_last
+ ? $cust_main->ship_first
+ : $first
+ ) : '',
+ $cust_svc->pkgnum ? ( $cust_main->ship_last
+ ? $cust_main->ship_company
+ : $company
+ ) : '',
+ );
+ $pship_name = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$ship_last, $ship_first</A>" : '';
+ $pship_company = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$ship_company</A>" : '';
+ }
+ print <<END;
+ <TR>
+ <TD><A HREF="${p}view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$svcnum</FONT></A></TD>
+ <TD><A HREF="${p}view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$username</FONT></A></TD>
+ <TD><FONT SIZE=-1>$domain</FONT></TD>
+ <TD><A HREF="${p}view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$uid</FONT></A></TD>
+ <TD><FONT SIZE=-1>$svc</FONT></TH>
+ <TD><FONT SIZE=-1>$pcustnum</FONT></TH>
+ <TD><FONT SIZE=-1>$pname<FONT></TH>
+ <TD><FONT SIZE=-1>$pcompany</FONT></TH>
+END
+ if ( defined dbdef->table('cust_main')->column('ship_last') ) {
+ print <<END;
+ <TD><FONT SIZE=-1>$pship_name<FONT></TH>
+ <TD><FONT SIZE=-1>$pship_company</FONT></TH>
+END
+ }
+ print "</TR>";
+
+ }
+
+ print "</TABLE>$pager<BR>".
+ '</BODY></HTML>';
+
+}
+
+sub svcnum_sort {
+ $a->getfield('svcnum') <=> $b->getfield('svcnum');
+}
+
+sub username_sort {
+ $a->getfield('username') cmp $b->getfield('username');
+}
+
+sub uid_sort {
+ $a->getfield('uid') <=> $b->getfield('uid');
+}
+
+sub usernamesearch {
+
+ my @svc_acct;
+
+ my %username_type;
+ foreach ( $cgi->param('username_type') ) {
+ $username_type{$_}++;
+ }
+
+ $cgi->param('username') =~ /^([\w\-\.\&]+)$/; #untaint username_text
+ my $username = $1;
+
+ if ( $username_type{'Exact'} || $username_type{'Fuzzy'} ) {
+ push @svc_acct, qsearch( 'svc_acct',
+ { 'username' => { 'op' => 'ILIKE',
+ 'value' => $username } } );
+ }
+
+ if ( $username_type{'Substring'} || $username_type{'All'} ) {
+ push @svc_acct, qsearch( 'svc_acct',
+ { 'username' => { 'op' => 'ILIKE',
+ 'value' => "%$username%" } } );
+ }
+
+ if ( $username_type{'Fuzzy'} || $username_type{'All'} ) {
+ &FS::svc_acct::check_and_rebuild_fuzzyfiles;
+ my $all_username = &FS::svc_acct::all_username;
+
+ my %username;
+ if ( $username_type{'Fuzzy'} || $username_type{'All'} ) {
+ foreach ( amatch($username, [ qw(i) ], @$all_username) ) {
+ $username{$_}++;
+ }
+ }
+
+ #if ($username_type{'Sound-alike'}) {
+ #}
+
+ foreach ( keys %username ) {
+ push @svc_acct, qsearch('svc_acct',{'username'=>$_});
+ }
+
+ }
+
+ #[ qsearch('svc_acct',{'username'=>$username}) ];
+ \@svc_acct;
+
+}
+
+%>
diff --git a/httemplate/search/svc_acct.html b/httemplate/search/svc_acct.html
new file mode 100755
index 0000000..7423605
--- /dev/null
+++ b/httemplate/search/svc_acct.html
@@ -0,0 +1,19 @@
+<HTML>
+ <HEAD>
+ <TITLE>Account Search</TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <FONT SIZE=7>
+ Account Search
+ </FONT>
+ <BR><BR>
+ <FORM ACTION="svc_acct.cgi" METHOD="post">
+ Search for <B>username</B>:
+ <INPUT TYPE="text" NAME="username">
+
+ <P><INPUT TYPE="submit" VALUE="Search">
+
+ </FORM>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/svc_domain.cgi b/httemplate/search/svc_domain.cgi
new file mode 100755
index 0000000..948b1d9
--- /dev/null
+++ b/httemplate/search/svc_domain.cgi
@@ -0,0 +1,161 @@
+<%
+
+my $conf = new FS::Conf;
+
+my($query)=$cgi->keywords;
+$query ||= ''; #to avoid use of unitialized value errors
+my(@svc_domain,$sortby);
+if ( $query eq 'svcnum' ) {
+ $sortby=\*svcnum_sort;
+ @svc_domain=qsearch('svc_domain',{});
+} elsif ( $query eq 'domain' ) {
+ $sortby=\*domain_sort;
+ @svc_domain=qsearch('svc_domain',{});
+} elsif ( $query eq 'UN_svcnum' ) {
+ $sortby=\*svcnum_sort;
+ @svc_domain = grep qsearchs('cust_svc',{
+ 'svcnum' => $_->svcnum,
+ 'pkgnum' => '',
+ }), qsearch('svc_domain',{});
+} elsif ( $query eq 'UN_domain' ) {
+ $sortby=\*domain_sort;
+ @svc_domain = grep qsearchs('cust_svc',{
+ 'svcnum' => $_->svcnum,
+ 'pkgnum' => '',
+ }), qsearch('svc_domain',{});
+} elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
+ @svc_domain =
+ qsearch( 'svc_domain', {}, '',
+ " WHERE $1 = ( SELECT svcpart FROM cust_svc ".
+ " WHERE cust_svc.svcnum = svc_domain.svcnum ) "
+ );
+ $sortby=\*svcnum_sort;
+} else {
+ $cgi->param('domain') =~ /^([\w\-\.]+)$/;
+ my($domain)=$1;
+ #push @svc_domain, qsearchs('svc_domain',{'domain'=>$domain});
+ @svc_domain = qsearchs('svc_domain',{'domain'=>$domain});
+}
+
+if ( scalar(@svc_domain) == 1 ) {
+ print $cgi->redirect(popurl(2). "view/svc_domain.cgi?". $svc_domain[0]->svcnum);
+ #exit;
+} elsif ( scalar(@svc_domain) == 0 ) {
+%>
+<!-- mason kludge -->
+<%
+ eidiot "No matching domains found!\n";
+} else {
+%>
+<!-- mason kludge -->
+<%
+ my($total)=scalar(@svc_domain);
+ print header("Domain Search Results",''), <<END;
+
+ $total matching domains found
+ <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
+ <TR>
+ <TH>Service #</TH>
+ <TH>Domain</TH>
+<!-- <TH>Mail to<BR><FONT SIZE=-1>(click to view account)</FONT></TH>
+ <TH>Forwards to<BR><FONT SIZE=-1>(click to view account)</FONT></TH>
+-->
+ </TR>
+END
+
+# my(%saw); # if we've multiple domains with the same
+ # svcnum, then we've a corrupt database
+
+ foreach my $svc_domain (
+# sort $sortby grep(!$saw{$_->svcnum}++, @svc_domain)
+ sort $sortby (@svc_domain)
+ ) {
+ my($svcnum,$domain)=(
+ $svc_domain->svcnum,
+ $svc_domain->domain,
+ );
+
+ #don't display all accounts here
+ my $rowspan = 1;
+
+ #my @svc_acct=qsearch('svc_acct',{'domsvc' => $svcnum});
+ #my $rowspan = 0;
+ #
+ #my $n1 = '';
+ #my($svc_acct, @rows);
+ #foreach $svc_acct (
+ # sort {$b->getfield('username') cmp $a->getfield('username')} (@svc_acct)
+ #) {
+ #
+ # my (@forwards) = ();
+ #
+ # my($svcnum,$username)=(
+ # $svc_acct->svcnum,
+ # $svc_acct->username,
+ # );
+ #
+ # my @svc_forward = qsearch( 'svc_forward', { 'srcsvc' => $svcnum } );
+ # my $svc_forward;
+ # foreach $svc_forward (@svc_forward) {
+ # my($dstsvc,$dst) = (
+ # $svc_forward->dstsvc,
+ # $svc_forward->dst,
+ # );
+ # if ($dstsvc) {
+ # my $dst_svc_acct=qsearchs( 'svc_acct', { 'svcnum' => $dstsvc } );
+ # my $destination=$dst_svc_acct->email;
+ # push @forwards, qq!<TD><A HREF="!, popurl(2),
+ # qq!view/svc_acct.cgi?$dstsvc">$destination</A>!,
+ # qq!</TD></TR>!
+ # ;
+ # }else{
+ # push @forwards, qq!<TD>$dst</TD></TR>!
+ # ;
+ # }
+ # }
+ #
+ # push @rows, qq!$n1<TD ROWSPAN=!, (scalar(@svc_forward) || 1),
+ # qq!><A HREF="!. popurl(2). qq!view/svc_acct.cgi?$svcnum">!,
+ # #print '', ( ($domuser eq '*') ? "<I>(anything)</I>" : $domuser );
+ # ( ($username eq '*') ? "<I>(anything)</I>" : $username ),
+ # qq!\@$domain</A> </TD>!,
+ # ;
+ #
+ # push @rows, @forwards;
+ #
+ # $rowspan += (scalar(@svc_forward) || 1);
+ # $n1 = "</TR><TR>";
+ #}
+ ##end of false laziness
+ #
+ #
+
+ print <<END;
+ <TR>
+ <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_domain.cgi?$svcnum">$svcnum</A></TD>
+ <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_domain.cgi?$svcnum">$domain</A></TD>
+END
+
+ #print @rows;
+ print "</TR>";
+
+ }
+
+ print <<END;
+ </TABLE>
+ </BODY>
+</HTML>
+END
+
+}
+
+sub svcnum_sort {
+ $a->getfield('svcnum') <=> $b->getfield('svcnum');
+}
+
+sub domain_sort {
+ $a->getfield('domain') cmp $b->getfield('domain');
+}
+
+
+%>
diff --git a/httemplate/search/svc_domain.html b/httemplate/search/svc_domain.html
new file mode 100755
index 0000000..94bb9a6
--- /dev/null
+++ b/httemplate/search/svc_domain.html
@@ -0,0 +1,19 @@
+<HTML>
+ <HEAD>
+ <TITLE>Domain Search</TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ <FONT SIZE=7>
+ Domain Search
+ </FONT>
+ <BR><BR>
+ <FORM ACTION="svc_domain.cgi" METHOD="post">
+ Search for <B>domain</B>:
+ <INPUT TYPE="text" NAME="domain">
+
+ <P><INPUT TYPE="submit" VALUE="Search">
+
+ </FORM>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/search/svc_forward.cgi b/httemplate/search/svc_forward.cgi
new file mode 100755
index 0000000..10094bc
--- /dev/null
+++ b/httemplate/search/svc_forward.cgi
@@ -0,0 +1,79 @@
+<%
+
+my $conf = new FS::Conf;
+
+my($query)=$cgi->keywords;
+$query ||= ''; #to avoid use of unitialized value errors
+my(@svc_forward,$sortby);
+if ( $query eq 'svcnum' ) {
+ $sortby=\*svcnum_sort;
+ @svc_forward=qsearch('svc_forward',{});
+} else {
+ eidiot('unimplemented');
+}
+
+if ( scalar(@svc_forward) == 1 ) {
+ print $cgi->redirect(popurl(2). "view/svc_forward.cgi?". $svc_forward[0]->svcnum);
+ #exit;
+} elsif ( scalar(@svc_forward) == 0 ) {
+%>
+<!-- mason kludge -->
+<%
+ eidiot "No matching forwards found!\n";
+} else {
+%>
+<!-- mason kludge -->
+<%
+ my $total = scalar(@svc_forward);
+ print header("Mail forward Search Results",''), <<END;
+
+ $total matching mail forwards found
+ <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
+ <TR>
+ <TH>Service #<BR><FONT SIZE=-1>(click to view forward)</FONT></TH>
+ <TH>Mail to<BR><FONT SIZE=-1>(click to view account)</FONT></TH>
+ <TH>Forwards to<BR><FONT SIZE=-1>(click to view account)</FONT></TH>
+ </TR>
+END
+
+ foreach my $svc_forward (
+ sort $sortby (@svc_forward)
+ ) {
+ my $svcnum = $svc_forward->svcnum;
+
+ my $src = $svc_forward->src;
+ $src = "<I>(anything)</I>$src" if $src =~ /^@/;
+ if ( $svc_forward->srcsvc_acct ) {
+ $src = qq!<A HREF="${p}view/svc_acct.cgi?!. $svc_forward->srcsvc. '">'.
+ $svc_forward->srcsvc_acct->email. '</A>';
+ }
+
+ my $dst = $svc_forward->dst;
+ if ( $svc_forward->dstsvc_acct ) {
+ $dst = qq!<A HREF="${p}view/svc_acct.cgi?!. $svc_forward->dstsvc. '">'.
+ $svc_forward->dstsvc_acct->email. '</A>';
+ }
+
+ print <<END;
+ <TR>
+ <TD><A HREF="${p}view/svc_forward.cgi?$svcnum">$svcnum</A></TD>
+ <TD>$src</TD>
+ <TD>$dst</TD>
+ </TR>
+END
+
+ }
+
+ print <<END;
+ </TABLE>
+ </BODY>
+</HTML>
+END
+
+}
+
+sub svcnum_sort {
+ $a->getfield('svcnum') <=> $b->getfield('svcnum');
+}
+
+%>
diff --git a/httemplate/search/svc_www.cgi b/httemplate/search/svc_www.cgi
new file mode 100755
index 0000000..1f05c23
--- /dev/null
+++ b/httemplate/search/svc_www.cgi
@@ -0,0 +1,42 @@
+<%
+
+#my $conf = new FS::Conf;
+
+my($query)=$cgi->keywords;
+$query ||= ''; #to avoid use of unitialized value errors
+my(@svc_www, $orderby);
+if ( $query eq 'svcnum' ) {
+ $orderby = 'ORDER BY svcnum';
+} else {
+ eidiot('unimplemented');
+}
+
+my $count_query = 'SELECT COUNT(*) FROM svc_www';
+my $sql_query = {
+ 'table' => 'svc_www',
+ 'hashref' => {},
+ 'extra_sql' => $orderby,
+};
+
+my $link = [ "${p}view/svc_www.cgi?", 'svcnum', ];
+#my $dlink = [ "${p}view/svc_www.cgi?", 'svcnum', ];
+my $ulink = [ "${p}view/svc_acct.cgi?", 'usersvc', ];
+
+
+%>
+<%= include( 'elements/search.html',
+ 'title' => 'Virtual Host Search Results',
+ 'name' => 'virtual hosts',
+ 'query' => $sql_query,
+ 'count_query' => $count_query,
+ 'header' => [ '#', 'Zone', 'User', ],
+ 'fields' => [ 'svcnum',
+ sub { $_[0]->domain_record->zone },
+ sub { $_[0]->svc_acct->email },
+ ],
+ 'links' => [ $link,
+ '',
+ $ulink,
+ ],
+ )
+%>
diff --git a/httemplate/view/cust_bill-pdf.cgi b/httemplate/view/cust_bill-pdf.cgi
new file mode 100755
index 0000000..2a86c32
--- /dev/null
+++ b/httemplate/view/cust_bill-pdf.cgi
@@ -0,0 +1,17 @@
+<%
+
+#untaint invnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)(.pdf)?$/;
+my $invnum = $1;
+
+my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
+die "Invoice #$invnum not found!" unless $cust_bill;
+
+my $pdf = $cust_bill->print_pdf;
+
+http_header('Content-Type' => 'application/pdf' );
+http_header('Content-Length' => length($pdf) );
+http_header('Cache-control' => 'max-age=60' );
+%>
+<%= $pdf %>
diff --git a/httemplate/view/cust_bill-ps.cgi b/httemplate/view/cust_bill-ps.cgi
new file mode 100755
index 0000000..03340a1
--- /dev/null
+++ b/httemplate/view/cust_bill-ps.cgi
@@ -0,0 +1,13 @@
+<%
+
+#untaint invnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $invnum = $1;
+
+my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
+die "Invoice #$invnum not found!" unless $cust_bill;
+
+http_header('Content-Type' => 'application/postscript' );
+%>
+<%= $cust_bill->print_ps %>
diff --git a/httemplate/view/cust_bill.cgi b/httemplate/view/cust_bill.cgi
new file mode 100755
index 0000000..7906af6
--- /dev/null
+++ b/httemplate/view/cust_bill.cgi
@@ -0,0 +1,61 @@
+<!-- mason kludge -->
+<%
+
+#untaint invnum
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $invnum = $1;
+
+my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
+die "Invoice #$invnum not found!" unless $cust_bill;
+my $custnum = $cust_bill->getfield('custnum');
+
+#my $printed = $cust_bill->printed;
+
+print header('Invoice View', menubar(
+ "Main Menu" => $p,
+ "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+));
+
+print qq!<A HREF="${p}edit/cust_pay.cgi?$invnum">Enter payments (check/cash) against this invoice</A> | !
+ if $cust_bill->owed > 0;
+
+print qq!<A HREF="${p}misc/print-invoice.cgi?$invnum">Reprint this invoice</A>!;
+if ( grep { $_ ne 'POST' } $cust_bill->cust_main->invoicing_list ) {
+ print qq! | <A HREF="${p}misc/email-invoice.cgi?$invnum">!.
+ qq!Re-email this invoice</A>!;
+}
+
+print '<BR><BR>';
+
+my $conf = new FS::Conf;
+if ( $conf->exists('invoice_latex') ) {
+ print menubar(
+ 'View typeset invoice' => "${p}view/cust_bill-pdf.cgi?$invnum.pdf",
+ ), '<BR><BR>';
+}
+
+#false laziness with search/cust_bill_event.cgi
+
+print table(). '<TR><TH>Event</TH><TH>Date</TH><TH>Status</TH></TR>';
+foreach my $cust_bill_event (
+ sort { $a->_date <=> $b->_date } $cust_bill->cust_bill_event
+) {
+ my $status = $cust_bill_event->status;
+ $status .= ': '. $cust_bill_event->statustext if $cust_bill_event->statustext;
+ print '<TR><TD>'. $cust_bill_event->part_bill_event->event. '</TD><TD>'.
+ time2str("%a %b %e %T %Y", $cust_bill_event->_date). '</TD><TD>'.
+ $status. '</TD></TR>';
+}
+print '</TABLE><BR><PRE>';
+
+print $cust_bill->print_text;
+
+ #formatting
+ print <<END;
+ </PRE></FONT>
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi
new file mode 100755
index 0000000..cf899d0
--- /dev/null
+++ b/httemplate/view/cust_main.cgi
@@ -0,0 +1,1020 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+
+my %uiview = ();
+my %uiadd = ();
+foreach my $part_svc ( qsearch('part_svc',{}) ) {
+ $uiview{$part_svc->svcpart} = popurl(2). "view/". $part_svc->svcdb . ".cgi";
+ $uiadd{$part_svc->svcpart}= popurl(2). "edit/". $part_svc->svcdb . ".cgi";
+}
+
+print header("Customer View", menubar(
+ 'Main Menu' => popurl(2)
+));
+
+%>
+
+<STYLE TYPE="text/css">
+.package TH { font-size: medium }
+.package TR { font-size: smaller }
+.package .provision { font-weight: bold }
+</STYLE>
+
+<%
+
+die "No customer specified (bad URL)!" unless $cgi->keywords;
+my($query) = $cgi->keywords; # needs parens with my, ->keywords returns array
+$query =~ /^(\d+)$/;
+my $custnum = $1;
+my $cust_main = qsearchs('cust_main',{'custnum'=>$custnum});
+die "Customer not found!" unless $cust_main;
+
+print qq!<A HREF="${p}edit/cust_main.cgi?$custnum">Edit this customer</A>!;
+
+%>
+
+<SCRIPT>
+function cancel_areyousure(href) {
+ if (confirm("Perminantly delete all services and cancel this customer?") == true)
+ window.location.href = href;
+}
+</SCRIPT>
+
+<%
+
+print qq! | <A HREF="javascript:cancel_areyousure('${p}misc/cust_main-cancel.cgi?$custnum')">!.
+ 'Cancel this customer</A>'
+ if $cust_main->ncancelled_pkgs;
+
+print qq! | <A HREF="${p}misc/delete-customer.cgi?$custnum">!.
+ 'Delete this customer</A>'
+ if $conf->exists('deletecustomers');
+
+unless ( $conf->exists('disable_customer_referrals') ) {
+ print qq! | <A HREF="!, popurl(2),
+ qq!edit/cust_main.cgi?referral_custnum=$custnum">!,
+ qq!Refer a new customer</A>!;
+
+ print qq! | <A HREF="!, popurl(2),
+ qq!search/cust_main.cgi?referral_custnum=$custnum">!,
+ qq!View this customer's referrals</A>!;
+}
+
+print '<BR><BR>';
+
+my $signupurl = $conf->config('signupurl');
+if ( $signupurl ) {
+print "This customer's signup URL: ".
+ "<a href=\"$signupurl?ref=$custnum\">$signupurl?ref=$custnum</a><BR><BR>";
+}
+
+print '<A NAME="cust_main"></A>';
+
+print &itable(), '<TR>';
+
+print '<TD VALIGN="top">';
+
+ print "Billing address", &ntable("#cccccc"), "<TR><TD>",
+ &ntable("#cccccc",2),
+ '<TR><TD ALIGN="right">Contact&nbsp;name</TD>',
+ '<TD COLSPAN=3 BGCOLOR="#ffffff">',
+ $cust_main->last, ', ', $cust_main->first,
+ '</TD>';
+print '<TD ALIGN="right">SS#</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->ss || '&nbsp', '</TD>'
+ if $conf->exists('show_ss');
+
+print '</TR>',
+ '<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->company,
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Address</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->address1,
+ '</TD></TR>',
+ ;
+ print '<TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->address2, '</TD></TR>'
+ if $cust_main->address2;
+ print '<TR><TD ALIGN="right">City</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->city,
+ '</TD><TD ALIGN="right">State</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->state,
+ '</TD><TD ALIGN="right">Zip</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->zip, '</TD></TR>',
+ '<TR><TD ALIGN="right">Country</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->country,
+ '</TD></TR>',
+ ;
+ my $daytime_label = FS::Msgcat::_gettext('daytime') || 'Day&nbsp;Phone';
+ my $night_label = FS::Msgcat::_gettext('night') || 'Night&nbsp;Phone';
+ print '<TR><TD ALIGN="right">'. $daytime_label.
+ '</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->daytime || '&nbsp', '</TD></TR>',
+ '<TR><TD ALIGN="right">'. $night_label.
+ '</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->night || '&nbsp', '</TD></TR>',
+ '<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->fax || '&nbsp', '</TD></TR>',
+ '</TABLE>', "</TD></TR></TABLE>"
+ ;
+
+ if ( defined $cust_main->dbdef_table->column('ship_last') ) {
+
+ my $pre = $cust_main->ship_last ? 'ship_' : '';
+
+ print "<BR>Service address", &ntable("#cccccc"), "<TR><TD>",
+ &ntable("#cccccc",2),
+ '<TR><TD ALIGN="right">Contact name</TD>',
+ '<TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}last"), ', ', $cust_main->get("${pre}first"),
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}company"),
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Address</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}address1"),
+ '</TD></TR>',
+ ;
+ print '<TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}address2"), '</TD></TR>'
+ if $cust_main->get("${pre}address2");
+ print '<TR><TD ALIGN="right">City</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}city"),
+ '</TD><TD ALIGN="right">State</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}state"),
+ '</TD><TD ALIGN="right">Zip</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}zip"), '</TD></TR>',
+ '<TR><TD ALIGN="right">Country</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}country"),
+ '</TD></TR>',
+ ;
+ print '<TR><TD ALIGN="right">'. $daytime_label. '</TD>',
+ '<TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}daytime") || '&nbsp', '</TD></TR>',
+ '<TR><TD ALIGN="right">'. $night_label. '</TD>'.
+ '<TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}night") || '&nbsp', '</TD></TR>',
+ '<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->get("${pre}fax") || '&nbsp', '</TD></TR>',
+ '</TABLE>', "</TD></TR></TABLE>"
+ ;
+
+ }
+
+print '</TD>';
+
+print '<TD VALIGN="top">';
+
+ print &ntable("#cccccc"), "<TR><TD>", &ntable("#cccccc",2),
+ '<TR><TD ALIGN="right">Customer&nbsp;number</TD><TD BGCOLOR="#ffffff">',
+ $custnum, '</TD></TR>',
+ ;
+
+ my @agents = qsearch( 'agent', {} );
+ my $agent;
+ unless ( scalar(@agents) == 1 ) {
+ $agent = qsearchs('agent',{ 'agentnum' => $cust_main->agentnum } );
+ print '<TR><TD ALIGN="right">Agent</TD><TD BGCOLOR="#ffffff">',
+ $agent->agentnum, ": ", $agent->agent, '</TD></TR>';
+ } else {
+ $agent = $agents[0];
+ }
+ my @referrals = qsearch( 'part_referral', {} );
+ unless ( scalar(@referrals) == 1 ) {
+ my $referral = qsearchs('part_referral', {
+ 'refnum' => $cust_main->refnum
+ } );
+ print '<TR><TD ALIGN="right">Advertising&nbsp;source</TD><TD BGCOLOR="#ffffff">',
+ $referral->refnum, ": ", $referral->referral, '</TD></TR>';
+ }
+ print '<TR><TD ALIGN="right">Order taker</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->otaker, '</TD></TR>';
+
+ print '<TR><TD ALIGN="right">Referring&nbsp;Customer</TD><TD BGCOLOR="#ffffff">';
+ my $referring_cust_main = '';
+ if ( $cust_main->referral_custnum
+ && ( $referring_cust_main =
+ qsearchs('cust_main', { custnum => $cust_main->referral_custnum } )
+ )
+ ) {
+ print '<A HREF="'. popurl(1). 'cust_main.cgi?'.
+ $cust_main->referral_custnum. '">'.
+ $cust_main->referral_custnum. ': '.
+ ( $referring_cust_main->company
+ ? $referring_cust_main->company. ' ('.
+ $referring_cust_main->last. ', '. $referring_cust_main->first.
+ ')'
+ : $referring_cust_main->last. ', '. $referring_cust_main->first
+ ).
+ '</A>';
+ }
+ print '</TD></TR>';
+
+ print '</TABLE></TD></TR></TABLE>';
+
+print '<BR>';
+
+if ( $conf->config('payby-default') ne 'HIDE' ) {
+
+ my @invoicing_list = $cust_main->invoicing_list;
+ print "Billing information (",
+ qq!<A HREF="!, popurl(2), qq!misc/bill.cgi?$custnum">!, "Bill now</A>)",
+ &ntable("#cccccc"), "<TR><TD>", &ntable("#cccccc",2),
+ '<TR><TD ALIGN="right">Tax&nbsp;exempt</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->tax ? 'yes' : 'no',
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Postal&nbsp;invoices</TD><TD BGCOLOR="#ffffff">',
+ ( grep { $_ eq 'POST' } @invoicing_list ) ? 'yes' : 'no',
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Email&nbsp;invoices</TD><TD BGCOLOR="#ffffff">',
+ join(', ', grep { $_ ne 'POST' } @invoicing_list ) || 'no',
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Billing&nbsp;type</TD><TD BGCOLOR="#ffffff">',
+ ;
+
+ if ( $cust_main->payby eq 'CARD' || $cust_main->payby eq 'DCRD' ) {
+ my $payinfo = $cust_main->payinfo_masked;
+ print 'Credit&nbsp;card&nbsp;',
+ ( $cust_main->payby eq 'CARD' ? '(automatic)' : '(on-demand)' ),
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Card number</TD><TD BGCOLOR="#ffffff">',
+ $payinfo, '</TD></TR>',
+ '<TR><TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->paydate, '</TD></TR>',
+ '<TR><TD ALIGN="right">Name on card</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payname, '</TD></TR>'
+ ;
+ } elsif ( $cust_main->payby eq 'CHEK' || $cust_main->payby eq 'DCHK') {
+ my( $account, $aba ) = split('@', $cust_main->payinfo );
+ print 'Electronic&nbsp;check&nbsp;',
+ ( $cust_main->payby eq 'CHEK' ? '(automatic)' : '(on-demand)' ),
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Account number</TD><TD BGCOLOR="#ffffff">',
+ $account, '</TD></TR>',
+ '<TR><TD ALIGN="right">ABA/Routing code</TD><TD BGCOLOR="#ffffff">',
+ $aba, '</TD></TR>',
+ '<TR><TD ALIGN="right">Bank name</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payname, '</TD></TR>'
+ ;
+ } elsif ( $cust_main->payby eq 'LECB' ) {
+ $cust_main->payinfo =~ /^(\d{3})(\d{3})(\d{4})$/;
+ my $payinfo = "$1-$2-$3";
+ print 'Phone&nbsp;bill&nbsp;billing</TD></TR>',
+ '<TR><TD ALIGN="right">Phone number</TD><TD BGCOLOR="#ffffff">',
+ $payinfo, '</TD></TR>',
+ ;
+ } elsif ( $cust_main->payby eq 'BILL' ) {
+ print 'Billing</TD></TR>';
+ print '<TR><TD ALIGN="right">P.O. </TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payinfo, '</TD></TR>',
+ if $cust_main->payinfo;
+ print '<TR><TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->paydate, '</TD></TR>',
+ '<TR><TD ALIGN="right">Attention</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payname, '</TD></TR>',
+ ;
+ } elsif ( $cust_main->payby eq 'COMP' ) {
+ print 'Complimentary</TD></TR>',
+ '<TR><TD ALIGN="right">Authorized&nbsp;by</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payinfo, '</TD></TR>',
+ '<TR><TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->paydate, '</TD></TR>',
+ ;
+ }
+
+ print "</TABLE></TD></TR></TABLE>";
+
+}
+
+print '</TD></TR></TABLE>';
+
+if ( defined $cust_main->dbdef_table->column('comments')
+ && $cust_main->comments =~ /[^\s\n\r]/ )
+{
+ print "<BR>Comments". &ntable("#cccccc"). "<TR><TD>".
+ &ntable("#cccccc",2).
+ '<TR><TD BGCOLOR="#ffffff"><PRE>'.
+ encode_entities($cust_main->comments).
+ '</PRE></TD></TR></TABLE></TABLE>';
+}
+
+print '</TD></TR></TABLE>';
+
+print '<BR>'.
+ '<FORM ACTION="'.popurl(2).'edit/process/quick-cust_pkg.cgi" METHOD="POST">'.
+ qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!.
+ '<SELECT NAME="pkgpart"><OPTION> ';
+
+foreach my $part_pkg (
+ qsearch( 'part_pkg', { 'disabled' => '' }, '',
+ ' AND 0 < ( SELECT COUNT(*) FROM type_pkgs '.
+ ' WHERE typenum = '. $agent->typenum.
+ ' AND type_pkgs.pkgpart = part_pkg.pkgpart )'
+ )
+) {
+ print '<OPTION VALUE="'. $part_pkg->pkgpart. '">'. $part_pkg->pkg. ' - '.
+ $part_pkg->comment;
+}
+
+print '</SELECT><INPUT TYPE="submit" VALUE="Order Package"></FORM><BR>';
+
+if ( $conf->config('payby-default') ne 'HIDE' ) {
+
+ print
+ qq!<FORM ACTION="${p}edit/process/quick-charge.cgi" METHOD="POST">!.
+ qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!.
+ qq!Description:<INPUT TYPE="text" NAME="pkg">!.
+ qq!&nbsp;Amount:<INPUT TYPE="text" NAME="amount" SIZE=6>!.
+ qq!&nbsp;!;
+
+ #false laziness w/ edit/part_pkg.cgi
+ if ( $conf->exists('enable_taxclasses') ) {
+ print '<SELECT NAME="taxclass">';
+ my $sth = dbh->prepare('SELECT DISTINCT taxclass FROM cust_main_county')
+ or die dbh->errstr;
+ $sth->execute or die $sth->errstr;
+ foreach my $taxclass ( map $_->[0], @{$sth->fetchall_arrayref} ) {
+ print qq!<OPTION VALUE="$taxclass"!;
+ #print ' SELECTED' if $taxclass eq $hashref->{taxclass};
+ print qq!>$taxclass</OPTION>!;
+ }
+ print '</SELECT>';
+ } else {
+ print '<INPUT TYPE="hidden" NAME="taxclass" VALUE="">';
+ }
+
+ print qq!<INPUT TYPE="submit" VALUE="One-time charge"></FORM><BR>!;
+
+}
+
+%>
+
+<SCRIPT>
+function cust_pkg_areyousure(href) {
+ if (confirm("Permanently delete included services and cancel this package?") == true)
+ window.location.href = href;
+}
+function svc_areyousure(href) {
+ if (confirm("Permanently unprovision and delete this service?") == true)
+ window.location.href = href;
+}
+</SCRIPT>
+
+<%
+
+print qq!<A NAME="cust_pkg">Packages</A> !,
+ qq!( <A HREF="!, popurl(2), qq!edit/cust_pkg.cgi?$custnum">Order and cancel packages</A> (preserves services) )!,
+;
+
+#begin display packages
+
+#get package info
+
+my $packages = get_packages($cust_main, $conf);
+
+if ( @$packages ) {
+%>
+<TABLE CLASS="package" BORDER=1 CELLSPACING=0 CELLPADDING=2 BORDERCOLOR="#999999">
+<TR>
+ <TH>Package</TH>
+ <TH>Status</TH>
+ <TH COLSPAN=2>Services</TH>
+</TR>
+<%
+foreach my $pkg (sort pkgsort_pkgnum_cancel @$packages) {
+ my $rowspan = 0;
+
+ if ($pkg->{cancel}) {
+ $rowspan = 0;
+ } else {
+ foreach my $svcpart (@{$pkg->{svcparts}}) {
+ $rowspan += $svcpart->{count};
+ $rowspan++ if ($svcpart->{count} < $svcpart->{quantity});
+ }
+ }
+
+%>
+<!--pkgnum: <%=$pkg->{pkgnum}%>-->
+<TR>
+ <TD ROWSPAN=<%=$rowspan%>>
+ <A NAME="cust_pkg<%=$pkg->{pkgnum}%>"><%=$pkg->{pkgnum}%></A>:
+ <%=$pkg->{pkg}%> - <%=$pkg->{comment}%><BR>
+<% unless ($pkg->{cancel}) { %>
+ (&nbsp;<%=pkg_change_link($pkg)%>&nbsp;)
+ (&nbsp;<%=pkg_dates_link($pkg)%>&nbsp;|&nbsp;<%=pkg_customize_link($pkg,$custnum)%>&nbsp;)
+<% } %>
+ </TD>
+<%
+ #foreach (qw(setup last_bill next_bill susp expire cancel)) {
+ # print qq! <TD ROWSPAN=$rowspan>! . pkg_datestr($pkg,$_,$conf) . qq!</TD>\n!;
+ #}
+ print "<TD ROWSPAN=$rowspan>". &itable('');
+
+ sub freq {
+
+ #false laziness w/edit/part_pkg.cgi
+ my %freq = ( #move this
+ '1d' => 'daily',
+ '1w' => 'weekly',
+ '2w' => 'biweekly (every 2 weeks)',
+ '1' => 'monthly',
+ '2' => 'bimonthly (every 2 months)',
+ '3' => 'quarterly (every 3 months)',
+ '6' => 'semiannually (every 6 months)',
+ '12' => 'annually',
+ '24' => 'biannually (every 2 years)',
+ );
+
+ my $freq = shift;
+ exists $freq{$freq} ? $freq{$freq} : "every&nbsp;$freq&nbsp;months";
+ }
+
+ #eomove
+
+ if ( $pkg->{cancel} ) { #status: cancelled
+
+ print '<TR><TD><FONT COLOR="#ff0000"><B>Cancelled&nbsp;</B></FONT></TD>'.
+ '<TD>'. pkg_datestr($pkg,'cancel',$conf). '</TD></TR>';
+ unless ( $pkg->{setup} ) {
+ print '<TR><TD COLSPAN=2>Never billed</TD></TR>';
+ } else {
+ print "<TR><TD>Setup&nbsp;</TD><TD>".
+ pkg_datestr($pkg, 'setup',$conf). '</TD></TR>';
+ print "<TR><TD>Last&nbsp;bill&nbsp;</TD><TD>".
+ pkg_datestr($pkg, 'last_bill',$conf). '</TD></TR>'
+ if $pkg->{'last_bill'};
+ print "<TR><TD>Suspended&nbsp;</TD><TD>".
+ pkg_datestr($pkg, 'susp',$conf). '</TD></TR>'
+ if $pkg->{'susp'};
+ }
+
+ } else {
+
+ if ( $pkg->{susp} ) { #status: suspended
+ print '<TR><TD><FONT COLOR="#FF9900"><B>Suspended</B>&nbsp;</FONT></TD>'.
+ '<TD>'. pkg_datestr($pkg,'susp',$conf). '</TD></TR>';
+ unless ( $pkg->{setup} ) {
+ print '<TR><TD COLSPAN=2>Never billed</TD></TR>';
+ } else {
+ print "<TR><TD>Setup&nbsp;</TD><TD>".
+ pkg_datestr($pkg, 'setup',$conf). '</TD></TR>';
+ }
+ print "<TR><TD>Last&nbsp;bill&nbsp;</TD><TD>".
+ pkg_datestr($pkg, 'last_bill',$conf). '</TD></TR>'
+ if $pkg->{'last_bill'};
+ # next bill ??
+ print "<TR><TD>Expires&nbsp;</TD><TD>".
+ pkg_datestr($pkg, 'expire',$conf). '</TD></TR>'
+ if $pkg->{'expire'};
+ print '<TR><TD COLSPAN=2>(&nbsp;'. pkg_unsuspend_link($pkg).
+ '&nbsp;|&nbsp;'. pkg_cancel_link($pkg). '&nbsp;)</TD></TR>';
+
+ } else { #status: active
+
+ unless ( $pkg->{setup} ) { #not setup
+
+ print '<TR><TD COLSPAN=2>Not&nbsp;yet&nbsp;billed&nbsp;(';
+ unless ( $pkg->{freq} ) {
+ print 'one-time&nbsp;charge)</TD></TR>';
+ print '<TR><TD COLSPAN=2>(&nbsp;'. pkg_cancel_link($pkg).
+ '&nbsp;)</TD</TR>';
+ } else {
+ print 'billed&nbsp;'. freq($pkg->{freq}). ')</TD></TR>';
+ }
+
+ } else { #setup
+
+ unless ( $pkg->{freq} ) {
+ print "<TR><TD COLSPAN=2>One-time&nbsp;charge</TD></TR>".
+ '<TR><TD>Billed&nbsp;</TD><TD>'.
+ pkg_datestr($pkg,'setup',$conf). '</TD></TR>';
+ } else {
+ print '<TR><TD COLSPAN=2><FONT COLOR="#00CC00"><B>Active</B></FONT>'.
+ ',&nbsp;billed&nbsp;'. freq($pkg->{freq}). '</TD></TR>'.
+ '<TR><TD>Setup&nbsp;</TD><TD>'.
+ pkg_datestr($pkg, 'setup',$conf). '</TD></TR>';
+ }
+
+ }
+
+ print "<TR><TD>Last&nbsp;bill&nbsp;</TD><TD>".
+ pkg_datestr($pkg, 'last_bill',$conf). '</TD></TR>'
+ if $pkg->{'last_bill'};
+ print "<TR><TD>Next&nbsp;bill&nbsp;</TD><TD>".
+ pkg_datestr($pkg, 'next_bill',$conf). '</TD></TR>'
+ if $pkg->{'next_bill'};
+ print "<TR><TD>Expires&nbsp;</TD><TD>".
+ pkg_datestr($pkg, 'expire',$conf). '</TD></TR>'
+ if $pkg->{'expire'};
+ if ( $pkg->{freq} ) {
+ print '<TR><TD COLSPAN=2>(&nbsp;'. pkg_suspend_link($pkg).
+ '&nbsp;|&nbsp;'. pkg_cancel_link($pkg). '&nbsp;)</TD></TR>';
+ }
+
+ }
+
+ }
+
+ print "</TABLE></TD>\n";
+
+ if ($rowspan == 0) { print qq!</TR>\n!; next; }
+
+ my $cnt = 0;
+ foreach my $svcpart (sort {$a->{svcpart} <=> $b->{svcpart}} @{$pkg->{svcparts}}) {
+ foreach my $service (@{$svcpart->{services}}) {
+ print '<TR>' if ($cnt > 0);
+%>
+ <TD><%=svc_link($svcpart,$service)%></TD>
+ <TD><%=svc_label_link($svcpart,$service)%><BR>(&nbsp;<%=svc_unprovision_link($service)%>&nbsp;)</TD>
+</TR>
+<%
+ $cnt++;
+ }
+ if ($svcpart->{count} < $svcpart->{quantity}) {
+ print qq!<TR>\n! if ($cnt > 0);
+ print qq! <TD COLSPAN=2>!.svc_provision_link($pkg, $svcpart, $conf).qq!</TD>\n</TR>\n!;
+ }
+ }
+}
+print '</TABLE>';
+}
+
+#end display packages
+%>
+
+<SCRIPT>
+function cust_pay_areyousure(href) {
+ if (confirm("Are you sure you want to delete this payment?")
+ == true)
+ window.location.href = href;
+}
+function cust_pay_unapply_areyousure(href) {
+ if (confirm("Are you sure you want to unapply this payment?")
+ == true)
+ window.location.href = href;
+}
+function cust_credit_unapply_areyousure(href) {
+ if (confirm("Are you sure you want to unapply this credit?")
+ == true)
+ window.location.href = href;
+}
+function cust_credit_areyousure(href) {
+ if (confirm("Are you sure you want to delete this credit?")
+ == true)
+ window.location.href = href;
+}
+</SCRIPT>
+
+<% if ( $conf->config('payby-default') ne 'HIDE' ) { %>
+
+ <BR><BR><A NAME="history"><FONT SIZE="+2">Payment History</FONT></A><BR>
+ <A HREF="<%= $p %>edit/cust_pay.cgi?custnum=<%= $custnum %>">Post cash/check payment</A>
+ | <A HREF="<%= $p %>misc/payment.cgi?payby=CARD;custnum=<%= $custnum %>">Process credit card payment</A>
+ | <A HREF="<%= $p %>misc/payment.cgi?payby=CHEK;custnum=<%= $custnum %>">Process electronic check (ACH) payment</A>
+ <BR><A HREF="<%= $p %>edit/cust_credit.cgi?<%= $custnum %>">Post credit</A>
+ <BR>
+
+ <%
+ #get payment history
+ my @history = ();
+
+ #invoices
+ foreach my $cust_bill ($cust_main->cust_bill) {
+ my $pre = ( $cust_bill->owed > 0 )
+ ? '<B><FONT SIZE="+1" COLOR="#FF0000">Open '
+ : '';
+ my $post = ( $cust_bill->owed > 0 ) ? '</FONT></B>' : '';
+ my $invnum = $cust_bill->invnum;
+ push @history, {
+ 'date' => $cust_bill->_date,
+ 'desc' => qq!<A HREF="${p}view/cust_bill.cgi?$invnum">!. $pre.
+ "Invoice #$invnum (Balance \$". $cust_bill->owed. ')'.
+ $post. '</A>',
+ 'charge' => $cust_bill->charged,
+ };
+ }
+
+ #payments (some false laziness w/credits)
+ foreach my $cust_pay ($cust_main->cust_pay) {
+
+ my $payby = $cust_pay->payby;
+ my $payinfo = $payby eq 'CARD'
+ ? $cust_pay->payinfo_masked
+ : $cust_pay->payinfo;
+ my @cust_bill_pay = $cust_pay->cust_bill_pay;
+
+ my $target = "$payby$payinfo";
+ $payby =~ s/^BILL$/Check #/ if $payinfo;
+ $payby =~ s/^BILL$//;
+ $payby =~ s/^(CARD|COMP)$/$1 /;
+ my $info = $payby ? " ($payby$payinfo)" : '';
+
+ my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
+ if ( scalar(@cust_bill_pay) == 0 ) {
+ #completely unapplied
+ $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
+ $post = '</FONT></B>';
+ $apply = qq! (<A HREF="${p}edit/cust_bill_pay.cgi?!.
+ $cust_pay->paynum. '">apply</A>)';
+ } elsif ( scalar(@cust_bill_pay) == 1 && $cust_pay->unapplied == 0 ) {
+ #applied to one invoice
+ $desc = ' applied to Invoice #'. $cust_bill_pay[0]->invnum;
+ } else {
+ #complicated
+ $desc = '<BR>';
+ foreach my $cust_bill_pay (@cust_bill_pay) {
+ $desc .= '&nbsp;&nbsp;'.
+ '$'. $cust_bill_pay->amount.
+ ' applied to Invoice #'. $cust_bill_pay->invnum.
+ '<BR>';
+ #' on '. time2str("%D", $cust_bill_pay->_date).
+
+ }
+ if ( $cust_pay->unapplied > 0 ) {
+ $desc .= '&nbsp;&nbsp;'.
+ '<B><FONT COLOR="#FF0000">$'.
+ $cust_pay->unapplied. ' unapplied</FONT></B>'.
+ qq! (<A HREF="${p}edit/cust_bill_pay.cgi?!.
+ $cust_pay->paynum. '">apply</A>)'.
+ '<BR>';
+ }
+ }
+
+ my $delete = '';
+ if ( $cust_pay->closed !~ /^Y/i && $conf->exists('deletepayments') ) {
+ $delete = qq! (<A HREF="javascript:cust_pay_areyousure('!.
+ qq!${p}misc/delete-cust_pay.cgi?!. $cust_pay->paynum.
+ qq!')">delete</A>)!;
+ }
+
+ my $unapply = '';
+ if ( $cust_pay->closed !~ /^Y/i
+ && $conf->exists('unapplypayments')
+ && scalar(@cust_bill_pay) ) {
+ $unapply = qq! (<A HREF="javascript:cust_pay_unapply_areyousure('!.
+ qq!${p}misc/unapply-cust_pay.cgi?!. $cust_pay->paynum.
+ qq!')">unapply</A>)!;
+ }
+
+ push @history, {
+ 'date' => $cust_pay->_date,
+ 'desc' => $pre. "Payment$post$info$desc".
+ "$apply$delete$unapply",
+ 'payment' => $cust_pay->paid,
+ 'target' => $target,
+ };
+ }
+
+ #credits (some false laziness w/payments)
+ foreach my $cust_credit ($cust_main->cust_credit) {
+
+ my @cust_credit_bill = $cust_credit->cust_credit_bill;
+ my @cust_credit_refund = $cust_credit->cust_credit_refund;
+
+ my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
+ if ( scalar(@cust_credit_bill) == 0
+ && scalar(@cust_credit_refund) == 0 ) {
+ #completely unapplied
+ $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
+ $post = '</FONT></B>';
+ $apply = qq! (<A HREF="${p}edit/cust_credit_bill.cgi?!.
+ $cust_credit->crednum. '">apply</A>)';
+ } elsif ( scalar(@cust_credit_bill) == 1
+ && scalar(@cust_credit_refund) == 0
+ && $cust_credit->credited == 0 ) {
+ #applied to one invoice
+ $desc = ' applied to Invoice #'. $cust_credit_bill[0]->invnum;
+ } elsif ( scalar(@cust_credit_bill) == 0
+ && scalar(@cust_credit_refund) == 1
+ && $cust_credit->credited == 0 ) {
+ #applied to one refund
+ $desc = ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date);
+ } else {
+ #complicated
+ $desc = '<BR>';
+ foreach my $app ( sort { $a->_date <=> $b->_date }
+ ( @cust_credit_bill, @cust_credit_refund ) ) {
+ if ( $app->isa('FS::cust_credit_bill') ) {
+ $desc .= '&nbsp;&nbsp;'.
+ '$'. $app->amount.
+ ' applied to Invoice #'. $app->invnum.
+ '<BR>';
+ #' on '. time2str("%D", $app->_date).
+ } elsif ( $app->isa('FS::cust_credit_refund') ) {
+ $desc .= '&nbsp;&nbsp;'.
+ '$'. $app->amount.
+ ' refunded on'. time2str("%D", $app->_date).
+ '<BR>';
+ } else {
+ die "$app is not a FS::cust_credit_bill or a FS::cust_credit_refund";
+ }
+ }
+ if ( $cust_credit->credited > 0 ) {
+ $desc .= '&nbsp;&nbsp;<B><FONT COLOR="#FF0000">$'.
+ $cust_credit->credited. ' unapplied</FONT></B>'.
+ qq! (<A HREF="${p}edit/cust_credit_bill.cgi?!.
+ $cust_credit->crednum. '">apply</A>)'.
+ '<BR>';
+ }
+ }
+#
+ my $delete = '';
+ if ( $cust_credit->closed !~ /^Y/i && $conf->exists('deletecredits') ) {
+ $delete = qq! (<A HREF="javascript:cust_credit_areyousure('!.
+ qq!${p}misc/delete-cust_credit.cgi?!. $cust_credit->crednum.
+ qq!')">delete</A>)!;
+ }
+
+ my $unapply = '';
+ if ( $cust_credit->closed !~ /^Y/i
+ && $conf->exists('unapplycredits')
+ && scalar(@cust_credit_bill) ) {
+ $unapply = qq! (<A HREF="javascript:cust_credit_unapply_areyousure('!.
+ qq!${p}misc/unapply-cust_credit.cgi?!. $cust_credit->crednum.
+ qq!')">unapply</A>)!;
+ }
+
+ push @history, {
+ 'date' => $cust_credit->_date,
+ 'desc' => $pre. "Credit$post by ". $cust_credit->otaker.
+ ' ('. $cust_credit->reason. ')'.
+ "$desc$apply$delete$unapply",
+ 'credit' => $cust_credit->amount,
+ };
+
+ }
+
+ #refunds
+ foreach my $cust_refund ($cust_main->cust_refund) {
+
+ my $payby = $cust_refund->payby;
+ my $payinfo = $payby eq 'CARD'
+ ? $cust_refund->payinfo_masked
+ : $cust_refund->payinfo;
+
+ $payby =~ s/^BILL$/Check #/ if $payinfo;
+ $payby =~ s/^(CARD|COMP)$/$1 /;
+
+ push @history, {
+ 'date' => $cust_refund->_date,
+ 'desc' => "Refund ($payby$payinfo) by ". $cust_refund->otaker,
+ 'refund' => $cust_refund->refund,
+ };
+
+ }
+
+ %>
+
+ <%= table() %>
+ <TR>
+ <TH>Date</TH>
+ <TH>Description</TH>
+ <TH><FONT SIZE=-1>Charge</FONT></TH>
+ <TH><FONT SIZE=-1>Payment</FONT></TH>
+ <TH><FONT SIZE=-1>In-house<BR>Credit</FONT></TH>
+ <TH><FONT SIZE=-1>Refund</FONT></TH>
+ <TH><FONT SIZE=-1>Balance</FONT></TH>
+ </TR>
+
+ <%
+ #display payment history
+
+ my %target;
+ my $balance = 0;
+ foreach my $item ( sort { $a->{'date'} <=> $b->{'date'} } @history ) {
+
+ my $charge = exists($item->{'charge'})
+ ? sprintf('$%.2f', $item->{'charge'})
+ : '';
+ my $payment = exists($item->{'payment'})
+ ? sprintf('-&nbsp;$%.2f', $item->{'payment'})
+ : '';
+ my $credit = exists($item->{'credit'})
+ ? sprintf('-&nbsp;$%.2f', $item->{'credit'})
+ : '';
+ my $refund = exists($item->{'refund'})
+ ? sprintf('$%.2f', $item->{'refund'})
+ : '';
+
+ my $target = exists($item->{'target'}) ? $item->{'target'} : '';
+
+ $balance += $item->{'charge'} if exists $item->{'charge'};
+ $balance -= $item->{'payment'} if exists $item->{'payment'};
+ $balance -= $item->{'credit'} if exists $item->{'credit'};
+ $balance += $item->{'refund'} if exists $item->{'refund'};
+ $balance = sprintf("%.2f", $balance);
+ $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp
+ ( my $showbalance = '$'. $balance ) =~ s/^\$\-/-&nbsp;\$/;
+
+ %>
+
+ <TR>
+ <TD>
+ <% unless ( !$target || $target{$target}++ ) { %>
+ <A NAME="<%= $target %>">
+ <% } %>
+ <%= time2str("%D",$item->{'date'}) %>
+ <% if ( $target && $target{$target} == 1 ) { %>
+ </A>
+ <% } %>
+ </FONT>
+ </TD>
+ <TD><%= $item->{'desc'} %></TD>
+ <TD ALIGN="right"><%= $charge %></TD>
+ <TD ALIGN="right"><%= $payment %></TD>
+ <TD ALIGN="right"><%= $credit %></TD>
+ <TD ALIGN="right"><%= $refund %></TD>
+ <TD ALIGN="right"><%= $showbalance %></TD>
+ </TR>
+
+ <% } %>
+
+ </TABLE>
+
+<% } %>
+
+</BODY></HTML>
+
+<%
+#subroutines
+
+sub get_packages {
+ my $cust_main = shift or return undef;
+ my $conf = shift;
+
+ my @packages = ();
+
+ foreach my $cust_pkg (
+ $conf->exists('hidecancelledpackages')
+ ? $cust_main->ncancelled_pkgs
+ : $cust_main->all_pkgs
+ ) {
+
+ my $part_pkg = $cust_pkg->part_pkg;
+
+ my %pkg = ();
+ $pkg{pkgnum} = $cust_pkg->pkgnum;
+ $pkg{pkg} = $part_pkg->pkg;
+ $pkg{pkgpart} = $part_pkg->pkgpart;
+ $pkg{comment} = $part_pkg->getfield('comment');
+ $pkg{freq} = $part_pkg->freq;
+ $pkg{setup} = $cust_pkg->getfield('setup');
+ $pkg{last_bill} = $cust_pkg->getfield('last_bill');
+ $pkg{next_bill} = $cust_pkg->getfield('bill');
+ $pkg{susp} = $cust_pkg->getfield('susp');
+ $pkg{expire} = $cust_pkg->getfield('expire');
+ $pkg{cancel} = $cust_pkg->getfield('cancel');
+
+ my %svcparts = ();
+
+ foreach my $pkg_svc (
+ qsearch('pkg_svc', { 'pkgpart' => $part_pkg->pkgpart })
+ ) {
+
+ next if ($pkg_svc->quantity == 0);
+
+ my $part_svc = qsearchs('part_svc', { 'svcpart' => $pkg_svc->svcpart });
+
+ my $svcpart = {};
+ $svcpart->{svcpart} = $part_svc->svcpart;
+ $svcpart->{svc} = $part_svc->svc;
+ $svcpart->{svcdb} = $part_svc->svcdb;
+ $svcpart->{quantity} = $pkg_svc->quantity;
+ $svcpart->{count} = 0;
+
+ $svcpart->{services} = [];
+
+ $svcparts{$svcpart->{svcpart}} = $svcpart;
+
+ }
+
+ foreach my $cust_svc ( $cust_pkg->cust_svc ) {
+ #warn "svcnum ". $cust_svc->svcnum. " / svcpart ". $cust_svc->svcpart. "\n";
+ my $svc = {
+ 'svcnum' => $cust_svc->svcnum,
+ 'label' => ($cust_svc->label)[1],
+ };
+
+ #false laziness with above, to catch extraneous services. whole
+ #damn thing should be OO...
+ my $svcpart = ( $svcparts{$cust_svc->svcpart} ||= {
+ 'svcpart' => $cust_svc->svcpart,
+ 'svc' => $cust_svc->part_svc->svc,
+ 'svcdb' => $cust_svc->part_svc->svcdb,
+ 'quantity' => 0,
+ 'count' => 0,
+ 'services' => [],
+ } );
+
+ push @{$svcpart->{services}}, $svc;
+
+ $svcpart->{count}++;
+
+ }
+
+ $pkg{svcparts} = [ values %svcparts ];
+
+ push @packages, \%pkg;
+
+ }
+
+ return \@packages;
+
+}
+
+sub svc_link {
+
+ my ($svcpart, $svc) = (shift,shift) or return '';
+ return qq!<A HREF="${p}view/$svcpart->{svcdb}.cgi?$svc->{svcnum}">$svcpart->{svc}</A>!;
+
+}
+
+sub svc_label_link {
+
+ my ($svcpart, $svc) = (shift,shift) or return '';
+ return qq!<A HREF="${p}view/$svcpart->{svcdb}.cgi?$svc->{svcnum}">$svc->{label}</A>!;
+
+}
+
+sub svc_provision_link {
+ my ($pkg, $svcpart, $conf) = @_;
+ ( my $svc_nbsp = $svcpart->{svc} ) =~ s/\s+/&nbsp;/g;
+ my $pkgnum_svcpart = "pkgnum$pkg->{pkgnum}-svcpart$svcpart->{svcpart}";
+ my $num_left = $svcpart->{quantity} - $svcpart->{count};
+
+ my $link = qq!<A CLASS="provision" HREF="${p}edit/$svcpart->{svcdb}.cgi?!.
+ qq!$pkgnum_svcpart">!.
+ "Provision&nbsp;$svc_nbsp&nbsp;($num_left)</A>";
+ if ( $conf->exists('legacy_link') ) {
+ $link .= '<BR>'.
+ qq!<A CLASS="provision" HREF="${p}misc/link.cgi?!.
+ qq!$pkgnum_svcpart">!.
+ "Link&nbsp;to&nbsp;legacy&nbsp;$svc_nbsp&nbsp;($num_left)</A>";
+ }
+ $link;
+}
+
+sub svc_unprovision_link {
+ my $svc = shift or return '';
+ return qq!<A HREF="javascript:svc_areyousure('${p}misc/unprovision.cgi?$svc->{svcnum}')">Unprovision</A>!;
+}
+
+# This should be generalized to use config options to determine order.
+sub pkgsort_pkgnum_cancel {
+ if ($a->{cancel} and $b->{cancel}) {
+ return ($a->{pkgnum} <=> $b->{pkgnum});
+ } elsif ($a->{cancel} or $b->{cancel}) {
+ return (-1) if ($b->{cancel});
+ return (1) if ($a->{cancel});
+ return (0);
+ } else {
+ return($a->{pkgnum} <=> $b->{pkgnum});
+ }
+}
+
+sub pkg_datestr {
+ my($pkg, $field, $conf) = @_ or return '';
+ return '&nbsp;' unless $pkg->{$field};
+ my $format = $conf->exists('pkg_showtimes')
+ ? '<B>%D</B>&nbsp;<FONT SIZE=-3>%l:%M:%S%P&nbsp;%z</FONT>'
+ : '<B>%b&nbsp;%o,&nbsp;%Y</B>';
+ ( my $strip = time2str($format, $pkg->{$field}) ) =~ s/ (\d)/$1/g;
+ $strip;
+}
+
+sub pkg_change_link {
+ my $pkg = shift or return '';
+ return qq!<a href="${p}misc/change_pkg.cgi?$pkg->{pkgnum}">Change&nbsp;package</a>!;
+}
+
+sub pkg_suspend_link {
+ my $pkg = shift or return '';
+ return qq!<a href="${p}misc/susp_pkg.cgi?$pkg->{pkgnum}">Suspend</a>!;
+}
+
+sub pkg_unsuspend_link {
+ my $pkg = shift or return '';
+ return qq!<a href="${p}misc/unsusp_pkg.cgi?$pkg->{pkgnum}">Unsuspend</a>!;
+}
+
+sub pkg_cancel_link {
+ my $pkg = shift or return '';
+ qq!<A HREF="javascript:cust_pkg_areyousure('${p}misc/cancel_pkg.cgi?$pkg->{pkgnum}')">Cancel now</A> | !.
+ qq!<A HREF="${p}misc/expire_pkg.cgi?$pkg->{pkgnum}">Cancel later</A>!;
+}
+
+sub pkg_dates_link {
+ my $pkg = shift or return '';
+ return qq!<A HREF="${p}edit/REAL_cust_pkg.cgi?$pkg->{pkgnum}">Edit&nbsp;dates</A>!;
+}
+
+sub pkg_customize_link {
+ my $pkg = shift or return '';
+ my $custnum = shift;
+ return qq!<A HREF="${p}edit/part_pkg.cgi?keywords=$custnum;clone=$pkg->{pkgpart};pkgnum=$pkg->{pkgnum}">Customize</A>!;
+}
+
+%>
+
diff --git a/httemplate/view/cust_pkg.cgi b/httemplate/view/cust_pkg.cgi
new file mode 100755
index 0000000..5f0e6bf
--- /dev/null
+++ b/httemplate/view/cust_pkg.cgi
@@ -0,0 +1,164 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+
+my %uiview = ();
+my %uiadd = ();
+foreach my $part_svc ( qsearch('part_svc',{}) ) {
+ $uiview{$part_svc->svcpart} = popurl(2). "view/". $part_svc->svcdb . ".cgi";
+ $uiadd{$part_svc->svcpart}= popurl(2). "edit/". $part_svc->svcdb . ".cgi";
+}
+
+my ($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $pkgnum = $1;
+
+#get package record
+my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+die "No package!" unless $cust_pkg;
+my $part_pkg = qsearchs('part_pkg',{'pkgpart'=>$cust_pkg->getfield('pkgpart')});
+
+my $custnum = $cust_pkg->getfield('custnum');
+print header('Package View', menubar(
+ "View this customer (#$custnum)" => popurl(2). "view/cust_main.cgi?$custnum",
+ 'Main Menu' => popurl(2)
+));
+
+#print info
+my ($susp,$cancel,$expire)=(
+ $cust_pkg->getfield('susp'),
+ $cust_pkg->getfield('cancel'),
+ $cust_pkg->getfield('expire'),
+);
+my($pkg,$comment)=($part_pkg->getfield('pkg'),$part_pkg->getfield('comment'));
+my($setup,$bill)=($cust_pkg->getfield('setup'),$cust_pkg->getfield('bill'));
+my $otaker = $cust_pkg->getfield('otaker');
+
+print <<END;
+<SCRIPT>
+function areyousure(href) {
+ if (confirm("Permanently delete included services and cancel this package?") == true)
+ window.location.href = href;
+}
+</SCRIPT>
+END
+
+print "Package information";
+print ' (<A HREF="'. popurl(2). 'misc/unsusp_pkg.cgi?'. $pkgnum.
+ '">unsuspend</A>)'
+ if ( $susp && ! $cancel );
+
+print ' (<A HREF="'. popurl(2). 'misc/susp_pkg.cgi?'. $pkgnum.
+ '">suspend</A>)'
+ unless ( $susp || $cancel );
+
+print ' (<A HREF="javascript:areyousure(\''. popurl(2). 'misc/cancel_pkg.cgi?'.
+ $pkgnum. '\')">cancel</A>)'
+ unless $cancel;
+
+print ' (<A HREF="'. popurl(2). 'edit/REAL_cust_pkg.cgi?'. $pkgnum.
+ '">edit dates</A>)';
+
+print &ntable("#cccccc"), '<TR><TD>', &ntable("#cccccc",2),
+ '<TR><TD ALIGN="right">Package number</TD><TD BGCOLOR="#ffffff">',
+ $pkgnum, '</TD></TR>',
+ '<TR><TD ALIGN="right">Package</TD><TD BGCOLOR="#ffffff">',
+ $pkg, '</TD></TR>',
+ '<TR><TD ALIGN="right">Comment</TD><TD BGCOLOR="#ffffff">',
+ $comment, '</TD></TR>',
+ '<TR><TD ALIGN="right">Setup date</TD><TD BGCOLOR="#ffffff">',
+ ( $setup ? time2str("%D",$setup) : "(Not setup)" ), '</TD></TR>';
+
+print '<TR><TD ALIGN="right">Last bill date</TD><TD BGCOLOR="#ffffff">',
+ ( $cust_pkg->get('last_bill') ? time2str("%D",$cust_pkg->get('last_bill')) : "&nbsp;" ),
+ '</TD></TR>'
+ if $cust_pkg->dbdef_table->column('last_bill');
+
+print '<TR><TD ALIGN="right">Next bill date</TD><TD BGCOLOR="#ffffff">',
+ ( $bill ? time2str("%D",$bill) : "&nbsp;" ), '</TD></TR>';
+
+print '<TR><TD ALIGN="right">Suspension date</TD><TD BGCOLOR="#ffffff">',
+ time2str("%D",$susp), '</TD></TR>' if $susp;
+print '<TR><TD ALIGN="right">Expiration date</TD><TD BGCOLOR="#ffffff">',
+ time2str("%D",$expire), '</TD></TR>' if $expire;
+print '<TR><TD ALIGN="right">Cancellation date</TD><TD BGCOLOR="#ffffff">',
+ time2str("%D",$cancel), '</TD></TR>' if $cancel;
+print '<TR><TD ALIGN="right">Order taker</TD><TD BGCOLOR="#ffffff">',
+ $otaker, '</TD></TR>',
+ '</TABLE></TD></TR></TABLE>';
+
+unless ($expire) {
+ print <<END;
+<FORM ACTION="../misc/expire_pkg.cgi" METHOD="post">
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">
+Expire (date): <INPUT TYPE="text" NAME="date" VALUE="" >
+<INPUT TYPE="submit" VALUE="Cancel later">
+END
+}
+
+unless ($cancel) {
+
+ #services
+ print '<BR>Service Information', &table();
+
+ #list of services this pkgpart includes
+ my $pkg_svc;
+ my %pkg_svc = ();
+ foreach $pkg_svc ( qsearch('pkg_svc',{'pkgpart'=> $cust_pkg->pkgpart }) ) {
+ $pkg_svc{$pkg_svc->svcpart} = $pkg_svc->quantity if $pkg_svc->quantity;
+ }
+
+ #list of records from cust_svc
+ my $svcpart;
+ foreach $svcpart (sort {$a <=> $b} keys %pkg_svc) {
+
+ my($svc)=qsearchs('part_svc',{'svcpart'=>$svcpart})->getfield('svc');
+
+ my(@cust_svc)=qsearch('cust_svc',{'pkgnum'=>$pkgnum,
+ 'svcpart'=>$svcpart,
+ });
+
+ my($enum);
+ for $enum ( 1 .. $pkg_svc{$svcpart} ) {
+
+ my($cust_svc);
+ if ( $cust_svc=shift @cust_svc ) {
+ my($svcnum)=$cust_svc->svcnum;
+ my($label, $value, $svcdb) = $cust_svc->label;
+ print <<END;
+<TR><TD><A HREF="$uiview{$svcpart}?$svcnum">(View/Edit) $svc: $value<A></TD></TR>
+END
+ } else {
+ print qq!<TR><TD>!.
+ qq!<A HREF="$uiadd{$svcpart}?pkgnum$pkgnum-svcpart$svcpart">!.
+ qq!(Provision) $svc</A>!;
+
+ print qq! or <A HREF="../misc/link.cgi?pkgnum$pkgnum-svcpart$svcpart">!.
+ qq!(Link to legacy) $svc</A>!
+ if $conf->exists('legacy_link');
+
+ print '</TD></TR>';
+ }
+
+ }
+ warn "WARNING: Leftover services pkgnum $pkgnum!" if @cust_svc;;
+ }
+
+ print "</TABLE><FONT SIZE=-1>",
+ "Choose (View/Edit) to view or edit an existing service<BR>",
+ "Choose (Provision) to setup a new service<BR>";
+
+ print "Choose (Link to legacy) to link to a legacy (pre-Freeside) service"
+ if $conf->exists('legacy_link');
+
+ print "</FONT>";
+}
+
+#formatting
+print <<END;
+ </BODY>
+</HTML>
+END
+
+%>
diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi
new file mode 100755
index 0000000..14d2745
--- /dev/null
+++ b/httemplate/view/svc_acct.cgi
@@ -0,0 +1,216 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $svcnum = $1;
+my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum});
+die "Unknown svcnum" unless $svc_acct;
+
+#false laziness w/all svc_*.cgi
+my $cust_svc = qsearchs( 'cust_svc' , { 'svcnum' => $svcnum } );
+my $pkgnum = $cust_svc->getfield('pkgnum');
+my($cust_pkg, $custnum);
+if ($pkgnum) {
+ $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } );
+ $custnum = $cust_pkg->custnum;
+} else {
+ $cust_pkg = '';
+ $custnum = '';
+}
+#eofalse
+
+my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
+die "Unknown svcpart" unless $part_svc;
+
+my $domain;
+if ( $svc_acct->domsvc ) {
+ my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $svc_acct->domsvc } );
+ die "Unknown domain" unless $svc_domain;
+ $domain = $svc_domain->domain;
+} else {
+ die "No svc_domain.svcnum record for svc_acct.domsvc: ". $cust_svc->domsvc;
+}
+
+%>
+
+<SCRIPT>
+function areyousure(href) {
+ if (confirm("Permanently delete this account?") == true)
+ window.location.href = href;
+}
+</SCRIPT>
+
+<%= header('Account View', menubar(
+ ( ( $pkgnum || $custnum )
+ ? ( "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ( "Cancel this (unaudited) account" =>
+ "javascript:areyousure(\'${p}misc/cancel-unaudited.cgi?$svcnum\')" )
+ ),
+ "Main menu" => $p,
+)) %>
+
+<%
+
+#if ( $cust_pkg && $cust_pkg->part_pkg->plan eq 'sqlradacct_hour' ) {
+if ( $part_svc->part_export('sqlradius')
+ || $part_svc->part_export('sqlradius_withdomain')
+) {
+
+ my $last_bill;
+ my %plandata;
+ if ( $cust_pkg ) {
+ #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really
+ #belong in plan data
+ %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); }
+ split("\n", $cust_pkg->part_pkg->plandata );
+
+ $last_bill = $cust_pkg->last_bill;
+ } else {
+ $last_bill = 0;
+ %plandata = ();
+ }
+
+ my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time );
+ my $hour = int($seconds/3600);
+ my $min = int( ($seconds%3600) / 60 );
+ my $sec = $seconds%60;
+
+ my $input = $svc_acct->attribute_since_sqlradacct(
+ $last_bill, time, 'AcctInputOctets'
+ ) / 1048576;
+ my $output = $svc_acct->attribute_since_sqlradacct(
+ $last_bill, time, 'AcctOutputOctets'
+ ) / 1048576;
+
+ if ( $seconds ) {
+ print "Online <B>$hour</B>h <B>$min</B>m <B>$sec</B>s";
+ } else {
+ print 'Has not logged on';
+ }
+
+ if ( $cust_pkg ) {
+ print ' since last bill ('. time2str("%C", $last_bill). ') - '.
+ $plandata{recur_included_hours}. ' total hours in plan<BR>';
+ } else {
+ print ' (no billing cycle available for unaudited account)<BR>';
+ }
+
+ print 'Input: <B>'. sprintf("%.3f", $input). '</B> megabytes<BR>';
+ print 'Output: <B>'. sprintf("%.3f", $output). '</B> megabytes<BR>';
+
+ print '<BR>';
+
+}
+
+#print qq!<BR><A HREF="../misc/sendconfig.cgi?$svcnum">Send account information</A>!;
+
+print qq!<A HREF="${p}edit/svc_acct.cgi?$svcnum">Edit this information</A><BR>!.
+ &ntable("#cccccc"). '<TR><TD>'. &ntable("#cccccc",2).
+ "<TR><TD ALIGN=\"right\">Service number</TD>".
+ "<TD BGCOLOR=\"#ffffff\">$svcnum</TD></TR>".
+ "<TR><TD ALIGN=\"right\">Service</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $part_svc->svc. "</TD></TR>".
+ "<TR><TD ALIGN=\"right\">Username</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct->username. "</TD></TR>"
+;
+
+print "<TR><TD ALIGN=\"right\">Domain</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $domain, "</TD></TR>";
+
+print "<TR><TD ALIGN=\"right\">Password</TD><TD BGCOLOR=\"#ffffff\">";
+my $password = $svc_acct->_password;
+if ( $password =~ /^\*\w+\* (.*)$/ ) {
+ $password = $1;
+ print "<I>(login disabled)</I> ";
+}
+if ( $conf->exists('showpasswords') ) {
+ print '<PRE>'. encode_entities($password). '</PRE>';
+} else {
+ print "<I>(hidden)</I>";
+}
+print "</TR></TD>";
+$password = '';
+
+if ( $conf->exists('security_phrase') ) {
+ my $sec_phrase = $svc_acct->sec_phrase;
+ print '<TR><TD ALIGN="right">Security phrase</TD><TD BGCOLOR="#ffffff">'.
+ $svc_acct->sec_phrase. '</TD></TR>';
+}
+
+my $svc_acct_pop = $svc_acct->popnum
+ ? qsearchs('svc_acct_pop',{'popnum'=>$svc_acct->popnum})
+ : '';
+print "<TR><TD ALIGN=\"right\">Access number</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct_pop->text. '</TD></TR>'
+ if $svc_acct_pop;
+
+if ($svc_acct->uid ne '') {
+ print "<TR><TD ALIGN=\"right\">Uid</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct->uid. "</TD></TR>",
+ "<TR><TD ALIGN=\"right\">Gid</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct->gid. "</TD></TR>",
+ "<TR><TD ALIGN=\"right\">GECOS</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct->finger. "</TD></TR>",
+ "<TR><TD ALIGN=\"right\">Home directory</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct->dir. "</TD></TR>",
+ "<TR><TD ALIGN=\"right\">Shell</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct->shell. "</TD></TR>",
+ "<TR><TD ALIGN=\"right\">Quota</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct->quota. "</TD></TR>"
+ ;
+} else {
+ print "<TR><TH COLSPAN=2>(No shell account)</TH></TR>";
+}
+
+if ($svc_acct->slipip) {
+ print "<TR><TD ALIGN=\"right\">IP address</TD><TD BGCOLOR=\"#ffffff\">".
+ ( ( $svc_acct->slipip eq "0.0.0.0" || $svc_acct->slipip eq '0e0' )
+ ? "<I>(Dynamic)</I>"
+ : $svc_acct->slipip
+ ). "</TD>";
+ my($attribute);
+ foreach $attribute ( grep /^radius_/, $svc_acct->fields ) {
+ #warn $attribute;
+ $attribute =~ /^radius_(.*)$/;
+ my $pattribute = $FS::raddb::attrib{$1};
+ print "<TR><TD ALIGN=\"right\">Radius (reply) $pattribute</TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct->getfield($attribute).
+ "</TD></TR>";
+ }
+ foreach $attribute ( grep /^rc_/, $svc_acct->fields ) {
+ #warn $attribute;
+ $attribute =~ /^rc_(.*)$/;
+ my $pattribute = $FS::raddb::attrib{$1};
+ print "<TR><TD ALIGN=\"right\">Radius (check) $pattribute: </TD>".
+ "<TD BGCOLOR=\"#ffffff\">". $svc_acct->getfield($attribute).
+ "</TD></TR>";
+ }
+} else {
+ print "<TR><TH COLSPAN=2>(No SLIP/PPP account)</TH></TR>";
+}
+
+print '<TR><TD ALIGN="right">RADIUS groups</TD><TD BGCOLOR="#ffffff">'.
+ join('<BR>', $svc_acct->radius_groups). '</TD></TR>';
+
+# Can this be abstracted further? Maybe a library function like
+# widget('HTML', 'view', $svc_acct) ? It would definitely make UI
+# style management easier.
+
+foreach (sort { $a cmp $b } $svc_acct->virtual_fields) {
+ print $svc_acct->pvf($_)->widget('HTML', 'view', $svc_acct->getfield($_)),
+ "\n";
+}
+%>
+</TABLE></TD></TR></TABLE>
+<%
+
+print '<BR><BR>';
+
+print join("\n", $conf->config('svc_acct-notes') ). '<BR><BR>'.
+ joblisting({'svcnum'=>$svcnum}, 1). '</BODY></HTML>';
+
+%>
diff --git a/httemplate/view/svc_broadband.cgi b/httemplate/view/svc_broadband.cgi
new file mode 100644
index 0000000..ae23386
--- /dev/null
+++ b/httemplate/view/svc_broadband.cgi
@@ -0,0 +1,142 @@
+<!-- mason kludge -->
+<%
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $svcnum = $1;
+my $svc_broadband = qsearchs( 'svc_broadband', { 'svcnum' => $svcnum } )
+ or die "svc_broadband: Unknown svcnum $svcnum";
+
+#false laziness w/all svc_*.cgi
+my $cust_svc = qsearchs( 'cust_svc', { 'svcnum' => $svcnum } );
+my $pkgnum = $cust_svc->getfield('pkgnum');
+my($cust_pkg, $custnum);
+if ($pkgnum) {
+ $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } );
+ $custnum = $cust_pkg->custnum;
+} else {
+ $cust_pkg = '';
+ $custnum = '';
+}
+#eofalse
+
+my $router = $svc_broadband->addr_block->router;
+
+if (not $router) { die "Could not lookup router for svc_broadband (svcnum $svcnum)" };
+
+my (
+ $routername,
+ $routernum,
+ $speed_down,
+ $speed_up,
+ $ip_addr
+ ) = (
+ $router->getfield('routername'),
+ $router->getfield('routernum'),
+ $svc_broadband->getfield('speed_down'),
+ $svc_broadband->getfield('speed_up'),
+ $svc_broadband->getfield('ip_addr')
+ );
+%>
+
+<%=header('Broadband Service View', menubar(
+ ( ( $custnum )
+ ? ( "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ( "Cancel this (unaudited) website" =>
+ "${p}misc/cancel-unaudited.cgi?$svcnum" )
+ ),
+ "Main menu" => $p,
+))
+%>
+
+<A HREF="<%=${p}%>edit/svc_broadband.cgi?<%=$svcnum%>">Edit this information</A>
+<BR>
+<%=ntable("#cccccc")%>
+ <TR>
+ <TD>
+ <%=ntable("#cccccc",2)%>
+ <TR>
+ <TD ALIGN="right">Service number</TD>
+ <TD BGCOLOR="#ffffff"><%=$svcnum%></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Router</TD>
+ <TD BGCOLOR="#ffffff"><%=$routernum%>: <%=$routername%></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Download Speed</TD>
+ <TD BGCOLOR="#ffffff"><%=$speed_down%></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Upload Speed</TD>
+ <TD BGCOLOR="#ffffff"><%=$speed_up%></TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">IP Address</TD>
+ <TD BGCOLOR="#ffffff"><%=$ip_addr%></TD>
+ </TR>
+ <TR COLSPAN="2"><TD></TD></TR>
+
+<%
+foreach (sort { $a cmp $b } $svc_broadband->virtual_fields) {
+ print $svc_broadband->pvf($_)->widget('HTML', 'view',
+ $svc_broadband->getfield($_)), "\n";
+}
+
+%>
+ </TABLE>
+ </TD>
+ </TR>
+</TABLE>
+
+<BR>
+<%=ntable("#cccccc", 2)%>
+<%
+ my $sb_router = qsearchs('router', { svcnum => $svcnum });
+ if ($sb_router) {
+ %>
+ <B>Router associated: <%=$sb_router->routername%> </B>
+ <A HREF="<%=popurl(2)%>edit/router.cgi?<%=$sb_router->routernum%>">
+ (details)
+ </A>
+ <BR>
+ <% my @addr_block;
+ if (@addr_block = $sb_router->addr_block) {
+ %>
+ <B>Address space </B>
+ <A HREF="<%=popurl(2)%>browse/addr_block.cgi">
+ (edit)
+ </A>
+ <BR>
+ <% print ntable("#cccccc", 1);
+ foreach (@addr_block) { %>
+ <TR>
+ <TD><%=$_->ip_gateway%>/<%=$_->ip_netmask%></TD>
+ </TR>
+ <% } %>
+ </TABLE>
+ <% } else { %>
+ <B>No address space allocated.</B>
+ <% } %>
+ <BR>
+ <%
+ } else {
+%>
+
+<FORM METHOD="GET" ACTION="<%=popurl(2)%>edit/router.cgi">
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%=$svcnum%>">
+Add router named
+ <INPUT TYPE="text" NAME="routername" SIZE="32" VALUE="Broadband router (<%=$svcnum%>)">
+ <INPUT TYPE="submit" VALUE="Add router">
+</FORM>
+
+<%
+}
+%>
+
+<BR>
+<%=joblisting({'svcnum'=>$svcnum}, 1)%>
+ </BODY>
+</HTML>
+
diff --git a/httemplate/view/svc_domain.cgi b/httemplate/view/svc_domain.cgi
new file mode 100755
index 0000000..cd9f79d
--- /dev/null
+++ b/httemplate/view/svc_domain.cgi
@@ -0,0 +1,108 @@
+<!-- mason kludge -->
+<%
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $svcnum = $1;
+my $svc_domain = qsearchs('svc_domain',{'svcnum'=>$svcnum});
+die "Unknown svcnum" unless $svc_domain;
+
+my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum});
+my $pkgnum = $cust_svc->getfield('pkgnum');
+my($cust_pkg, $custnum);
+if ($pkgnum) {
+ $cust_pkg=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+ $custnum=$cust_pkg->getfield('custnum');
+} else {
+ $cust_pkg = '';
+ $custnum = '';
+}
+
+my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
+die "Unknown svcpart" unless $part_svc;
+
+my $email = '';
+if ($svc_domain->catchall) {
+ my $svc_acct = qsearchs('svc_acct',{'svcnum'=> $svc_domain->catchall } );
+ die "Unknown svcpart" unless $svc_acct;
+ $email = $svc_acct->email;
+}
+
+my $domain = $svc_domain->domain;
+
+%>
+
+<%= header('Domain View', menubar(
+ ( ( $pkgnum || $custnum )
+ ? ( "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ( "Cancel this (unaudited) domain" =>
+ "${p}misc/cancel-unaudited.cgi?$svcnum" )
+ ),
+ "Main menu" => $p,
+)) %>
+
+Service #<%= $svcnum %>
+<BR>Service: <B><%= $part_svc->svc %></B>
+<BR>Domain name: <B><%= $domain %></B>
+<BR>Catch all email <A HREF="<%= ${p} %>misc/catchall.cgi?<%= $svcnum %>">(change)</A>:
+<%= $email ? "<B>$email</B>" : "<I>(none)<I>" %>
+<BR><BR><A HREF="<%= ${p} %>misc/whois.cgi?custnum=<%=$custnum%>;svcnum=<%=$svcnum%>;domain=<%=$domain%>">View whois information.</A>
+<BR><BR>
+<SCRIPT>
+ function areyousure(href) {
+ if ( confirm("Remove this record?") == true )
+ window.location.href = href;
+ }
+ function slave_areyousure() {
+ return confirm("Remove all records and slave from " + document.SlaveForm.recdata.value + "?");
+ }
+</SCRIPT>
+
+<% my @records; if ( @records = $svc_domain->domain_record ) { %>
+ <%= ntable("",2) %>
+ <tr><th>Zone</th><th>Type</th><th>Data</th></tr>
+
+ <% foreach my $domain_record ( @records ) {
+ my $type = $domain_record->rectype eq '_mstr'
+ ? "(slave)"
+ : $domain_record->recaf. ' '. $domain_record->rectype;
+ %>
+
+ <tr><td><%= $domain_record->reczone %></td>
+ <td><%= $type %></td>
+ <td><%= $domain_record->recdata %>
+
+ <% unless ( $domain_record->rectype eq 'SOA' ) { %>
+ (<A HREF="javascript:areyousure('<%=$p%>misc/delete-domain_record.cgi?<%=$domain_record->recnum%>')">delete</A>)
+ <% } %>
+ </td></tr>
+ <% } %>
+ </table>
+<% } %>
+
+<BR>
+<FORM METHOD="POST" ACTION="<%=$p%>edit/process/domain_record.cgi">
+<INPUT TYPE="hidden" NAME="svcnum" VALUE="<%=$svcnum%>">
+<INPUT TYPE="text" NAME="reczone">
+<INPUT TYPE="hidden" NAME="recaf" VALUE="IN"> IN
+ <SELECT NAME="rectype">
+<% foreach (qw( A NS CNAME MX PTR) ) { %>
+ <OPTION VALUE="<%=$_%>"><%=$_%></OPTION>
+<% } %>
+ </SELECT>
+<INPUT TYPE="text" NAME="recdata"> <INPUT TYPE="submit" VALUE="Add record">
+</FORM><BR><BR>or<BR><BR>
+<FORM NAME="SlaveForm" METHOD="POST" ACTION="<%=$p%>edit/process/domain_record.cgi">
+<INPUT TYPE="hidden" NAME="svcnum" VALUE="<%=$svcnum%>">
+
+<% if ( @records ) { %> Delete all records and <% } %>
+Slave from nameserver IP
+<INPUT TYPE="hidden" NAME="svcnum" VALUE="<%=$svcnum%>">
+<INPUT TYPE="hidden" NAME="reczone" VALUE="@">
+<INPUT TYPE="hidden" NAME="recaf" VALUE="IN">
+<INPUT TYPE="hidden" NAME="rectype" VALUE="_mstr">
+<INPUT TYPE="text" NAME="recdata"> <INPUT TYPE="submit" VALUE="Slave domain" onClick="return slave_areyousure()">
+</FORM>
+<BR><BR><%= joblisting({'svcnum'=>$svcnum}, 1) %>
+</BODY></HTML>
diff --git a/httemplate/view/svc_external.cgi b/httemplate/view/svc_external.cgi
new file mode 100644
index 0000000..59cc357
--- /dev/null
+++ b/httemplate/view/svc_external.cgi
@@ -0,0 +1,51 @@
+<!-- mason kludge -->
+<%
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $svcnum = $1;
+my $svc_external = qsearchs( 'svc_external', { 'svcnum' => $svcnum } )
+ or die "svc_external: Unknown svcnum $svcnum";
+
+#false laziness w/all svc_*.cgi
+my $cust_svc = qsearchs( 'cust_svc', { 'svcnum' => $svcnum } );
+my $pkgnum = $cust_svc->getfield('pkgnum');
+my($cust_pkg, $custnum);
+if ($pkgnum) {
+ $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } );
+ $custnum = $cust_pkg->custnum;
+} else {
+ $cust_pkg = '';
+ $custnum = '';
+}
+#eofalse
+
+%>
+
+<%= header('External Service View', menubar(
+ ( ( $custnum )
+ ? ( "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ( "Cancel this (unaudited) external service" =>
+ "${p}misc/cancel-unaudited.cgi?$svcnum" )
+ ),
+ "Main menu" => $p,
+)) %>
+
+<A HREF="<%=$p%>edit/svc_external.cgi?<%=$svcnum%>">Edit this information</A><BR>
+<%= ntable("#cccccc") %><TR><TD><%= ntable("#cccccc",2) %>
+
+<TR><TD ALIGN="right">Service number</TD>
+ <TD BGCOLOR="#ffffff"><%= $svcnum %></TD></TR>
+<TR><TD ALIGN="right">External ID</TD>
+ <TD BGCOLOR="#ffffff"><%= $svc_external->id %></TD></TR>
+<TR><TD ALIGN="right">Title</TD>
+ <TD BGCOLOR="#ffffff"><%= $svc_external->title %></TD></TR>
+
+<% foreach (sort { $a cmp $b } $svc_external->virtual_fields) { %>
+ <%= $svc_external->pvf($_)->widget('HTML', 'view', $svc_external->getfield($_)) %>
+<% } %>
+
+</TABLE></TD></TR></TABLE>
+<BR><%= joblisting({'svcnum'=>$svcnum}, 1) %>
+</BODY></HTML>
diff --git a/httemplate/view/svc_forward.cgi b/httemplate/view/svc_forward.cgi
new file mode 100755
index 0000000..52360bc
--- /dev/null
+++ b/httemplate/view/svc_forward.cgi
@@ -0,0 +1,84 @@
+<!-- mason kludge -->
+<%
+
+my $conf = new FS::Conf;
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $svcnum = $1;
+my $svc_forward = qsearchs('svc_forward',{'svcnum'=>$svcnum});
+die "Unknown svcnum" unless $svc_forward;
+
+my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum});
+my $pkgnum = $cust_svc->getfield('pkgnum');
+my($cust_pkg, $custnum);
+if ($pkgnum) {
+ $cust_pkg=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+ $custnum=$cust_pkg->getfield('custnum');
+} else {
+ $cust_pkg = '';
+ $custnum = '';
+}
+
+my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } )
+ or die "Unkonwn svcpart";
+
+print header('Mail Forward View', menubar(
+ ( ( $pkgnum || $custnum )
+ ? ( "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ( "Cancel this (unaudited) mail forward" =>
+ "${p}misc/cancel-unaudited.cgi?$svcnum" )
+ ),
+ "Main menu" => $p,
+));
+
+my($srcsvc,$dstsvc,$dst) = (
+ $svc_forward->srcsvc,
+ $svc_forward->dstsvc,
+ $svc_forward->dst,
+);
+my $src = $svc_forward->dbdef_table->column('src') ? $svc_forward->src : '';
+
+my $svc = $part_svc->svc;
+
+my $source;
+if ($srcsvc) {
+ my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$srcsvc})
+ or die "Corrupted database: no svc_acct.svcnum matching srcsvc $srcsvc";
+ $source = $svc_acct->email;
+} else {
+ $source = $src;
+}
+
+my $destination;
+if ($dstsvc) {
+ my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$dstsvc})
+ or die "Corrupted database: no svc_acct.svcnum matching dstsvc $dstsvc";
+ $destination = $svc_acct->email;
+} else {
+ $destination = $dst;
+}
+
+print qq!<A HREF="${p}edit/svc_forward.cgi?$svcnum">Edit this information</A>!.
+ ntable("#cccccc",2).
+ '<TR><TD ALIGN="right">Service number</TD>'.
+ qq!<TD BGCOLOR="#ffffff">$svcnum</TD></TR>!.
+ '<TR><TD ALIGN="right">Service</TD>'.
+ qq!<TD BGCOLOR="#ffffff">$svc</TD></TR>!.
+ qq!<TR><TD ALIGN="right">Email to</TD>!.
+ qq!<TD BGCOLOR="#ffffff">$source</TD></TR>!.
+ qq!<TR><TD ALIGN="right">Forwards to </TD>!.
+ qq!<TD BGCOLOR="#ffffff">$destination</TD></TR>!;
+
+foreach (sort { $a cmp $b } $svc_forward->virtual_fields) {
+ print $svc_forward->pvf($_)->widget('HTML', 'view', $svc_forward->getfield($_)),
+ "\n";
+}
+
+print qq! </TABLE>!.
+ '<BR>'. joblisting({'svcnum'=>$svcnum}, 1).
+ '</BODY></HTML>'
+;
+
+%>
diff --git a/httemplate/view/svc_www.cgi b/httemplate/view/svc_www.cgi
new file mode 100644
index 0000000..2980f84
--- /dev/null
+++ b/httemplate/view/svc_www.cgi
@@ -0,0 +1,61 @@
+<!-- mason kludge -->
+<%
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $svcnum = $1;
+my $svc_www = qsearchs( 'svc_www', { 'svcnum' => $svcnum } )
+ or die "svc_www: Unknown svcnum $svcnum";
+
+#false laziness w/all svc_*.cgi
+my $cust_svc = qsearchs( 'cust_svc', { 'svcnum' => $svcnum } );
+my $pkgnum = $cust_svc->getfield('pkgnum');
+my($cust_pkg, $custnum);
+if ($pkgnum) {
+ $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $pkgnum } );
+ $custnum = $cust_pkg->custnum;
+} else {
+ $cust_pkg = '';
+ $custnum = '';
+}
+#eofalse
+
+my $usersvc = $svc_www->usersvc;
+my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $usersvc } )
+ or die "svc_www: Unknown usersvc $usersvc";
+my $email = $svc_acct->email;
+
+my $domain_record = qsearchs('domain_record', { 'recnum' => $svc_www->recnum } )
+ or die "svc_www: Unknown recnum ". $svc_www->recnum;
+
+my $www = $domain_record->zone;
+
+print header('Website View', menubar(
+ ( ( $custnum )
+ ? ( "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ( "Cancel this (unaudited) website" =>
+ "${p}misc/cancel-unaudited.cgi?$svcnum" )
+ ),
+ "Main menu" => $p,
+)).
+ qq!<A HREF="${p}edit/svc_www.cgi?$svcnum">Edit this information</A><BR>!.
+ ntable("#cccccc"). '<TR><TD>'. ntable("#cccccc",2).
+ qq!<TR><TD ALIGN="right">Service number</TD>!.
+ qq!<TD BGCOLOR="#ffffff">$svcnum</TD></TR>!.
+ qq!<TR><TD ALIGN="right">Website name</TD>!.
+ qq!<TD BGCOLOR="#ffffff"><A HREF="http://$www">$www<A></TD></TR>!.
+ qq!<TR><TD ALIGN="right">Account</TD>!.
+ qq!<TD BGCOLOR="#ffffff"><A HREF="${p}view/svc_acct.cgi?$usersvc">$email</A></TD></TR>!;
+
+foreach (sort { $a cmp $b } $svc_www->virtual_fields) {
+ print $svc_www->pvf($_)->widget('HTML', 'view', $svc_www->getfield($_)),
+ "\n";
+}
+
+
+print '</TABLE></TD></TR></TABLE>'.
+ '<BR>'. joblisting({'svcnum'=>$svcnum}, 1).
+ '</BODY></HTML>'
+;
+%>
diff --git a/init.d/freeside-init b/init.d/freeside-init
new file mode 100644
index 0000000..1ca7dff
--- /dev/null
+++ b/init.d/freeside-init
@@ -0,0 +1,58 @@
+#! /bin/sh
+#
+# chkconfig: 345 86 16
+# description: Freeside daemons
+
+QUEUED_USER=%%%QUEUED_USER%%%
+
+FREESIDE_PATH="%%%FREESIDE_PATH%%%"
+
+SELFSERVICE_USER=%%%SELFSERVICE_USER%%%
+SELFSERVICE_MACHINES="%%%SELFSERVICE_MACHINES%%%"
+
+case "$1" in
+ start)
+ # Start daemons.
+ echo -n "Starting freeside-queued: "
+ freeside-queued $QUEUED_USER
+ echo "done."
+
+ for MACHINE in $SELFSERVICE_MACHINES; do
+ echo -n "Starting freeside-selfservice-server to $MACHINE: "
+ freeside-selfservice-server $SELFSERVICE_USER $MACHINE
+ echo "done."
+ done
+
+ ;;
+ stop)
+ # Stop daemons.
+ echo -n "Stopping freeside-queued: "
+ kill `cat /var/run/freeside-queued.pid`
+ echo "done."
+
+ if [ -e /var/run/freeside-selfservice-server.$SELFSERVICE_USER.pid ]
+ then
+ echo -n "Stopping (old) freeside-selfservice-server: "
+ kill `cat /var/run/freeside-selfservice-server.$SELFSERVICE_USER.pid`
+ rm /var/run/freeside-selfservice-server.$SELFSERVICE_USER.pid
+ fi
+
+ for MACHINE in $SELFSERVICE_MACHINES; do
+ echo -n "Stopping freeside-selfservice-server to $MACHINE: "
+ kill `cat /var/run/freeside-selfservice-server.$SELFSERVICE_USER.$MACHINE.pid`
+ echo "done."
+ done
+
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+ *)
+ echo "Usage: freeside {start|stop|restart}"
+ exit 1
+esac
+
+exit 0
+
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/Changes b/install/5.005/DBD-Pg-1.22-fixvercmp/Changes
new file mode 100644
index 0000000..c345628
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/Changes
@@ -0,0 +1,352 @@
+1.22 Wed Mar 26 22:33:44 EST 2003
+ - Win32 compile fix for snprintf [Joe Spears]
+ - Fix memory allocation problem in bytea escaping [Barrie Slaymaker]
+ - Add utf8 support [Dominic Mitchell <dom@semantico.com>]
+ - Transform Perl arrays into PostgreSQL arrays [Alexey Slynko]
+ - Fix for foreign_key_info() [Keith Keller]
+ - Fix PG_TEXT parameter binding
+ - Doc cleanups [turnstep]
+ - Fix warning from func($table, 'table_attributes') [turnstep]
+ - Added suppport for schemas [turnstep]
+ - Fix binary to a bytea field conversion [Chris Dunlop <chris@onthe.net.au>]
+1.21 Sun Jan 12 21:00:44 EST 2003
+ - System tables no longer returned by tables(). [Dave Rolsky]
+ - Fix table_attributes to handle removal of pg_relcheck in 7.3,
+ from Ian Barwick <barwick@gmx.net>
+ - Properly reset transaction status after failed transaction when
+ autocommit is off. Properly report transaction failure message.
+ Kai <kai@xs4all.nl>
+ - New pg_bool_tf database handle that when set to true booleans are
+ returned as 't'/'f' rather than 1/0.
+
+1.20 Wed Nov 27 16:19:26 2002
+ - Maintenance transferred to GBorg,
+ http://gborg.postgresql.org/project/dbdpg/projdisplay.php. Incremented
+ version number to reflect new management. [Bruce Momjian]
+ - README cleaned up. [Bruce Momjian]
+ - Added t/15funct.t, a series of tests that determine if the meta data
+ is working. [Thomas Lowery]
+ - Added implementations of column_info() and table_info(), and
+ primary_key_info(). [Thomas Lowery]
+ - The POD formatting was cleaned up. [David Wheeler]
+ - The preparser was updated to better handle escaped characters. [Rudy
+ Lippan]
+ - Removed redundant use of strlen() in pg_error() (Jason E. Stewart).
+ - Test suite cleaned up, converted to use Test::More, and updated to use
+ standard DBI environment variables for connecting to a test database.
+ [Jason E. Stewart]
+ - Added eg/lotest.pl as a demonstration of using large objects in buffers
+ rather than files. Contributed by Garth Webb.
+ - Added LISTEN/NOTIFY functionality. Congributed by Alex Pilosov.
+ - Added constants for common PostgreSQL data types, plus simple tests to
+ make sure that they work. These are exportable via "use DBD::Pg
+ qw(:pg_types);". [David Wheeler]
+ - Deprecatated the undocumented (and invalid) use of SQL_BINARY in
+ bind_param() and documented the correct approach: "bind_param($num,
+ $val { pg_type => PG_BYTEA });". Use of SQL_BINARY in bind_param() will
+ now issue a warning if $h->{Warn} is true. [David Wheeler]
+ - Removed invalid (and broken) support for SQL_BINARY in quote(). [David
+ Wheeler]
+ - Added App::Info::RDBMS::PostgreSQL to the distribution (but it won't
+ be installed) to help Makefile.PL find the PostgreSQL include and
+ library files. [David Wheeler]
+ - Fixed compile-time warnings. [David Wheeler and Jason E. Stewart]
+
+2002-04-27 Jeffrey W. Baker <jwbaker@acm.org>
+
+ - dbdimp.c: Add default at end of switch statement for pg_type attrib.
+ - t/13pgtype.t: test for above.
+
+2002-04-09 Jeffrey W. Baker <jwbaker@acm.org>
+
+ - Pg.pm, dbdimp.c: Applied patch from
+ Thomas A. Lowery <tlowery@stlowery.net> concerning metadata
+ in table_info and so forth.
+
+2002-03-06 Jeffrey W. Baker <jwbaker@acm.org>
+ - Pg.pm (quote): Applied patch from David Wheeler <david@wheeler.net>
+ to simplfiy and speed up quoting.
+ - t/11quoting.t: Tests for above patch.
+ - t/12placeholders.t: Tests for placeholder parsing in quoted strings.
+
+2002-03-06 Jeffrey W. Baker
+ - Version 1.10 uploaded to CPAN.
+
+1.01 Jun 27, 2001
+ - fixed core dump when trying to use a BYTEA value with
+ a byte outside 0..127 Alex Pilosov <alex@pilosoft.com>
+
+1.00 May 27, 2001
+ - Fetching all records now resets Active flag as it should.
+
+0.99 May 24, 2001
+ - fix the segmentation fault in pg_error.
+
+0.98 Apr 25, 2001
+ - bug-fix for core-dump after any failed function call.
+ - applied patch from Alex Pilosov <alex@pilosoft.com>
+ which adds support for the datatype bytea
+
+0.97 Apr 20, 2001
+ - fix bug in connect method, which erroneously set the userid
+ and the password to the environment variables DBI_USER and
+ DBI_PASS.
+ - applied patch from Jan-Pieter Cornet <john@pc.xs4all.nl>,
+ which removed the special handling of a backslash when
+ used for octal presentation. Now a backslash always will
+ be escaped.
+
+0.96 Apr 09, 2001
+ - remove memory-leak in ping function, bug-fix
+ from Doug Perham <dperham@wgate.com>
+ - correct the recognition of primary keys in
+ table_attributes(). Patch from Brian Powell
+ <brian@nicklebys.com>.
+ - applied patch from David D. Kilzer <ddkilzer@lubricants-oil.com>
+ which fixes a segmentation fault in DBD::pg::blob_read() when
+ reading LOBs that required perl to reallocate space for the
+ variable holding the scalar value
+ - updated test.pl to create a test blob larger than 256 bytes
+ (now 128 Kbytes)
+ - apply patch from Tom Lane, which fixes a seg-fault when
+ inserting large amounts of text.
+ - apply patch from Peter Haworth pmh@edison.ioppublishing.com,
+ which removes the newlines from the error messages and which
+ quotes date placeholders.
+
+0.95 Jul 10, 2000
+ - add Win32 port from Bob Kline <bkline@rksystems.com>.
+
+0.94 Jul 07, 2000
+ - applied patch from Rudy Lippan <almighty@randomc.com>
+ which fixes a memory-leak with failed connections.
+ - applied patch from Hein Roehrig <hein@acm.org>
+ which fixes a bug with escaping a backslash except for
+ octal presentation
+ - applied patch from Francis J. Lacoste <francis.lacoste@iNsu.COM
+ which fixes a segmentation fault when all binded parameters are NULL
+ - adapt test.pl to avoid warnings with postgresql-7.0
+ - added support for 'COPY FROM STDIN' and 'COPY TO STDOUT'
+ - added patch from Mark Stosberg <mark@summersault.com>
+ to enhance the table_attributes subroutine
+
+0.93 Sep 29, 1999
+ - it is required now to set the environment variables POSTGRES_INCLUDE
+ and POSTGRES_LIB for compiling the module.
+ - add Win32 port from Bob Kline <bkline@rksystems.com>.
+ - support for all large-object functions via the func
+ interface.
+ - fixed bug with placeholders and casts spotted by
+ mschout@gkg.net
+ - replaced the method attributes by the method table_attributes,
+ from Scott Williams <scott@james.com>.
+ - fix type definitions for type_info_all().
+ bug spotted by "carlos" <emarcet@intramed.net.ar>.
+ - now the Pg-specific quote() method also evaluates the
+ data-type paramater.
+
+0.92 Jun 16, 1999
+ - proposal from Philip Warner <pjw@rhyme.com.au>:
+ increase BUFSIZE from 1024 to 32768 in order to improve
+ I/O performance.
+ - bug-fix in Makefile.PL for $POSTGRES_HOME not defined
+ spotted by mdalphin@amgen.com (Mark Dalphin)
+ - bug-fix for data-type datetime in type_info_all
+ spotted by Alan Grover <awgrover@iconnect-inc.com>
+ - bug-fix for escaped 's spotted by Hankin <hankin@consultco.com>
+ - removed 'large objects' related tests from test.pl
+
+0.91 Feb 14, 1999
+ - removed restriction for commercial use in copyright
+ - corrected DATA_TYPE in type_info_all()
+
+0.90 Jan 15, 1998
+ - discard parameter authtype from connect string
+ - remove work-around for bug in the large object
+ interface of postgresql
+
+0.89 Nov 05, 1998
+ - bug-fix from Jan Iven <j.iven@rz.uni-sb.de>:
+ fix problem with quoting Null in bind variables.
+
+0.88 Oct 10, 1998
+ - fixed blob_read
+ - suppressed warning when testing DBI::errstr
+
+0.87 Sep 05, 1998
+ - Pg.xs adapted to Driver.xst from DBI-1.0
+ - major rewrite of module documentation
+ - major rewrite of the test script
+ - use built-in DBI method for $dbh->do
+ - add macro dHTR in order to avoid compile errors
+ with threaded perl5.005
+ - renamed attribute AutoEscape to pg_auto_escape
+ - renamed attribute SIZE to pg_size
+ - new attribute pg_type
+ - added support for DBI->data_sources($driver)
+ - added support for $dbh->table_info
+ - blob_read documented and added to test.pl
+ - added support for attr parameter in bind_param()
+
+0.86 Aug 21, 1998
+ - added /usr/lib/ to search path for libpq.
+ - added ChopBlanks, patch from
+ Victor Krasinsky <victor@rdovira.lviv.ua>
+ - changed test.pl to test multiple database handles
+
+0.85 July 19, 1998
+ - non-printable characters in parameters will not be
+ converted to '.'. They are passed unchanged to the
+ database.
+
+0.84 July 18, 1998
+ - bug-fix from Max Cohan <mcohan@adnc.net>:
+ check for \xxx presentation before escaping backslash
+ in parameters.
+ - introduce new database handle attribute AutoEscape, which
+ controls escaping of quotes and backslashes in parameters.
+ When set to on, all quotes except at the beginning and
+ at the end of a line will be escaped and all backslashes
+ except when used to indicate an octal presentation (\xxx)
+ will be escaped. Default of AutoEscape is on.
+
+0.83 July 10, 1998
+ - bug-fix from Max Cohan <mcohan@adnc.net>:
+ using traces together with undef in place-holders dumped
+ core.
+
+0.82 June 20, 1998
+ - bug-fix from Matthew Lenz <matthew@nocturnal.org>:
+ corrected include path in Makefile.PL .
+ - added 'use strict;' to test.pl
+
+0.81 June 13, 1998
+ - bug-fix from Rolf Grossmann <grossman@securitas.net>:
+ undefined parameters in an execute statement will be
+ translated from 'undef' to 'NULL'. Also every parameter
+ for bind_param() will be quoted by default (escape quote
+ and backslash). Appropriate tests have been added to test.pl.
+ - change ping method to use libpq-interface.
+
+0.80 June 07, 1998
+ - adapted to postgresql-6.4:
+ the backend protocol has changed, which needs an adapted
+ ping method. A ping-test has been added to the test-script.
+ Also some type identifiers have changed.
+
+0.73 June 03, 1998
+ - changed include directives in Makefile.PL from
+ archlib to installarchlib and from sitearch to
+ installsitearch (Tony.Curtis@vcpc.univie.ac.at).
+ - applied patch from Junio Hamano <junio@twinsun.com>
+ quote method also doubles backslash.
+
+0.72 April 20, 1998
+ - applied patch from Michael J Schout <mschout@gkg.net>
+ which fixed the bug with queries containing the cast
+ operator.
+ - applied patch from "Irving Reid" <irving@tor.securecomputing.com>
+ which fixed a memory leak.
+
+0.71 April 04, 1998
+ - applied patch from "Irving Reid"
+ <irving@tor.securecomputing.com> which fixed the
+ the problem with the InactiveDestroy message.
+
+0.70 March 28, 1998
+ - linking again with the shared version of libpq
+ due to problems on several operating systems.
+
+0.69 March 6, 1998
+ - expanded the search path for include files
+ - module is now linked with static libpq.a
+
+0.68 March 3, 1998
+ - return to UNIX domain sockets in test-scripts
+
+0.67 February 21, 1998
+ - remove part of Driver.xst due to compile
+ error on some systems.
+
+0.66 February 19, 1998
+ - remove defines in Pg.h so that
+ it compiles also with postgresql-6.2.1
+ - changed ping method: set RaiseError=0
+
+0.65 February 14, 1998
+ - adapted to changes in DBI-0.91, so that the
+ default setting for AutoCommit and PrintError is
+ again conformant to the DBI specs.
+
+0.64 February 01, 1998
+ - changed syntax of data_source (ODBC-conformant):
+ 'dbi:Pg:dbname=dbname;host=host;port=port'
+ !!! PLEASE ADAPT YOUR SCRIPTS !!!
+ - implemented place-holders
+ - implemented ping-method
+ - added support for $dbh->{RaiseError} and $dbh->{PrintError},
+ note: DBI-default for PrintError is on !
+ - allow commit and rollback only if AutoCommit = off
+ - added documentation for $dbh->tables;
+ - new method to get meta-information about a given table:
+ $dbh->DBD::Pg::db::attributes($table);
+ - host-parameter in test.pl is set explicitly to localhost
+
+0.63 October 05, 1997
+ - adapted to PostgreSQL-6.2:
+ o $sth->rows as well as $sth->execute
+ and $sth->do return the number of
+ affected rows even for non-Select
+ statements.
+ o support for password authorization added,
+ please check the man-page for pg_passwd.
+ - the data_source parameter of the connect
+ method accepts two additional parameters
+ which are treated as host and port:
+ DBI->connect("dbi:Pg:dbname:host:port", "uid", "pwd")
+ - support for AutoCommit, please read the
+ module documentation for impacts on your
+ scripts !
+ - more perl-ish handling of data type bool,
+ please read the module documentation for
+ impacts on your scripts !
+
+0.62 August 26, 1997
+ - added blobs/README
+
+0.61 August 23, 1997
+ - adapted to DBI-0.89/Driver.xst
+ - added support for blob_read
+
+0.52 August 15, 1997
+ - added support for literal $sth->{'TYPE'},
+ pg_type.pl / pg_type.pm.
+
+0.51 August 12, 1997
+ - changed attributes to be DBI conformant:
+ o OID_STATUS to pg_oid_status
+ o CMD_STATUS to pg_cmd_status
+
+0.5 August 05, 1997
+ - support for user authentication
+ - support for bind_columns
+ - added $dbh->tables
+
+0.4 Jun 24, 1997
+ - adapted to DBI-0.84:
+ o new syntax for DBI->connect !
+ o execute returns 0E0 -> n for SELECT stmt
+ -1 for non SELECT stmt
+ -2 on error
+ - new attribute $sth->{'OID_STATUS'}
+ - new attribute $sth->{'CMD_STATUS'}
+
+0.3 Apr 24, 1997
+ - bug fix release, ( still alpha ! )
+
+0.2 Mar 13, 1997
+ - complete rewrite, ( still alpha ! )
+
+0.1 Feb 15, 1997
+ - creation, ( totally pre-alpha ! )
+
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/MANIFEST b/install/5.005/DBD-Pg-1.22-fixvercmp/MANIFEST
new file mode 100644
index 0000000..7d1b700
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/MANIFEST
@@ -0,0 +1,38 @@
+Changes
+MANIFEST
+Makefile.PL
+Pg.h
+Pg.pm
+Pg.xs
+README
+README.win32
+dbd-pg.pod
+dbdimp.c
+dbdimp.h
+eg/ApacheDBI.pl
+eg/lotest.pl
+eg/notify_test.patch
+t/00basic.t
+t/01connect.t
+t/01constants.t
+t/01setup.t
+t/02prepare.t
+t/03bind.t
+t/04execute.t
+t/05fetch.t
+t/06disconnect.t
+t/07reuse.t
+t/08txn.t
+t/09autocommit.t
+t/11quoting.t
+t/12placeholders.t
+t/13pgtype.t
+t/15funct.t
+t/99cleanup.t
+t/lib/App/Info.pm
+t/lib/App/Info/Handler.pm
+t/lib/App/Info/Handler/Prompt.pm
+t/lib/App/Info/RDBMS.pm
+t/lib/App/Info/RDBMS/PostgreSQL.pm
+t/lib/App/Info/Request.pm
+t/lib/App/Info/Util.pm
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/Makefile.PL b/install/5.005/DBD-Pg-1.22-fixvercmp/Makefile.PL
new file mode 100644
index 0000000..0633280
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/Makefile.PL
@@ -0,0 +1,83 @@
+
+# $Id: Makefile.PL,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+use ExtUtils::MakeMaker;
+use Config;
+use strict;
+
+use DBI 1.00;
+use DBI::DBD;
+
+my $lib;
+BEGIN {
+ my %sep = (MacOS => ':',
+ MSWin32 => '\\',
+ os2 => '\\',
+ VMS => '\\',
+ NetWare => '\\',
+ dos => '\\');
+ my $s = $sep{$^O} || '/';
+ $lib = join $s, 't', 'lib';
+}
+
+use lib $lib;
+print "Configuring Pg\n";
+print "Remember to actually read the README file !\n";
+
+my $POSTGRES_INCLUDE;
+my $POSTGRES_LIB;
+
+if ((!$ENV{POSTGRES_INCLUDE} or !$ENV{POSTGRES_LIB}) and !$ENV{POSTGRES_HOME}) {
+ # Use App::Info to get the data we need.
+ require App::Info::RDBMS::PostgreSQL;
+ require App::Info::Handler::Prompt;
+ my $p = App::Info::Handler::Prompt->new;
+ my $pg = App::Info::RDBMS::PostgreSQL->new(on_unknown => $p);
+ $POSTGRES_INCLUDE = $pg->inc_dir;
+ $POSTGRES_LIB = $pg->lib_dir;
+} elsif ((!$ENV{POSTGRES_INCLUDE} or !$ENV{POSTGRES_LIB}) and $ENV{POSTGRES_HOME}) {
+ $POSTGRES_INCLUDE = "$ENV{POSTGRES_HOME}/include";
+ $POSTGRES_LIB = "$ENV{POSTGRES_HOME}/lib";
+} else {
+ $POSTGRES_INCLUDE = "$ENV{POSTGRES_INCLUDE}";
+ $POSTGRES_LIB = "$ENV{POSTGRES_LIB}";
+}
+
+my $os = $^O;
+print "OS: $os\n";
+
+my $dbi_arch_dir;
+if ($os eq 'MSWin32') {
+ $dbi_arch_dir = "\$(INSTALLSITEARCH)/auto/DBI";
+} else {
+ $dbi_arch_dir = dbd_dbi_arch_dir();
+}
+
+my %opts = (
+ NAME => 'DBD::Pg',
+ VERSION_FROM => 'Pg.pm',
+ INC => "-I$POSTGRES_INCLUDE -I$dbi_arch_dir",
+ OBJECT => "Pg\$(OBJ_EXT) dbdimp\$(OBJ_EXT)",
+ LIBS => ["-L$POSTGRES_LIB -lpq"],
+ AUTHOR => 'http://gborg.postgresql.org/project/dbdpg/projdisplay.php',
+ ABSTRACT => 'PostgreSQL database driver for the DBI module',
+ PREREQ_PM => { 'Test::Simple' => 0.17 }, # Need Test::More
+);
+
+if ($os eq 'hpux') {
+ my $osvers = $Config{osvers};
+ if ($osvers < 10) {
+ print "Warning: Forced to build static not dynamic on $os $osvers.\a\n";
+ $opts{LINKTYPE} = 'static';
+ }
+}
+
+if ($Config{dlsrc} =~ /dl_none/) {
+ $opts{LINKTYPE} = 'static';
+}
+
+WriteMakefile(%opts);
+
+exit(0);
+
+# end of Makefile.PL
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/Pg.h b/install/5.005/DBD-Pg-1.22-fixvercmp/Pg.h
new file mode 100644
index 0000000..b77a9f8
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/Pg.h
@@ -0,0 +1,46 @@
+/*
+ $Id: Pg.h,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+ Copyright (c) 1997,1998,1999,2000 Edmund Mergl
+ Portions Copyright (c) 1994,1995,1996,1997 Tim Bunce
+
+ You may distribute under the terms of either the GNU General Public
+ License or the Artistic License, as specified in the Perl README file.
+
+*/
+
+
+#ifdef WIN32
+static int errno;
+#endif
+
+#include "libpq-fe.h"
+
+#ifdef NEVER
+#include<sys/stat.h>
+#include "libpq/libpq-fs.h"
+#endif
+#ifndef INV_READ
+#define INV_READ 0x00040000
+#endif
+#ifndef INV_WRITE
+#define INV_WRITE 0x00020000
+#endif
+
+#ifdef BUFSIZ
+#undef BUFSIZ
+#endif
+/* this should improve I/O performance for large objects */
+#define BUFSIZ 32768
+
+
+#define NEED_DBIXS_VERSION 93
+
+#include <DBIXS.h> /* installed by the DBI module */
+
+#include "dbdimp.h" /* read in our implementation details */
+
+#include <dbd_xsh.h> /* installed by the DBI module */
+
+
+/* end of Pg.h */
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/Pg.pm b/install/5.005/DBD-Pg-1.22-fixvercmp/Pg.pm
new file mode 100644
index 0000000..284e563
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/Pg.pm
@@ -0,0 +1,1913 @@
+
+# $Id: Pg.pm,v 1.1 2004-04-29 09:21:28 ivan Exp $
+#
+# Copyright (c) 1997,1998,1999,2000 Edmund Mergl
+# Copyright (c) 2002 Jeffrey W. Baker
+# Portions Copyright (c) 1994,1995,1996,1997 Tim Bunce
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the Perl README file.
+
+
+require 5.004;
+
+$DBD::Pg::VERSION = '1.22';
+
+{
+ package DBD::Pg;
+
+ use DBI ();
+ use DynaLoader ();
+ use Exporter ();
+ @ISA = qw(DynaLoader Exporter);
+
+ %EXPORT_TAGS = (
+ pg_types => [ qw(
+ PG_BOOL PG_BYTEA PG_CHAR PG_INT8 PG_INT2 PG_INT4 PG_TEXT PG_OID
+ PG_FLOAT4 PG_FLOAT8 PG_ABSTIME PG_RELTIME PG_TINTERVAL PG_BPCHAR
+ PG_VARCHAR PG_DATE PG_TIME PG_DATETIME PG_TIMESPAN PG_TIMESTAMP
+ )]);
+
+ Exporter::export_ok_tags('pg_types');
+
+ require_version DBI 1.00;
+
+ bootstrap DBD::Pg $VERSION;
+
+ $err = 0; # holds error code for DBI::err
+ $errstr = ""; # holds error string for DBI::errstr
+ $drh = undef; # holds driver handle once initialized
+
+ sub driver{
+ return $drh if $drh;
+ my($class, $attr) = @_;
+
+ $class .= "::dr";
+
+ # not a 'my' since we use it above to prevent multiple drivers
+
+ $drh = DBI::_new_drh($class, {
+ 'Name' => 'Pg',
+ 'Version' => $VERSION,
+ 'Err' => \$DBD::Pg::err,
+ 'Errstr' => \$DBD::Pg::errstr,
+ 'Attribution' => 'PostgreSQL DBD by Edmund Mergl',
+ });
+
+ $drh;
+ }
+
+ ## Used by both the dr and db packages
+ sub pg_server_version {
+ my $dbh = shift;
+ return $dbh->{pg_server_version} if defined $dbh->{pg_server_version};
+ my ($version) = $dbh->selectrow_array("SELECT version();");
+ return 0 unless $version =~ /^PostgreSQL ([\d\.]+)/;
+ $dbh{pg_server_version} = $1;
+ return $dbh{pg_server_version};
+ }
+
+ sub pg_use_catalog {
+ my $dbh = shift;
+ my $version = DBD::Pg::pg_server_version($dbh);
+ $version =~ /^(\d+\.\d+)/;
+ return $1 < 7.3 ? "" : "pg_catalog.";
+ }
+
+ 1;
+}
+
+
+{ package DBD::Pg::dr; # ====== DRIVER ======
+ use strict;
+
+ sub data_sources {
+ my $drh = shift;
+ my $dbh = DBD::Pg::dr::connect($drh, 'dbname=template1') or return undef;
+ $dbh->{AutoCommit} = 1;
+ my $CATALOG = DBD::Pg::pg_use_catalog($dbh);
+ my $sth = $dbh->prepare("SELECT datname FROM ${CATALOG}pg_database ORDER BY datname");
+ $sth->execute or return undef;
+ my (@sources, @datname);
+ while (@datname = $sth->fetchrow_array) {
+ push @sources, "dbi:Pg:dbname=$datname[0]";
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ return @sources;
+ }
+
+
+ sub connect {
+ my($drh, $dbname, $user, $auth)= @_;
+
+ # create a 'blank' dbh
+
+ my $Name = $dbname;
+ $Name =~ s/^.*dbname\s*=\s*//;
+ $Name =~ s/\s*;.*$//;
+
+ $user = "" unless defined($user);
+ $auth = "" unless defined($auth);
+
+ $user = $ENV{DBI_USER} if $user eq "";
+ $auth = $ENV{DBI_PASS} if $auth eq "";
+
+ $user = "" unless defined($user);
+ $auth = "" unless defined($auth);
+
+ my($dbh) = DBI::_new_dbh($drh, {
+ 'Name' => $Name,
+ 'User' => $user, 'CURRENT_USER' => $user,
+ });
+
+ # Connect to the database..
+ DBD::Pg::db::_login($dbh, $dbname, $user, $auth) or return undef;
+
+ $dbh;
+ }
+
+}
+
+
+{ package DBD::Pg::db; # ====== DATABASE ======
+ use strict;
+ use Carp ();
+
+ sub prepare {
+ my($dbh, $statement, @attribs)= @_;
+
+ # create a 'blank' sth
+
+ my $sth = DBI::_new_sth($dbh, {
+ 'Statement' => $statement,
+ });
+
+ DBD::Pg::st::_prepare($sth, $statement, @attribs) or return undef;
+
+ $sth;
+ }
+
+
+ sub ping {
+ my($dbh) = @_;
+
+ local $SIG{__WARN__} = sub { } if $dbh->{PrintError};
+ local $dbh->{RaiseError} = 0 if $dbh->{RaiseError};
+ my $ret = DBD::Pg::db::_ping($dbh);
+
+ return $ret;
+ }
+
+ # Column expected in statement handle returned.
+ # table_cat, table_schem, table_name, column_name, data_type, type_name,
+ # column_size, buffer_length, DECIMAL_DIGITS, NUM_PREC_RADIX, NULLABLE,
+ # REMARKS, COLUMN_DEF, SQL_DATA_TYPE, SQL_DATETIME_SUB, CHAR_OCTET_LENGTH,
+ # ORDINAL_POSITION, IS_NULLABLE
+ # The result set is ordered by TABLE_CAT, TABLE_SCHEM,
+ # TABLE_NAME and ORDINAL_POSITION.
+
+ sub column_info {
+ my ($dbh) = shift;
+ my @attrs = @_;
+ # my ($dbh, $catalog, $schema, $table, $column) = @_;
+ my $CATALOG = DBD::Pg::pg_use_catalog($dbh);
+
+ my @wh = ();
+ my @flds = qw/catname n.nspname c.relname a.attname/;
+
+ for my $idx (0 .. $#attrs) {
+ next if ($flds[$idx] eq 'catname'); # Skip catalog
+ if(defined $attrs[$idx] and length $attrs[$idx]) {
+ # Insure that the value is enclosed in single quotes.
+ $attrs[$idx] =~ s/^'?(\w+)'?$/'$1'/;
+ if ($attrs[$idx] =~ m/[,%]/) {
+ # contains a meta character.
+ push( @wh, q{( } . join ( " OR "
+ , map { m/\%/
+ ? qq{$flds[$idx] ILIKE $_ }
+ : qq{$flds[$idx] = $_ }
+ } (split /,/, $attrs[$idx]) )
+ . q{ )}
+ );
+ }
+ else {
+ push( @wh, qq{$flds[$idx] = $attrs[$idx]} );
+ }
+ }
+ }
+
+ my $wh = ""; # ();
+ $wh = join( " AND ", '', @wh ) if (@wh);
+ my $version = DBD::Pg::pg_server_version($dbh);
+ $version =~ /^(\d+\.\d+)/;
+ $version = $1;
+ my $showschema = $version < 7.3 ? "NULL::text" : "n.nspname";
+ my $schemajoin = $version < 7.3 ? "" : "LEFT JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace)";
+ my $col_info_sql = qq{
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , $showschema AS "TABLE_SCHEM"
+ , c.relname AS "TABLE_NAME"
+ , a.attname AS "COLUMN_NAME"
+ , t.typname AS "DATA_TYPE"
+ , NULL::text AS "TYPE_NAME"
+ , a.attlen AS "COLUMN_SIZE"
+ , NULL::text AS "BUFFER_LENGTH"
+ , NULL::text AS "DECIMAL_DIGITS"
+ , NULL::text AS "NUM_PREC_RADIX"
+ , a.attnotnull AS "NULLABLE"
+ , NULL::text AS "REMARKS"
+ , a.atthasdef AS "COLUMN_DEF"
+ , NULL::text AS "SQL_DATA_TYPE"
+ , NULL::text AS "SQL_DATETIME_SUB"
+ , NULL::text AS "CHAR_OCTET_LENGTH"
+ , a.attnum AS "ORDINAL_POSITION"
+ , a.attnotnull AS "IS_NULLABLE"
+ , a.atttypmod as atttypmod
+ , a.attnotnull as attnotnull
+ , a.atthasdef as atthasdef
+ , a.attnum as attnum
+ FROM
+ ${CATALOG}pg_attribute a
+ , ${CATALOG}pg_type t
+ , ${CATALOG}pg_class c
+ $schemajoin
+ WHERE
+ a.attrelid = c.oid
+ AND a.attnum >= 0
+ AND t.oid = a.atttypid
+ AND c.relkind in ('r','v')
+ $wh
+ ORDER BY 2, 3, 4
+ };
+
+ my $sth = $dbh->prepare( $col_info_sql ) or return undef;
+ $sth->execute();
+
+ return $sth;
+ }
+
+ sub primary_key_info {
+ my $dbh = shift;
+ my ($catalog, $schema, $table) = @_;
+ my @attrs = @_;
+ my $CATALOG = DBD::Pg::pg_use_catalog($dbh);
+
+ # TABLE_CAT:, TABLE_SCHEM:, TABLE_NAME:, COLUMN_NAME:, KEY_SEQ:
+ # , PK_NAME:
+
+ my @wh = (); my @dat = (); # Used to hold data for the attributes.
+
+ my $version = DBD::Pg::pg_server_version($dbh);
+ $version =~ /^(\d+\.\d+)/;
+ $version = $1;
+
+ my @flds = qw/catname u.usename bc.relname/;
+ $flds[1] = 'n.nspname' unless ($version < 7.3);
+
+ for my $idx (0 .. $#attrs) {
+ next if ($flds[$idx] eq 'catname'); # Skip catalog
+ if(defined $attrs[$idx] and length $attrs[$idx]) {
+ if ($attrs[$idx] =~ m/[,%_?]/) {
+ # contains a meta character.
+ push( @wh, q{( } . join ( " OR "
+ , map { push(@dat, $_);
+ m/[%_?]/
+ ? qq{$flds[$idx] iLIKE ? }
+ : qq{$flds[$idx] = ? }
+ } (split /,/, $attrs[$idx]) )
+ . q{ )}
+ );
+ }
+ else {
+ push( @dat, $attrs[$idx] );
+ push( @wh, qq{$flds[$idx] = ? } );
+ }
+ }
+ }
+
+ my $wh = '';
+ $wh = join( " AND ", '', @wh ) if (@wh);
+
+ # Base primary key selection query borrowed from phpPgAdmin.
+ my $showschema = $version < 7.3 ? "NULL::text" : "n.nspname";
+ my $schemajoin = $version < 7.3 ? "" : "LEFT JOIN pg_catalog.pg_namespace n ON (n.oid = bc.relnamespace)";
+ my $pri_key_sql = qq{
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , $showschema AS "TABLE_SCHEM"
+ , bc.relname AS "TABLE_NAME"
+ , a.attname AS "COLUMN_NAME"
+ , a.attnum AS "KEY_SEQ"
+ , ic.relname AS "PK_NAME"
+ FROM
+ ${CATALOG}pg_index i
+ , ${CATALOG}pg_attribute a
+ , ${CATALOG}pg_class ic
+ , ${CATALOG}pg_class bc
+ $schemajoin
+ WHERE
+ i.indrelid = bc.oid
+ AND i.indexrelid = ic.oid
+ AND
+ (
+ i.indkey[0] = a.attnum
+ OR
+ i.indkey[1] = a.attnum
+ OR
+ i.indkey[2] = a.attnum
+ OR
+ i.indkey[3] = a.attnum
+ OR
+ i.indkey[4] = a.attnum
+ OR
+ i.indkey[5] = a.attnum
+ OR
+ i.indkey[6] = a.attnum
+ OR
+ i.indkey[7] = a.attnum
+ OR
+ i.indkey[8] = a.attnum
+ OR
+ i.indkey[9] = a.attnum
+ OR
+ i.indkey[10] = a.attnum
+ OR
+ i.indkey[11] = a.attnum
+ OR
+ i.indkey[12] = a.attnum
+ )
+ AND a.attrelid = bc.oid
+ AND i.indproc = '0'::oid
+ AND i.indisprimary = 't'
+ $wh
+ ORDER BY 2, 3, 5
+ };
+
+ my $sth = $dbh->prepare( $pri_key_sql ) or return undef;
+ $sth->execute(@dat);
+
+ return $sth;
+ }
+
+ sub foreign_key_info {
+ # todo: verify schema work as expected
+ # add code to handle multiple-column keys correctly
+ # return something nicer for pre-7.3?
+ # try to clean up SQL, perl code
+ # create a test script?
+
+ my $dbh = shift;
+ my ($pk_catalog, $pk_schema, $pk_table,
+ $fk_catalog, $fk_schema, $fk_table) = @_;
+
+ # this query doesn't work for Postgres before 7.3
+ my $version = $dbh->pg_server_version;
+ $version =~ /^(\d+)\.(\d)/;
+ return undef if ($1.$2 < 73);
+
+ # Used to hold data for the attributes.
+ my @dat = ();
+
+ # SQL to find primary/unique keys of a table
+ my $pkey_sql = qq{
+ SELECT
+ NULL::text AS PKTABLE_CAT,
+ pknam.nspname AS PKTABLE_SCHEM,
+ pkc.relname AS PKTABLE_NAME,
+ pka.attname AS PKCOLUMN_NAME,
+ NULL::text AS FKTABLE_CAT,
+ NULL::text AS FKTABLE_SCHEM,
+ NULL::text AS FKTABLE_NAME,
+ NULL::text AS FKCOLUMN_NAME,
+ pkcon.conkey[1] AS KEY_SEQ,
+ CASE
+ WHEN pkcon.confupdtype = 'c' THEN 0
+ WHEN pkcon.confupdtype = 'r' THEN 1
+ WHEN pkcon.confupdtype = 'n' THEN 2
+ WHEN pkcon.confupdtype = 'a' THEN 3
+ WHEN pkcon.confupdtype = 'd' THEN 4
+ END AS UPDATE_RULE,
+ CASE
+ WHEN pkcon.confdeltype = 'c' THEN 0
+ WHEN pkcon.confdeltype = 'r' THEN 1
+ WHEN pkcon.confdeltype = 'n' THEN 2
+ WHEN pkcon.confdeltype = 'a' THEN 3
+ WHEN pkcon.confdeltype = 'd' THEN 4
+ END AS DELETE_RULE,
+ NULL::text AS FK_NAME,
+ pkcon.conname AS PK_NAME,
+ CASE
+ WHEN pkcon.condeferrable = 'f' THEN 7
+ WHEN pkcon.condeferred = 't' THEN 6
+ WHEN pkcon.condeferred = 'f' THEN 5
+ END AS DEFERRABILITY,
+ CASE
+ WHEN pkcon.contype = 'p' THEN 'PRIMARY'
+ WHEN pkcon.contype = 'u' THEN 'UNIQUE'
+ END AS UNIQUE_OR_PRIMARY
+ FROM
+ pg_constraint AS pkcon
+ JOIN
+ pg_class pkc ON pkc.oid=pkcon.conrelid
+ JOIN
+ pg_namespace pknam ON pkcon.connamespace=pknam.oid
+ JOIN
+ pg_attribute pka ON pka.attnum=pkcon.conkey[1] AND pka.attrelid=pkc.oid
+ };
+
+ # SQL to find foreign keys of a table
+ my $fkey_sql = qq{
+ SELECT
+ NULL::text AS PKTABLE_CAT,
+ pknam.nspname AS PKTABLE_SCHEM,
+ pkc.relname AS PKTABLE_NAME,
+ pka.attname AS PKCOLUMN_NAME,
+ NULL::text AS FKTABLE_CAT,
+ fknam.nspname AS FKTABLE_SCHEM,
+ fkc.relname AS FKTABLE_NAME,
+ fka.attname AS FKCOLUMN_NAME,
+ fkcon.conkey[1] AS KEY_SEQ,
+ CASE
+ WHEN fkcon.confupdtype = 'c' THEN 0
+ WHEN fkcon.confupdtype = 'r' THEN 1
+ WHEN fkcon.confupdtype = 'n' THEN 2
+ WHEN fkcon.confupdtype = 'a' THEN 3
+ WHEN fkcon.confupdtype = 'd' THEN 4
+ END AS UPDATE_RULE,
+ CASE
+ WHEN fkcon.confdeltype = 'c' THEN 0
+ WHEN fkcon.confdeltype = 'r' THEN 1
+ WHEN fkcon.confdeltype = 'n' THEN 2
+ WHEN fkcon.confdeltype = 'a' THEN 3
+ WHEN fkcon.confdeltype = 'd' THEN 4
+ END AS DELETE_RULE,
+ fkcon.conname AS FK_NAME,
+ pkcon.conname AS PK_NAME,
+ CASE
+ WHEN fkcon.condeferrable = 'f' THEN 7
+ WHEN fkcon.condeferred = 't' THEN 6
+ WHEN fkcon.condeferred = 'f' THEN 5
+ END AS DEFERRABILITY,
+ CASE
+ WHEN pkcon.contype = 'p' THEN 'PRIMARY'
+ WHEN pkcon.contype = 'u' THEN 'UNIQUE'
+ END AS UNIQUE_OR_PRIMARY
+ FROM
+ pg_constraint AS fkcon
+ JOIN
+ pg_constraint AS pkcon ON fkcon.confrelid=pkcon.conrelid
+ AND fkcon.confkey=pkcon.conkey
+ JOIN
+ pg_class fkc ON fkc.oid=fkcon.conrelid
+ JOIN
+ pg_class pkc ON pkc.oid=fkcon.confrelid
+ JOIN
+ pg_namespace pknam ON pkcon.connamespace=pknam.oid
+ JOIN
+ pg_namespace fknam ON fkcon.connamespace=fknam.oid
+ JOIN
+ pg_attribute fka ON fka.attnum=fkcon.conkey[1] AND fka.attrelid=fkc.oid
+ JOIN
+ pg_attribute pka ON pka.attnum=pkcon.conkey[1] AND pka.attrelid=pkc.oid
+ };
+
+ # if schema are provided, use this SQL
+ my $pk_schema_sql = " AND pknam.nspname = ? ";
+ my $fk_schema_sql = " AND fknam.nspname = ? ";
+
+ my $key_sql;
+
+ # if $fk_table: generate SQL stub, which will be same
+ # whether or not $pk_table supplied
+ if ($fk_table)
+ {
+ $key_sql = $fkey_sql . qq{
+ WHERE
+ fkc.relname = ?
+ };
+ push @dat, $fk_table;
+
+ if ($fk_schema)
+ {
+ $key_sql .= $fk_schema_sql;
+ push @dat,$fk_schema;
+ }
+ }
+
+ # if $fk_table and $pk_table: (defined by DBI, not SQL/CLI)
+ # return foreign key of $fk_table that refers to $pk_table
+ # (if any)
+ if ($pk_table and $fk_table)
+ {
+ $key_sql .= qq{
+ AND
+ pkc.relname = ?
+ };
+ push @dat, $pk_table;
+
+ if ($pk_schema)
+ {
+ $key_sql .= $pk_schema_sql;
+ push @dat,$pk_schema;
+ }
+ }
+
+ # if $fk_table but no $pk_table:
+ # return all foreign keys of $fk_table, and all
+ # primary keys of tables to which $fk_table refers
+ if (!$pk_table and $fk_table)
+ {
+ # find primary/unique keys referenced by $fk_table
+ # (this one is a little tricky)
+ $key_sql .= ' UNION ' . $pkey_sql . qq{
+ WHERE
+ pkcon.conname IN
+ (
+ SELECT
+ pkcon.conname
+ FROM
+ pg_constraint AS fkcon
+ JOIN
+ pg_constraint AS pkcon ON fkcon.confrelid=pkcon.conrelid AND
+ fkcon.confkey=pkcon.conkey
+ JOIN
+ pg_class fkc ON fkc.oid=fkcon.conrelid
+ WHERE
+ fkc.relname = ?
+ )
+ };
+ push @dat, $fk_table;
+
+ if ($fk_schema)
+ {
+ $key_sql .= $pk_schema_sql;
+ push @dat,$fk_schema;
+ }
+ }
+
+ # if $pk_table but no $fk_table:
+ # return primary key of $pk_table and all foreign keys
+ # that reference $pk_table
+ # question: what about unique keys?
+ # (DBI and SQL/CLI both state to omit unique keys)
+
+ if ($pk_table and !$fk_table)
+ {
+ # find primary key (only!) of $pk_table
+ $key_sql = $pkey_sql . qq{
+ WHERE
+ pkc.relname = ?
+ AND
+ pkcon.contype = 'p'
+ };
+ @dat = ($pk_table);
+
+ if ($pk_schema)
+ {
+ $key_sql .= $pk_schema_sql;
+ push @dat,$pk_schema;
+ }
+
+ # find all foreign keys that reference $pk_table
+ $key_sql .= 'UNION ' . $fkey_sql . qq{
+ WHERE
+ pkc.relname = ?
+ AND
+ pkcon.contype = 'p'
+ };
+ push @dat, $pk_table;
+
+ if ($pk_schema)
+ {
+ $key_sql .= $fk_schema_sql;
+ push @dat,$pk_schema;
+ }
+ }
+
+ return undef unless $key_sql;
+ my $sth = $dbh->prepare( $key_sql ) or
+ return undef;
+ $sth->execute(@dat);
+
+ return $sth;
+ }
+
+
+ sub table_info { # DBI spec: TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS
+ my $dbh = shift;
+ my ($catalog, $schema, $table, $type) = @_;
+ my @attrs = @_;
+
+ my $tbl_sql = ();
+
+ my $version = DBD::Pg::pg_server_version($dbh);
+ $version =~ /^(\d+\.\d+)/;
+ $version = $1;
+ my $CATALOG = DBD::Pg::pg_use_catalog($dbh);
+
+ if ( # Rules 19a
+ (defined $catalog and $catalog eq '%')
+ and (defined $schema and $schema eq '')
+ and (defined $table and $table eq '')
+ ) {
+ $tbl_sql = q{
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , NULL::text AS "TABLE_SCHEM"
+ , NULL::text AS "TABLE_NAME"
+ , NULL::text AS "TABLE_TYPE"
+ , NULL::text AS "REMARKS"
+ };
+ }
+ elsif (# Rules 19b
+ (defined $catalog and $catalog eq '')
+ and (defined $schema and $schema eq '%')
+ and (defined $table and $table eq '')
+ ) {
+ $tbl_sql = ($version < 7.3) ? q{
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , NULL::text AS "TABLE_SCHEM"
+ , NULL::text AS "TABLE_NAME"
+ , NULL::text AS "TABLE_TYPE"
+ , NULL::text AS "REMARKS"
+ } : q{
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , n.nspname AS "TABLE_SCHEM"
+ , NULL::text AS "TABLE_NAME"
+ , NULL::text AS "TABLE_TYPE"
+ , NULL::text AS "REMARKS"
+ FROM pg_catalog.pg_namespace n
+ ORDER BY 1
+ };
+ }
+ elsif (# Rules 19c
+ (defined $catalog and $catalog eq '')
+ and (defined $schema and $schema eq '')
+ and (defined $table and $table eq '')
+ and (defined $type and $type eq '%')
+ ) {
+ # From the postgresql 7.2.1 manual 3.5 pg_class
+ # 'r' = ordinary table
+ #, 'i' = index
+ #, 'S' = sequence
+ #, 'v' = view
+ #, 's' = special
+ #, 't' = secondary TOAST table
+ $tbl_sql = q{
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , NULL::text AS "TABLE_SCHEM"
+ , NULL::text AS "TABLE_NAME"
+ , 'table' AS "TABLE_TYPE"
+ , 'ordinary table - r' AS "REMARKS"
+ union
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , NULL::text AS "TABLE_SCHEM"
+ , NULL::text AS "TABLE_NAME"
+ , 'index' AS "TABLE_TYPE"
+ , 'index - i' AS "REMARKS"
+ union
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , NULL::text AS "TABLE_SCHEM"
+ , NULL::text AS "TABLE_NAME"
+ , 'sequence' AS "TABLE_TYPE"
+ , 'sequence - S' AS "REMARKS"
+ union
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , NULL::text AS "TABLE_SCHEM"
+ , NULL::text AS "TABLE_NAME"
+ , 'view' AS "TABLE_TYPE"
+ , 'view - v' AS "REMARKS"
+ union
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , NULL::text AS "TABLE_SCHEM"
+ , NULL::text AS "TABLE_NAME"
+ , 'special' AS "TABLE_TYPE"
+ , 'special - s' AS "REMARKS"
+ union
+ SELECT
+ NULL::text AS "TABLE_CAT"
+ , NULL::text AS "TABLE_SCHEM"
+ , NULL::text AS "TABLE_NAME"
+ , 'secondary' AS "TABLE_TYPE"
+ , 'secondary TOAST table - t' AS "REMARKS"
+ };
+ }
+ else {
+ # Default SQL
+ my $showschema = $version < 7.3 ? "NULL::text" : "n.nspname";
+ my $schemajoin = $version < 7.3 ? "" : "LEFT JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace)";
+ my $schemacase = $version < 7.3 ? "CASE WHEN c.relname ~ '^pg_' THEN 'SYSTEM TABLE' ELSE 'TABLE' END" :
+ "CASE WHEN n.nspname ~ '^pg_' THEN 'SYSTEM TABLE' ELSE 'TABLE' END";
+ $tbl_sql = qq{
+ SELECT NULL::text AS "TABLE_CAT"
+ , $showschema AS "TABLE_SCHEM"
+ , c.relname AS "TABLE_NAME"
+ , CASE
+ WHEN c.relkind = 'v' THEN 'VIEW'
+ ELSE $schemacase
+ END AS "TABLE_TYPE"
+ , d.description AS "REMARKS"
+ FROM ${CATALOG}pg_user AS u
+ , ${CATALOG}pg_class AS c
+ LEFT JOIN
+ ${CATALOG}pg_description AS d
+ ON (c.relfilenode = d.objoid AND d.objsubid = 0)
+ $schemajoin
+ WHERE
+ ((c.relkind = 'r'
+ AND c.relhasrules = FALSE) OR
+ (c.relkind = 'v'
+ AND c.relhasrules = TRUE))
+ AND c.relname !~ '^xin[vx][0-9]+'
+ AND c.relowner = u.usesysid
+ ORDER BY 1, 2, 3
+ };
+
+ # Did we receive any arguments?
+ if (@attrs) {
+ my @wh = ();
+ my @flds = qw/catname n.nspname c.relname c.relkind/;
+
+ for my $idx (0 .. $#attrs) {
+ next if ($flds[$idx] eq 'catname'); # Skip catalog
+ if(defined $attrs[$idx] and length $attrs[$idx]) {
+ # Change the "name" of the types to the real value.
+ if ($flds[$idx] =~ m/relkind/) {
+ $attrs[$idx] =~ s/^\'?table\'?/'r'/i;
+ $attrs[$idx] =~ s/^\'?index\'?/'i'/i;
+ $attrs[$idx] =~ s/^\'?sequence\'?/'S'/i;
+ $attrs[$idx] =~ s/^\'?view\'?/'v'/i;
+ $attrs[$idx] =~ s/^\'?special\'?/'s'/i;
+ $attrs[$idx] =~ s/^\'?secondary\'?/'t'/i;
+ }
+ # Insure that the value is enclosed in single quotes.
+ $attrs[$idx] =~ s/^'?(\w+)'?$/'$1'/;
+ if ($attrs[$idx] =~ m/[,%]/) {
+ # contains a meta character.
+ push( @wh, q{( } . join ( " OR "
+ , map { m/\%/
+ ? qq{$flds[$idx] LIKE $_ }
+ : qq{$flds[$idx] = $_ }
+ } (split /,/, $attrs[$idx]) )
+ . q{ )}
+ );
+ }
+ else {
+ push( @wh, qq{$flds[$idx] = $attrs[$idx]} );
+ }
+ }
+ }
+
+ my $wh = ();
+ if (@wh) {
+ $wh = join( " AND ",'', @wh );
+ $tbl_sql = qq{
+ SELECT NULL::text AS "TABLE_CAT"
+ , $showschema AS "TABLE_SCHEM"
+ , c.relname AS "TABLE_NAME"
+ , CASE
+ WHEN c.relkind = 'r' THEN
+ CASE WHEN n.nspname ~ '^pg_' THEN 'SYSTEM TABLE' ELSE 'TABLE' END
+ WHEN c.relkind = 'v' THEN 'VIEW'
+ WHEN c.relkind = 'i' THEN 'INDEX'
+ WHEN c.relkind = 'S' THEN 'SEQUENCE'
+ WHEN c.relkind = 's' THEN 'SPECIAL'
+ WHEN c.relkind = 't' THEN 'SECONDARY'
+ ELSE 'UNKNOWN'
+ END AS "TABLE_TYPE"
+ , d.description AS "REMARKS"
+ FROM ${CATALOG}pg_class AS c
+ LEFT JOIN
+ ${CATALOG}pg_description AS d
+ ON (c.relfilenode = d.objoid AND d.objsubid = 0)
+ $schemajoin
+ WHERE
+ c.relname !~ '^xin[vx][0-9]+'
+ $wh
+ ORDER BY 2, 3
+ };
+ }
+ }
+ }
+
+ my $sth = $dbh->prepare( $tbl_sql ) or return undef;
+ $sth->execute();
+
+ return $sth;
+ }
+
+
+ sub tables {
+ my($dbh) = @_;
+ my $version = DBD::Pg::pg_server_version($dbh);
+ $version =~ /^(\d+\.\d+)/;
+ $version = $1;
+ my $SQL = ($version < 7.3) ?
+ "SELECT relname AS \"TABLE_NAME\"
+ FROM pg_class
+ WHERE relkind = 'r'
+ AND relname !~ '^pg_'
+ AND relname !~ '^xin[vx][0-9]+'
+ ORDER BY 1" :
+ "SELECT n.nspname AS \"SCHEMA_NAME\", c.relname AS \"TABLE_NAME\"
+ FROM pg_catalog.pg_class c
+ LEFT JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace)
+ WHERE c.relkind = 'r'
+ AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
+ AND pg_catalog.pg_table_is_visible(c.oid)
+ ORDER BY 1,2";
+ my $sth = $dbh->prepare($SQL) or return undef;
+ $sth->execute or return undef;
+ my (@tables, @relname);
+ while (@relname = $sth->fetchrow_array) {
+ push @tables, $version < 7.3 ? $relname[0] : "$relname[0].$relname[1]";
+ }
+ $sth->finish;
+
+ return @tables;
+ }
+
+
+ sub table_attributes {
+ my ($dbh, $table) = @_;
+ my $CATALOG = DBD::Pg::pg_use_catalog($dbh);
+ my $result = [];
+ my $attrs = $dbh->selectall_arrayref(
+ "select a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum
+ from ${CATALOG}pg_attribute a,
+ ${CATALOG}pg_class c,
+ ${CATALOG}pg_type t
+ where c.relname = ?
+ and a.attrelid = c.oid
+ and a.attnum >= 0
+ and t.oid = a.atttypid
+ order by 1
+ ", undef, $table);
+
+ return $result unless scalar(@$attrs);
+
+ # Select the array value for tables primary key.
+ my $pk_key_sql = qq{SELECT pg_index.indkey
+ FROM ${CATALOG}pg_class, ${CATALOG}pg_index
+ WHERE
+ pg_class.oid = pg_index.indrelid
+ AND pg_class.relname = '$table'
+ AND pg_index.indisprimary = 't'
+ };
+ # Expand this (returned as a string) a real array.
+ my @pk = ();
+ my $pkeys = $dbh->selectrow_array( $pk_key_sql );
+ if (defined $pkeys) {
+ foreach (split( /\s+/, $pkeys))
+ {
+ push @pk, $_;
+ }
+ }
+ my $pk_bt =
+ (@pk) ? "AND pg_attribute.attnum in (" . join ( ", ", @pk ) . ")"
+ : "";
+
+ # Get the primary key
+ my $pri_key = $dbh->selectcol_arrayref("SELECT pg_attribute.attname
+ FROM ${CATALOG}pg_class, ${CATALOG}pg_attribute, ${CATALOG}pg_index
+ WHERE pg_class.oid = pg_attribute.attrelid
+ AND pg_class.oid = pg_index.indrelid
+ $pk_bt
+ AND pg_index.indisprimary = 't'
+ AND pg_class.relname = ?
+ ORDER BY pg_attribute.attnum
+ ", undef, $table );
+ $pri_key = [] unless $pri_key;
+
+ foreach my $attr (reverse @$attrs) {
+ my ($col_name, $col_type, $size, $mod, $notnull, $hasdef, $attnum) = @$attr;
+ my $col_size = do {
+ if ($size > 0) {
+ $size;
+ } elsif ($mod > 0xffff) {
+ my $prec = ($mod & 0xffff) - 4;
+ $mod >>= 16;
+ my $dig = $mod;
+ $dig;
+ } elsif ($mod >= 4) {
+ $mod - 4;
+ } else {
+ $mod;
+ }
+ };
+
+ # Get the default value, if any
+ my ($default) = $dbh->selectrow_array("SELECT adsrc FROM ${CATALOG}pg_attrdef WHERE adnum = $attnum") if -1 == $attnum;
+ $default = '' unless $default;
+
+ # Test for any constraints
+ # Note: as of PostgreSQL 7.3 pg_relcheck has been replaced
+ # by pg_constraint. To maintain compatibility, check
+ # version number and execute appropriate query.
+
+ my $version = pg_server_version( $dbh );
+
+ my $con_query = $version < 7.3
+ ? "SELECT rcsrc FROM pg_relcheck WHERE rcname = '${table}_$col_name'"
+ : "SELECT consrc FROM pg_catalog.pg_constraint WHERE contype = 'c' AND conname = '${table}_$col_name'";
+ my ($constraint) = $dbh->selectrow_array($con_query);
+ $constraint = '' unless $constraint;
+
+ # Check to see if this is the primary key
+ my $is_primary_key = scalar(grep { /^$col_name$/i } @$pri_key) ? 1 : 0;
+
+ push @$result,
+ { NAME => $col_name,
+ TYPE => $col_type,
+ SIZE => $col_size,
+ NOTNULL => $notnull,
+ DEFAULT => $default,
+ CONSTRAINT => $constraint,
+ PRIMARY_KEY => $is_primary_key,
+ };
+ }
+
+ return $result;
+ }
+
+
+ sub type_info_all {
+ my ($dbh) = @_;
+
+ #my $names = {
+ # TYPE_NAME => 0,
+ # DATA_TYPE => 1,
+ # PRECISION => 2,
+ # LITERAL_PREFIX => 3,
+ # LITERAL_SUFFIX => 4,
+ # CREATE_PARAMS => 5,
+ # NULLABLE => 6,
+ # CASE_SENSITIVE => 7,
+ # SEARCHABLE => 8,
+ # UNSIGNED_ATTRIBUTE => 9,
+ # MONEY =>10,
+ # AUTO_INCREMENT =>11,
+ # LOCAL_TYPE_NAME =>12,
+ # MINIMUM_SCALE =>13,
+ # MAXIMUM_SCALE =>14,
+ # };
+
+ my $names = {
+ TYPE_NAME => 0,
+ DATA_TYPE => 1,
+ COLUMN_SIZE => 2, # was PRECISION originally
+ LITERAL_PREFIX => 3,
+ LITERAL_SUFFIX => 4,
+ CREATE_PARAMS => 5,
+ NULLABLE => 6,
+ CASE_SENSITIVE => 7,
+ SEARCHABLE => 8,
+ UNSIGNED_ATTRIBUTE=> 9,
+ FIXED_PREC_SCALE => 10, # was MONEY originally
+ AUTO_UNIQUE_VALUE => 11, # was AUTO_INCREMENT originally
+ LOCAL_TYPE_NAME => 12,
+ MINIMUM_SCALE => 13,
+ MAXIMUM_SCALE => 14,
+ NUM_PREC_RADIX => 15,
+ };
+
+
+ # typname |typlen|typprtlen| SQL92
+ # --------------+------+---------+ -------
+ # bool | 1| 1| BOOLEAN
+ # text | -1| -1| like VARCHAR, but automatic storage allocation
+ # bpchar | -1| -1| CHARACTER(n) bp=blank padded
+ # varchar | -1| -1| VARCHAR(n)
+ # int2 | 2| 5| SMALLINT
+ # int4 | 4| 10| INTEGER
+ # int8 | 8| 20| /
+ # money | 4| 24| /
+ # float4 | 4| 12| FLOAT(p) for p<7=float4, for p<16=float8
+ # float8 | 8| 24| REAL
+ # abstime | 4| 20| /
+ # reltime | 4| 20| /
+ # tinterval | 12| 47| /
+ # date | 4| 10| /
+ # time | 8| 16| /
+ # datetime | 8| 47| /
+ # timespan | 12| 47| INTERVAL
+ # timestamp | 4| 19| TIMESTAMP
+ # --------------+------+---------+
+
+ # DBI type definitions / PostgreSQL definitions # type needs to be DBI-specific (not pg_type)
+ #
+ # SQL_ALL_TYPES 0
+ # SQL_CHAR 1 1042 bpchar
+ # SQL_NUMERIC 2 700 float4
+ # SQL_DECIMAL 3 700 float4
+ # SQL_INTEGER 4 23 int4
+ # SQL_SMALLINT 5 21 int2
+ # SQL_FLOAT 6 700 float4
+ # SQL_REAL 7 701 float8
+ # SQL_DOUBLE 8 20 int8
+ # SQL_DATE 9 1082 date
+ # SQL_TIME 10 1083 time
+ # SQL_TIMESTAMP 11 1296 timestamp
+ # SQL_VARCHAR 12 1043 varchar
+
+ my $ti = [
+ $names,
+ # name type prec prefix suffix create params null case se unsign mon incr local min max
+ #
+ [ 'bytea', -2, 4096, '\'', '\'', undef, 1, '1', 3, undef, '0', '0', 'BYTEA', undef, undef, undef ],
+ [ 'bool', 0, 1, '\'', '\'', undef, 1, '0', 2, undef, '0', '0', 'BOOLEAN', undef, undef, undef ],
+ [ 'int8', 8, 20, undef, undef, undef, 1, '0', 2, '0', '0', '0', 'LONGINT', undef, undef, undef ],
+ [ 'int2', 5, 5, undef, undef, undef, 1, '0', 2, '0', '0', '0', 'SMALLINT', undef, undef, undef ],
+ [ 'int4', 4, 10, undef, undef, undef, 1, '0', 2, '0', '0', '0', 'INTEGER', undef, undef, undef ],
+ [ 'text', 12, 4096, '\'', '\'', undef, 1, '1', 3, undef, '0', '0', 'TEXT', undef, undef, undef ],
+ [ 'float4', 6, 12, undef, undef, 'precision', 1, '0', 2, '0', '0', '0', 'FLOAT', undef, undef, undef ],
+ [ 'float8', 7, 24, undef, undef, 'precision', 1, '0', 2, '0', '0', '0', 'REAL', undef, undef, undef ],
+ [ 'abstime', 10, 20, '\'', '\'', undef, 1, '0', 2, undef, '0', '0', 'ABSTIME', undef, undef, undef ],
+ [ 'reltime', 10, 20, '\'', '\'', undef, 1, '0', 2, undef, '0', '0', 'RELTIME', undef, undef, undef ],
+ [ 'tinterval', 11, 47, '\'', '\'', undef, 1, '0', 2, undef, '0', '0', 'TINTERVAL', undef, undef, undef ],
+ [ 'money', 0, 24, undef, undef, undef, 1, '0', 2, undef, '1', '0', 'MONEY', undef, undef, undef ],
+ [ 'bpchar', 1, 4096, '\'', '\'', 'max length', 1, '1', 3, undef, '0', '0', 'CHARACTER', undef, undef, undef ],
+ [ 'bpchar', 12, 4096, '\'', '\'', 'max length', 1, '1', 3, undef, '0', '0', 'CHARACTER', undef, undef, undef ],
+ [ 'varchar', 12, 4096, '\'', '\'', 'max length', 1, '1', 3, undef, '0', '0', 'VARCHAR', undef, undef, undef ],
+ [ 'date', 9, 10, '\'', '\'', undef, 1, '0', 2, undef, '0', '0', 'DATE', undef, undef, undef ],
+ [ 'time', 10, 16, '\'', '\'', undef, 1, '0', 2, undef, '0', '0', 'TIME', undef, undef, undef ],
+ [ 'datetime', 11, 47, '\'', '\'', undef, 1, '0', 2, undef, '0', '0', 'DATETIME', undef, undef, undef ],
+ [ 'timespan', 11, 47, '\'', '\'', undef, 1, '0', 2, undef, '0', '0', 'INTERVAL', undef, undef, undef ],
+ [ 'timestamp', 10, 19, '\'', '\'', undef, 1, '0', 2, undef, '0', '0', 'TIMESTAMP', undef, undef, undef ]
+ #
+ # intentionally omitted: char, all geometric types, all array types
+ ];
+ return $ti;
+ }
+
+
+ # Characters that need to be escaped by quote().
+ my %esc = ( "'" => '\\047', # '\\' . sprintf("%03o", ord("'")), # ISO SQL 2
+ '\\' => '\\134', # '\\' . sprintf("%03o", ord("\\")),
+ );
+
+ # Set up lookup for SQL types we don't want to escape.
+ my %no_escape = map { $_ => 1 }
+ DBI::SQL_INTEGER, DBI::SQL_SMALLINT, DBI::SQL_DECIMAL,
+ DBI::SQL_FLOAT, DBI::SQL_REAL, DBI::SQL_DOUBLE, DBI::SQL_NUMERIC;
+
+ sub quote {
+ my ($dbh, $str, $data_type) = @_;
+ return "NULL" unless defined $str;
+ return $str if $data_type && $no_escape{$data_type};
+
+ $dbh->DBI::set_err(1, "Use of SQL_BINARY invalid in quote()")
+ if $data_type && $data_type == DBI::SQL_BINARY;
+
+ $str =~ s/(['\\\0])/$esc{$1}/g;
+ return "'$str'";
+ }
+
+} # end of package DBD::Pg::db
+
+{ package DBD::Pg::st; # ====== STATEMENT ======
+
+ # all done in XS
+
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+DBD::Pg - PostgreSQL database driver for the DBI module
+
+=head1 SYNOPSIS
+
+ use DBI;
+
+ $dbh = DBI->connect("dbi:Pg:dbname=$dbname", "", "");
+
+ # for some advanced uses you may need PostgreSQL type values:
+ use DBD::Oracle qw(:pg_types);
+
+ # See the DBI module documentation for full details
+
+=head1 DESCRIPTION
+
+DBD::Pg is a Perl module which works with the DBI module to provide access to
+PostgreSQL databases.
+
+=head1 MODULE DOCUMENTATION
+
+This documentation describes driver specific behavior and restrictions. It is
+not supposed to be used as the only reference for the user. In any case
+consult the DBI documentation first!
+
+=head1 THE DBI CLASS
+
+=head2 DBI Class Methods
+
+=over 4
+
+=item B<connect>
+
+To connect to a database with a minimum of parameters, use the following
+syntax:
+
+ $dbh = DBI->connect("dbi:Pg:dbname=$dbname", "", "");
+
+This connects to the database $dbname at localhost without any user
+authentication. This is sufficient for the defaults of PostgreSQL.
+
+The following connect statement shows all possible parameters:
+
+ $dbh = DBI->connect("dbi:Pg:dbname=$dbname;host=$host;port=$port;" .
+ "options=$options;tty=$tty", "$username", "$password");
+
+If a parameter is undefined PostgreSQL first looks for specific environment
+variables and then it uses hard coded defaults:
+
+ parameter environment variable hard coded default
+ --------------------------------------------------
+ dbname PGDATABASE current userid
+ host PGHOST localhost
+ port PGPORT 5432
+ options PGOPTIONS ""
+ tty PGTTY ""
+ username PGUSER current userid
+ password PGPASSWORD ""
+
+If a host is specified, the postmaster on this host needs to be started with
+the C<-i> option (TCP/IP sockets).
+
+The options parameter specifies runtime options for the Postgres
+backend. Common usage is to increase the number of buffers with the C<-B>
+option. Also important is the C<-F> option, which disables automatic fsync()
+call after each transaction. For further details please refer to the
+L<postgres>.
+
+For authentication with username and password appropriate entries have to be
+made in pg_hba.conf. Please refer to the L<pg_hba.conf> and the L<pg_passwd>
+for the different types of authentication. Note that for these two parameters
+DBI distinguishes between empty and undefined. If these parameters are
+undefined DBI substitutes the values of the environment variables DBI_USER and
+DBI_PASS if present.
+
+=item B<available_drivers>
+
+ @driver_names = DBI->available_drivers;
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<data_sources>
+
+ @data_sources = DBI->data_sources('Pg');
+
+The driver supports this method. Note that the necessary database connection to
+the database template1 will be done on the localhost without any
+user-authentication. Other preferences can only be set with the environment
+variables PGHOST, DBI_USER and DBI_PASS.
+
+=item B<trace>
+
+ DBI->trace($trace_level, $trace_file)
+
+Implemented by DBI, no driver-specific impact.
+
+=back
+
+=head2 DBI Dynamic Attributes
+
+See Common Methods.
+
+=head1 METHODS COMMON TO ALL HANDLES
+
+=over 4
+
+=item B<err>
+
+ $rv = $h->err;
+
+Supported by the driver as proposed by DBI. For the connect method it returns
+PQstatus. In all other cases it returns PQresultStatus of the current handle.
+
+=item B<errstr>
+
+ $str = $h->errstr;
+
+Supported by the driver as proposed by DBI. It returns the PQerrorMessage
+related to the current handle.
+
+=item B<state>
+
+ $str = $h->state;
+
+This driver does not (yet) support the state method.
+
+=item B<trace>
+
+ $h->trace($trace_level, $trace_filename);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<trace_msg>
+
+ $h->trace_msg($message_text);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<func>
+
+This driver supports a variety of driver specific functions accessible via the
+func interface:
+
+ $attrs = $dbh->func($table, 'table_attributes');
+
+This method returns for the given table a reference to an array of hashes:
+
+ NAME attribute name
+ TYPE attribute type
+ SIZE attribute size (-1 for variable size)
+ NULLABLE flag nullable
+ DEFAULT default value
+ CONSTRAINT constraint
+ PRIMARY_KEY flag is_primary_key
+
+ $lobjId = $dbh->func($mode, 'lo_creat');
+
+Creates a new large object and returns the object-id. $mode is a bit-mask
+describing different attributes of the new object. Use the following
+constants:
+
+ $dbh->{pg_INV_WRITE}
+ $dbh->{pg_INV_READ}
+
+Upon failure it returns undef.
+
+ $lobj_fd = $dbh->func($lobjId, $mode, 'lo_open');
+
+Opens an existing large object and returns an object-descriptor for use in
+subsequent lo_* calls. For the mode bits see lo_create. Returns undef upon
+failure. Note that 0 is a perfectly correct object descriptor!
+
+ $nbytes = $dbh->func($lobj_fd, $buf, $len, 'lo_write');
+
+Writes $len bytes of $buf into the large object $lobj_fd. Returns the number
+of bytes written and undef upon failure.
+
+ $nbytes = $dbh->func($lobj_fd, $buf, $len, 'lo_read');
+
+Reads $len bytes into $buf from large object $lobj_fd. Returns the number of
+bytes read and undef upon failure.
+
+ $loc = $dbh->func($lobj_fd, $offset, $whence, 'lo_lseek');
+
+Change the current read or write location on the large object
+$obj_id. Currently $whence can only be 0 (L_SET). Returns the current location
+and undef upon failure.
+
+ $loc = $dbh->func($lobj_fd, 'lo_tell');
+
+Returns the current read or write location on the large object $lobj_fd and
+undef upon failure.
+
+ $lobj_fd = $dbh->func($lobj_fd, 'lo_close');
+
+Closes an existing large object. Returns true upon success and false upon
+failure.
+
+ $lobj_fd = $dbh->func($lobj_fd, 'lo_unlink');
+
+Deletes an existing large object. Returns true upon success and false upon
+failure.
+
+ $lobjId = $dbh->func($filename, 'lo_import');
+
+Imports a Unix file as large object and returns the object id of the new
+object or undef upon failure.
+
+ $ret = $dbh->func($lobjId, 'lo_export', 'filename');
+
+Exports a large object into a Unix file. Returns false upon failure, true
+otherwise.
+
+ $ret = $dbh->func($line, 'putline');
+
+Used together with the SQL-command 'COPY table FROM STDIN' to copy large
+amount of data into a table avoiding the overhead of using single
+insert commands. The application must explicitly send the two characters "\."
+to indicate to the backend that it has finished sending its data. See test.pl
+for an example on how to use this function.
+
+ $ret = $dbh->func($buffer, length, 'getline');
+
+Used together with the SQL-command 'COPY table TO STDOUT' to dump a complete
+table. See test.pl for an example on how to use this function.
+
+ $ret = $dbh->func('pg_notifies');
+
+Returns either undef or a reference to two-element array [ $table,
+$backend_pid ] of asynchronous notifications received.
+
+ $fd = $dbh->func('getfd');
+
+Returns fd of the actual connection to server. Can be used with select() and
+func('pg_notifies').
+
+=back
+
+=head1 ATTRIBUTES COMMON TO ALL HANDLES
+
+=over 4
+
+=item B<Warn> (boolean, inherited)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<Active> (boolean, read-only)
+
+Supported by the driver as proposed by DBI. A database handle is active while
+it is connected and statement handle is active until it is finished.
+
+=item B<Kids> (integer, read-only)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<ActiveKids> (integer, read-only)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<CachedKids> (hash ref)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<CompatMode> (boolean, inherited)
+
+Not used by this driver.
+
+=item B<InactiveDestroy> (boolean)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<PrintError> (boolean, inherited)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<RaiseError> (boolean, inherited)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<HandleError> (boolean, inherited)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<ChopBlanks> (boolean, inherited)
+
+Supported by the driver as proposed by DBI. This method is similar to the
+SQL-function RTRIM.
+
+=item B<LongReadLen> (integer, inherited)
+
+Implemented by DBI, not used by the driver.
+
+=item B<LongTruncOk> (boolean, inherited)
+
+Implemented by DBI, not used by the driver.
+
+=item B<Taint> (boolean, inherited)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<private_*>
+
+Implemented by DBI, no driver-specific impact.
+
+=back
+
+=head1 DBI DATABASE HANDLE OBJECTS
+
+=head2 Database Handle Methods
+
+=over 4
+
+=item B<selectrow_array>
+
+ @row_ary = $dbh->selectrow_array($statement, \%attr, @bind_values);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<selectrow_arrayref>
+
+ $ary_ref = $dbh->selectrow_arrayref($statement, \%attr, @bind_values);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<selectrow_hashref>
+
+ $hash_ref = $dbh->selectrow_hashref($statement, \%attr, @bind_values);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<selectall_arrayref>
+
+ $ary_ref = $dbh->selectall_arrayref($statement, \%attr, @bind_values);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<selectall_hashref>
+
+ $hash_ref = $dbh->selectall_hashref($statement, $key_field);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<selectcol_arrayref>
+
+ $ary_ref = $dbh->selectcol_arrayref($statement, \%attr, @bind_values);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<prepare>
+
+ $sth = $dbh->prepare($statement, \%attr);
+
+PostgreSQL does not have the concept of preparing a statement. Hence the
+prepare method just stores the statement after checking for place-holders. No
+information about the statement is available after preparing it.
+
+=item B<prepare_cached>
+
+ $sth = $dbh->prepare_cached($statement, \%attr);
+
+Implemented by DBI, no driver-specific impact. This method is not useful for
+this driver, because preparing a statement has no database interaction.
+
+=item B<do>
+
+ $rv = $dbh->do($statement, \%attr, @bind_values);
+
+Implemented by DBI, no driver-specific impact. See the notes for the execute
+method elsewhere in this document.
+
+=item B<commit>
+
+ $rc = $dbh->commit;
+
+Supported by the driver as proposed by DBI. See also the notes about
+B<Transactions> elsewhere in this document.
+
+=item B<rollback>
+
+ $rc = $dbh->rollback;
+
+Supported by the driver as proposed by DBI. See also the notes about
+B<Transactions> elsewhere in this document.
+
+=item B<disconnect>
+
+ $rc = $dbh->disconnect;
+
+Supported by the driver as proposed by DBI.
+
+=item B<ping>
+
+ $rc = $dbh->ping;
+
+This driver supports the ping-method, which can be used to check the validity
+of a database-handle. The ping method issues an empty query and checks the
+result status.
+
+=item B<table_info>
+
+ $sth = $dbh->table_info;
+
+Supported by the driver as proposed by DBI. This method returns all tables and
+views which are owned by the current user. It does not select any indexes and
+sequences. Also System tables are not selected. As TABLE_QUALIFIER the reltype
+attribute is returned and the REMARKS are undefined.
+
+=item B<foreign_key_info>
+
+ $sth = $dbh->foreign_key_info( $pk_catalog, $pk_schema, $pk_table,
+ $fk_catalog, $fk_schema, $fk_table );
+
+Supported by the driver as proposed by DBI. Unimplemented for Postgres
+servers before 7.3 (returns undef). Currently only returns information
+about first column of any multiple-column keys.
+
+=item B<tables>
+
+ @names = $dbh->tables;
+
+Supported by the driver as proposed by DBI. This method returns all tables and
+views which are owned by the current user. It does not select any indexes and
+sequences, or system tables.
+
+=item B<type_info_all>
+
+ $type_info_all = $dbh->type_info_all;
+
+Supported by the driver as proposed by DBI. Only for SQL data-types and for
+frequently used data-types information is provided. The mapping between the
+PostgreSQL typename and the SQL92 data-type (if possible) has been done
+according to the following table:
+
+ +---------------+------------------------------------+
+ | typname | SQL92 |
+ |---------------+------------------------------------|
+ | bool | BOOL |
+ | text | / |
+ | bpchar | CHAR(n) |
+ | varchar | VARCHAR(n) |
+ | int2 | SMALLINT |
+ | int4 | INT |
+ | int8 | / |
+ | money | / |
+ | float4 | FLOAT(p) p<7=float4, p<16=float8 |
+ | float8 | REAL |
+ | abstime | / |
+ | reltime | / |
+ | tinterval | / |
+ | date | / |
+ | time | / |
+ | datetime | / |
+ | timespan | TINTERVAL |
+ | timestamp | TIMESTAMP |
+ +---------------+------------------------------------+
+
+For further details concerning the PostgreSQL specific data-types please read
+the L<pgbuiltin>.
+
+=item B<type_info>
+
+ @type_info = $dbh->type_info($data_type);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<quote>
+
+ $sql = $dbh->quote($value, $data_type);
+
+This module implements its own quote method. In addition to the DBI method it
+also doubles the backslash, because PostgreSQL treats a backslash as an escape
+character.
+
+B<NOTE:> The undocumented (and invalid) support for the C<SQL_BINARY> data
+type is officially deprecated. Use C<PG_BYTEA> with C<bind_param()> instead:
+
+ $rv = $sth->bind_param($param_num, $bind_value,
+ { pg_type => DBD::Pg::PG_BYTEA });
+
+=back
+
+=head2 Database Handle Attributes
+
+=over 4
+
+=item B<AutoCommit> (boolean)
+
+Supported by the driver as proposed by DBI. According to the classification of
+DBI, PostgreSQL is a database, in which a transaction must be explicitly
+started. Without starting a transaction, every change to the database becomes
+immediately permanent. The default of AutoCommit is on, which corresponds to
+the default behavior of PostgreSQL. When setting AutoCommit to off, a
+transaction will be started and every commit or rollback will automatically
+start a new transaction. For details see the notes about B<Transactions>
+elsewhere in this document.
+
+=item B<Driver> (handle)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<Name> (string, read-only)
+
+The default method of DBI is overridden by a driver specific method, which
+returns only the database name. Anything else from the connection string is
+stripped off. Note, that here the method is read-only in contrast to the DBI
+specs.
+
+=item B<RowCacheSize> (integer)
+
+Implemented by DBI, not used by the driver.
+
+=item B<pg_auto_escape> (boolean)
+
+PostgreSQL specific attribute. If true, then quotes and backslashes in all
+parameters will be escaped in the following way:
+
+ escape quote with a quote (SQL)
+ escape backslash with a backslash
+
+The default is on. Note, that PostgreSQL also accepts quotes, which are
+escaped by a backslash. Any other ASCII character can be used directly in a
+string constant.
+
+=item B<pg_enable_utf8> (boolean)
+
+PostgreSQL specific attribute. If true, then the utf8 flag will be
+turned for returned character data (if the data is valid utf8). For
+details about the utf8 flag, see L<Encode>. This is only relevant under
+perl 5.8 and higher.
+
+B<NB>: This attribute is experimental and may be subject to change.
+
+=item B<pg_INV_READ> (integer, read-only)
+
+Constant to be used for the mode in lo_creat and lo_open.
+
+=item B<pg_INV_WRITE> (integer, read-only)
+
+Constant to be used for the mode in lo_creat and lo_open.
+
+=back
+
+=head1 DBI STATEMENT HANDLE OBJECTS
+
+=head2 Statement Handle Methods
+
+=over 4
+
+=item B<bind_param>
+
+ $rv = $sth->bind_param($param_num, $bind_value, \%attr);
+
+Supported by the driver as proposed by DBI.
+
+B<NOTE:> The undocumented (and invalid) support for the C<SQL_BINARY>
+SQL type is officially deprecated. Use C<PG_BYTEA> instead:
+
+ $rv = $sth->bind_param($param_num, $bind_value,
+ { pg_type => DBD::Pg::PG_BYTEA });
+
+=item B<bind_param_inout>
+
+Not supported by this driver.
+
+=item B<execute>
+
+ $rv = $sth->execute(@bind_values);
+
+Supported by the driver as proposed by DBI. In addition to 'UPDATE', 'DELETE',
+'INSERT' statements, for which it returns always the number of affected rows,
+the execute method can also be used for 'SELECT ... INTO table' statements.
+
+=item B<fetchrow_arrayref>
+
+ $ary_ref = $sth->fetchrow_arrayref;
+
+Supported by the driver as proposed by DBI.
+
+=item B<fetchrow_array>
+
+ @ary = $sth->fetchrow_array;
+
+Supported by the driver as proposed by DBI.
+
+=item B<fetchrow_hashref>
+
+ $hash_ref = $sth->fetchrow_hashref;
+
+Supported by the driver as proposed by DBI.
+
+=item B<fetchall_arrayref>
+
+ $tbl_ary_ref = $sth->fetchall_arrayref;
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<finish>
+
+ $rc = $sth->finish;
+
+Supported by the driver as proposed by DBI.
+
+=item B<rows>
+
+ $rv = $sth->rows;
+
+Supported by the driver as proposed by DBI. In contrast to many other drivers
+the number of rows is available immediately after executing the statement.
+
+=item B<bind_col>
+
+ $rc = $sth->bind_col($column_number, \$var_to_bind, \%attr);
+
+Supported by the driver as proposed by DBI.
+
+=item B<bind_columns>
+
+ $rc = $sth->bind_columns(\%attr, @list_of_refs_to_vars_to_bind);
+
+Supported by the driver as proposed by DBI.
+
+=item B<dump_results>
+
+ $rows = $sth->dump_results($maxlen, $lsep, $fsep, $fh);
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<blob_read>
+
+ $blob = $sth->blob_read($id, $offset, $len);
+
+Supported by this driver as proposed by DBI. Implemented by DBI but not
+documented, so this method might change.
+
+This method seems to be heavily influenced by the current implementation of
+blobs in Oracle. Nevertheless we try to be as compatible as possible. Whereas
+Oracle suffers from the limitation that blobs are related to tables and every
+table can have only one blob (data-type LONG), PostgreSQL handles its blobs
+independent of any table by using so called object identifiers. This explains
+why the blob_read method is blessed into the STATEMENT package and not part of
+the DATABASE package. Here the field parameter has been used to handle this
+object identifier. The offset and len parameter may be set to zero, in which
+case the driver fetches the whole blob at once.
+
+Starting with PostgreSQL-6.5 every access to a blob has to be put into a
+transaction. This holds even for a read-only access.
+
+See also the PostgreSQL-specific functions concerning blobs which are
+available via the func-interface.
+
+For further information and examples about blobs, please read the chapter
+about Large Objects in the PostgreSQL Programmer's Guide.
+
+=back
+
+=head2 Statement Handle Attributes
+
+=over 4
+
+=item B<NUM_OF_FIELDS> (integer, read-only)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<NUM_OF_PARAMS> (integer, read-only)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<NAME> (array-ref, read-only)
+
+Supported by the driver as proposed by DBI.
+
+=item B<NAME_lc> (array-ref, read-only)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<NAME_uc> (array-ref, read-only)
+
+Implemented by DBI, no driver-specific impact.
+
+=item B<TYPE> (array-ref, read-only)
+
+Supported by the driver as proposed by DBI, with the restriction, that the
+types are PostgreSQL specific data-types which do not correspond to
+international standards.
+
+=item B<PRECISION> (array-ref, read-only)
+
+Not supported by the driver.
+
+=item B<SCALE> (array-ref, read-only)
+
+Not supported by the driver.
+
+=item B<NULLABLE> (array-ref, read-only)
+
+Not supported by the driver.
+
+=item B<CursorName> (string, read-only)
+
+Not supported by the driver. See the note about B<Cursors> elsewhere in this
+document.
+
+=item B<Statement> (string, read-only)
+
+Supported by the driver as proposed by DBI.
+
+=item B<RowCache> (integer, read-only)
+
+Not supported by the driver.
+
+=item B<pg_size> (array-ref, read-only)
+
+PostgreSQL specific attribute. It returns a reference to an array of integer
+values for each column. The integer shows the size of the column in
+bytes. Variable length columns are indicated by -1.
+
+=item B<pg_type> (hash-ref, read-only)
+
+PostgreSQL specific attribute. It returns a reference to an array of strings
+for each column. The string shows the name of the data_type.
+
+=item B<pg_oid_status> (integer, read-only)
+
+PostgreSQL specific attribute. It returns the OID of the last INSERT command.
+
+=item B<pg_cmd_status> (integer, read-only)
+
+PostgreSQL specific attribute. It returns the type of the last
+command. Possible types are: INSERT, DELETE, UPDATE, SELECT.
+
+=back
+
+=head1 FURTHER INFORMATION
+
+=head2 Transactions
+
+The transaction behavior is now controlled with the attribute AutoCommit. For
+a complete definition of AutoCommit please refer to the DBI documentation.
+
+According to the DBI specification the default for AutoCommit is TRUE. In this
+mode, any change to the database becomes valid immediately. Any 'begin',
+'commit' or 'rollback' statement will be rejected.
+
+If AutoCommit is switched-off, immediately a transaction will be started by
+issuing a 'begin' statement. Any 'commit' or 'rollback' will start a new
+transaction. A disconnect will issue a 'rollback' statement.
+
+=head2 Large Objects
+
+The driver supports all large-objects related functions provided by libpq via
+the func-interface. Please note, that starting with PostgreSQL 6.5 any access
+to a large object - even read-only - has to be put into a transaction!
+
+=head2 Cursors
+
+Although PostgreSQL has a cursor concept, it has not been used in the current
+implementation. Cursors in PostgreSQL can only be used inside a transaction
+block. Because only one transaction block at a time is allowed, this would
+have implied the restriction, not to use any nested SELECT statements. Hence
+the execute method fetches all data at once into data structures located in
+the frontend application. This has to be considered when selecting large
+amounts of data!
+
+=head2 Data-Type bool
+
+The current implementation of PostgreSQL returns 't' for true and 'f' for
+false. From the Perl point of view a rather unfortunate choice. The DBD::Pg
+module translates the result for the data-type bool in a perl-ish like manner:
+'f' -> '0' and 't' -> '1'. This way the application does not have to check the
+database-specific returned values for the data-type bool, because Perl treats
+'0' as false and '1' as true.
+
+Boolean values can be passed to PostgreSQL as TRUE, 't', 'true', 'y', 'yes' or
+'1' for true and FALSE, 'f', 'false', 'n', 'no' or '0' for false.
+
+=head2 Schema support
+
+PostgreSQL version 7.3 introduced schema support. Note that the PostgreSQL
+schema concept may differ to that of other databases. Please refer to the
+PostgreSQL documentation for more details.
+
+Currently DBD::Pg does not provide explicit support for PostgreSQL schemas.
+However, schema functionality may be used without any restrictions by
+explicitly addressing schema objects, e.g.
+
+ my $res = $dbh->selectall_arrayref("SELECT * FROM my_schema.my_table");
+
+or by manipulating the schema search path with SET search_path, e.g.
+
+ $dbh->do("SET search_path TO my_schema, public");
+
+B<NOTE:> If you create an object with the same name as a PostgreSQL system
+object (as contained in the pg_catalog schema) and explicitly set the search
+path so that pg_catalog comes after the new object's schema, some DBD::Pg
+methods (particularly those querying PostgreSQL system objects) may fail.
+This problem should be fixed in a future release of DBD::Pg. Creating objects
+with the same name as system objects (or beginning with 'pg_') is not
+recommended practice and should be avoided in any case.
+
+=head1 SEE ALSO
+
+L<DBI>
+
+=head1 AUTHORS
+
+DBI and DBD-Oracle by Tim Bunce (Tim.Bunce@ig.co.uk)
+
+DBD-Pg by Edmund Mergl (E.Mergl@bawue.de) and Jeffrey W. Baker
+(jwbaker@acm.org). By David Wheeler <david@wheeler.net>, Jason
+Stewart <jason@openinformatics.com> and Bruce Momjian
+<pgman@candle.pha.pa.us> after v1.13.
+
+Major parts of this package have been copied from DBI and DBD-Oracle.
+
+=head1 COPYRIGHT
+
+The DBD::Pg module is free software. You may distribute under the terms of
+either the GNU General Public License or the Artistic License, as specified in
+the Perl README file.
+
+=head1 ACKNOWLEDGMENTS
+
+See also B<DBI/ACKNOWLEDGMENTS>.
+
+=cut
+
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/Pg.xs b/install/5.005/DBD-Pg-1.22-fixvercmp/Pg.xs
new file mode 100644
index 0000000..e5e4362
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/Pg.xs
@@ -0,0 +1,644 @@
+/*
+ $Id: Pg.xs,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+ Copyright (c) 1997,1998,1999,2000 Edmund Mergl
+ Portions Copyright (c) 1994,1995,1996,1997 Tim Bunce
+
+ You may distribute under the terms of either the GNU General Public
+ License or the Artistic License, as specified in the Perl README file.
+
+*/
+
+
+#include "Pg.h"
+
+
+#ifdef _MSC_VER
+#define strncasecmp(a,b,c) _strnicmp((a),(b),(c))
+#endif
+
+
+
+DBISTATE_DECLARE;
+
+
+MODULE = DBD::Pg PACKAGE = DBD::Pg
+
+I32
+constant(name=Nullch)
+ char *name
+ PROTOTYPE:
+ ALIAS:
+ PG_BOOL = 16
+ PG_BYTEA = 17
+ PG_CHAR = 18
+ PG_INT8 = 20
+ PG_INT2 = 21
+ PG_INT4 = 23
+ PG_TEXT = 25
+ PG_OID = 26
+ PG_FLOAT4 = 700
+ PG_FLOAT8 = 701
+ PG_ABSTIME = 702
+ PG_RELTIME = 703
+ PG_TINTERVAL = 704
+ PG_BPCHAR = 1042
+ PG_VARCHAR = 1043
+ PG_DATE = 1082
+ PG_TIME = 1083
+ PG_DATETIME = 1184
+ PG_TIMESPAN = 1186
+ PG_TIMESTAMP = 1296
+ CODE:
+ if (!ix) {
+ if (!name) name = GvNAME(CvGV(cv));
+ croak("Unknown DBD::Pg constant '%s'", name);
+ }
+ else RETVAL = ix;
+ OUTPUT:
+ RETVAL
+
+PROTOTYPES: DISABLE
+
+BOOT:
+ items = 0; /* avoid 'unused variable' warning */
+ DBISTATE_INIT;
+ /* XXX this interface will change: */
+ DBI_IMP_SIZE("DBD::Pg::dr::imp_data_size", sizeof(imp_drh_t));
+ DBI_IMP_SIZE("DBD::Pg::db::imp_data_size", sizeof(imp_dbh_t));
+ DBI_IMP_SIZE("DBD::Pg::st::imp_data_size", sizeof(imp_sth_t));
+ dbd_init(DBIS);
+
+
+# ------------------------------------------------------------
+# driver level interface
+# ------------------------------------------------------------
+MODULE = DBD::Pg PACKAGE = DBD::Pg::dr
+
+# disconnect_all renamed and ALIASed to avoid length clash on VMS :-(
+void
+discon_all_(drh)
+ SV * drh
+ ALIAS:
+ disconnect_all = 1
+ CODE:
+ D_imp_drh(drh);
+ ST(0) = dbd_discon_all(drh, imp_drh) ? &sv_yes : &sv_no;
+
+
+
+# ------------------------------------------------------------
+# database level interface
+# ------------------------------------------------------------
+MODULE = DBD::Pg PACKAGE = DBD::Pg::db
+
+void
+_login(dbh, dbname, username, pwd)
+ SV * dbh
+ char * dbname
+ char * username
+ char * pwd
+ CODE:
+ D_imp_dbh(dbh);
+ ST(0) = pg_db_login(dbh, imp_dbh, dbname, username, pwd) ? &sv_yes : &sv_no;
+
+
+int
+_ping(dbh)
+ SV * dbh
+ CODE:
+ int ret;
+ ret = dbd_db_ping(dbh);
+ if (ret == 0) {
+ XST_mUNDEF(0);
+ }
+ else {
+ XST_mIV(0, ret);
+ }
+
+void
+getfd(dbh)
+ SV * dbh
+ CODE:
+ int ret;
+ D_imp_dbh(dbh);
+
+ ret = dbd_db_getfd(dbh, imp_dbh);
+ ST(0) = sv_2mortal( newSViv( ret ) );
+
+void
+pg_notifies(dbh)
+ SV * dbh
+ CODE:
+ D_imp_dbh(dbh);
+
+ ST(0) = dbd_db_pg_notifies(dbh, imp_dbh);
+
+void
+commit(dbh)
+ SV * dbh
+ CODE:
+ D_imp_dbh(dbh);
+ if (DBIc_has(imp_dbh, DBIcf_AutoCommit)) {
+ warn("commit ineffective with AutoCommit enabled");
+ }
+ ST(0) = dbd_db_commit(dbh, imp_dbh) ? &sv_yes : &sv_no;
+
+
+void
+rollback(dbh)
+ SV * dbh
+ CODE:
+ D_imp_dbh(dbh);
+ if (DBIc_has(imp_dbh, DBIcf_AutoCommit)) {
+ warn("rollback ineffective with AutoCommit enabled");
+ }
+ ST(0) = dbd_db_rollback(dbh, imp_dbh) ? &sv_yes : &sv_no;
+
+
+void
+disconnect(dbh)
+ SV * dbh
+ CODE:
+ D_imp_dbh(dbh);
+ if ( !DBIc_ACTIVE(imp_dbh) ) {
+ XSRETURN_YES;
+ }
+ /* pre-disconnect checks and tidy-ups */
+ if (DBIc_CACHED_KIDS(imp_dbh)) {
+ SvREFCNT_dec(DBIc_CACHED_KIDS(imp_dbh));
+ DBIc_CACHED_KIDS(imp_dbh) = Nullhv;
+ }
+ /* Check for disconnect() being called whilst refs to cursors */
+ /* still exists. This possibly needs some more thought. */
+ if (DBIc_ACTIVE_KIDS(imp_dbh) && DBIc_WARN(imp_dbh) && !dirty) {
+ char *plural = (DBIc_ACTIVE_KIDS(imp_dbh)==1) ? "" : "s";
+ warn("disconnect(%s) invalidates %d active statement%s. %s",
+ SvPV(dbh,na), (int)DBIc_ACTIVE_KIDS(imp_dbh), plural,
+ "Either destroy statement handles or call finish on them before disconnecting.");
+ }
+ ST(0) = dbd_db_disconnect(dbh, imp_dbh) ? &sv_yes : &sv_no;
+
+
+void
+STORE(dbh, keysv, valuesv)
+ SV * dbh
+ SV * keysv
+ SV * valuesv
+ CODE:
+ D_imp_dbh(dbh);
+ ST(0) = &sv_yes;
+ if (!dbd_db_STORE_attrib(dbh, imp_dbh, keysv, valuesv)) {
+ if (!DBIS->set_attr(dbh, keysv, valuesv)) {
+ ST(0) = &sv_no;
+ }
+ }
+
+
+void
+FETCH(dbh, keysv)
+ SV * dbh
+ SV * keysv
+ CODE:
+ D_imp_dbh(dbh);
+ SV *valuesv = dbd_db_FETCH_attrib(dbh, imp_dbh, keysv);
+ if (!valuesv) {
+ valuesv = DBIS->get_attr(dbh, keysv);
+ }
+ ST(0) = valuesv; /* dbd_db_FETCH_attrib did sv_2mortal */
+
+
+void
+DESTROY(dbh)
+ SV * dbh
+ PPCODE:
+ D_imp_dbh(dbh);
+ ST(0) = &sv_yes;
+ if (!DBIc_IMPSET(imp_dbh)) { /* was never fully set up */
+ if (DBIc_WARN(imp_dbh) && !dirty && dbis->debug >= 2) {
+ warn("Database handle %s DESTROY ignored - never set up", SvPV(dbh,na));
+ }
+ }
+ else {
+ /* pre-disconnect checks and tidy-ups */
+ if (DBIc_CACHED_KIDS(imp_dbh)) {
+ SvREFCNT_dec(DBIc_CACHED_KIDS(imp_dbh));
+ DBIc_CACHED_KIDS(imp_dbh) = Nullhv;
+ }
+ if (DBIc_IADESTROY(imp_dbh)) { /* want's ineffective destroy */
+ DBIc_ACTIVE_off(imp_dbh);
+ }
+ if (DBIc_ACTIVE(imp_dbh)) {
+ if (DBIc_WARN(imp_dbh) && (!dirty || dbis->debug >= 3)) {
+ warn("Database handle destroyed without explicit disconnect");
+ }
+ /* The application has not explicitly disconnected. That's bad. */
+ /* To ensure integrity we *must* issue a rollback. This will be */
+ /* harmless if the application has issued a commit. If it hasn't */
+ /* then it'll ensure integrity. Consider a Ctrl-C killing perl */
+ /* between two statements that must be executed as a transaction. */
+ /* Perl will call DESTROY on the dbh and, if we don't rollback, */
+ /* the server will automatically commit! Bham! Corrupt database! */
+ if (!DBIc_has(imp_dbh,DBIcf_AutoCommit)) {
+ dbd_db_rollback(dbh, imp_dbh); /* ROLLBACK! */
+ }
+ dbd_db_disconnect(dbh, imp_dbh);
+ }
+ dbd_db_destroy(dbh, imp_dbh);
+ }
+
+
+# driver specific functions
+
+
+void
+lo_open(dbh, lobjId, mode)
+ SV * dbh
+ unsigned int lobjId
+ int mode
+ CODE:
+ int ret = pg_db_lo_open(dbh, lobjId, mode);
+ ST(0) = (-1 != ret) ? sv_2mortal(newSViv(ret)) : &sv_undef;
+
+void
+lo_close(dbh, fd)
+ SV * dbh
+ int fd
+ CODE:
+ ST(0) = (-1 != pg_db_lo_close(dbh, fd)) ? &sv_yes : &sv_no;
+
+
+void
+lo_read(dbh, fd, buf, len)
+ SV * dbh
+ int fd
+ char * buf
+ int len
+ PREINIT:
+ SV *bufsv = SvROK(ST(2)) ? SvRV(ST(2)) : ST(2);
+ int ret;
+ CODE:
+ buf = SvGROW(bufsv, len + 1);
+ ret = pg_db_lo_read(dbh, fd, buf, len);
+ if (ret > 0) {
+ SvCUR_set(bufsv, ret);
+ *SvEND(bufsv) = '\0';
+ sv_setpvn(ST(2), buf, ret);
+ SvSETMAGIC(ST(2));
+ }
+ ST(0) = (-1 != ret) ? sv_2mortal(newSViv(ret)) : &sv_undef;
+
+
+void
+lo_write(dbh, fd, buf, len)
+ SV * dbh
+ int fd
+ char * buf
+ int len
+ CODE:
+ int ret = pg_db_lo_write(dbh, fd, buf, len);
+ ST(0) = (-1 != ret) ? sv_2mortal(newSViv(ret)) : &sv_undef;
+
+
+void
+lo_lseek(dbh, fd, offset, whence)
+ SV * dbh
+ int fd
+ int offset
+ int whence
+ CODE:
+ int ret = pg_db_lo_lseek(dbh, fd, offset, whence);
+ ST(0) = (-1 != ret) ? sv_2mortal(newSViv(ret)) : &sv_undef;
+
+
+void
+lo_creat(dbh, mode)
+ SV * dbh
+ int mode
+ CODE:
+ int ret = pg_db_lo_creat(dbh, mode);
+ ST(0) = (-1 != ret) ? sv_2mortal(newSViv(ret)) : &sv_undef;
+
+
+void
+lo_tell(dbh, fd)
+ SV * dbh
+ int fd
+ CODE:
+ int ret = pg_db_lo_tell(dbh, fd);
+ ST(0) = (-1 != ret) ? sv_2mortal(newSViv(ret)) : &sv_undef;
+
+
+void
+lo_unlink(dbh, lobjId)
+ SV * dbh
+ unsigned int lobjId
+ CODE:
+ ST(0) = (-1 != pg_db_lo_unlink(dbh, lobjId)) ? &sv_yes : &sv_no;
+
+
+void
+lo_import(dbh, filename)
+ SV * dbh
+ char * filename
+ CODE:
+ unsigned int ret = pg_db_lo_import(dbh, filename);
+ ST(0) = (ret) ? sv_2mortal(newSViv(ret)) : &sv_undef;
+
+
+void
+lo_export(dbh, lobjId, filename)
+ SV * dbh
+ unsigned int lobjId
+ char * filename
+ CODE:
+ ST(0) = (-1 != pg_db_lo_export(dbh, lobjId, filename)) ? &sv_yes : &sv_no;
+
+
+void
+putline(dbh, buf)
+ SV * dbh
+ char * buf
+ CODE:
+ int ret = pg_db_putline(dbh, buf);
+ ST(0) = (-1 != ret) ? &sv_yes : &sv_no;
+
+
+void
+getline(dbh, buf, len)
+ PREINIT:
+ SV *bufsv = SvROK(ST(1)) ? SvRV(ST(1)) : ST(1);
+ INPUT:
+ SV * dbh
+ int len
+ char * buf = sv_grow(bufsv, len);
+ CODE:
+ int ret = pg_db_getline(dbh, buf, len);
+ if (*buf == '\\' && *(buf+1) == '.') {
+ ret = -1;
+ }
+ sv_setpv((SV*)ST(1), buf);
+ SvSETMAGIC(ST(1));
+ ST(0) = (-1 != ret) ? &sv_yes : &sv_no;
+
+
+void
+endcopy(dbh)
+ SV * dbh
+ CODE:
+ ST(0) = (-1 != pg_db_endcopy(dbh)) ? &sv_yes : &sv_no;
+
+
+# -- end of DBD::Pg::db
+
+
+# ------------------------------------------------------------
+# statement interface
+# ------------------------------------------------------------
+MODULE = DBD::Pg PACKAGE = DBD::Pg::st
+
+void
+_prepare(sth, statement, attribs=Nullsv)
+ SV * sth
+ char * statement
+ SV * attribs
+ CODE:
+ {
+ D_imp_sth(sth);
+ D_imp_dbh_from_sth;
+ DBD_ATTRIBS_CHECK("_prepare", sth, attribs);
+ if (!strncasecmp(statement, "begin", 5) ||
+ !strncasecmp(statement, "end", 4) ||
+ !strncasecmp(statement, "commit", 6) ||
+ !strncasecmp(statement, "abort", 5) ||
+ !strncasecmp(statement, "rollback", 8) ) {
+ warn("please use DBI functions for transaction handling");
+ ST(0) = &sv_no;
+ } else {
+ ST(0) = dbd_st_prepare(sth, imp_sth, statement, attribs) ? &sv_yes : &sv_no;
+ }
+ }
+
+
+void
+rows(sth)
+ SV * sth
+ CODE:
+ D_imp_sth(sth);
+ XST_mIV(0, dbd_st_rows(sth, imp_sth));
+
+
+void
+bind_param(sth, param, value, attribs=Nullsv)
+ SV * sth
+ SV * param
+ SV * value
+ SV * attribs
+ CODE:
+ {
+ IV sql_type = 0;
+ D_imp_sth(sth);
+ if (attribs) {
+ if (SvNIOK(attribs)) {
+ sql_type = SvIV(attribs);
+ attribs = Nullsv;
+ }
+ else {
+ SV **svp;
+ DBD_ATTRIBS_CHECK("bind_param", sth, attribs);
+ /* XXX we should perhaps complain if TYPE is not SvNIOK */
+ DBD_ATTRIB_GET_IV(attribs, "TYPE", 4, svp, sql_type);
+ }
+ }
+ ST(0) = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, FALSE, 0) ? &sv_yes : &sv_no;
+ }
+
+
+void
+bind_param_inout(sth, param, value_ref, maxlen, attribs=Nullsv)
+ SV * sth
+ SV * param
+ SV * value_ref
+ IV maxlen
+ SV * attribs
+ CODE:
+ {
+ IV sql_type = 0;
+ D_imp_sth(sth);
+ if (!SvROK(value_ref) || SvTYPE(SvRV(value_ref)) > SVt_PVMG) {
+ croak("bind_param_inout needs a reference to a scalar value");
+ }
+ if (SvREADONLY(SvRV(value_ref))) {
+ croak(no_modify);
+ }
+ if (attribs) {
+ if (SvNIOK(attribs)) {
+ sql_type = SvIV(attribs);
+ attribs = Nullsv;
+ }
+ else {
+ SV **svp;
+ DBD_ATTRIBS_CHECK("bind_param", sth, attribs);
+ DBD_ATTRIB_GET_IV(attribs, "TYPE", 4, svp, sql_type);
+ }
+ }
+ ST(0) = dbd_bind_ph(sth, imp_sth, param, SvRV(value_ref), sql_type, attribs, TRUE, maxlen) ? &sv_yes : &sv_no;
+ }
+
+
+void
+execute(sth, ...)
+ SV * sth
+ CODE:
+ D_imp_sth(sth);
+ int ret;
+ if (items > 1) {
+ /* Handle binding supplied values to placeholders */
+ int i;
+ SV *idx;
+ imp_sth->all_params_len = 0; /* used for malloc of statement string in case we have placeholders */
+ if (items-1 != DBIc_NUM_PARAMS(imp_sth)) {
+ croak("execute called with %ld bind variables, %d needed", items-1, DBIc_NUM_PARAMS(imp_sth));
+ XSRETURN_UNDEF;
+ }
+ idx = sv_2mortal(newSViv(0));
+ for(i=1; i < items ; ++i) {
+ sv_setiv(idx, i);
+ if (!dbd_bind_ph(sth, imp_sth, idx, ST(i), 0, Nullsv, FALSE, 0)) {
+ XSRETURN_UNDEF; /* dbd_bind_ph already registered error */
+ }
+ }
+ }
+ ret = dbd_st_execute(sth, imp_sth);
+ /* remember that dbd_st_execute must return <= -2 for error */
+ if (ret == 0) { /* ok with no rows affected */
+ XST_mPV(0, "0E0"); /* (true but zero) */
+ }
+ else if (ret < -1) { /* -1 == unknown number of rows */
+ XST_mUNDEF(0); /* <= -2 means error */
+ }
+ else {
+ XST_mIV(0, ret); /* typically 1, rowcount or -1 */
+ }
+
+
+void
+fetchrow_arrayref(sth)
+ SV * sth
+ ALIAS:
+ fetch = 1
+ CODE:
+ D_imp_sth(sth);
+ AV *av = dbd_st_fetch(sth, imp_sth);
+ ST(0) = (av) ? sv_2mortal(newRV_inc((SV *)av)) : &sv_undef;
+
+
+void
+fetchrow_array(sth)
+ SV * sth
+ ALIAS:
+ fetchrow = 1
+ PPCODE:
+ D_imp_sth(sth);
+ AV *av;
+ av = dbd_st_fetch(sth, imp_sth);
+ if (av) {
+ int num_fields = AvFILL(av)+1;
+ int i;
+ EXTEND(sp, num_fields);
+ for(i=0; i < num_fields; ++i) {
+ PUSHs(AvARRAY(av)[i]);
+ }
+ }
+
+
+void
+finish(sth)
+ SV * sth
+ CODE:
+ D_imp_sth(sth);
+ D_imp_dbh_from_sth;
+ if (!DBIc_ACTIVE(imp_dbh)) {
+ /* Either an explicit disconnect() or global destruction */
+ /* has disconnected us from the database. Finish is meaningless */
+ /* XXX warn */
+ XSRETURN_YES;
+ }
+ if (!DBIc_ACTIVE(imp_sth)) {
+ /* No active statement to finish */
+ XSRETURN_YES;
+ }
+ ST(0) = dbd_st_finish(sth, imp_sth) ? &sv_yes : &sv_no;
+
+
+void
+blob_read(sth, field, offset, len, destrv=Nullsv, destoffset=0)
+ SV * sth
+ int field
+ long offset
+ long len
+ SV * destrv
+ long destoffset
+ CODE:
+ {
+ D_imp_sth(sth);
+ if (!destrv) {
+ destrv = sv_2mortal(newRV_inc(sv_2mortal(newSViv(0))));
+ }
+ ST(0) = dbd_st_blob_read(sth, imp_sth, field, offset, len, destrv, destoffset) ? SvRV(destrv) : &sv_undef;
+ }
+
+void
+STORE(sth, keysv, valuesv)
+ SV * sth
+ SV * keysv
+ SV * valuesv
+ CODE:
+ D_imp_sth(sth);
+ ST(0) = &sv_yes;
+ if (!dbd_st_STORE_attrib(sth, imp_sth, keysv, valuesv)) {
+ if (!DBIS->set_attr(sth, keysv, valuesv)) {
+ ST(0) = &sv_no;
+ }
+ }
+
+
+# FETCH renamed and ALIASed to avoid case clash on VMS :-(
+void
+FETCH_attrib(sth, keysv)
+ SV * sth
+ SV * keysv
+ ALIAS:
+ FETCH = 1
+ CODE:
+ D_imp_sth(sth);
+ SV *valuesv = dbd_st_FETCH_attrib(sth, imp_sth, keysv);
+ if (!valuesv) {
+ valuesv = DBIS->get_attr(sth, keysv);
+ }
+ ST(0) = valuesv; /* dbd_st_FETCH_attrib did sv_2mortal */
+
+
+void
+DESTROY(sth)
+ SV * sth
+ PPCODE:
+ D_imp_sth(sth);
+ ST(0) = &sv_yes;
+ if (!DBIc_IMPSET(imp_sth)) { /* was never fully set up */
+ if (DBIc_WARN(imp_sth) && !dirty && dbis->debug >= 2) {
+ warn("Statement handle %s DESTROY ignored - never set up", SvPV(sth,na));
+ }
+ }
+ else {
+ if (DBIc_IADESTROY(imp_sth)) { /* want's ineffective destroy */
+ DBIc_ACTIVE_off(imp_sth);
+ }
+ if (DBIc_ACTIVE(imp_sth)) {
+ dbd_st_finish(sth, imp_sth);
+ }
+ dbd_st_destroy(sth, imp_sth);
+ }
+
+
+# end of Pg.xs
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/README b/install/5.005/DBD-Pg-1.22-fixvercmp/README
new file mode 100644
index 0000000..7edebde
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/README
@@ -0,0 +1,166 @@
+
+DBD::Pg -- the DBI PostgreSQL interface for Perl
+
+# $Id: README,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+DESCRIPTION:
+------------
+
+This is version 1.21 of DBD-Pg. The web site for this interface is at:
+
+ http://gborg.postgresql.org/project/dbdpg/projdisplay.php
+
+For further information about DBI look at:
+
+ http://dbi.perl.org/
+
+For information about PostgreSQL, visit:
+
+ http://www.postgresql.org/
+
+COPYRIGHT:
+----------
+
+ Portions Copyright (c) 1994,1995,1996,1997 Tim Bunce
+ Copyright (c) 1997,1998,1999,2000 Edmund Mergl
+ Copyright (c) 2002 Jeffrey W. Baker
+ Copyright (c) 2002 PostgreSQL Global Development Group
+
+You may distribute under the terms of either the GNU General Public
+License or the Artistic License, as specified in the Perl README file.
+
+
+HOW TO GET THE LATEST VERSION:
+------------------------------
+
+Use the following URL to look for new versions of this module:
+
+ http://gborg.postgresql.org/project/dbdpg/projdisplay.php
+
+or
+
+ http://www.perl.com/CPAN/modules/by-module/DBD/
+
+Note, that this request will be redirected automatically to the
+nearest CPAN site.
+
+
+IF YOU HAVE PROBLEMS:
+---------------------
+
+Please send comments and bug-reports to <dbd-general@gborg.postgresql.org>
+
+Please include the output of perl -v and perl -V, the version of PostgreSQL,
+the version of DBD-Pg, the version of DBI, and details about your platform
+in your bug-report.
+
+
+REQUIREMENTS:
+-------------
+
+ build, test, and install Perl 5 (at least 5.005)
+ build, test, and install the DBI module (at least 1.30)
+ build, test, and install PostgreSQL (at least 7.3)
+ build, test, and install Test::Simple (at least 0.17)
+
+INSTALLATION:
+-------------
+
+By default Makefile.PL uses App:Info to find the location of the
+PostgreSQL library and include directories. However, if you want to
+control it yourself, define the environment variables POSTGRES_INCLUDE
+and POSTGRES_LIB, or POSTGRES_HOME.
+
+ 1. perl Makefile.PL
+ 2. make
+ 3. make test
+ 4. make install
+
+Do steps 1 to 3 as normal user, not as root!
+
+
+TESTING:
+--------
+
+The tests are designed to connect to a live database. The following
+environment variables must be set for the tests to run:
+
+ DBI_DSN=dbi:Pg:dbname=<database>
+ DBI_USER=<username>
+ DBI_PASS=<password>
+
+If you are using the shared library libpq.so check if your dynamic
+loader finds libpq.so. With Linux the command /sbin/ldconfig -v should
+tell you, where it finds libpq.so. If ldconfig does not find libpq.so,
+either add an appropriate entry to /etc/ld.so.conf and re-run ldconfig
+or add the path to the environment variable LD_LIBRARY_PATH.
+
+A typical error message resulting from not finding libpq.so is:
+
+ install_driver(Pg) failed: Can't load './blib/arch/auto/DBD/Pg/Pg.so'
+ for module DBD::Pg: File not found at
+
+If you get an error message like:
+
+ perl: error while loading shared libraries:
+ /usr/lib/perl5/site_perl/5.6.0/i386-linux/auto/DBD/Pg/Pg.so: undefined
+ symbol: PQconnectdb
+
+when you call DBI->connect, then your libpq.so was probably not seen at
+build-time. This should have caused 'make test' to fail; did you really
+run it and look at the output? Check the setting of POSTGRES_LIB and
+recompile DBD-Pg.
+
+Some linux distributions have incomplete perl installations. If you have
+compile errors like "XS_VERSION_BOOTCHECK undeclared", do:
+
+ find .../lib/perl5 -name XSUB.h -print
+
+If this file is not present, you need to recompile and re-install perl.
+
+SGI users: if you get segmentation faults make sure, you use the malloc
+which comes with perl when compiling perl (the default is not to).
+"David R. Noble" <drnoble@engsci.sandia.gov>
+
+HP users: if you get error messages like:
+
+ can't open shared library: .../lib/libpq.sl
+ No such file or directory
+
+when running the test script, try to replace the 'shared' option in the
+LDDFLAGS with 'archive'. Dan Lauterbach <danla@dimensional.com>
+
+
+FreeBSD users: if you get during make test the error message:
+
+ 'DBD driver has not implemented the AutoCommit attribute'
+
+recompile the DBI module and the DBD-Pg module and disable optimization.
+This error message is due to the broken optimization in gcc-2.7.2.1.
+
+If you get compiler errors like:
+ In function `XS_DBD__Pg__dr_discon_all_'
+ `sv_yes' undeclared (first use in this function)
+
+It may be because there is a 'patchlevel.h' file from another package
+(such as 'hdf') in your POSTGRES_INCLUDE dir. The presence of this file
+prevents the compiler from finding the perl include file
+'mach/CORE/patchlevel.h'. Do 'pg_config --includedir' to identify the
+POSTGRES_INCLUDE dir. Rename patchlevel.h whilst you build DBD::Pg.
+
+
+Sun Users: if you get compile errors like:
+
+ /usr/include/string.h:57: parse error before `]'
+
+then you need to remove from pgsql/include/libpq-fe.h the define for
+strerror, which clashes with the definition in the standard include
+file.
+
+Win32 Users: Running DBD-Pg scripts on Win32 needs some configuration work
+on the server side:
+
+ o add a postgres user with the same name as the NT-User
+ (eg Administrator)
+ o make sure, that your pg_hba.conf on the server is configured,
+ such that a connection from another host will be accepted
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/README.win32 b/install/5.005/DBD-Pg-1.22-fixvercmp/README.win32
new file mode 100644
index 0000000..3cbe673
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/README.win32
@@ -0,0 +1,63 @@
+
+$Id: README.win32,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+
+Here is a step-by-step procedure for getting DBD-Pg to work on Windows
+NT. This Port has been done by Bob Kline <bkline@rksystems.com>.
+
+
+prerequisites: (older versions might also work, but these are the
+-------------- versions I used)
+
+ o Windows NT4 SP4
+ o Visual Studio 6.0
+ o ActivePerl-5_6_0_613 with DBI-1.13
+ o postgresql-7.0.2
+ o DBD-Pg-0.95
+
+Here we assume, that perl and postgresql have been installed in C:\. Now
+perform the following steps:
+
+
+1. compile libpq
+----------------
+
+set POSTGRES_HOME=C:\postgresql-7.0.2
+cd postgresql-7.0.2
+mkdir lib
+mkdir include
+cd src
+copy include\port\win32.h include\os.h
+edit interfaces\libpq\fe-connect.c and add as first statement in connectDBStart() the following code:
+ #ifdef WIN32
+ static int WeHaveCalledWSAStartup;
+ if (!WeHaveCalledWSAStartup) {
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(1, 1), &wsaData)) {
+ printfPQExpBuffer(&conn->errorMessage, "WSAStartup failed: errno=%d\n", h_errno);
+ goto connect_errReturn;
+ }
+ WeHaveCalledWSAStartup = 1;
+ }
+ #endif
+edit interfaces\libpq\win32.mak and change the flag /ML to /MD: CPP_PROJ=/nologo /MD ...
+nmake /f win32.mak
+cd ..
+copy src\interfaces\libpq\Release\libpq.lib lib
+copy src\interfaces\libpq\libpq-fe.h include
+copy src\include\postgres_ext.h include
+cd ..
+
+
+2. build DBD-Pg
+---------------
+
+cd DBD-Pg
+perl Makefile.PL CAPI=TRUE
+nmake
+set the environment variable PGHOST to the name of the postgresql server: set PGHOST=myserver
+add on the server a postgres user with the same name as the NT-User (eg Administrator)
+make sure, that your pg_hba.conf on the server is configured, such that a connection from another host will be accepted
+mkdir C:\tmp
+nmake test (expect to get errors concerning blobs)
+nmake install
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/dbd-pg.pod b/install/5.005/DBD-Pg-1.22-fixvercmp/dbd-pg.pod
new file mode 100644
index 0000000..ccbbc63
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/dbd-pg.pod
@@ -0,0 +1,411 @@
+
+# $Id: dbd-pg.pod,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+=head1 NAME
+
+DBD::Pg - PostgreSQL database driver for the DBI module
+
+=head1 DESCRIPTION
+
+DBD::Pg is a Perl module which works with the DBI module to provide
+access to PostgreSQL databases.
+
+=head1 DBD::Pg
+
+=begin docbook
+<!-- The following blank =head1 is to allow us to use purely =head2 headings -->
+<!-- This keeps the POD fairly simple with regards to Pod::DocBook -->
+
+=end docbook
+
+=head1
+
+=head2 Version
+
+Version 0.91.
+
+=head2 Author and Contact Details
+
+The driver author is Edmund Mergl. He can be contacted via the
+I<dbi-users> mailing list.
+
+
+=head2 Supported Database Versions and Options
+
+The DBD-Pg-0.92 module supports Postgresql 6.5.
+
+
+=head2 Connect Syntax
+
+The C<DBI-E<gt>connect()> Data Source Name, or I<DSN>, can be one of the
+following:
+
+ dbi:Pg:dbname=$dbname
+ dbi:Pg:dbname=$dbname;host=$host;port=$port;options=$options;tty=$tty
+
+All parameters, including the userid and password parameter of the
+connect command, have a hard-coded default which can be overridden
+by setting appropriate environment variables:
+
+ Parameter Environment Variable Default
+ --------- -------------------- --------------
+ dbname PGDATABASE current userid
+ host PGHOST localhost
+ port PGPORT 5432
+ options PGOPTIONS ""
+ tty PGTTY ""
+ username PGUSER current userid
+ password PGPASSWORD ""
+
+There are no driver specific attributes for the C<DBI->connect()> method.
+
+
+=head2 Numeric Data Handling
+
+Postgresql supports the following numeric types:
+
+ Postgresql Range
+ ---------- --------------------------
+ int2 -32768 to +32767
+ int4 -2147483648 to +2147483647
+ float4 6 decimal places
+ float8 15 decimal places
+
+Some platforms also support the int8 type.
+C<DBD::Pg> always returns all numbers as strings.
+
+
+=head2 String Data Handling
+
+Postgresql supports the following string data types:
+
+ CHAR single character
+ CHAR(size) fixed length blank-padded
+ VARCHAR(size) variable length with limit
+ TEXT variable length
+
+All string data types have a limit of 4096 bytes.
+The CHAR type is fixed length and blank padded.
+
+There is no special handling for data with the 8th bit set. They
+are stored unchanged in the database.
+None of the character types can store embedded nulls and Unicode is
+not formally supported.
+
+Strings can be concatenated using the C<||> operator.
+
+
+=head2 Date Data Handling
+
+Postgresql supports the following date time data types:
+
+ Type Storage Recommendation Description
+ --------- -------- -------------------------- ----------------------------
+ abstime 4 bytes original date and time limited range
+ date 4 bytes SQL92 type wide range
+ datetime 8 bytes best general date and time wide range, high precision
+ interval 12 bytes SQL92 type equivalent to timespan
+ reltime 4 bytes original time interval limited range, low precision
+ time 4 bytes SQL92 type wide range
+ timespan 12 bytes best general time interval wide range, high precision
+ timestamp 4 bytes SQL92 type limited range
+
+ Data Type Range Resolution
+ ---------- ---------------------------------- -----------
+ abstime 1901-12-14 2038-01-19 1 sec
+ timestamp 1901-12-14 2038-01-19 1 sec
+ reltime -68 years +68 years 1 sec
+ tinterval -178000000 years +178000000 years 1 microsec
+ timespan -178000000 years 178000000 years 1 microsec
+ date 4713 BC 32767 AD 1 day
+ datetime 4713 BC 1465001 AD 1 microsec
+ time 00:00:00:00 23:59:59:99 1 microsec
+
+Postgresql supports a range of date formats:
+
+ Name Example
+ ----------- ----------------------
+ ISO 1997-12-17 0:37:16-08
+ SQL 12/17/1997 07:37:16.00 PST
+ Postgres Wed Dec 17 07:37:16 1997 PST
+ European 17/12/1997 15:37:16.00 MET
+ NonEuropean 12/17/1997 15:37:16.00 MET
+ US 12/17/1997 07:37:16.00 MET
+
+The default output format does not depend on the client/server locale.
+It depends on, in increasing priority: the PGDATESTYLE environment
+variable at the server, the PGDATESTYLE environment variable at the client, and
+the C<SET DATESTYLE> SQL command.
+
+All of the formats described above can be used for input. A great many
+others can also be used. There is no specific default input format.
+If the format of a date input is ambiguous then the current DATESTYLE
+is used to help disambiguate.
+
+If you specify a date/time value without a time component, the default
+time is 00:00:00 (midnight). To specify a date/time value without a date
+is not allowed.
+If a date with a two digit year is input then if the year was less than
+70, add 2000; otherwise, add 1900.
+
+The currect date/time is returned by the keyword C<'now'> or C<'current'>,
+which has to be casted to a valid data type. For example:
+
+ SELECT 'now'::datetime
+
+Postgresql supports a range of date time functions for converting
+between types, extracting parts of a date time value, truncating to a
+given unit, etc. The usual arithmetic can be performed on date and
+interval values, e.g., date-date=interval, etc.
+
+The following SQL expression can be used to convert an integer "seconds
+since 1-jan-1970 GMT" value to the corresponding database date time:
+
+ DATETIME(unixtime_field)
+
+and to do the reverse:
+
+ DATE_PART('epoch', datetime_field)
+
+The server stores all dates internally in GMT. Times are converted to
+local time on the database server before being sent to the client
+frontend, hence by default are in the server time zone.
+
+The TZ environment variable is used by the server as default time
+zone. The PGTZ environment variable on the client side is used to send
+the time zone information to the backend upon connection. The SQL C<SET
+TIME ZONE> command can set the time zone for the current session.
+
+
+=head2 LONG/BLOB Data Handling
+
+Postgresql handles BLOBS using a so called "large objects" type. The
+handling of this type differs from all other data types. The data are
+broken into chunks, which are stored in tuples in the database. Access
+to large objects is given by an interface which is modelled closely
+after the UNIX file system. The maximum size is limited by the file
+size of the operating system.
+
+
+If you just select the field, you get a "large object identifier" and
+not the data itself. The I<LongReadLen> and I<LongTruncOk> attributes are
+not implemented because they don't make sense in this case. The only
+method implemented by the driver is the undocumented DBI method
+C<blob_read()>.
+
+
+=head2 Other Data Handling issues
+
+The C<DBD::Pg> driver supports the C<type_info()> method.
+
+Postgresql supports automatic conversions between data types wherever
+it's reasonable.
+
+=head2 Transactions, Isolation and Locking
+
+Postgresql supports transactions.
+The current default isolation transaction level is "Serializable" and
+is currently implemented using table level locks. Both may change.
+No other isolation levels for transactions are supported.
+
+With AutoCommit on, a query never places a lock on a table. Readers
+never block writers and writers never block readers. This behavior
+changes whenever a transaction is started (AutoCommit off). Then a
+query induces a shared lock on a table and blocks anyone else
+until the transaction has been finished.
+
+The C<LOCK TABLE table_name> statement can be used to apply an explicit
+lock on a table. This only works inside a transaction (AutoCommit off).
+
+To ensure that a table being selected does not change before you make
+an update later in the transaction, you must explicitly lock it with a
+C<LOCK TABLE> statement before executing the select.
+
+
+=head2 No-Table Expression Select Syntax
+
+To select a constant expression, that is, an expression that doesn't involve
+data from a database table or view, just omit the "from" clause.
+Here's an example that selects the current time as a datetime:
+
+ SELECT 'now'::datetime;
+
+=head2 Table Join Syntax
+
+Outer joins are not supported. Inner joins use the traditional syntax.
+
+=head2 Table and Column Names
+
+The max size of table and column names cannot exceed 31 charaters in
+length.
+Only alphanumeric characters can be used; the first character must
+be a letter.
+
+If an identifier is enclosed by double quotation marks (C<">), it can
+contain any combination of characters except double quotation marks.
+
+Postgresql converts all identifiers to lower-case unless enclosed in
+double quotation marks.
+National character set characters can be used, if enclosed in quotation
+marks.
+
+
+=head2 Case Sensitivity of LIKE Operator
+
+Postgresql has the following string matching operators:
+
+ Glyph Description Example
+ ----- ---------------------------------------- -----------------------------
+ ~~ Same as SQL "LIKE" operator 'scrappy,marc' ~~ '%scrappy%'
+ !~~ Same as SQL "NOT LIKE" operator 'bruce' !~~ '%al%'
+ ~ Match (regex), case sensitive 'thomas' ~ '.*thomas.*'
+ ~* Match (regex), case insensitive 'thomas' ~* '.*Thomas.*'
+ !~ Does not match (regex), case sensitive 'thomas' !~ '.*Thomas.*'
+ !~* Does not match (regex), case insensitive 'thomas' !~ '.*vadim.*'
+
+
+=head2 Row ID
+
+The Postgresql "row id" pseudocolumn is called I<oid>, object identifier.
+It can be treated as a string and used to rapidly (re)select rows.
+
+
+=head2 Automatic Key or Sequence Generation
+
+Postgresql does not support automatic key generation such as "auto
+increment" or "system generated" keys.
+
+However, Postgresql does support "sequence generators". Any number of
+named sequence generators can be created in a database. Sequences
+are used via functions called C<NEXTVAL> and C<CURRVAL>. Typical usage:
+
+ INSERT INTO table (k, v) VALUES (nextval('seq_name'), ?);
+
+To get the value just inserted, you can use the corresponding C<currval()>
+SQL function in the same session, or
+
+ SELECT last_value FROM seq_name
+
+
+=head2 Automatic Row Numbering and Row Count Limiting
+
+Postgresql does not support any way of automatically numbering returned rows.
+
+
+=head2 Parameter Binding
+
+Parameter binding is emulated by the driver.
+Both the C<?> and C<:1> style of placeholders are supported.
+
+The TYPE attribute of the C<bind_param()> method may be used to
+influence how parameters are treated. These SQL types are bound as
+VARCHAR: SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT,
+SQL_FLOAT, SQL_REAL, SQL_DOUBLE, SQL_VARCHAR.
+
+The SQL_CHAR type is bound as a CHAR thus enabling fixed-width blank
+padded comparison semantics.
+
+Unsupported values of the TYPE attribute generate a warning.
+
+
+=head2 Stored Procedures
+
+C<DBD::Pg> does not support stored procedures.
+
+
+=head2 Table Metadata
+
+C<DBD::Pg> supports the C<table_info()> method.
+
+The I<pg_attribute> table contains detailed information about all columns
+of all the tables in the database, one row per table.
+
+The I<pg_index> table contains detailed information about all indexes in
+the database, one row per index.
+
+Primary keys are implemented as unique indexes. See I<pg_index> above.
+
+
+=head2 Driver-specific Attributes and Methods
+
+There are no significant C<DBD::Pg> driver-specific database handle attributes.
+
+C<DBD::Pg> has the following driver-specific statement handle attributes:
+
+=over 8
+
+=item I<pg_size>
+
+Returns a reference to an array of integer values for each column. The
+integer shows the storage (not display) size of the column in bytes.
+Variable length columns are indicated by -1.
+
+=item I<pg_type>
+
+Returns a reference to an array of strings for each column. The string
+shows the name of the data type.
+
+=item I<pg_oid_status>
+
+Returns the OID of the last INSERT command.
+
+=item I<pg_cmd_status>
+
+Returns the name of the last command type. Possible types are: INSERT,
+DELETE, UPDATE, SELECT.
+
+=back
+
+
+C<DBD::Pg> has no private methods.
+
+
+=head2 Positioned updates and deletes
+
+Postgresql does not support positioned updates or deletes.
+
+
+=head2 Differences from the DBI Specification
+
+C<DBD::Pg> has no significant differences in behavior from the
+current DBI specification.
+
+Note that C<DBD::Pg> does not fully parse the statement until
+it's executed. Thus attributes like I<$sth-E<gt>{NUM_OF_FIELDS}> are not
+available until after C<$sth-E<gt>execute> has been called. This is valid
+behaviour but is important to note when porting applications
+originally written for other drivers.
+
+
+=head2 URLs to More Database/Driver Specific Information
+
+ http://www.postgresql.org
+
+
+=head2 Concurrent use of Multiple Handles
+
+C<DBD::Pg> supports an unlimited number of concurrent database
+connections to one or more databases.
+
+It also supports the preparation and execution of a new statement
+handle while still fetching data from another statement handle,
+provided it is
+associated with the same database handle.
+
+
+=head2 Other Significant Database or Driver Features
+
+Postgres offers substantial additional power by incorporating the
+following four additional basic concepts in such a way that users can
+easily extend the system: classes, inheritance, types, and functions.
+
+Other features provide additional power and flexibility: constraints,
+triggers, rules, transaction integrity, procedural languages, and large objects.
+
+It's also free Open Source Software with an active community of developers.
+
+=cut
+
+# This driver summary for DBD::Pg is Copyright (c) 1999 Tim Bunce
+# and Edmund Mergl.
+# $Id: dbd-pg.pod,v 1.1 2004-04-29 09:21:28 ivan Exp $
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/dbdimp.c b/install/5.005/DBD-Pg-1.22-fixvercmp/dbdimp.c
new file mode 100644
index 0000000..55f4ee7
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/dbdimp.c
@@ -0,0 +1,2024 @@
+/*
+ $Id: dbdimp.c,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+ Copyright (c) 1997,1998,1999,2000 Edmund Mergl
+ Copyright (c) 2002 Jeffrey W. Baker
+ Portions Copyright (c) 1994,1995,1996,1997 Tim Bunce
+
+ You may distribute under the terms of either the GNU General Public
+ License or the Artistic License, as specified in the Perl README file.
+
+*/
+
+
+/*
+ hard-coded OIDs: (here we need the postgresql types)
+ pg_sql_type() 1042 (bpchar), 1043 (varchar)
+ ddb_st_fetch() 1042 (bpchar), 16 (bool)
+ ddb_preparse() 1043 (varchar)
+ pgtype_bind_ok()
+*/
+
+#include "Pg.h"
+
+/* XXX DBI should provide a better version of this */
+#define IS_DBI_HANDLE(h) (SvROK(h) && SvTYPE(SvRV(h)) == SVt_PVHV && SvRMAGICAL(SvRV(h)) && (SvMAGIC(SvRV(h)))->mg_type == 'P')
+
+DBISTATE_DECLARE;
+
+/* hard-coded array delimiter */
+static char* array_delimiter = ",";
+
+static void dbd_preparse (imp_sth_t *imp_sth, char *statement);
+
+
+void
+dbd_init (dbistate)
+ dbistate_t *dbistate;
+{
+ DBIS = dbistate;
+}
+
+
+int
+dbd_discon_all (drh, imp_drh)
+ SV *drh;
+ imp_drh_t *imp_drh;
+{
+ dTHR;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_discon_all\n"); }
+
+ /* The disconnect_all concept is flawed and needs more work */
+ if (!dirty && !SvTRUE(perl_get_sv("DBI::PERL_ENDING",0))) {
+ sv_setiv(DBIc_ERR(imp_drh), (IV)1);
+ sv_setpv(DBIc_ERRSTR(imp_drh),
+ (char*)"disconnect_all not implemented");
+ DBIh_EVENT2(drh, ERROR_event,
+ DBIc_ERR(imp_drh), DBIc_ERRSTR(imp_drh));
+ return FALSE;
+ }
+ if (perl_destruct_level) {
+ perl_destruct_level = 0;
+ }
+ return FALSE;
+}
+
+
+/* Database specific error handling. */
+
+void
+pg_error (h, error_num, error_msg)
+ SV *h;
+ int error_num;
+ char *error_msg;
+{
+ D_imp_xxh(h);
+ char *err, *src, *dst;
+ int len = strlen(error_msg);
+
+ err = (char *)malloc(len + 1);
+ if (!err) {
+ return;
+ }
+ src = error_msg;
+ dst = err;
+
+ /* copy error message without trailing newlines */
+ while (*src != '\0' && *src != '\n') {
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+
+ sv_setiv(DBIc_ERR(imp_xxh), (IV)error_num); /* set err early */
+ sv_setpv(DBIc_ERRSTR(imp_xxh), (char*)err);
+ DBIh_EVENT2(h, ERROR_event, DBIc_ERR(imp_xxh), DBIc_ERRSTR(imp_xxh));
+ if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, "%s error %d recorded: %s\n", err, error_num, SvPV(DBIc_ERRSTR(imp_xxh),na)); }
+ free(err);
+}
+
+static int
+pgtype_bind_ok (dbtype)
+ int dbtype;
+{
+ /* basically we support types that can be returned as strings */
+ switch(dbtype) {
+ case 16: /* bool */
+ case 17: /* bytea */
+ case 18: /* char */
+ case 20: /* int8 */
+ case 21: /* int2 */
+ case 23: /* int4 */
+ case 25: /* text */
+ case 26: /* oid */
+ case 700: /* float4 */
+ case 701: /* float8 */
+ case 702: /* abstime */
+ case 703: /* reltime */
+ case 704: /* tinterval */
+ case 1042: /* bpchar */
+ case 1043: /* varchar */
+ case 1082: /* date */
+ case 1083: /* time */
+ case 1184: /* datetime */
+ case 1186: /* timespan */
+ case 1296: /* timestamp */
+ return 1;
+ }
+ return 0;
+}
+
+
+/* ================================================================== */
+
+int
+pg_db_login (dbh, imp_dbh, dbname, uid, pwd)
+ SV *dbh;
+ imp_dbh_t *imp_dbh;
+ char *dbname;
+ char *uid;
+ char *pwd;
+{
+ dTHR;
+
+ char *conn_str;
+ char *src;
+ char *dest;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "pg_db_login\n"); }
+
+ /* build connect string */
+ /* DBD-Pg syntax: 'dbname=dbname;host=host;port=port' */
+ /* pgsql syntax: 'dbname=dbname host=host port=port user=uid password=pwd' */
+
+ conn_str = (char *)malloc(strlen(dbname) + strlen(uid) + strlen(pwd) + 16 + 1);
+ if (! conn_str) {
+ return 0;
+ }
+
+ src = dbname;
+ dest = conn_str;
+ while (*src) {
+ if (*src != ';') {
+ *dest++ = *src++;
+ continue;
+ }
+ *dest++ = ' ';
+ src++;
+ }
+ *dest = '\0';
+
+ if (strlen(uid)) {
+ strcat(conn_str, " user=");
+ strcat(conn_str, uid);
+ }
+ if (strlen(uid) && strlen(pwd)) {
+ strcat(conn_str, " password=");
+ strcat(conn_str, pwd);
+ }
+
+ if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, "pg_db_login: conn_str = >%s<\n", conn_str); }
+
+ /* make a connection to the database */
+ imp_dbh->conn = PQconnectdb(conn_str);
+ free(conn_str);
+
+ /* check to see that the backend connection was successfully made */
+ if (PQstatus(imp_dbh->conn) != CONNECTION_OK) {
+ pg_error(dbh, PQstatus(imp_dbh->conn), PQerrorMessage(imp_dbh->conn));
+ PQfinish(imp_dbh->conn);
+ return 0;
+ }
+
+ imp_dbh->init_commit = 1; /* initialize AutoCommit */
+ imp_dbh->pg_auto_escape = 1; /* initialize pg_auto_escape */
+ imp_dbh->pg_bool_tf = 0; /* initialize pg_bool_tf */
+
+ DBIc_IMPSET_on(imp_dbh); /* imp_dbh set up now */
+ DBIc_ACTIVE_on(imp_dbh); /* call disconnect before freeing */
+ return 1;
+}
+
+
+int
+dbd_db_getfd (dbh, imp_dbh)
+ SV *dbh;
+ imp_dbh_t *imp_dbh;
+{
+ char id;
+ SV* retsv;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_getfd\n"); }
+
+ return PQsocket(imp_dbh->conn);
+}
+
+SV *
+dbd_db_pg_notifies (dbh, imp_dbh)
+ SV *dbh;
+ imp_dbh_t *imp_dbh;
+{
+ char id;
+ PGnotify* notify;
+ AV* ret;
+ SV* retsv;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_pg_notifies\n"); }
+
+ PQconsumeInput(imp_dbh->conn);
+
+ notify = PQnotifies(imp_dbh->conn);
+
+ if (!notify) return &sv_undef;
+
+ ret=newAV();
+
+ av_push(ret, newSVpv(notify->relname,0) );
+ av_push(ret, newSViv(notify->be_pid) );
+
+ /* Should free notify memory with PQfreemem() */
+
+ retsv = newRV(sv_2mortal((SV*)ret));
+
+ return retsv;
+}
+
+int
+dbd_db_ping (dbh)
+ SV *dbh;
+{
+ char id;
+ D_imp_dbh(dbh);
+ PGresult* result;
+ ExecStatusType status;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_ping\n"); }
+
+ if (NULL != imp_dbh->conn) {
+ result = PQexec(imp_dbh->conn, " ");
+ status = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+
+ if (PGRES_EMPTY_QUERY != status) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int
+dbd_db_commit (dbh, imp_dbh)
+ SV *dbh;
+ imp_dbh_t *imp_dbh;
+{
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_commit\n"); }
+
+ /* no commit if AutoCommit = on */
+ if (DBIc_has(imp_dbh, DBIcf_AutoCommit) != FALSE) {
+ return 0;
+ }
+
+ if (NULL != imp_dbh->conn) {
+ PGresult* result = 0;
+ ExecStatusType commitstatus, beginstatus;
+
+ /* execute commit */
+ result = PQexec(imp_dbh->conn, "commit");
+ commitstatus = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+
+ /* check result */
+ if (commitstatus != PGRES_COMMAND_OK) {
+ /* Only put the error message in DBH->errstr */
+ pg_error(dbh, commitstatus, PQerrorMessage(imp_dbh->conn));
+ }
+
+ /* start new transaction. AutoCommit must be FALSE, ref. 20 lines up */
+ result = PQexec(imp_dbh->conn, "begin");
+ beginstatus = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+ if (beginstatus != PGRES_COMMAND_OK) {
+ /* Maybe add some loud barf here? Raising some very high error? */
+ pg_error(dbh, beginstatus, "begin failed\n");
+ return 0;
+ }
+
+ /* if the initial COMMIT failed, return 0 now */
+ if (commitstatus != PGRES_COMMAND_OK) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int
+dbd_db_rollback (dbh, imp_dbh)
+ SV *dbh;
+ imp_dbh_t *imp_dbh;
+{
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_rollback\n"); }
+
+ /* no rollback if AutoCommit = on */
+ if (DBIc_has(imp_dbh, DBIcf_AutoCommit) != FALSE) {
+ return 0;
+ }
+
+ if (NULL != imp_dbh->conn) {
+ PGresult* result = 0;
+ ExecStatusType status;
+
+ /* execute rollback */
+ result = PQexec(imp_dbh->conn, "rollback");
+ status = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+
+ /* check result */
+ if (status != PGRES_COMMAND_OK) {
+ pg_error(dbh, status, "rollback failed\n");
+ return 0;
+ }
+
+ /* start new transaction. AutoCommit must be FALSE, ref. 20 lines up */
+ result = PQexec(imp_dbh->conn, "begin");
+ status = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+ if (status != PGRES_COMMAND_OK) {
+ pg_error(dbh, status, "begin failed\n");
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int
+dbd_db_disconnect (dbh, imp_dbh)
+ SV *dbh;
+ imp_dbh_t *imp_dbh;
+{
+ dTHR;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_disconnect\n"); }
+
+ /* We assume that disconnect will always work */
+ /* since most errors imply already disconnected. */
+ DBIc_ACTIVE_off(imp_dbh);
+
+ if (NULL != imp_dbh->conn) {
+ /* rollback if AutoCommit = off */
+ if (DBIc_has(imp_dbh, DBIcf_AutoCommit) == FALSE) {
+ PGresult* result = 0;
+ ExecStatusType status;
+ result = PQexec(imp_dbh->conn, "rollback");
+ status = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+ if (status != PGRES_COMMAND_OK) {
+ pg_error(dbh, status, "rollback failed\n");
+ return 0;
+ }
+ if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, "dbd_db_disconnect: AutoCommit=off -> rollback\n"); }
+ }
+
+ PQfinish(imp_dbh->conn);
+
+ imp_dbh->conn = NULL;
+ }
+
+ /* We don't free imp_dbh since a reference still exists */
+ /* The DESTROY method is the only one to 'free' memory. */
+ /* Note that statement objects may still exists for this dbh! */
+ return 1;
+}
+
+
+void
+dbd_db_destroy (dbh, imp_dbh)
+ SV *dbh;
+ imp_dbh_t *imp_dbh;
+{
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_destroy\n"); }
+
+ if (DBIc_ACTIVE(imp_dbh)) {
+ dbd_db_disconnect(dbh, imp_dbh);
+ }
+
+ /* Nothing in imp_dbh to be freed */
+ DBIc_IMPSET_off(imp_dbh);
+}
+
+
+int
+dbd_db_STORE_attrib (dbh, imp_dbh, keysv, valuesv)
+ SV *dbh;
+ imp_dbh_t *imp_dbh;
+ SV *keysv;
+ SV *valuesv;
+{
+ STRLEN kl;
+ char *key = SvPV(keysv,kl);
+ int newval = SvTRUE(valuesv);
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_STORE\n"); }
+
+ if (kl==10 && strEQ(key, "AutoCommit")) {
+ int oldval = DBIc_has(imp_dbh, DBIcf_AutoCommit);
+ DBIc_set(imp_dbh, DBIcf_AutoCommit, newval);
+ if (oldval == FALSE && newval != FALSE && imp_dbh->init_commit) {
+ /* do nothing, fall through */
+ if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, "dbd_db_STORE: initialize AutoCommit to on\n"); }
+ } else if (oldval == FALSE && newval != FALSE) {
+ if (NULL != imp_dbh->conn) {
+ /* commit any outstanding changes */
+ PGresult* result = 0;
+ ExecStatusType status;
+ result = PQexec(imp_dbh->conn, "commit");
+ status = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+ if (status != PGRES_COMMAND_OK) {
+ pg_error(dbh, status, "commit failed\n");
+ return 0;
+ }
+ }
+ if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, "dbd_db_STORE: switch AutoCommit to on: commit\n"); }
+ } else if ((oldval != FALSE && newval == FALSE) || (oldval == FALSE && newval == FALSE && imp_dbh->init_commit)) {
+ if (NULL != imp_dbh->conn) {
+ /* start new transaction */
+ PGresult* result = 0;
+ ExecStatusType status;
+ result = PQexec(imp_dbh->conn, "begin");
+ status = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+ if (status != PGRES_COMMAND_OK) {
+ pg_error(dbh, status, "begin failed\n");
+ return 0;
+ }
+ }
+ if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, "dbd_db_STORE: switch AutoCommit to off: begin\n"); }
+ }
+ /* only needed once */
+ imp_dbh->init_commit = 0;
+ return 1;
+ } else if (kl==14 && strEQ(key, "pg_auto_escape")) {
+ imp_dbh->pg_auto_escape = newval;
+ } else if (kl==10 && strEQ(key, "pg_bool_tf")) {
+ imp_dbh->pg_bool_tf = newval;
+#ifdef SvUTF8_off
+ } else if (kl==14 && strEQ(key, "pg_enable_utf8")) {
+ imp_dbh->pg_enable_utf8 = newval;
+#endif
+ } else {
+ return 0;
+ }
+}
+
+
+SV *
+dbd_db_FETCH_attrib (dbh, imp_dbh, keysv)
+ SV *dbh;
+ imp_dbh_t *imp_dbh;
+ SV *keysv;
+{
+ STRLEN kl;
+ char *key = SvPV(keysv,kl);
+ SV *retsv = Nullsv;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_FETCH\n"); }
+
+ if (kl==10 && strEQ(key, "AutoCommit")) {
+ retsv = boolSV(DBIc_has(imp_dbh, DBIcf_AutoCommit));
+ } else if (kl==14 && strEQ(key, "pg_auto_escape")) {
+ retsv = newSViv((IV)imp_dbh->pg_auto_escape);
+ } else if (kl==10 && strEQ(key, "pg_bool_tf")) {
+ retsv = newSViv((IV)imp_dbh->pg_bool_tf);
+#ifdef SvUTF8_off
+ } else if (kl==14 && strEQ(key, "pg_enable_utf8")) {
+ retsv = newSViv((IV)imp_dbh->pg_enable_utf8);
+#endif
+ } else if (kl==11 && strEQ(key, "pg_INV_READ")) {
+ retsv = newSViv((IV)INV_READ);
+ } else if (kl==12 && strEQ(key, "pg_INV_WRITE")) {
+ retsv = newSViv((IV)INV_WRITE);
+ }
+
+ if (!retsv) {
+ return Nullsv;
+ }
+ if (retsv == &sv_yes || retsv == &sv_no) {
+ return retsv; /* no need to mortalize yes or no */
+ }
+ return sv_2mortal(retsv);
+}
+
+
+/* driver specific functins */
+
+
+int
+pg_db_lo_open (dbh, lobjId, mode)
+ SV *dbh;
+ unsigned int lobjId;
+ int mode;
+{
+ D_imp_dbh(dbh);
+ return lo_open(imp_dbh->conn, lobjId, mode);
+}
+
+
+int
+pg_db_lo_close (dbh, fd)
+ SV *dbh;
+ int fd;
+{
+ D_imp_dbh(dbh);
+ return lo_close(imp_dbh->conn, fd);
+}
+
+
+int
+pg_db_lo_read (dbh, fd, buf, len)
+ SV *dbh;
+ int fd;
+ char *buf;
+ int len;
+{
+ D_imp_dbh(dbh);
+ return lo_read(imp_dbh->conn, fd, buf, len);
+}
+
+
+int
+pg_db_lo_write (dbh, fd, buf, len)
+ SV *dbh;
+ int fd;
+ char *buf;
+ int len;
+{
+ D_imp_dbh(dbh);
+ return lo_write(imp_dbh->conn, fd, buf, len);
+}
+
+
+int
+pg_db_lo_lseek (dbh, fd, offset, whence)
+ SV *dbh;
+ int fd;
+ int offset;
+ int whence;
+{
+ D_imp_dbh(dbh);
+ return lo_lseek(imp_dbh->conn, fd, offset, whence);
+}
+
+
+unsigned int
+pg_db_lo_creat (dbh, mode)
+ SV *dbh;
+ int mode;
+{
+ D_imp_dbh(dbh);
+ return lo_creat(imp_dbh->conn, mode);
+}
+
+
+int
+pg_db_lo_tell (dbh, fd)
+ SV *dbh;
+ int fd;
+{
+ D_imp_dbh(dbh);
+ return lo_tell(imp_dbh->conn, fd);
+}
+
+
+int
+pg_db_lo_unlink (dbh, lobjId)
+ SV *dbh;
+ unsigned int lobjId;
+{
+ D_imp_dbh(dbh);
+ return lo_unlink(imp_dbh->conn, lobjId);
+}
+
+
+unsigned int
+pg_db_lo_import (dbh, filename)
+ SV *dbh;
+ char *filename;
+{
+ D_imp_dbh(dbh);
+ return lo_import(imp_dbh->conn, filename);
+}
+
+
+int
+pg_db_lo_export (dbh, lobjId, filename)
+ SV *dbh;
+ unsigned int lobjId;
+ char *filename;
+{
+ D_imp_dbh(dbh);
+ return lo_export(imp_dbh->conn, lobjId, filename);
+}
+
+
+int
+pg_db_putline (dbh, buffer)
+ SV *dbh;
+ char *buffer;
+{
+ D_imp_dbh(dbh);
+ return PQputline(imp_dbh->conn, buffer);
+}
+
+
+int
+pg_db_getline (dbh, buffer, length)
+ SV *dbh;
+ char *buffer;
+ int length;
+{
+ D_imp_dbh(dbh);
+ return PQgetline(imp_dbh->conn, buffer, length);
+}
+
+
+int
+pg_db_endcopy (dbh)
+ SV *dbh;
+{
+ D_imp_dbh(dbh);
+ return PQendcopy(imp_dbh->conn);
+}
+
+
+/* ================================================================== */
+
+
+int
+dbd_st_prepare (sth, imp_sth, statement, attribs)
+ SV *sth;
+ imp_sth_t *imp_sth;
+ char *statement;
+ SV *attribs;
+{
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_prepare: statement = >%s<\n", statement); }
+
+ /* scan statement for '?', ':1' and/or ':foo' style placeholders */
+ dbd_preparse(imp_sth, statement);
+
+ /* initialize new statement handle */
+ imp_sth->result = 0;
+ imp_sth->cur_tuple = 0;
+
+ DBIc_IMPSET_on(imp_sth);
+ return 1;
+}
+
+
+static void
+dbd_preparse (imp_sth, statement)
+ imp_sth_t *imp_sth;
+ char *statement;
+{
+ bool in_literal = FALSE;
+ char in_comment = '\0';
+ char *src, *start, *dest;
+ phs_t phs_tpl;
+ SV *phs_sv;
+ int idx=0;
+ char *style="", *laststyle=Nullch;
+ STRLEN namelen;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_preparse: statement = >%s<\n", statement); }
+
+ /* allocate room for copy of statement with spare capacity */
+ /* for editing '?' or ':1' into ':p1'. */
+ /* */
+ /* Note: the calculated length used here for the safemalloc */
+ /* isn't related in any way to the actual worst case length */
+ /* of the translated statement, but allowing for 3 times */
+ /* the length of the original statement should be safe... */
+ imp_sth->statement = (char*)safemalloc(strlen(statement) * 3 + 1);
+
+ /* initialise phs ready to be cloned per placeholder */
+ memset(&phs_tpl, 0, sizeof(phs_tpl));
+ phs_tpl.ftype = 1043; /* VARCHAR */
+
+ src = statement;
+ dest = imp_sth->statement;
+ while(*src) {
+
+ if (in_comment) {
+ /* SQL-style and C++-style */
+ if ((in_comment == '-' || in_comment == '/') && *src == '\n') {
+ in_comment = '\0';
+ }
+ /* C-style */
+ else if (in_comment == '*' && *src == '*' && *(src+1) == '/') {
+ *dest++ = *src++; /* avoids asterisk-slash-asterisk issues */
+ in_comment = '\0';
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (in_literal) {
+ /* check if literal ends but keep quotes in literal */
+ if (*src == in_literal) {
+ int bs=0;
+ char *str;
+ str = src-1;
+ while (*(str-bs) == '\\')
+ bs++;
+ if (!(bs & 1))
+ in_literal = 0;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* Look for comments: SQL-style or C++-style or C-style */
+ if ((*src == '-' && *(src+1) == '-') ||
+ (*src == '/' && *(src+1) == '/') ||
+ (*src == '/' && *(src+1) == '*'))
+ {
+ in_comment = *(src+1);
+ /* We know *src & the next char are to be copied, so do */
+ /* it. In the case of C-style comments, it happens to */
+ /* help us avoid slash-asterisk-slash oddities. */
+ *dest++ = *src++;
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* check if no placeholders */
+ if (*src != ':' && *src != '?') {
+ if (*src == '\'' || *src == '"') {
+ in_literal = *src;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* check for cast operator */
+ if (*src == ':' && (*(src-1) == ':' || *(src+1) == ':')) {
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* only here for : or ? outside of a comment or literal and no cast */
+
+ start = dest; /* save name inc colon */
+ *dest++ = *src++;
+ if (*start == '?') { /* X/Open standard */
+ sprintf(start,":p%d", ++idx); /* '?' -> ':p1' (etc) */
+ dest = start+strlen(start);
+ style = "?";
+
+ } else if (isDIGIT(*src)) { /* ':1' */
+ idx = atoi(src);
+ *dest++ = 'p'; /* ':1'->':p1' */
+ if (idx <= 0) {
+ croak("Placeholder :%d invalid, placeholders must be >= 1", idx);
+ }
+ while(isDIGIT(*src)) {
+ *dest++ = *src++;
+ }
+ style = ":1";
+
+ } else if (isALNUM(*src)) { /* ':foo' */
+ while(isALNUM(*src)) { /* includes '_' */
+ *dest++ = *src++;
+ }
+ style = ":foo";
+ } else { /* perhaps ':=' PL/SQL construct */
+ continue;
+ }
+ *dest = '\0'; /* handy for debugging */
+ namelen = (dest-start);
+ if (laststyle && style != laststyle) {
+ croak("Can't mix placeholder styles (%s/%s)",style,laststyle);
+ }
+ laststyle = style;
+ if (imp_sth->all_params_hv == NULL) {
+ imp_sth->all_params_hv = newHV();
+ }
+ phs_tpl.sv = &sv_undef;
+ phs_sv = newSVpv((char*)&phs_tpl, sizeof(phs_tpl)+namelen+1);
+ hv_store(imp_sth->all_params_hv, start, namelen, phs_sv, 0);
+ strcpy( ((phs_t*)(void*)SvPVX(phs_sv))->name, start);
+ }
+ *dest = '\0';
+ if (imp_sth->all_params_hv) {
+ DBIc_NUM_PARAMS(imp_sth) = (int)HvKEYS(imp_sth->all_params_hv);
+ if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, " dbd_preparse scanned %d distinct placeholders\n", (int)DBIc_NUM_PARAMS(imp_sth)); }
+ }
+}
+
+
+/* if it LOOKS like a string, this function will determine whether the type needs to be surrounded in single quotes */
+static int pg_sql_needquote (sql_type)
+ int sql_type;
+{
+ if (sql_type > 1000 || sql_type == 17 || sql_type == 25 ) {
+ return 1;
+ }
+ return 0;
+}
+
+
+
+static int
+pg_sql_type (imp_sth, name, sql_type)
+ imp_sth_t *imp_sth;
+ char *name;
+ int sql_type;
+{
+ switch (sql_type) {
+ case SQL_CHAR:
+ return 1042; /* bpchar */
+ case SQL_NUMERIC:
+ return 700; /* float4 */
+ case SQL_DECIMAL:
+ return 700; /* float4 */
+ case SQL_INTEGER:
+ return 23; /* int4 */
+ case SQL_SMALLINT:
+ return 21; /* int2 */
+ case SQL_FLOAT:
+ return 700; /* float4 */
+ case SQL_REAL:
+ return 701; /* float8 */
+ case SQL_DOUBLE:
+ return 20; /* int8 */
+ case SQL_VARCHAR:
+ return 1043; /* varchar */
+ case SQL_BINARY:
+ return 17; /* bytea */
+ default:
+ if (DBIc_WARN(imp_sth) && imp_sth && name) {
+ warn("SQL type %d for '%s' is not fully supported, bound as VARCHAR instead",
+ sql_type, name);
+ }
+ return pg_sql_type(imp_sth, name, SQL_VARCHAR);
+ }
+}
+
+static int
+sql_pg_type (imp_sth, name, sql_type)
+ imp_sth_t *imp_sth;
+ char *name;
+ int sql_type;
+{
+ if (dbis->debug >= 1) {
+ PerlIO_printf(DBILOGFP, "sql_pg_type name '%s' type '%d'\n", name, sql_type );
+ }
+
+ switch (sql_type) {
+ case 17: /* bytea */
+ return SQL_BINARY;
+ case 20: /* int8 */
+ return SQL_DOUBLE;
+ case 21: /* int2 */
+ return SQL_SMALLINT;
+ case 23: /* int4 */
+ return SQL_INTEGER;
+ case 700: /* float4 */
+ return SQL_NUMERIC;
+ case 701: /* float8 */
+ return SQL_REAL;
+ case 1042: /* bpchar */
+ return SQL_CHAR;
+ case 1043: /* varchar */
+ return SQL_VARCHAR;
+ case 1082: /* date */
+ return SQL_DATE;
+ case 1083: /* time */
+ return SQL_TIME;
+ case 1296: /* date */
+ return SQL_TIMESTAMP;
+
+ default:
+ return sql_type;
+ }
+}
+
+
+static int
+dbd_rebind_ph (sth, imp_sth, phs)
+ SV *sth;
+ imp_sth_t *imp_sth;
+ phs_t *phs;
+{
+ STRLEN value_len;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_rebind\n"); }
+
+ /* convert to a string ASAP */
+ if (!SvPOK(phs->sv) && SvOK(phs->sv)) {
+ sv_2pv(phs->sv, &na);
+ }
+
+ if (dbis->debug >= 2) {
+ char *val = neatsvpv(phs->sv,0);
+ PerlIO_printf(DBILOGFP, " bind %s <== %.1000s (", phs->name, val);
+ if (SvOK(phs->sv)) {
+ PerlIO_printf(DBILOGFP, "size %ld/%ld/%ld, ", (long)SvCUR(phs->sv),(long)SvLEN(phs->sv),phs->maxlen);
+ } else {
+ PerlIO_printf(DBILOGFP, "NULL, ");
+ }
+ PerlIO_printf(DBILOGFP, "ptype %d, otype %d%s)\n", (int)SvTYPE(phs->sv), phs->ftype, (phs->is_inout) ? ", inout" : "");
+ }
+
+ /* At the moment we always do sv_setsv() and rebind. */
+ /* Later we may optimise this so that more often we can */
+ /* just copy the value & length over and not rebind. */
+
+ if (phs->is_inout) { /* XXX */
+ if (SvREADONLY(phs->sv)) {
+ croak(no_modify);
+ }
+ /* phs->sv _is_ the real live variable, it may 'mutate' later */
+ /* pre-upgrade high to reduce risk of SvPVX realloc/move */
+ (void)SvUPGRADE(phs->sv, SVt_PVNV);
+ /* ensure room for result, 28 is magic number (see sv_2pv) */
+ SvGROW(phs->sv, (phs->maxlen < 28) ? 28 : phs->maxlen+1);
+ }
+ else {
+ /* phs->sv is copy of real variable, upgrade to at least string */
+ (void)SvUPGRADE(phs->sv, SVt_PV);
+ }
+
+ /* At this point phs->sv must be at least a PV with a valid buffer, */
+ /* even if it's undef (null) */
+ /* Here we set phs->progv, phs->indp, and value_len. */
+ if (SvOK(phs->sv)) {
+ phs->progv = SvPV(phs->sv, value_len);
+ phs->indp = 0;
+ }
+ else { /* it's null but point to buffer in case it's an out var */
+ phs->progv = SvPVX(phs->sv);
+ phs->indp = -1;
+ value_len = 0;
+ }
+ phs->sv_type = SvTYPE(phs->sv); /* part of mutation check */
+ phs->maxlen = SvLEN(phs->sv)-1; /* avail buffer space */
+ if (phs->maxlen < 0) { /* can happen with nulls */
+ phs->maxlen = 0;
+ }
+
+ phs->alen = value_len + phs->alen_incnull;
+
+ imp_sth->all_params_len += SvOK(phs->sv) ? phs->alen : 4; /* NULL */
+
+ if (dbis->debug >= 3) {
+ PerlIO_printf(DBILOGFP, " bind %s <== '%.*s' (size %ld/%ld, otype %d, indp %d)\n",
+ phs->name,
+ (int)(phs->alen>SvIV(DBIS->neatsvpvlen) ? SvIV(DBIS->neatsvpvlen) : phs->alen),
+ (phs->progv) ? phs->progv : "",
+ (long)phs->alen, (long)phs->maxlen, phs->ftype, phs->indp);
+ }
+
+ return 1;
+}
+
+
+void dereference(value)
+SV** value;
+{
+ AV* buf;
+ SV* val;
+ char *src;
+ int is_ref;
+ STRLEN len;
+
+ if (SvTYPE(SvRV(*value)) != SVt_PVAV)
+ croak("Not an array reference (%s)", neatsvpv(*value,0));
+
+ buf = (AV *) SvRV(*value);
+ sv_setpv(*value, "{");
+ while ( SvOK(val = av_shift(buf)) ) {
+ is_ref = SvROK(val);
+ if (is_ref)
+ dereference(&val);
+ else
+ sv_catpv(*value, "\"");
+ /* Quote */
+ src = SvPV(val, len);
+ while (len--) {
+ if (!is_ref && *src == '\"')
+ sv_catpv(*value, "\\");
+ sv_catpvn(*value, src++, 1);
+ }
+ /* End of quote */
+ if (!is_ref)
+ sv_catpv(*value, "\"");
+ if (av_len(buf) > -1)
+ sv_catpv(*value, array_delimiter);
+ }
+ sv_catpv(*value, "}");
+ av_clear(buf);
+}
+
+int
+dbd_bind_ph (sth, imp_sth, ph_namesv, newvalue, sql_type, attribs, is_inout, maxlen)
+ SV *sth;
+ imp_sth_t *imp_sth;
+ SV *ph_namesv;
+ SV *newvalue;
+ IV sql_type;
+ SV *attribs;
+ int is_inout;
+ IV maxlen;
+{
+ SV **phs_svp;
+ STRLEN name_len;
+ char *name;
+ char namebuf[30];
+ phs_t *phs;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_bind_ph\n"); }
+
+ /* check if placeholder was passed as a number */
+
+ if (SvGMAGICAL(ph_namesv)) { /* eg if from tainted expression */
+ mg_get(ph_namesv);
+ }
+ if (!SvNIOKp(ph_namesv)) {
+ name = SvPV(ph_namesv, name_len);
+ }
+ if (SvNIOKp(ph_namesv) || (name && isDIGIT(name[0]))) {
+ sprintf(namebuf, ":p%d", (int)SvIV(ph_namesv));
+ name = namebuf;
+ name_len = strlen(name);
+ }
+ assert(name != Nullch);
+
+ if (SvTYPE(newvalue) > SVt_PVLV) { /* hook for later array logic */
+ croak("Can't bind a non-scalar value (%s)", neatsvpv(newvalue,0));
+ }
+ if (SvROK(newvalue) && !IS_DBI_HANDLE(newvalue)) {
+ /* dbi handle allowed for cursor variables */
+ dereference(&newvalue);
+ }
+ if (SvTYPE(newvalue) == SVt_PVLV && is_inout) { /* may allow later */
+ croak("Can't bind ``lvalue'' mode scalar as inout parameter (currently)");
+ }
+
+ if (dbis->debug >= 2) {
+ PerlIO_printf(DBILOGFP, " bind %s <== %s (type %ld", name, neatsvpv(newvalue,0), (long)sql_type);
+ if (is_inout) {
+ PerlIO_printf(DBILOGFP, ", inout 0x%lx, maxlen %ld", (long)newvalue, (long)maxlen);
+ }
+ if (attribs) {
+ PerlIO_printf(DBILOGFP, ", attribs: %s", neatsvpv(attribs,0));
+ }
+ PerlIO_printf(DBILOGFP, ")\n");
+ }
+
+ phs_svp = hv_fetch(imp_sth->all_params_hv, name, name_len, 0);
+ if (phs_svp == NULL) {
+ croak("Can't bind unknown placeholder '%s' (%s)", name, neatsvpv(ph_namesv,0));
+ }
+ phs = (phs_t*)(void*)SvPVX(*phs_svp); /* placeholder struct */
+
+ if (phs->sv == &sv_undef) { /* first bind for this placeholder */
+ phs->ftype = 1043; /* our default type VARCHAR */
+ phs->is_inout = is_inout;
+ if (is_inout) {
+ /* phs->sv assigned in the code below */
+ ++imp_sth->has_inout_params;
+ /* build array of phs's so we can deal with out vars fast */
+ if (!imp_sth->out_params_av) {
+ imp_sth->out_params_av = newAV();
+ }
+ av_push(imp_sth->out_params_av, SvREFCNT_inc(*phs_svp));
+ }
+
+ if (attribs) { /* only look for pg_type on first bind of var */
+ SV **svp;
+ /* Setup / Clear attributes as defined by attribs. */
+ /* XXX If attribs is EMPTY then reset attribs to default? */
+ if ( (svp = hv_fetch((HV*)SvRV(attribs), "pg_type", 7, 0)) != NULL) {
+ int pg_type = SvIV(*svp);
+ if (!pgtype_bind_ok(pg_type)) {
+ croak("Can't bind %s, pg_type %d not supported by DBD::Pg", phs->name, pg_type);
+ }
+ if (sql_type) {
+ croak("Can't specify both TYPE (%d) and pg_type (%d) for %s", sql_type, pg_type, phs->name);
+ }
+ phs->ftype = pg_type;
+ }
+ }
+ if (sql_type) {
+ /* SQL_BINARY (-2) is deprecated. */
+ if (sql_type == -2 && DBIc_WARN(imp_sth)) {
+ warn("Use of SQL type SQL_BINARY (%d) is deprecated. Use { pg_type => DBD::Pg::PG_BYTEA } instead.", sql_type);
+ }
+ phs->ftype = pg_sql_type(imp_sth, phs->name, sql_type);
+ }
+ } /* was first bind for this placeholder */
+
+ /* check later rebinds for any changes */
+ else if (is_inout || phs->is_inout) {
+ croak("Can't rebind or change param %s in/out mode after first bind (%d => %d)", phs->name, phs->is_inout , is_inout);
+ }
+ else if (sql_type && phs->ftype != pg_sql_type(imp_sth, phs->name, sql_type)) {
+ croak("Can't change TYPE of param %s to %d after initial bind", phs->name, sql_type);
+ }
+
+ phs->maxlen = maxlen; /* 0 if not inout */
+
+ if (!is_inout) { /* normal bind to take a (new) copy of current value */
+ if (phs->sv == &sv_undef) { /* (first time bind) */
+ phs->sv = newSV(0);
+ }
+ sv_setsv(phs->sv, newvalue);
+ } else if (newvalue != phs->sv) {
+ if (phs->sv) {
+ SvREFCNT_dec(phs->sv);
+ }
+ phs->sv = SvREFCNT_inc(newvalue); /* point to live var */
+ }
+
+ return dbd_rebind_ph(sth, imp_sth, phs);
+}
+
+
+int
+dbd_st_execute (sth, imp_sth) /* <= -2:error, >=0:ok row count, (-1=unknown count) */
+ SV *sth;
+ imp_sth_t *imp_sth;
+{
+ dTHR;
+
+ D_imp_dbh_from_sth;
+ ExecStatusType status = -1;
+ char *cmdStatus;
+ char *cmdTuples;
+ char *statement;
+ int ret = -2;
+ int num_fields;
+ int i;
+ STRLEN len;
+ bool in_literal = FALSE;
+ char in_comment = '\0';
+ char *src;
+ char *dest;
+ char *val;
+ char namebuf[30];
+ phs_t *phs;
+ SV **svp;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_execute\n"); }
+
+ /*
+ here we get the statement from the statement handle where
+ it has been stored when creating a blank sth during prepare
+ svp = hv_fetch((HV *)SvRV(sth), "Statement", 9, FALSE);
+ statement = SvPV(*svp, na);
+ */
+
+ if (NULL == imp_dbh->conn) {
+ pg_error(sth, -1, "execute on disconnected handle");
+ return -2;
+ }
+
+ statement = imp_sth->statement;
+ if (! statement) {
+ /* are we prepared ? */
+ pg_error(sth, -1, "statement not prepared\n");
+ return -2;
+ }
+
+ /* do we have input parameters ? */
+ if ((int)DBIc_NUM_PARAMS(imp_sth) > 0) {
+ /*
+ we have to allocate some additional memory for possible escaping
+ quotes and backslashes:
+ max_len = length of statement
+ + total length of all params allowing for worst case all
+ characters binary-escaped (\\xxx)
+ + null terminator
+ Note: parameters look like :p1 at this point, so there's no
+ need to explicitly allow for surrounding quotes because '' is
+ shorter than :p1
+ */
+ int max_len = strlen(imp_sth->statement) + imp_sth->all_params_len * 5 + 1;
+ statement = (char*)safemalloc( max_len );
+ dest = statement;
+ src = imp_sth->statement;
+ /* scan statement for ':p1' style placeholders */
+ while(*src) {
+
+ if (in_comment) {
+ /* SQL-style and C++-style */
+ if ((in_comment == '-' || in_comment == '/') && *src == '\n') {
+ in_comment = '\0';
+ }
+ /* C-style */
+ else if (in_comment == '*' && *src == '*' && *(src+1) == '/') {
+ *dest++ = *src++; /* avoids asterisk-slash-asterisk issues */
+ in_comment = '\0';
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (in_literal) {
+ /* check if literal ends but keep quotes in literal */
+ if (*src == in_literal) {
+ int bs=0;
+ char *str;
+ str = src-1;
+ while (*(str-bs) == '\\')
+ bs++;
+ if (!(bs & 1))
+ in_literal = 0;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* Look for comments: SQL-style or C++-style or C-style */
+ if ((*src == '-' && *(src+1) == '-') ||
+ (*src == '/' && *(src+1) == '/') ||
+ (*src == '/' && *(src+1) == '*'))
+ {
+ in_comment = *(src+1);
+ /* We know *src & the next char are to be copied, so do */
+ /* it. In the case of C-style comments, it happens to */
+ /* help us avoid slash-asterisk-slash oddities. */
+ *dest++ = *src++;
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* check if no placeholders */
+ if (*src != ':' && *src != '?') {
+ if (*src == '\'' || *src == '"') {
+ in_literal = *src;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* check for cast operator */
+ if (*src == ':' && (*(src-1) == ':' || *(src+1) == ':')) {
+ *dest++ = *src++;
+ continue;
+ }
+
+
+ i = 0;
+ namebuf[i++] = *src++; /* ':' */
+ namebuf[i++] = *src++; /* 'p' */
+
+ while (isDIGIT(*src) && i < (sizeof(namebuf)-1) ) {
+ namebuf[i++] = *src++;
+ }
+ if ( i == (sizeof(namebuf) - 1)) {
+ pg_error(sth, -1, "namebuf buffer overrun\n");
+ return -2;
+ }
+ namebuf[i] = '\0';
+ svp = hv_fetch(imp_sth->all_params_hv, namebuf, i, 0);
+ if (svp == NULL) {
+ pg_error(sth, -1, "parameter unknown\n");
+ return -2;
+ }
+ /* get attribute */
+ phs = (phs_t*)(void*)SvPVX(*svp);
+ /* replace undef with NULL */
+ if(!SvOK(phs->sv)) {
+ val = "NULL";
+ len = 4;
+ } else {
+ val = SvPV(phs->sv, len);
+ }
+ /* quote string attribute */
+ if(!SvNIOK(phs->sv) && SvOK(phs->sv) && pg_sql_needquote(phs->ftype)) { /* avoid quoting NULL, tpf: bind_param as numeric */
+ *dest++ = '\'';
+ }
+ while (len--) {
+ if (imp_dbh->pg_auto_escape) {
+ /* if the parameter was bound as PG_BYTEA, escape nonprintables */
+ if (phs->ftype == 17 && !isPRINT(*val)) { /* escape null character */
+ dest+=snprintf(dest, (statement + max_len) - dest, "\\\\%03o", *((unsigned char *)val));
+ if (dest > statement + max_len) {
+ pg_error(sth, -1, "statement buffer overrun\n");
+ return -2;
+ }
+ val++;
+ continue; /* do not copy the null */
+ }
+ /* escape quote */
+ if (*val == '\'') {
+ *dest++ = '\'';
+ }
+ /* escape backslash */
+ if (*val == '\\') {
+ if (phs->ftype == 17) { /* four backslashes. really. */
+ *dest++ = '\\';
+ *dest++ = '\\';
+ *dest++ = '\\';
+ } else {
+ *dest++ = '\\';
+ }
+ }
+ }
+ /* copy attribute to statement */
+ *dest++ = *val++;
+ }
+ /* quote string attribute */
+ if(!SvNIOK(phs->sv) && SvOK(phs->sv) && pg_sql_needquote(phs->ftype)) { /* avoid quoting NULL, tpf: bind_param as numeric */
+ *dest++ = '\'';
+ }
+ }
+ *dest = '\0';
+ }
+
+ if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, "dbd_st_execute: statement = >%s<\n", statement); }
+
+ /* clear old result (if any) */
+ if (imp_sth->result) {
+ PQclear(imp_sth->result);
+ }
+
+ /* execute statement */
+ imp_sth->result = PQexec(imp_dbh->conn, statement);
+
+ /* free statement string in case of input parameters */
+ if ((int)DBIc_NUM_PARAMS(imp_sth) > 0) {
+ Safefree(statement);
+ }
+
+ /* check status */
+ status = imp_sth->result ? PQresultStatus(imp_sth->result) : -1;
+ cmdStatus = imp_sth->result ? (char *)PQcmdStatus(imp_sth->result) : "";
+ cmdTuples = imp_sth->result ? (char *)PQcmdTuples(imp_sth->result) : "";
+
+ if (PGRES_TUPLES_OK == status) {
+ /* select statement */
+ num_fields = PQnfields(imp_sth->result);
+ imp_sth->cur_tuple = 0;
+ DBIc_NUM_FIELDS(imp_sth) = num_fields;
+ DBIc_ACTIVE_on(imp_sth);
+ ret = PQntuples(imp_sth->result);
+ } else if (PGRES_COMMAND_OK == status) {
+ /* non-select statement */
+ if (! strncmp(cmdStatus, "DELETE", 6) || ! strncmp(cmdStatus, "INSERT", 6) || ! strncmp(cmdStatus, "UPDATE", 6)) {
+ ret = atoi(cmdTuples);
+ } else {
+ ret = -1;
+ }
+ } else if (PGRES_COPY_OUT == status || PGRES_COPY_IN == status) {
+ /* Copy Out/In data transfer in progress */
+ ret = -1;
+ } else {
+ pg_error(sth, status, PQerrorMessage(imp_dbh->conn));
+ ret = -2;
+ }
+
+ /* store the number of affected rows */
+ imp_sth->rows = ret;
+
+ return ret;
+}
+
+
+int
+is_high_bit_set(val)
+ char *val;
+{
+ while (*val++)
+ if (*val & 0x80) return 1;
+ return 0;
+}
+
+AV *
+dbd_st_fetch (sth, imp_sth)
+ SV *sth;
+ imp_sth_t *imp_sth;
+{
+ D_imp_dbh_from_sth;
+ int num_fields;
+ int i;
+ AV *av;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_fetch\n"); }
+
+ /* Check that execute() was executed sucessfully */
+ if ( !DBIc_ACTIVE(imp_sth) ) {
+ pg_error(sth, 1, "no statement executing\n");
+
+ return Nullav;
+ }
+
+ if ( imp_sth->cur_tuple == PQntuples(imp_sth->result) ) {
+ imp_sth->cur_tuple = 0;
+ DBIc_ACTIVE_off(imp_sth);
+ return Nullav; /* we reached the last tuple */
+ }
+
+ av = DBIS->get_fbav(imp_sth);
+ num_fields = AvFILL(av)+1;
+
+ for(i = 0; i < num_fields; ++i) {
+
+ SV *sv = AvARRAY(av)[i];
+ if (PQgetisnull(imp_sth->result, imp_sth->cur_tuple, i)) {
+ sv_setsv(sv, &sv_undef);
+ } else {
+ char *val = (char*)PQgetvalue(imp_sth->result, imp_sth->cur_tuple, i);
+ int val_len = strlen(val);
+ int type = PQftype(imp_sth->result, i); /* hopefully these hard coded values will not change */
+ if (16 == type && ! imp_dbh->pg_bool_tf) {
+ *val = (*val == 'f') ? '0' : '1'; /* bool: translate postgres into perl */
+ }
+ if (17 == type) { /* decode \001 -> chr(1), etc, in-place */
+ char *p = val; /* points to next available pos */
+ char *s = val; /* points to current scanning pos */
+ int c1,c2,c3;
+ while (*s) {
+ if (*s == '\\') {
+ if (*(s+1) == '\\') { /* double backslash */
+ *p++ = '\\';
+ s += 2;
+ continue;
+ }
+ else if ( isdigit(c1=(*(s+1))) &&
+ isdigit(c2=(*(s+2))) &&
+ isdigit(c3=(*(s+3))) ) {
+ *p++ = (c1 - '0') * 64 + (c2 - '0') * 8 + (c3 - '0');
+ s += 4;
+ continue;
+ }
+ }
+ *p++ = *s++;
+ }
+ val_len = (p - val);
+ }
+ else if (1042 == type && DBIc_has(imp_sth,DBIcf_ChopBlanks)) {
+ char *str = val;
+ while((val_len > 0) && (str[val_len-1] == ' ')) {
+ val_len--;
+ }
+ val[val_len] = '\0';
+ }
+ sv_setpvn(sv, val, val_len);
+#ifdef SvUTF8_off
+ if (imp_dbh->pg_enable_utf8) {
+ SvUTF8_off(sv);
+ /* XXX Is this all the character data types? */
+ if (18 == type || 25 == type || 1042 ==type || 1043 == type) {
+ if (is_high_bit_set(val) && is_utf8_string(val, val_len))
+ SvUTF8_on(sv);
+ }
+ }
+#endif
+ }
+ }
+
+ imp_sth->cur_tuple += 1;
+
+ return av;
+}
+
+
+int
+dbd_st_blob_read (sth, imp_sth, lobjId, offset, len, destrv, destoffset)
+ SV *sth;
+ imp_sth_t *imp_sth;
+ int lobjId;
+ long offset;
+ long len;
+ SV *destrv;
+ long destoffset;
+{
+ D_imp_dbh_from_sth;
+ int ret, lobj_fd, nbytes, nread;
+ PGresult* result;
+ ExecStatusType status;
+ SV *bufsv;
+ char *tmp;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_blob_read\n"); }
+ /* safety check */
+ if (lobjId <= 0) {
+ pg_error(sth, -1, "dbd_st_blob_read: lobjId <= 0");
+ return 0;
+ }
+ if (offset < 0) {
+ pg_error(sth, -1, "dbd_st_blob_read: offset < 0");
+ return 0;
+ }
+ if (len < 0) {
+ pg_error(sth, -1, "dbd_st_blob_read: len < 0");
+ return 0;
+ }
+ if (! SvROK(destrv)) {
+ pg_error(sth, -1, "dbd_st_blob_read: destrv not a reference");
+ return 0;
+ }
+ if (destoffset < 0) {
+ pg_error(sth, -1, "dbd_st_blob_read: destoffset < 0");
+ return 0;
+ }
+
+ /* dereference destination and ensure it's writable string */
+ bufsv = SvRV(destrv);
+ if (! destoffset) {
+ sv_setpvn(bufsv, "", 0);
+ }
+
+ /* execute begin
+ result = PQexec(imp_dbh->conn, "begin");
+ status = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+ if (status != PGRES_COMMAND_OK) {
+ pg_error(sth, status, PQerrorMessage(imp_dbh->conn));
+ return 0;
+ }
+ */
+
+ /* open large object */
+ lobj_fd = lo_open(imp_dbh->conn, lobjId, INV_READ);
+ if (lobj_fd < 0) {
+ pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
+ return 0;
+ }
+
+ /* seek on large object */
+ if (offset > 0) {
+ ret = lo_lseek(imp_dbh->conn, lobj_fd, offset, SEEK_SET);
+ if (ret < 0) {
+ pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
+ return 0;
+ }
+ }
+
+ /* read from large object */
+ nread = 0;
+ SvGROW(bufsv, destoffset + nread + BUFSIZ + 1);
+ tmp = (SvPVX(bufsv)) + destoffset + nread;
+ while ((nbytes = lo_read(imp_dbh->conn, lobj_fd, tmp, BUFSIZ)) > 0) {
+ nread += nbytes;
+ /* break if user wants only a specified chunk */
+ if (len > 0 && nread > len) {
+ nread = len;
+ break;
+ }
+ SvGROW(bufsv, destoffset + nread + BUFSIZ + 1);
+ tmp = (SvPVX(bufsv)) + destoffset + nread;
+ }
+
+ /* terminate string */
+ SvCUR_set(bufsv, destoffset + nread);
+ *SvEND(bufsv) = '\0';
+
+ /* close large object */
+ ret = lo_close(imp_dbh->conn, lobj_fd);
+ if (ret < 0) {
+ pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
+ return 0;
+ }
+
+ /* execute end
+ result = PQexec(imp_dbh->conn, "end");
+ status = result ? PQresultStatus(result) : -1;
+ PQclear(result);
+ if (status != PGRES_COMMAND_OK) {
+ pg_error(sth, status, PQerrorMessage(imp_dbh->conn));
+ return 0;
+ }
+ */
+
+ return nread;
+}
+
+
+int
+dbd_st_rows (sth, imp_sth)
+ SV *sth;
+ imp_sth_t *imp_sth;
+{
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_rows\n"); }
+
+ return imp_sth->rows;
+}
+
+
+int
+dbd_st_finish (sth, imp_sth)
+ SV *sth;
+ imp_sth_t *imp_sth;
+{
+ dTHR;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_finish\n"); }
+
+ if (DBIc_ACTIVE(imp_sth) && imp_sth->result) {
+ PQclear(imp_sth->result);
+ imp_sth->result = 0;
+ imp_sth->rows = 0;
+ }
+
+ DBIc_ACTIVE_off(imp_sth);
+ return 1;
+}
+
+
+void
+dbd_st_destroy (sth, imp_sth)
+ SV *sth;
+ imp_sth_t *imp_sth;
+{
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_destroy\n"); }
+
+ /* Free off contents of imp_sth */
+
+ Safefree(imp_sth->statement);
+ if (imp_sth->result) {
+ PQclear(imp_sth->result);
+ imp_sth->result = 0;
+ }
+
+ if (imp_sth->out_params_av)
+ sv_free((SV*)imp_sth->out_params_av);
+
+ if (imp_sth->all_params_hv) {
+ HV *hv = imp_sth->all_params_hv;
+ SV *sv;
+ char *key;
+ I32 retlen;
+ hv_iterinit(hv);
+ while( (sv = hv_iternextsv(hv, &key, &retlen)) != NULL ) {
+ if (sv != &sv_undef) {
+ phs_t *phs_tpl = (phs_t*)(void*)SvPVX(sv);
+ sv_free(phs_tpl->sv);
+ }
+ }
+ sv_free((SV*)imp_sth->all_params_hv);
+ }
+
+ DBIc_IMPSET_off(imp_sth); /* let DBI know we've done it */
+}
+
+
+int
+dbd_st_STORE_attrib (sth, imp_sth, keysv, valuesv)
+ SV *sth;
+ imp_sth_t *imp_sth;
+ SV *keysv;
+ SV *valuesv;
+{
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_STORE\n"); }
+
+ return FALSE;
+}
+
+
+SV *
+dbd_st_FETCH_attrib (sth, imp_sth, keysv)
+ SV *sth;
+ imp_sth_t *imp_sth;
+ SV *keysv;
+{
+ STRLEN kl;
+ char *key = SvPV(keysv,kl);
+ int i, sz;
+ SV *retsv = Nullsv;
+
+ if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_FETCH\n"); }
+
+ if (! imp_sth->result) {
+ return Nullsv;
+ }
+
+ i = DBIc_NUM_FIELDS(imp_sth);
+
+ if (kl == 4 && strEQ(key, "NAME")) {
+ AV *av = newAV();
+ retsv = newRV(sv_2mortal((SV*)av));
+ while(--i >= 0) {
+ av_store(av, i, newSVpv(PQfname(imp_sth->result, i),0));
+ }
+ } else if ( kl== 4 && strEQ(key, "TYPE")) {
+ /* Need to convert the Pg type to ANSI/SQL type. */
+ AV *av = newAV();
+ retsv = newRV(sv_2mortal((SV*)av));
+ while(--i >= 0) {
+ av_store(av, i, newSViv(sql_pg_type( imp_sth,
+ PQfname(imp_sth->result, i),
+ PQftype(imp_sth->result, i))));
+ }
+ } else if (kl==9 && strEQ(key, "PRECISION")) {
+ AV *av = newAV();
+ retsv = newRV(sv_2mortal((SV*)av));
+ while(--i >= 0) {
+ sz = PQfsize(imp_sth->result, i);
+ av_store(av, i, sz > 0 ? newSViv(sz) : &sv_undef);
+ }
+ } else if (kl==5 && strEQ(key, "SCALE")) {
+ AV *av = newAV();
+ retsv = newRV(sv_2mortal((SV*)av));
+ while(--i >= 0) {
+ av_store(av, i, &sv_undef);
+ }
+ } else if (kl==8 && strEQ(key, "NULLABLE")) {
+ AV *av = newAV();
+ retsv = newRV(sv_2mortal((SV*)av));
+ while(--i >= 0) {
+ av_store(av, i, newSViv(2));
+ }
+ } else if (kl==10 && strEQ(key, "CursorName")) {
+ retsv = &sv_undef;
+ } else if (kl==11 && strEQ(key, "RowsInCache")) {
+ retsv = &sv_undef;
+ } else if (kl==7 && strEQ(key, "pg_size")) {
+ AV *av = newAV();
+ retsv = newRV(sv_2mortal((SV*)av));
+ while(--i >= 0) {
+ av_store(av, i, newSViv(PQfsize(imp_sth->result, i)));
+ }
+ } else if (kl==7 && strEQ(key, "pg_type")) {
+ AV *av = newAV();
+ char *type_nam;
+ retsv = newRV(sv_2mortal((SV*)av));
+ while(--i >= 0) {
+ switch (PQftype(imp_sth->result, i)) {
+ case 16:
+ type_nam = "bool";
+ break;
+ case 17:
+ type_nam = "bytea";
+ break;
+ case 18:
+ type_nam = "char";
+ break;
+ case 19:
+ type_nam = "name";
+ break;
+ case 20:
+ type_nam = "int8";
+ break;
+ case 21:
+ type_nam = "int2";
+ break;
+ case 22:
+ type_nam = "int28";
+ break;
+ case 23:
+ type_nam = "int4";
+ break;
+ case 24:
+ type_nam = "regproc";
+ break;
+ case 25:
+ type_nam = "text";
+ break;
+ case 26:
+ type_nam = "oid";
+ break;
+ case 27:
+ type_nam = "tid";
+ break;
+ case 28:
+ type_nam = "xid";
+ break;
+ case 29:
+ type_nam = "cid";
+ break;
+ case 30:
+ type_nam = "oid8";
+ break;
+ case 32:
+ type_nam = "SET";
+ break;
+ case 210:
+ type_nam = "smgr";
+ break;
+ case 600:
+ type_nam = "point";
+ break;
+ case 601:
+ type_nam = "lseg";
+ break;
+ case 602:
+ type_nam = "path";
+ break;
+ case 603:
+ type_nam = "box";
+ break;
+ case 604:
+ type_nam = "polygon";
+ break;
+ case 605:
+ type_nam = "filename";
+ break;
+ case 628:
+ type_nam = "line";
+ break;
+ case 629:
+ type_nam = "_line";
+ break;
+ case 700:
+ type_nam = "float4";
+ break;
+ case 701:
+ type_nam = "float8";
+ break;
+ case 702:
+ type_nam = "abstime";
+ break;
+ case 703:
+ type_nam = "reltime";
+ break;
+ case 704:
+ type_nam = "tinterval";
+ break;
+ case 705:
+ type_nam = "unknown";
+ break;
+ case 718:
+ type_nam = "circle";
+ break;
+ case 719:
+ type_nam = "_circle";
+ break;
+ case 790:
+ type_nam = "money";
+ break;
+ case 791:
+ type_nam = "_money";
+ break;
+ case 810:
+ type_nam = "oidint2";
+ break;
+ case 910:
+ type_nam = "oidint4";
+ break;
+ case 911:
+ type_nam = "oidname";
+ break;
+ case 1000:
+ type_nam = "_bool";
+ break;
+ case 1001:
+ type_nam = "_bytea";
+ break;
+ case 1002:
+ type_nam = "_char";
+ break;
+ case 1003:
+ type_nam = "_name";
+ break;
+ case 1005:
+ type_nam = "_int2";
+ break;
+ case 1006:
+ type_nam = "_int28";
+ break;
+ case 1007:
+ type_nam = "_int4";
+ break;
+ case 1008:
+ type_nam = "_regproc";
+ break;
+ case 1009:
+ type_nam = "_text";
+ break;
+ case 1028:
+ type_nam = "_oid";
+ break;
+ case 1010:
+ type_nam = "_tid";
+ break;
+ case 1011:
+ type_nam = "_xid";
+ break;
+ case 1012:
+ type_nam = "_cid";
+ break;
+ case 1013:
+ type_nam = "_oid8";
+ break;
+ case 1014:
+ type_nam = "_lock";
+ break;
+ case 1015:
+ type_nam = "_stub";
+ break;
+ case 1016:
+ type_nam = "_ref";
+ break;
+ case 1017:
+ type_nam = "_point";
+ break;
+ case 1018:
+ type_nam = "_lseg";
+ break;
+ case 1019:
+ type_nam = "_path";
+ break;
+ case 1020:
+ type_nam = "_box";
+ break;
+ case 1021:
+ type_nam = "_float4";
+ break;
+ case 1022:
+ type_nam = "_float8";
+ break;
+ case 1023:
+ type_nam = "_abstime";
+ break;
+ case 1024:
+ type_nam = "_reltime";
+ break;
+ case 1025:
+ type_nam = "_tinterval";
+ break;
+ case 1026:
+ type_nam = "_filename";
+ break;
+ case 1027:
+ type_nam = "_polygon";
+ break;
+ case 1033:
+ type_nam = "aclitem";
+ break;
+ case 1034:
+ type_nam = "_aclitem";
+ break;
+ case 1042:
+ type_nam = "bpchar";
+ break;
+ case 1043:
+ type_nam = "varchar";
+ break;
+ case 1082:
+ type_nam = "date";
+ break;
+ case 1083:
+ type_nam = "time";
+ break;
+ case 1182:
+ type_nam = "_date";
+ break;
+ case 1183:
+ type_nam = "_time";
+ break;
+ case 1184:
+ type_nam = "datetime";
+ break;
+ case 1185:
+ type_nam = "_datetime";
+ break;
+ case 1186:
+ type_nam = "timespan";
+ break;
+ case 1187:
+ type_nam = "_timespan";
+ break;
+ case 1231:
+ type_nam = "_numeric";
+ break;
+ case 1296:
+ type_nam = "timestamp";
+ break;
+ case 1700:
+ type_nam = "numeric";
+ break;
+
+ default:
+ type_nam = "unknown";
+
+ }
+ av_store(av, i, newSVpv(type_nam, 0));
+ }
+ } else if (kl==13 && strEQ(key, "pg_oid_status")) {
+ retsv = newSVpv((char *)PQoidStatus(imp_sth->result), 0);
+ } else if (kl==13 && strEQ(key, "pg_cmd_status")) {
+ retsv = newSVpv((char *)PQcmdStatus(imp_sth->result), 0);
+ } else {
+ return Nullsv;
+ }
+
+ return sv_2mortal(retsv);
+}
+
+
+/* end of dbdimp.c */
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/dbdimp.h b/install/5.005/DBD-Pg-1.22-fixvercmp/dbdimp.h
new file mode 100644
index 0000000..58c105b
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/dbdimp.h
@@ -0,0 +1,81 @@
+/*
+ $Id: dbdimp.h,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+ Copyright (c) 1997,1998,1999,2000 Edmund Mergl
+ Portions Copyright (c) 1994,1995,1996,1997 Tim Bunce
+
+ You may distribute under the terms of either the GNU General Public
+ License or the Artistic License, as specified in the Perl README file.
+*/
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+/* Define drh implementor data structure */
+struct imp_drh_st {
+ dbih_drc_t com; /* MUST be first element in structure */
+};
+
+/* Define dbh implementor data structure */
+struct imp_dbh_st {
+ dbih_dbc_t com; /* MUST be first element in structure */
+
+ PGconn * conn; /* connection structure */
+ int init_commit; /* initialize AutoCommit */
+ int pg_auto_escape; /* initialize AutoEscape */
+ int pg_bool_tf; /* do bools return 't'/'f' */
+#ifdef SvUTF8_off
+ int pg_enable_utf8; /* should we attempt to make utf8 strings? */
+#endif
+};
+
+/* Define sth implementor data structure */
+struct imp_sth_st {
+ dbih_stc_t com; /* MUST be first element in structure */
+
+ PGresult* result; /* result structure */
+ int cur_tuple; /* current tuple */
+ int rows; /* number of affected rows */
+
+ /* Input Details */
+ char *statement; /* sql (see sth_scan) */
+ HV *all_params_hv; /* all params, keyed by name */
+ AV *out_params_av; /* quick access to inout params */
+ int pg_pad_empty; /* convert ""->" " when binding */
+ int all_params_len; /* length-sum of all params */
+
+ /* (In/)Out Parameter Details */
+ bool has_inout_params;
+};
+
+
+#define sword signed int
+#define sb2 signed short
+#define ub2 unsigned short
+
+typedef struct phs_st phs_t; /* scalar placeholder */
+
+struct phs_st { /* scalar placeholder EXPERIMENTAL */
+ sword ftype; /* external OCI field type */
+
+ SV *sv; /* the scalar holding the value */
+ int sv_type; /* original sv type at time of bind */
+ bool is_inout;
+
+ IV maxlen; /* max possible len (=allocated buffer) */
+
+ /* these will become an array */
+ sb2 indp; /* null indicator */
+ char *progv;
+ ub2 arcode;
+ IV alen; /* effective length ( <= maxlen ) */
+
+ int alen_incnull; /* 0 or 1 if alen should include null */
+ char name[1]; /* struct is malloc'd bigger as needed */
+};
+
+
+SV * dbd_db_pg_notifies (SV *dbh, imp_dbh_t *imp_dbh);
+
+/* end of dbdimp.h */
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/eg/ApacheDBI.pl b/install/5.005/DBD-Pg-1.22-fixvercmp/eg/ApacheDBI.pl
new file mode 100755
index 0000000..b084f70
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/eg/ApacheDBI.pl
@@ -0,0 +1,70 @@
+#!/usr/local/bin/perl
+
+# $Id: ApacheDBI.pl,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+# don't forget to create in postgres the user who is running
+# the httpd, eg 'createuser nobody' !
+#
+# demo script, tested with:
+# - PostgreSQL-7.1.1
+# - apache_1.3.12
+# - mod_perl-1.23
+# - perl5.6.0
+# - DBI-1.14
+
+use CGI;
+use DBI;
+use strict;
+
+my $query = new CGI;
+
+print $query->header,
+ $query->start_html(-title=>'A Simple Example'),
+ $query->startform,
+ "<CENTER><H3>Testing Module DBI</H3></CENTER>",
+ "<P><CENTER><TABLE CELLPADDING=4 CELLSPACING=2 BORDER=1>",
+ "<TR><TD>Enter the data source: </TD>",
+ "<TD>", $query->textfield(-name=>'data_source', -size=>40, -default=>'dbi:Pg:dbname=template1'), "</TD>",
+ "</TR>",
+ "<TR><TD>Enter the user name: </TD>",
+ "<TD>", $query->textfield(-name=>'username'), "</TD>",
+ "</TR>",
+ "<TR><TD>Enter the password: </TD>",
+ "<TD>", $query->textfield(-name=>'auth'), "</TD>",
+ "</TR>",
+ "<TR><TD>Enter the select command: </TD>",
+ "<TD>", $query->textfield(-name=>'cmd', -size=>40), "</TD>",
+ "</TR>",
+ "</TABLE></CENTER><P>",
+ "<CENTER>", $query->submit(-value=>'Submit'), "</CENTER>",
+ $query->endform;
+
+if ($query->param) {
+
+ my $data_source = $query->param('data_source');
+ my $username = $query->param('username');
+ my $auth = $query->param('auth');
+ my $cmd = $query->param('cmd');
+ my $dbh = DBI->connect($data_source, $username, $auth);
+ if ($dbh) {
+ my $sth = $dbh->prepare($cmd);
+ my $ret = $sth->execute;
+ if ($ret) {
+ my($i, $ary_ref);
+ print "<P><CENTER><TABLE CELLPADDING=4 CELLSPACING=2 BORDER=1>\n";
+ while ($ary_ref = $sth->fetchrow_arrayref) {
+ print "<TR><TD>", join("</TD><TD>", @$ary_ref), "</TD></TR>\n";
+ }
+ print "</TABLE></CENTER><P>\n";
+ $sth->finish;
+ } else {
+ print "<CENTER><H2>", $DBI::errstr, "</H2></CENTER>\n";
+ }
+ $dbh->disconnect;
+ } else {
+ print "<CENTER><H2>", $DBI::errstr, "</H2></CENTER>\n";
+ }
+}
+
+print $query->end_html;
+
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/eg/lotest.pl b/install/5.005/DBD-Pg-1.22-fixvercmp/eg/lotest.pl
new file mode 100644
index 0000000..6192c49
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/eg/lotest.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use DBI;
+use DBD::Pg;
+
+my $dsn = "dbname=p1";
+my $dbh = DBI->connect('dbi:Pg:dbname=p1', undef, undef, { AutoCommit => 1 });
+
+my $buf = 'abcdefghijklmnopqrstuvwxyz' x 400;
+
+my $id = write_blob($dbh, undef, $buf);
+
+my $dat = read_blob($dbh, $id);
+
+print "Done\n";
+
+sub write_blob {
+ my ($dbh, $lobj_id, $data) = @_;
+
+ # begin transaction
+ $dbh->{AutoCommit} = 0;
+
+ # Create a new lo if we are not passed an lo object ID.
+ unless ($lobj_id) {
+ # Create the object.
+ $lobj_id = $dbh->func($dbh->{'pg_INV_WRITE'}, 'lo_creat');
+ }
+
+ # Open it to get a file descriptor.
+ my $lobj_fd = $dbh->func($lobj_id, $dbh->{'pg_INV_WRITE'}, 'lo_open');
+
+ $dbh->func($lobj_fd, 0, 0, 'lo_lseek');
+
+ # Write some data to it.
+ my $len = $dbh->func($lobj_fd, $data, length($data), 'lo_write');
+
+ die "Errors writing lo\n" if $len != length($data);
+
+ # Close 'er up.
+ $dbh->func($lobj_fd, 'lo_close') or die "Problems closing lo object\n";
+
+ # end transaction
+ $dbh->{AutoCommit} = 1;
+
+ return $lobj_id;
+}
+
+sub read_blob {
+ my ($dbh, $lobj_id) = @_;
+ my $data = '';
+ my $read_len = 256;
+ my $chunk = '';
+
+ # begin transaction
+ $dbh->{AutoCommit} = 0;
+
+ my $lobj_fd = $dbh->func($lobj_id, $dbh->{'pg_INV_READ'}, 'lo_open');
+
+ $dbh->func($lobj_fd, 0, 0, 'lo_lseek');
+
+ # Pull out all the data.
+ while ($dbh->func($lobj_fd, $chunk, $read_len, 'lo_read')) {
+ $data .= $chunk;
+ }
+
+ $dbh->func($lobj_fd, 'lo_close') or die "Problems closing lo object\n";
+
+ # end transaction
+ $dbh->{AutoCommit} = 1;
+
+ return $data;
+}
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/eg/notify_test.patch b/install/5.005/DBD-Pg-1.22-fixvercmp/eg/notify_test.patch
new file mode 100644
index 0000000..6f8acf8
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/eg/notify_test.patch
@@ -0,0 +1,82 @@
+diff -r --unified DBD-Pg-1.00/test.pl DBD-Pg-1.00.alex/test.pl
+--- DBD-Pg-1.00/test.pl Sun May 27 10:10:13 2001
++++ DBD-Pg-1.00.alex/test.pl Sun Jun 10 15:38:09 2001
+@@ -40,7 +40,7 @@
+ my $dsn_main = "dbi:Pg:dbname=$dbmain";
+ my $dsn_test = "dbi:Pg:dbname=$dbtest";
+
+-my ($dbh0, $dbh, $sth);
++my ($dbh0, $dbh, $dbh1, $sth);
+
+ #DBI->trace(3); # make your choice
+
+@@ -445,16 +445,56 @@
+ # end transaction
+ $dbh->{AutoCommit} = 1;
+
++# compare large objects
++
+ ( $dbh->func($lobjId, 'lo_unlink') )
+ and print "\$dbh->func(lo_unlink) ...... ok\n"
+ or print "\$dbh->func(lo_unlink) ...... not ok\n";
+
+-# compare large objects
+-
+ ( $pgin cmp $buf and $pgin cmp $blob )
+ and print "compare blobs .............. not ok\n"
+ or print "compare blobs .............. ok\n";
+
++my $fd;
++( $fd=$dbh->func( 'getfd') )
++ and print "\$dbh->func(getfd) .......... ok\n"
++ or print "\$dbh->func(getfd) .......... not ok\n";
++
++( $dbh->do( 'LISTEN test ') )
++ and print "\$dbh->do('LISTEN test') .... ok\n"
++ or print "\$dbh->do('LISTEN test') .... not ok\n";
++
++( $dbh1 = DBI->connect("$dsn_test", '', '', { AutoCommit => 1 }) )
++ and print "DBI->connect (for notify)... ok\n"
++ or die "DBI->connect (for notify)... not ok: ", $DBI::errstr;
++
++# there should be no data for read on $fd , until we send a notify
++
++ my $rout;
++ my $rin = '';
++ vec($rin,$fd,1) = 1;
++ my $nfound = select( $rout=$rin, undef, undef, 0);
++
++( $nfound==0 )
++ and print "select(\$fd) returns no data. ok\n"
++ or die "select(\$fd) returns no data. not ok\n";
++
++( $dbh1->do( 'NOTIFY test ') )
++ and print "\$dbh1->do('NOTIFY test') ... ok\n"
++ or print "\$dbh1->do('NOTIFY test') ... not ok\n";
++
++ my $nfound = select( $rout=$rin, undef, undef, 1);
++
++( $nfound==1 )
++ and print "select(\$fd) returns data.... ok\n"
++ or die "select(\$fd) returns data.... not ok\n";
++
++my $notify_r;
++
++( $notify_r = $dbh->func('notifies') )
++ and print "\$dbh->func('notifies')...... ok\n"
++ or die "\$dbh->func('notifies')...... not ok\n";
++
+ ######################### disconnect and drop test database
+
+ # disconnect
+@@ -462,6 +502,10 @@
+ ( $dbh->disconnect )
+ and print "\$dbh->disconnect ........... ok\n"
+ or die "\$dbh->disconnect ........... not ok: ", $DBI::errstr;
++
++( $dbh1->disconnect )
++ and print "\$dbh1->disconnect .......... ok\n"
++ or die "\$dbh1->disconnect .......... not ok: ", $DBI::errstr;
+
+ $dbh0->do("DROP DATABASE $dbtest");
+ $dbh0->disconnect;
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/00basic.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/00basic.t
new file mode 100644
index 0000000..1c0cb28
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/00basic.t
@@ -0,0 +1,10 @@
+print "1..1\n";
+
+use DBI;
+use DBD::Pg;
+
+if ($DBD::Pg::VERSION) {
+ print "ok 1\n";
+} else {
+ print "not ok 1\n";
+}
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/01connect.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/01connect.t
new file mode 100644
index 0000000..be17b50
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/01connect.t
@@ -0,0 +1,26 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 2;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+
+ok((defined $dbh and $dbh->disconnect()),
+ 'connect with transaction'
+ );
+
+undef $dbh;
+$dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 1});
+
+ok((defined $dbh and $dbh->disconnect()),
+ 'connect without transaction'
+ );
+
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/01constants.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/01constants.t
new file mode 100644
index 0000000..09907e9
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/01constants.t
@@ -0,0 +1,25 @@
+use strict;
+use Test::More tests => 20;
+
+use DBD::Pg qw(:pg_types);
+
+ok(PG_BOOL == 16, 'PG_BOOL');
+ok(PG_BYTEA == 17, 'PG_BYTEA');
+ok(PG_CHAR == 18, 'PG_CHAR');
+ok(PG_INT8 == 20, 'PG_INT8');
+ok(PG_INT2 == 21, 'PG_INT2');
+ok(PG_INT4 == 23, 'PG_INT4');
+ok(PG_TEXT == 25, 'PG_TEXT');
+ok(PG_OID == 26, 'PG_OID');
+ok(PG_FLOAT4 == 700, 'PG_FLOAT4');
+ok(PG_FLOAT8 == 701, 'PG_FLOAT8');
+ok(PG_ABSTIME == 702, 'PG_ABSTIME');
+ok(PG_RELTIME == 703, 'PG_RELTIME');
+ok(PG_TINTERVAL == 704, 'PG_TINTERVAL');
+ok(PG_BPCHAR == 1042, 'PG_BPCHAR');
+ok(PG_VARCHAR == 1043, 'PG_VARCHAR');
+ok(PG_DATE == 1082, 'PG_DATE');
+ok(PG_TIME == 1083, 'PG_TIME');
+ok(PG_DATETIME == 1184, 'PG_DATETIME');
+ok(PG_TIMESPAN == 1186, 'PG_TIMESPAN');
+ok(PG_TIMESTAMP == 1296, 'PG_TIMESTAMP');
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/01setup.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/01setup.t
new file mode 100644
index 0000000..d0b57a3
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/01setup.t
@@ -0,0 +1,38 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 3;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 1});
+ok(defined $dbh,'connect without transaction');
+{
+ local $dbh->{PrintError} = 0;
+ local $dbh->{RaiseError} = 0;
+ $dbh->do(q{DROP TABLE test});
+}
+
+my $sql = <<SQL;
+CREATE TABLE test (
+ id int,
+ name text,
+ val text,
+ score float,
+ date timestamp default 'now()',
+ array text[][]
+)
+SQL
+
+ok($dbh->do($sql),
+ 'create table'
+ );
+
+ok($dbh->disconnect(),
+ 'disconnect'
+ );
+
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/02prepare.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/02prepare.t
new file mode 100644
index 0000000..373aca2
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/02prepare.t
@@ -0,0 +1,84 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 8;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+my $sql = <<SQL;
+ SELECT *
+ FROM test
+SQL
+
+ok($dbh->prepare($sql),
+ "prepare: $sql"
+ );
+
+$sql = <<SQL;
+ SELECT id
+ FROM test
+SQL
+
+ok($dbh->prepare($sql),
+ "prepare: $sql"
+ );
+
+$sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+SQL
+
+ok($dbh->prepare($sql),
+ "prepare: $sql"
+ );
+
+$sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE id = 1
+SQL
+
+ok($dbh->prepare($sql),
+ "prepare: $sql"
+ );
+
+$sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE id = ?
+SQL
+
+ok($dbh->prepare($sql),
+ "prepare: $sql"
+ );
+
+$sql = <<SQL;
+ SELECT *
+ FROM test
+ WHERE id = ?
+ AND name = ?
+ AND value = ?
+ AND score = ?
+ and data = ?
+SQL
+
+ok($dbh->prepare($sql),
+ "prepare: $sql"
+ );
+
+ok($dbh->disconnect(),
+ 'disconnect'
+ );
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/03bind.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/03bind.t
new file mode 100644
index 0000000..df7c884
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/03bind.t
@@ -0,0 +1,85 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 11;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+my $sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE id = ?
+SQL
+my $sth = $dbh->prepare($sql);
+ok(defined $sth,
+ "prepare: $sql"
+ );
+
+ok($sth->bind_param(1, 'foo'),
+ 'bind int column with string'
+ );
+
+ok($sth->bind_param(1, 1),
+ 'rebind int column with int'
+ );
+
+$sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE id = ?
+ AND name = ?
+SQL
+$sth = $dbh->prepare($sql);
+ok(defined $sth,
+ "prepare: $sql"
+ );
+
+ok($sth->bind_param(1, 'foo'),
+ 'bind int column with string',
+ );
+ok($sth->bind_param(2, 'bar'),
+ 'bind string column with text'
+ );
+ok($sth->bind_param(2, 'baz'),
+ 'rebind string column with text'
+ );
+
+ok($sth->finish(),
+ 'finish'
+ );
+
+# Make sure that we get warnings when we try to use SQL_BINARY.
+{
+ local $SIG{__WARN__} =
+ sub { ok($_[0] =~ /^Use of SQL type SQL_BINARY/,
+ 'warning with SQL_BINARY'
+ );
+ };
+
+ $sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE id = ?
+ AND name = ?
+SQL
+ $sth = $dbh->prepare($sql);
+
+ $sth->bind_param(1, 'foo', DBI::SQL_BINARY);
+}
+
+ok($dbh->disconnect(),
+ 'disconnect'
+ );
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/04execute.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/04execute.t
new file mode 100644
index 0000000..9643878
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/04execute.t
@@ -0,0 +1,113 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 13;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+my $sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE id = ?
+SQL
+my $sth = $dbh->prepare($sql);
+ok(defined $sth,
+ "prepare: $sql"
+ );
+
+$sth->bind_param(1, 1);
+ok($sth->execute(),
+ 'exectute with one bind param'
+ );
+
+$sth->bind_param(1, 2);
+ok($sth->execute(),
+ 'exectute with rebinding one param'
+ );
+
+$sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE id = ?
+ AND name = ?
+SQL
+$sth = $dbh->prepare($sql);
+ok(defined $sth,
+ "prepare: $sql"
+ );
+
+$sth->bind_param(1, 2);
+$sth->bind_param(2, 'foo');
+ok($sth->execute(),
+ 'exectute with two bind params'
+ );
+
+eval {
+ local $dbh->{PrintError} = 0;
+ $sth = $dbh->prepare($sql);
+ $sth->bind_param(1, 2);
+ $sth->execute();
+};
+ok(!$@,
+ 'execute with only first of two params bound'
+ );
+
+eval {
+ local $dbh->{PrintError} = 0;
+ $sth = $dbh->prepare($sql);
+ $sth->bind_param(2, 'foo');
+ $sth->execute();
+};
+ok(!$@,
+ 'execute with only second of two params bound'
+ );
+
+eval {
+ local $dbh->{PrintError} = 0;
+ $sth = $dbh->prepare($sql);
+ $sth->execute();
+};
+ok(!$@,
+ 'execute with neither of two params bound'
+ );
+
+$sth = $dbh->prepare($sql);
+ok($sth->execute(1, 'foo'),
+ 'execute with both params bound in execute'
+ );
+
+eval {
+ local $dbh->{PrintError} = 0;
+ $sth = $dbh->prepare(q{
+ SELECT id
+ , name
+ FROM test
+ WHERE id = ?
+ AND name = ?
+ });
+ $sth->execute(1);
+};
+ok($@,
+ 'execute with only one of two params bound in execute'
+ );
+
+
+ok($sth->finish(),
+ 'finish'
+ );
+
+ok($dbh->disconnect(),
+ 'disconnect'
+ );
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/05fetch.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/05fetch.t
new file mode 100644
index 0000000..b6f8f66
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/05fetch.t
@@ -0,0 +1,131 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 10;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+$dbh->do(q{INSERT INTO test (id, name, val) VALUES (1, 'foo', 'horse')});
+$dbh->do(q{INSERT INTO test (id, name, val) VALUES (2, 'bar', 'chicken')});
+$dbh->do(q{INSERT INTO test (id, name, val) VALUES (3, 'baz', 'pig')});
+ok($dbh->commit(),
+ 'commit'
+ );
+
+my $sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+SQL
+my $sth = $dbh->prepare($sql);
+$sth->execute();
+
+my $rows = 0;
+while (my ($id, $name) = $sth->fetchrow_array()) {
+ if (defined($id) && defined($name)) {
+ $rows++;
+ }
+}
+$sth->finish();
+ok($rows == 3,
+ 'fetch three rows'
+ );
+
+$sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE 1 = 0
+SQL
+$sth = $dbh->prepare($sql);
+$sth->execute();
+
+$rows = 0;
+while (my ($id, $name) = $sth->fetchrow_array()) {
+ $rows++;
+}
+$sth->finish();
+
+ok($rows == 0,
+ 'fetch zero rows'
+ );
+
+$sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE id = ?
+SQL
+$sth = $dbh->prepare($sql);
+$sth->execute(1);
+
+$rows = 0;
+while (my ($id, $name) = $sth->fetchrow_array()) {
+ if (defined($id) && defined($name)) {
+ $rows++;
+ }
+}
+$sth->finish();
+
+ok($rows == 1,
+ 'fetch one row on id'
+ );
+
+# Attempt to test whether or not we can get unicode out of the database
+# correctly. Reuse the previous sth.
+SKIP: {
+ eval "use Encode";
+ skip "need Encode module for unicode tests", 3 if $@;
+ local $dbh->{pg_enable_utf8} = 1;
+ $dbh->do("INSERT INTO test (id, name, val) VALUES (4, '\001\000dam', 'cow')");
+ $sth->execute(4);
+ my ($id, $name) = $sth->fetchrow_array();
+ ok(Encode::is_utf8($name),
+ 'returned data has utf8 bit set'
+ );
+ is(length($name), 4,
+ 'returned utf8 data is not corrupted'
+ );
+ $sth->finish();
+ $sth->execute(1);
+ my ($id2, $name2) = $sth->fetchrow_array();
+ ok(! Encode::is_utf8($name2),
+ 'returned ASCII data has not got utf8 bit set'
+ );
+ $sth->finish();
+}
+
+$sql = <<SQL;
+ SELECT id
+ , name
+ FROM test
+ WHERE name = ?
+SQL
+$sth = $dbh->prepare($sql);
+$sth->execute('foo');
+
+$rows = 0;
+while (my ($id, $name) = $sth->fetchrow_array()) {
+ if (defined($id) && defined($name)) {
+ $rows++;
+ }
+}
+$sth->finish();
+
+ok($rows == 1,
+ 'fetch one row on name'
+ );
+
+ok($dbh->disconnect(),
+ 'disconnect'
+ );
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/06disconnect.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/06disconnect.t
new file mode 100644
index 0000000..5d76bc0
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/06disconnect.t
@@ -0,0 +1,31 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 3;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+ok($dbh->disconnect(),
+ 'disconnect'
+ );
+
+$dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+
+$dbh->disconnect();
+$dbh->disconnect();
+$dbh->disconnect();
+ok($dbh->disconnect(),
+ 'disconnect on already disconnected dbh'
+ );
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/07reuse.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/07reuse.t
new file mode 100644
index 0000000..d09dfc0
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/07reuse.t
@@ -0,0 +1,28 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 3;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, PrintError => 0, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+my $sth = $dbh->prepare(q{SELECT * FROM test});
+ok($dbh->disconnect(),
+ 'disconnect with un-finished statement'
+ );
+
+eval {
+ $sth->execute();
+};
+ok($@,
+ 'execute on disconnected statement'
+ );
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/08txn.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/08txn.t
new file mode 100644
index 0000000..467aa31
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/08txn.t
@@ -0,0 +1,102 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 18;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh1 = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh1,
+ 'connect first dbh'
+ );
+
+my $dbh2 = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh2,
+ 'connect second dbh'
+ );
+
+$dbh1->do(q{DELETE FROM test});
+ok($dbh1->commit(),
+ 'delete'
+ );
+
+my $rows = ($dbh1->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 0,
+ 'fetch on empty table from dbh1'
+ );
+
+$rows = ($dbh2->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 0,
+ 'fetch on empty table from dbh2'
+ );
+
+$dbh1->do(q{INSERT INTO test (id, name, val) VALUES (1, 'foo', 'horse')});
+$dbh1->do(q{INSERT INTO test (id, name, val) VALUES (2, 'bar', 'chicken')});
+$dbh1->do(q{INSERT INTO test (id, name, val) VALUES (3, 'baz', 'pig')});
+
+$rows = ($dbh1->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 3,
+ 'fetch three rows on dbh1'
+ );
+
+$rows = ($dbh2->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 0,
+ 'fetch on dbh2 before commit'
+ );
+
+ok($dbh1->commit(),
+ 'commit work'
+ );
+
+$rows = ($dbh1->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 3,
+ 'fetch on dbh1 after commit'
+ );
+
+$rows = ($dbh2->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 3,
+ 'fetch on dbh2 after commit'
+ );
+
+ok($dbh1->do(q{DELETE FROM test}),
+ 'delete'
+ );
+
+$rows = ($dbh1->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 0,
+ 'fetch on empty table from dbh1'
+ );
+
+$rows = ($dbh2->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 3,
+ 'fetch on from dbh2 without commit'
+ );
+
+ok($dbh1->rollback(),
+ 'rollback'
+ );
+
+$rows = ($dbh1->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 3,
+ 'fetch on from dbh1 after rollback'
+ );
+
+$rows = ($dbh2->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 3,
+ 'fetch on from dbh2 after rollback'
+ );
+
+ok($dbh1->disconnect(),
+ 'disconnect on dbh1'
+);
+
+ok($dbh2->disconnect(),
+ 'disconnect on dbh2'
+);
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/09autocommit.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/09autocommit.t
new file mode 100644
index 0000000..9b1b69f
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/09autocommit.t
@@ -0,0 +1,68 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 12;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh1 = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 1}
+ );
+ok(defined $dbh1,
+ 'connect first dbh'
+ );
+
+my $dbh2 = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 1}
+ );
+ok(defined $dbh2,
+ 'connect second dbh'
+ );
+
+ok($dbh1->do(q{DELETE FROM test}),
+ 'delete'
+ );
+
+my $rows = ($dbh1->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 0,
+ 'fetch on empty table from dbh1'
+ );
+
+$rows = ($dbh2->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 0,
+ 'fetch on empty table from dbh2'
+ );
+
+ok($dbh1->do(q{INSERT INTO test (id, name, val) VALUES (1, 'foo', 'horse')}),
+ 'insert'
+ );
+
+$rows = ($dbh1->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 1,
+ 'fetch one row from dbh1'
+ );
+
+$rows = ($dbh2->selectrow_array(q{SELECT COUNT(*) FROM test}))[0];
+ok($rows == 1,
+ 'fetch one row from dbh1'
+ );
+
+local $SIG{__WARN__} = sub {};
+ok(!$dbh1->commit(),
+ 'commit'
+ );
+
+ok(!$dbh1->rollback(),
+ 'rollback'
+ );
+
+ok($dbh1->disconnect(),
+ 'disconnect on dbh1'
+);
+
+ok($dbh2->disconnect(),
+ 'disconnect on dbh2'
+);
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/11quoting.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/11quoting.t
new file mode 100644
index 0000000..afec963
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/11quoting.t
@@ -0,0 +1,50 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 8;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+my %tests = (
+ one=>["'", "'\\" . sprintf("%03o", ord("'")) . "'"],
+ two=>["''", "'" . ("\\" . sprintf("%03o", ord("'")))x2 . "'"],
+ three=>["\\", "'\\" . sprintf("%03o", ord("\\")) . "'"],
+ four=>["\\'", sprintf("'\\%03o\\%03o'", ord("\\"), ord("'"))],
+ five=>["\\'?:", sprintf("'\\%03o\\%03o?:'", ord("\\"), ord("'"))],
+ );
+
+foreach my $test (keys %tests) {
+ my ($unq, $quo, $ref);
+
+ $unq = $tests{$test}->[0];
+ $ref = $tests{$test}->[1];
+ $quo = $dbh->quote($unq);
+
+ ok($quo eq $ref,
+ "$test: $unq -> expected $quo got $ref"
+ );
+}
+
+# Make sure that SQL_BINARY doesn't work.
+# eval { $dbh->quote('foo', { TYPE => DBI::SQL_BINARY })};
+eval {
+ local $dbh->{PrintError} = 0;
+ $dbh->quote('foo', DBI::SQL_BINARY);
+};
+ok($@ && $@ =~ /Use of SQL_BINARY invalid in quote/,
+ 'SQL_BINARY'
+);
+
+ok($dbh->disconnect(),
+ 'disconnect'
+ );
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/12placeholders.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/12placeholders.t
new file mode 100644
index 0000000..bd79ea7
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/12placeholders.t
@@ -0,0 +1,125 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 9;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+my $quo = $dbh->quote("\\'?:");
+my $sth = $dbh->prepare(qq{
+ INSERT INTO test (name) VALUES ($quo)
+ });
+$sth->execute();
+
+my $sql = <<SQL;
+ SELECT name
+ FROM test
+ WHERE name = $quo;
+SQL
+$sth = $dbh->prepare($sql);
+$sth->execute();
+
+my ($retr) = $sth->fetchrow_array();
+ok((defined($retr) && $retr eq "\\'?:"),
+ 'fetch'
+ );
+
+eval {
+ local $dbh->{PrintError} = 0;
+ $sth->execute('foo');
+};
+ok($@,
+ 'execute with one bind param where none expected'
+ );
+
+$sql = <<SQL;
+ SELECT name
+ FROM test
+ WHERE name = ?
+SQL
+$sth = $dbh->prepare($sql);
+
+$sth->execute("\\'?:");
+
+($retr) = $sth->fetchrow_array();
+ok((defined($retr) && $retr eq "\\'?:"),
+ 'execute with ? placeholder'
+ );
+
+$sql = <<SQL;
+ SELECT name
+ FROM test
+ WHERE name = :1
+SQL
+$sth = $dbh->prepare($sql);
+
+$sth->execute("\\'?:");
+
+($retr) = $sth->fetchrow_array();
+ok((defined($retr) && $retr eq "\\'?:"),
+ 'execute with :1 placeholder'
+ );
+
+$sql = <<SQL;
+ SELECT name
+ FROM test
+ WHERE name = '?'
+SQL
+$sth = $dbh->prepare($sql);
+
+eval {
+ local $dbh->{PrintError} = 0;
+ $sth->execute('foo');
+};
+ok($@,
+ 'execute with quoted ?'
+ );
+
+$sql = <<SQL;
+ SELECT name
+ FROM test
+ WHERE name = ':1'
+SQL
+$sth = $dbh->prepare($sql);
+
+eval {
+ local $dbh->{PrintError} = 0;
+ $sth->execute('foo');
+};
+ok($@,
+ 'execute with quoted :1'
+ );
+
+$sql = <<SQL;
+ SELECT name
+ FROM test
+ WHERE name = '\\\\'
+ AND name = '?'
+SQL
+$sth = $dbh->prepare($sql);
+
+eval {
+ local $dbh->{PrintError} = 0;
+ local $sth->{PrintError} = 0;
+ $sth->execute('foo');
+};
+ok($@,
+ 'execute with quoted ?'
+ );
+
+$sth->finish();
+$dbh->rollback();
+
+ok($dbh->disconnect(),
+ 'disconnect'
+ );
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/13pgtype.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/13pgtype.t
new file mode 100644
index 0000000..8db819e
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/13pgtype.t
@@ -0,0 +1,43 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 3;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+eval {
+ local $dbh->{PrintError} = 0;
+ $dbh->do(q{DROP TABLE tt});
+ $dbh->commit();
+};
+$dbh->rollback();
+
+$dbh->do(q{CREATE TABLE tt (blah numeric(5,2), foo text)});
+my $sth = $dbh->prepare(qq{
+ SELECT * FROM tt WHERE FALSE
+ });
+$sth->execute();
+
+my @types = @{$sth->{pg_type}};
+
+ok($types[0] eq 'numeric',
+ 'type numeric'
+ );
+
+ok($types[1] eq 'text',
+ 'type text'
+ );
+
+$sth->finish();
+$dbh->rollback();
+$dbh->disconnect();
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/15funct.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/15funct.t
new file mode 100644
index 0000000..1bc2cf9
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/15funct.t
@@ -0,0 +1,353 @@
+#!/usr/bin/perl -w -I./t
+$| = 1;
+
+# vim:ts=2:sw=2:ai:aw:nu:
+use DBI qw(:sql_types);
+use Data::Dumper;
+use strict;
+use Test::More;
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 59;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+#
+# Test the different methods, so are expected to fail.
+#
+
+my $sth;
+
+# foreach (@{ $DBI::EXPORT_TAGS{sql_types} }) {
+# no strict 'refs';
+# printf "%s=%d\n", $_, &{"DBI::$_"};
+# }
+
+my $get_info = {
+ SQL_DBMS_NAME => 17
+ , SQL_DBMS_VER => 18
+ , SQL_IDENTIFIER_QUOTE_CHAR => 29
+ , SQL_CATALOG_NAME_SEPARATOR => 41
+ , SQL_CATALOG_LOCATION => 114
+};
+
+# Ping
+ eval {
+ ok( $dbh->ping(), "Testing Ping" );
+ };
+ok ( !$@, "Ping Tested" );
+
+# Get Info
+ eval {
+ $sth = $dbh->get_info();
+ };
+ok ($@, "Call to get_info with 0 arguements, error expected: $@" );
+$sth = undef;
+
+# Table Info
+ eval {
+ $sth = $dbh->table_info();
+ };
+ok ((!$@ and defined $sth), "table_info tested" );
+$sth = undef;
+
+# Column Info
+ eval {
+ $sth = $dbh->column_info();
+ };
+ok ((!$@ and defined $sth), "column_info tested" );
+#ok ($@, "Call to column_info with 0 arguements, error expected: $@" );
+$sth = undef;
+
+
+# Tables
+ eval {
+ $sth = $dbh->tables();
+ };
+ok ((!$@ and defined $sth), "tables tested" );
+$sth = undef;
+
+# Type Info All
+ eval {
+ $sth = $dbh->type_info_all();
+ };
+ok ((!$@ and defined $sth), "type_info_all tested" );
+$sth = undef;
+
+# Type Info
+ eval {
+ my @types = $dbh->type_info();
+ die unless @types;
+ };
+ok (!$@, "type_info(undef)");
+$sth = undef;
+
+# Quote
+ eval {
+ my $val = $dbh->quote();
+ die unless $val;
+ };
+ok ($@, "quote error expected: $@");
+
+$sth = undef;
+# Tests for quote:
+my @qt_vals = (1, 2, undef, 'NULL', "ThisIsAString", "This is Another String");
+my @expt_vals = (q{'1'}, q{'2'}, "NULL", q{'NULL'}, q{'ThisIsAString'}, q{'This is Another String'});
+for (my $x = 0; $x <= $#qt_vals; $x++) {
+ local $^W = 0;
+ my $val = $dbh->quote( $qt_vals[$x] );
+ is( $val, $expt_vals[$x], "$x: quote on $qt_vals[$x] returned $val" );
+}
+
+is( $dbh->quote( 1, SQL_INTEGER() ), 1, "quote(1, SQL_INTEGER)" );
+
+
+# Quote Identifier
+ eval {
+ my $val = $dbh->quote_identifier();
+ die unless $val;
+ };
+
+ok ($@, "quote_identifier error expected: $@");
+$sth = undef;
+
+SKIP: {
+ skip("get_info() not yet implemented", 1);
+ # , SQL_IDENTIFIER_QUOTE_CHAR => 29
+ # , SQL_CATALOG_NAME_SEPARATOR => 41
+ my $qt = $dbh->get_info( $get_info->{SQL_IDENTIFIER_QUOTE_CHAR} );
+ my $sep = $dbh->get_info( $get_info->{SQL_CATALOG_NAME_SEPARATOR} );
+
+ # Uncomment this line and remove the next line when get_info() is implemented.
+# my $cmp_str = qq{${qt}link${qt}${sep}${qt}schema${qt}${sep}${qt}table${qt}};
+ my $cmp_str = '';
+ is( $dbh->quote_identifier( "link", "schema", "table" )
+ , $cmp_str
+ , q{quote_identifier( "link", "schema", "table" )}
+ );
+}
+
+# Test ping
+
+ok ($dbh->ping, "Ping the current connection ..." );
+
+# Test Get Info.
+
+# SQL_KEYWORDS
+# SQL_CATALOG_TERM
+# SQL_DATA_SOURCE_NAME
+# SQL_DBMS_NAME
+# SQL_DBMS_VERSION
+# SQL_DRIVER_NAME
+# SQL_DRIVER_VER
+# SQL_PROCEDURE_TERM
+# SQL_SCHEMA_TERM
+# SQL_TABLE_TERM
+# SQL_USER_NAME
+
+SKIP: {
+ skip("get_info() not yet implemented", 5);
+ foreach my $info (sort keys %$get_info) {
+ my $type = $dbh->get_info($get_info->{$info});
+ ok( defined $type, "get_info($info) ($get_info->{$info}) " .
+ ($type || '') );
+ }
+}
+
+# Test Table Info
+$sth = $dbh->table_info( undef, undef, undef );
+ok( defined $sth, "table_info(undef, undef, undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->table_info( undef, undef, undef, "VIEW" );
+ok( defined $sth, "table_info(undef, undef, undef, \"VIEW\") tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+# Test Table Info Rule 19a
+$sth = $dbh->table_info( '%', '', '');
+ok( defined $sth, "table_info('%', '', '',) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+# Test Table Info Rule 19b
+$sth = $dbh->table_info( '', '%', '');
+ok( defined $sth, "table_info('', '%', '',) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+# Test Table Info Rule 19c
+$sth = $dbh->table_info( '', '', '', '%');
+ok( defined $sth, "table_info('', '', '', '%',) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+# Test to see if this database contains any of the defined table types.
+$sth = $dbh->table_info( '', '', '', '%');
+ok( defined $sth, "table_info('', '', '', '%',) tested" );
+if ($sth) {
+ my $ref = $sth->fetchall_hashref( 'TABLE_TYPE' );
+ foreach my $type ( sort keys %$ref ) {
+ my $tsth = $dbh->table_info( undef, undef, undef, $type );
+ ok( defined $tsth, "table_info(undef, undef, undef, $type) tested" );
+ DBI::dump_results($tsth) if defined $tsth;
+ $tsth->finish;
+ }
+ $sth->finish;
+}
+$sth = undef;
+
+# Test Column Info
+$sth = $dbh->column_info( undef, undef, undef, undef );
+ok( defined $sth, "column_info(undef, undef, undef, undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'auser'", undef, undef );
+ok( defined $sth, "column_info(undef, 'auser', undef, undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'ause%'", undef, undef );
+ok( defined $sth, "column_info(undef, 'ause%', undef, undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'auser','replicator'", undef, undef );
+ok( defined $sth, "column_info(undef, 'auser','replicator', undef, undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'auser','repl%'", undef, undef );
+ok( defined $sth, "column_info(undef, 'auser','repl%', undef, undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'fred','repl%'", undef, undef );
+ok( defined $sth, "column_info(undef, 'fred','repl%', undef, undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'fred','jim'", undef, undef );
+ok( defined $sth, "column_info(undef, 'fred','jim', undef, undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'auser'", "'pga_schema'", undef );
+ok( defined $sth, "column_info(undef, 'auser', 'pga_schema', undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'auser'", "'pga_%'", undef );
+ok( defined $sth, "column_info(undef, 'auser', 'pga_%', undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'ause%'", "'pga_%'", undef );
+ok( defined $sth, "column_info(undef, 'ause%', 'pga_%', undef) tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'auser'", "'pga_schema'", "'schemaname'" );
+ok( defined $sth, "column_info(undef, 'auser', 'pga_schema', 'schemaname') tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'auser'", "'pga_schema'", "'schema%'" );
+ok( defined $sth, "column_info(undef, 'auser', 'pga_schema', 'schema%') tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'auser'", "'pga_%'", "'schema%'" );
+ok( defined $sth, "column_info(undef, 'auser', 'pga_%', 'schema%') tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+$sth = $dbh->column_info( undef, "'ause%'", "'pga_%'", "'schema%'" );
+ok( defined $sth, "column_info(undef, 'ause%', 'pga_%', 'schema%') tested" );
+DBI::dump_results($sth) if defined $sth;
+$sth = undef;
+
+# Test call to primary_key_info
+local ($dbh->{Warn}, $dbh->{PrintError});
+$dbh->{PrintError} = $dbh->{Warn} = 0;
+
+# Primary Key Info
+eval {
+ $sth = $dbh->primary_key_info();
+ die unless $sth;
+};
+ok ($@, "Call to primary_key_info with 0 arguements, error expected: $@" );
+$sth = undef;
+
+# Primary Key
+eval {
+ $sth = $dbh->primary_key();
+ die unless $sth;
+};
+ok ($@, "Call to primary_key with 0 arguements, error expected: $@" );
+$sth = undef;
+
+$sth = $dbh->primary_key_info(undef, undef, undef );
+
+ok( defined $sth, "Statement handle defined for primary_key_info()" );
+
+if ( defined $sth ) {
+ while( my $row = $sth->fetchrow_arrayref ) {
+ local $^W = 0;
+ # print join( ", ", @$row, "\n" );
+ }
+
+ undef $sth;
+
+}
+
+$sth = $dbh->primary_key_info(undef, undef, undef );
+ok( defined $sth, "Statement handle defined for primary_key_info()" );
+
+my ( %catalogs, %schemas, %tables);
+
+my $cnt = 0;
+while( my ($catalog, $schema, $table) = $sth->fetchrow_array ) {
+ local $^W = 0;
+ $catalogs{$catalog}++ if $catalog;
+ $schemas{$schema}++ if $schema;
+ $tables{$table}++ if $table;
+ $cnt++;
+}
+ok( $cnt > 0, "At least one table has a primary key." );
+
+$sth = $dbh->primary_key_info(undef, qq{'$ENV{DBI_USER}'}, undef );
+ok(
+ defined $sth
+ , "Getting primary keys for tables owned by $ENV{DBI_USER}");
+DBI::dump_results($sth) if defined $sth;
+
+undef $sth;
+
+SKIP: {
+ # foreign_key_info
+ local ($dbh->{Warn}, $dbh->{PrintError});
+ $dbh->{PrintError} = $dbh->{Warn} = 0;
+ eval {
+ $sth = $dbh->foreign_key_info();
+ die unless $sth;
+ };
+ skip "foreign_key_info not supported by driver", 1 if $@;
+ ok( defined $sth, "Statement handle defined for foreign_key_info()" );
+ DBI::dump_results($sth) if defined $sth;
+ $sth = undef;
+}
+
+ok( $dbh->disconnect, "Disconnect from database" );
+
+exit(0);
+
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/99cleanup.t b/install/5.005/DBD-Pg-1.22-fixvercmp/t/99cleanup.t
new file mode 100644
index 0000000..e7563ab
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/99cleanup.t
@@ -0,0 +1,24 @@
+use strict;
+use DBI;
+use Test::More;
+
+if (defined $ENV{DBI_DSN}) {
+ plan tests => 3;
+} else {
+ plan skip_all => 'cannot test without DB info';
+}
+
+my $dbh = DBI->connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS},
+ {RaiseError => 1, AutoCommit => 0}
+ );
+ok(defined $dbh,
+ 'connect with transaction'
+ );
+
+ok($dbh->do(q{DROP TABLE test}),
+ 'drop'
+ );
+
+ok($dbh->disconnect(),
+ 'disconnect'
+ );
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info.pm b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info.pm
new file mode 100644
index 0000000..417247f
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info.pm
@@ -0,0 +1,1167 @@
+package App::Info;
+
+# $Id: Info.pm,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+=head1 NAME
+
+App::Info - Information about software packages on a system
+
+=head1 SYNOPSIS
+
+ use App::Info::Category::FooApp;
+
+ my $app = App::Info::Category::FooApp->new;
+
+ if ($app->installed) {
+ print "App name: ", $app->name, "\n";
+ print "Version: ", $app->version, "\n";
+ print "Bin dir: ", $app->bin_dir, "\n";
+ } else {
+ print "App not installed on your system. :-(\n";
+ }
+
+=head1 DESCRIPTION
+
+App::Info is an abstract base class designed to provide a generalized
+interface for subclasses that provide metadata about software packages
+installed on a system. The idea is that these classes can be used in Perl
+application installers in order to determine whether software dependencies
+have been fulfilled, and to get necessary metadata about those software
+packages.
+
+App::Info provides an event model for handling events triggered by App::Info
+subclasses. The events are classified as "info", "error", "unknown", and
+"confirm" events, and multiple handlers may be specified to handle any or all
+of these event types. This allows App::Info clients to flexibly handle events
+in any way they deem necessary. Implementing new event handlers is
+straight-forward, and use the triggering of events by App::Info subclasses is
+likewise kept easy-to-use.
+
+A few L<sample subclasses|"SEE ALSO"> are provided with the distribution, but
+others are invited to write their own subclasses and contribute them to the
+CPAN. Contributors are welcome to extend their subclasses to provide more
+information relevant to the application for which data is to be provided (see
+L<App::Info::HTTPD::Apache|App::Info::HTTPD::Apache> for an example), but are
+encouraged to, at a minimum, implement the abstract methods defined here and
+in the category abstract base classes (e.g.,
+L<App::Info::HTTPD|App::Info::HTTPD> and L<App::Info::Lib|App::Info::Lib>).
+See L<Subclassing|"SUBCLASSING"> for more information on implementing new
+subclasses.
+
+=cut
+
+use strict;
+use Carp ();
+use App::Info::Handler;
+use App::Info::Request;
+use vars qw($VERSION);
+
+$VERSION = '0.23';
+
+##############################################################################
+##############################################################################
+# This code ref is used by the abstract methods to throw an exception when
+# they're called directly.
+my $croak = sub {
+ my ($caller, $meth) = @_;
+ $caller = ref $caller || $caller;
+ if ($caller eq __PACKAGE__) {
+ $meth = __PACKAGE__ . '::' . $meth;
+ Carp::croak(__PACKAGE__ . " is an abstract base class. Attempt to " .
+ " call non-existent method $meth");
+ } else {
+ Carp::croak("Class $caller inherited from the abstract base class " .
+ __PACKAGE__ . ", but failed to redefine the $meth() " .
+ "method. Attempt to call non-existent method " .
+ "${caller}::$meth");
+ }
+};
+
+##############################################################################
+# This code reference is used by new() and the on_* error handler methods to
+# set the error handlers.
+my $set_handlers = sub {
+ my $on_key = shift;
+ # Default is to do nothing.
+ return [] unless $on_key;
+ my $ref = ref $on_key;
+ if ($ref) {
+ $on_key = [$on_key] unless $ref eq 'ARRAY';
+ # Make sure they're all handlers.
+ foreach my $h (@$on_key) {
+ if (my $r = ref $h) {
+ Carp::croak("$r object is not an App::Info::Handler")
+ unless UNIVERSAL::isa($h, 'App::Info::Handler');
+ } else {
+ # Look up the handler.
+ $h = App::Info::Handler->new( key => $h);
+ }
+ }
+ # Return 'em!
+ return $on_key;
+ } else {
+ # Look up the handler.
+ return [ App::Info::Handler->new( key => $on_key) ];
+ }
+};
+
+##############################################################################
+##############################################################################
+
+=head1 INTERFACE
+
+This section documents the public interface of App::Info.
+
+=head2 Constructor
+
+=head3 new
+
+ my $app = App::Info::Category::FooApp->new(@params);
+
+Constructs an App::Info object and returns it. The @params arguments define
+how the App::Info object will respond to certain events, and correspond to
+their like-named methods. See the L<"Event Handler Object Methods"> section
+for more information on App::Info events and how to handle them. The
+parameters to C<new()> for the different types of App::Info events are:
+
+=over 4
+
+=item on_info
+
+=item on_error
+
+=item on_unknown
+
+=item on_confirm
+
+=back
+
+When passing event handlers to C<new()>, the list of handlers for each type
+should be an anonymous array, for example:
+
+ my $app = App::Info::Category::FooApp->new( on_info => \@handlers );
+
+=cut
+
+sub new {
+ my ($pkg, %p) = @_;
+ my $class = ref $pkg || $pkg;
+ # Fail if the method isn't overridden.
+ $croak->($pkg, 'new') if $class eq __PACKAGE__;
+
+ # Set up handlers.
+ for (qw(on_error on_unknown on_info on_confirm)) {
+ $p{$_} = $set_handlers->($p{$_});
+ }
+
+ # Do it!
+ return bless \%p, $class;
+}
+
+##############################################################################
+##############################################################################
+
+=head2 Metadata Object Methods
+
+These are abstract methods in App::Info and must be provided by its
+subclasses. They provide the essential metadata of the software package
+supported by the App::Info subclass.
+
+=head3 key_name
+
+ my $key_name = $app->key_name;
+
+Returns a string that uniquely identifies the software for which the App::Info
+subclass provides data. This value should be unique across all App::Info
+classes. Typically, it's simply the name of the software.
+
+=cut
+
+sub key_name { $croak->(shift, 'key_name') }
+
+=head3 installed
+
+ if ($app->installed) {
+ print "App is installed.\n"
+ } else {
+ print "App is not installed.\n"
+ }
+
+Returns a true value if the application is installed, and a false value if it
+is not.
+
+=cut
+
+sub installed { $croak->(shift, 'installed') }
+
+##############################################################################
+
+=head3 name
+
+ my $name = $app->name;
+
+Returns the name of the application.
+
+=cut
+
+sub name { $croak->(shift, 'name') }
+
+##############################################################################
+
+=head3 version
+
+ my $version = $app->version;
+
+Returns the full version number of the application.
+
+=cut
+
+##############################################################################
+
+sub version { $croak->(shift, 'version') }
+
+=head3 major_version
+
+ my $major_version = $app->major_version;
+
+Returns the major version number of the application. For example, if
+C<version()> returns "7.1.2", then this method returns "7".
+
+=cut
+
+sub major_version { $croak->(shift, 'major_version') }
+
+##############################################################################
+
+=head3 minor_version
+
+ my $minor_version = $app->minor_version;
+
+Returns the minor version number of the application. For example, if
+C<version()> returns "7.1.2", then this method returns "1".
+
+=cut
+
+sub minor_version { $croak->(shift, 'minor_version') }
+
+##############################################################################
+
+=head3 patch_version
+
+ my $patch_version = $app->patch_version;
+
+Returns the patch version number of the application. For example, if
+C<version()> returns "7.1.2", then this method returns "2".
+
+=cut
+
+sub patch_version { $croak->(shift, 'patch_version') }
+
+##############################################################################
+
+=head3 bin_dir
+
+ my $bin_dir = $app->bin_dir;
+
+Returns the full path the application's bin directory, if it exists.
+
+=cut
+
+sub bin_dir { $croak->(shift, 'bin_dir') }
+
+##############################################################################
+
+=head3 inc_dir
+
+ my $inc_dir = $app->inc_dir;
+
+Returns the full path the application's include directory, if it exists.
+
+=cut
+
+sub inc_dir { $croak->(shift, 'inc_dir') }
+
+##############################################################################
+
+=head3 lib_dir
+
+ my $lib_dir = $app->lib_dir;
+
+Returns the full path the application's lib directory, if it exists.
+
+=cut
+
+sub lib_dir { $croak->(shift, 'lib_dir') }
+
+##############################################################################
+
+=head3 so_lib_dir
+
+ my $so_lib_dir = $app->so_lib_dir;
+
+Returns the full path the application's shared library directory, if it
+exists.
+
+=cut
+
+sub so_lib_dir { $croak->(shift, 'so_lib_dir') }
+
+##############################################################################
+
+=head3 home_url
+
+ my $home_url = $app->home_url;
+
+The URL for the software's home page.
+
+=cut
+
+sub home_url { $croak->(shift, 'home_url') }
+
+##############################################################################
+
+=head3 download_url
+
+ my $download_url = $app->download_url;
+
+The URL for the software's download page.
+
+=cut
+
+sub download_url { $croak->(shift, 'download_url') }
+
+##############################################################################
+##############################################################################
+
+=head2 Event Handler Object Methods
+
+These methods provide control over App::Info event handling. Events can be
+handled by one or more objects of subclasses of App::Info::Handler. The first
+to return a true value will be the last to execute. This approach allows
+handlers to be stacked, and makes it relatively easy to create new handlers.
+L<App::Info::Handler|App::Info::Handler> for information on writing event
+handlers.
+
+Each of the event handler methods takes a list of event handlers as its
+arguments. If none are passed, the existing list of handlers for the relevant
+event type will be returned. If new handlers are passed in, they will be
+returned.
+
+The event handlers may be specified as one or more objects of the
+App::Info::Handler class or subclasses, as one or more strings that tell
+App::Info construct such handlers itself, or a combination of the two. The
+strings can only be used if the relevant App::Info::Handler subclasses have
+registered strings with App::Info. For example, the App::Info::Handler::Print
+class included in the App::Info distribution registers the strings "stderr"
+and "stdout" when it starts up. These strings may then be used to tell
+App::Info to construct App::Info::Handler::Print objects that print to STDERR
+or to STDOUT, respectively. See the App::Info::Handler subclasses for what
+strings they register with App::Info.
+
+=head3 on_info
+
+ my @handlers = $app->on_info;
+ $app->on_info(@handlers);
+
+Info events are triggered when the App::Info subclass wants to send an
+informational status message. By default, these events are ignored, but a
+common need is for such messages to simply print to STDOUT. Use the
+L<App::Info::Handler::Print|App::Info::Handler::Print> class included with the
+App::Info distribution to have info messages print to STDOUT:
+
+ use App::Info::Handler::Print;
+ $app->on_info('stdout');
+ # Or:
+ my $stdout_handler = App::Info::Handler::Print->new('stdout');
+ $app->on_info($stdout_handler);
+
+=cut
+
+sub on_info {
+ my $self = shift;
+ $self->{on_info} = $set_handlers->(\@_) if @_;
+ return @{ $self->{on_info} };
+}
+
+=head3 on_error
+
+ my @handlers = $app->on_error;
+ $app->on_error(@handlers);
+
+Error events are triggered when the App::Info subclass runs into an unexpected
+but not fatal problem. (Note that fatal problems will likely throw an
+exception.) By default, these events are ignored. A common way of handling
+these events is to print them to STDERR, once again using the
+L<App::Info::Handler::Print|App::Info::Handler::Print> class included with the
+App::Info distribution:
+
+ use App::Info::Handler::Print;
+ my $app->on_error('stderr');
+ # Or:
+ my $stderr_handler = App::Info::Handler::Print->new('stderr');
+ $app->on_error($stderr_handler);
+
+Another approach might be to turn such events into fatal exceptions. Use the
+included L<App::Info::Handler::Carp|App::Info::Handler::Carp> class for this
+purpose:
+
+ use App::Info::Handler::Carp;
+ my $app->on_error('croak');
+ # Or:
+ my $croaker = App::Info::Handler::Carp->new('croak');
+ $app->on_error($croaker);
+
+=cut
+
+sub on_error {
+ my $self = shift;
+ $self->{on_error} = $set_handlers->(\@_) if @_;
+ return @{ $self->{on_error} };
+}
+
+=head3 on_unknown
+
+ my @handlers = $app->on_unknown;
+ $app->on_uknown(@handlers);
+
+Unknown events are trigged when the App::Info subclass cannot find the value
+to be returned by a method call. By default, these events are ignored. A
+common way of handling them is to have the application prompt the user for the
+relevant data. The App::Info::Handler::Prompt class included with the
+App::Info distribution can do just that:
+
+ use App::Info::Handler::Prompt;
+ my $app->on_unknown('prompt');
+ # Or:
+ my $prompter = App::Info::Handler::Prompt;
+ $app->on_unknown($prompter);
+
+See L<App::Info::Handler::Prompt|App::Info::Handler::Prompt> for information
+on how it works.
+
+=cut
+
+sub on_unknown {
+ my $self = shift;
+ $self->{on_unknown} = $set_handlers->(\@_) if @_;
+ return @{ $self->{on_unknown} };
+}
+
+=head3 on_confirm
+
+ my @handlers = $app->on_confirm;
+ $app->on_confirm(@handlers);
+
+Confirm events are triggered when the App::Info subclass has found an
+important piece of information (such as the location of the executable it'll
+use to collect information for the rest of its methods) and wants to confirm
+that the information is correct. These events will most often be triggered
+during the App::Info subclass object construction. Here, too, the
+App::Info::Handler::Prompt class included with the App::Info distribution can
+help out:
+
+ use App::Info::Handler::Prompt;
+ my $app->on_confirm('prompt');
+ # Or:
+ my $prompter = App::Info::Handler::Prompt;
+ $app->on_confirm($prompter);
+
+=cut
+
+sub on_confirm {
+ my $self = shift;
+ $self->{on_confirm} = $set_handlers->(\@_) if @_;
+ return @{ $self->{on_confirm} };
+}
+
+##############################################################################
+##############################################################################
+
+=head1 SUBCLASSING
+
+As an abstract base class, App::Info is not intended to be used directly.
+Instead, you'll use concrete subclasses that implement the interface it
+defines. These subclasses each provide the metadata necessary for a given
+software package, via the interface outlined above (plus any additional
+methods the class author deems sensible for a given application).
+
+This section describes the facilities App::Info provides for subclassing. The
+goal of the App::Info design has been to make subclassing straight-forward, so
+that developers can focus on gathering the data they need for their
+application and minimize the work necessary to handle unknown values or to
+confirm values. As a result, there are essentially three concepts that
+developers need to understand when subclassing App::Info: organization,
+utility methods, and events.
+
+=head2 Organization
+
+The organizational idea behind App::Info is to name subclasses by broad
+software categories. This approach allows the categories themselves to
+function as abstract base classes that extend App::Info, so that they can
+specify more methods for all of their base classes to implement. For example,
+App::Info::HTTPD has specified the C<httpd_root()> abstract method that its
+subclasses must implement. So as you get ready to implement your own subclass,
+think about what category of software you're gathering information about.
+New categories can be added as necessary.
+
+=head2 Utility Methods
+
+Once you've decided on the proper category, you can start implementing your
+App::Info concrete subclass. As you do so, take advantage of App::Info::Util,
+wherein I've tried to encapsulate common functionality to make subclassing
+easier. I found that most of what I was doing repetitively was looking for
+files and directories, and searching through files. Thus, App::Info::Util
+subclasses L<File::Spec|File::Spec> in order to offer easy access to
+commonly-used methods from that class, e.g., C<path()>. Plus, it has several
+of its own methods to assist you in finding files and directories in lists of
+files and directories, as well as methods for searching through files and
+returning the values found in those files. See
+L<App::Info::Util|App::Info::Util> for more information, and the App::Info
+subclasses in this distribution for usage examples.
+
+I recommend the use of a package-scoped lexical App::Info::Util object. That
+way it's nice and handy when you need to carry out common tasks. If you find
+you're doing something over and over that's not already addressed by an
+App::Info::Util method, consider submitting a patch to App::Info::Util to add
+the functionality you need.
+
+=head2 Events
+
+Use the methods described below to trigger events. Events are designed to
+provide a simple way for App::Info subclass developers to send status messages
+and errors, to confirm data values, and to request a value when the class
+caonnot determine a value itself. Events may optionally be handled by module
+users who assign App::Info::Handler subclass objects to your App::Info
+subclass object using the event handling methods described in the L<"Event
+Handler Object Methods"> section.
+
+=cut
+
+##############################################################################
+# This code reference is used by the event methods to manage the stack of
+# event handlers that may be available to handle each of the events.
+my $handler = sub {
+ my ($self, $meth, $params) = @_;
+
+ # Sanity check. We really want to keep control over this.
+ Carp::croak("Cannot call protected method $meth()")
+ unless UNIVERSAL::isa($self, scalar caller(1));
+
+ # Create the request object.
+ $params->{type} ||= $meth;
+ my $req = App::Info::Request->new(%$params);
+
+ # Do the deed. The ultimate handling handler may die.
+ foreach my $eh (@{$self->{"on_$meth"}}) {
+ last if $eh->handler($req);
+ }
+
+ # Return the requst.
+ return $req;
+};
+
+##############################################################################
+
+=head3 info
+
+ $self->info(@message);
+
+Use this method to display status messages for the user. You may wish to use
+it to inform users that you're searching for a particular file, or attempting
+to parse a file or some other resource for the data you need. For example, a
+common use might be in the object constructor: generally, when an App::Info
+object is created, some important initial piece of information is being
+sought, such as an executable file. That file may be in one of many locations,
+so it makes sense to let the user know that you're looking for it:
+
+ $self->info("Searching for executable");
+
+Note that, due to the nature of App::Info event handlers, your informational
+message may be used or displayed any number of ways, or indeed not at all (as
+is the default behavior).
+
+The C<@message> will be joined into a single string and stored in the
+C<message> attribute of the App::Info::Request object passed to info event
+handlers.
+
+=cut
+
+sub info {
+ my $self = shift;
+ # Execute the handler sequence.
+ my $req = $handler->($self, 'info', { message => join '', @_ });
+}
+
+##############################################################################
+
+=head3 error
+
+ $self->error(@error);
+
+Use this method to inform the user that something unexpected has happened. An
+example might be when you invoke another program to parse its output, but it's
+output isn't what you expected:
+
+ $self->error("Unable to parse version from `/bin/myapp -c`");
+
+As with all events, keep in mind that error events may be handled in any
+number of ways, or not at all.
+
+The C<@erorr> will be joined into a single string and stored in the C<message>
+attribute of the App::Info::Request object passed to error event handlers. If
+that seems confusing, think of it as an "error message" rather than an "error
+error." :-)
+
+=cut
+
+sub error {
+ my $self = shift;
+ # Execute the handler sequence.
+ my $req = $handler->($self, 'error', { message => join '', @_ });
+}
+
+##############################################################################
+
+=head3 unknown
+
+ my $val = $self->unknown(@params);
+
+Use this method when a value is unknown. This will give the user the option --
+assuming the appropriate handler handles the event -- to provide the needed
+data. The value entered will be returned by C<unknown()>. The parameters are
+as follows:
+
+=over 4
+
+=item key
+
+The C<key> parameter uniquely identifies the data point in your class, and is
+used by App::Info to ensure that an unknown event is handled only once, no
+matter how many times the method is called. The same value will be returned by
+subsequent calls to C<unknown()> as was returned by the first call, and no
+handlers will be activated. Typical values are "version" and "lib_dir".
+
+=item prompt
+
+The C<prompt> parameter is the prompt to be displayed should an event handler
+decide to prompt for the appropriate value. Such a prompt might be something
+like "Path to your httpd executable?". If this parameter is not provided,
+App::Info will construct one for you using your class' C<key_name()> method
+and the C<key> parameter. The result would be something like "Enter a valid
+FooApp version". The C<prompt> parameter value will be stored in the
+C<message> attribute of the App::Info::Request object passed to event
+handlers.
+
+=item callback
+
+Assuming a handler has collected a value for your unknown data point, it might
+make sense to validate the value. For example, if you prompt the user for a
+directory location, and the user enters one, it makes sense to ensure that the
+directory actually exists. The C<callback> parameter allows you to do this. It
+is a code reference that takes the new value or values as its arguments, and
+returns true if the value is valid, and false if it is not. For the sake of
+convenience, the first argument to the callback code reference is also stored
+in C<$_> .This makes it easy to validate using functions or operators that,
+er, operate on C<$_> by default, but still allows you to get more information
+from C<@_> if necessary. For the directory example, a good callback might be
+C<sub { -d }>. The C<callback> parameter code reference will be stored in the
+C<callback> attribute of the App::Info::Request object passed to event
+handlers.
+
+=item error
+
+The error parameter is the error message to display in the event that the
+C<callback> code reference returns false. This message may then be used by the
+event handler to let the user know what went wrong with the data she entered.
+For example, if the unknown value was a directory, and the user entered a
+value that the C<callback> identified as invalid, a message to display might
+be something like "Invalid directory path". Note that if the C<error>
+parameter is not provided, App::Info will supply the generic error message
+"Invalid value". This value will be stored in the C<error> attribute of the
+App::Info::Request object passed to event handlers.
+
+=back
+
+This may be the event method you use most, as it should be called in every
+metadata method if you cannot provide the data needed by that method. It will
+typically be the last part of the method. Here's an example demonstrating each
+of the above arguments:
+
+ my $dir = $self->unknown( key => 'lib_dir',
+ prompt => "Enter lib directory path",
+ callback => sub { -d },
+ error => "Not a directory");
+
+=cut
+
+sub unknown {
+ my ($self, %params) = @_;
+ my $key = delete $params{key}
+ or Carp::croak("No key parameter passed to unknown()");
+ # Just return the value if we've already handled this value. Ideally this
+ # shouldn't happen.
+ return $self->{__unknown__}{$key} if exists $self->{__unknown__}{$key};
+
+ # Create a prompt and error message, if necessary.
+ $params{message} = delete $params{prompt} ||
+ "Enter a valid " . $self->key_name . " $key";
+ $params{error} ||= 'Invalid value';
+
+ # Execute the handler sequence.
+ my $req = $handler->($self, "unknown", \%params);
+
+ # Mark that we've provided this value and then return it.
+ $self->{__unknown__}{$key} = $req->value;
+ return $self->{__unknown__}{$key};
+}
+
+##############################################################################
+
+=head3 confirm
+
+ my $val = $self->confirm(@params);
+
+This method is very similar to C<unknown()>, but serves a different purpose.
+Use this method for significant data points where you've found an appropriate
+value, but want to ensure it's really the correct value. A "significant data
+point" is usually a value essential for your class to collect metadata values.
+For example, you might need to locate an executable that you can then call to
+collect other data. In general, this will only happen once for an object --
+during object construction -- but there may be cases in which it is needed
+more than that. But hopefully, once you've confirmed in the constructor that
+you've found what you need, you can use that information to collect the data
+needed by all of the metadata methods and can assume that they'll be right
+because that first, significant data point has been confirmed.
+
+Other than where and how often to call C<confirm()>, its use is quite similar
+to that of C<unknown()>. Its parameters are as follows:
+
+=over
+
+=item key
+
+Same as for C<unknown()>, a string that uniquely identifies the data point in
+your class, and ensures that the event is handled only once for a given key.
+The same value will be returned by subsequent calls to C<confirm()> as was
+returned by the first call for a given key.
+
+=item prompt
+
+Same as for C<unknown()>. Although C<confirm()> is called to confirm a value,
+typically the prompt should request the relevant value, just as for
+C<unknown()>. The difference is that the handler I<should> use the C<value>
+parameter as the default should the user not provide a value. The C<prompt>
+parameter will be stored in the C<message> attribute of the App::Info::Request
+object passed to event handlers.
+
+=item value
+
+The value to be confirmed. This is the value you've found, and it will be
+provided to the user as the default option when they're prompted for a new
+value. This value will be stored in the C<value> attribute of the
+App::Info::Request object passed to event handlers.
+
+=item callback
+
+Same as for C<unknown()>. Because the user can enter data to replace the
+default value provided via the C<value> parameter, you might want to validate
+it. Use this code reference to do so. The callback will be stored in the
+C<callback> attribute of the App::Info::Request object passed to event
+handlers.
+
+=item error
+
+Same as for C<unknown()>: an error message to display in the event that a
+value entered by the user isn't validated by the C<callback> code reference.
+This value will be stored in the C<error> attribute of the App::Info::Request
+object passed to event handlers.
+
+=back
+
+Here's an example usage demonstrating all of the above arguments:
+
+ my $exe = $self->confirm( key => 'shell',
+ prompt => 'Path to your shell?',
+ value => '/bin/sh',
+ callback => sub { -x },
+ error => 'Not an executable');
+
+
+=cut
+
+sub confirm {
+ my ($self, %params) = @_;
+ my $key = delete $params{key}
+ or Carp::croak("No key parameter passed to confirm()");
+ return $self->{__confirm__}{$key} if exists $self->{__confirm__}{$key};
+
+ # Create a prompt and error message, if necessary.
+ $params{message} = delete $params{prompt} ||
+ "Enter a valid " . $self->key_name . " $key";
+ $params{error} ||= 'Invalid value';
+
+ # Execute the handler sequence.
+ my $req = $handler->($self, "confirm", \%params);
+
+ # Mark that we've confirmed this value.
+ $self->{__confirm__}{$key} = $req->value;
+
+ return $self->{__confirm__}{$key}
+}
+
+1;
+__END__
+
+=head2 Event Examples
+
+Below I provide some examples demonstrating the use of the event methods.
+These are meant to emphasize the contexts in which it's appropriate to use
+them.
+
+Let's start with the simplest, first. Let's say that to find the version
+number for an application, you need to search a file for the relevant data.
+Your App::Info concrete subclass might have a private method that handles this
+work, and this method is the appropriate place to use the C<info()> and, if
+necessary, C<error()> methods.
+
+ sub _find_version {
+ my $self = shift;
+
+ # Try to find the revelant file. We cover this method below.
+ # Just return if we cant' find it.
+ my $file = $self->_find_file('version.conf') or return;
+
+ # Send a status message.
+ $self->info("Searching '$file' file for version");
+
+ # Search the file. $util is an App::Info::Util object.
+ my $ver = $util->search_file($file, qr/^Version\s+(.*)$/);
+
+ # Trigger an error message, if necessary. We really think we'll have the
+ # value, but we have to cover our butts in the unlikely event that we're
+ # wrong.
+ $self->error("Unable to find version in file '$file'") unless $ver;
+
+ # Return the version number.
+ return $ver;
+ }
+
+Here we've used the C<info()> method to display a status message to let the
+user know what we're doing. Then we used the C<error()> method when something
+unexpected happened, which in this case was that we weren't able to find the
+version number in the file.
+
+Note the C<_find_file()> method we've thrown in. This might be a method that
+we call whenever we need to find a file that might be in one of a list of
+directories. This method, too, will be an appropriate place for an C<info()>
+method call. But rather than call the C<error()> method when the file can't be
+found, you might want to give an event handler a chance to supply that value
+for you. Use the C<unknown()> method for a case such as this:
+
+ sub _find_file {
+ my ($self, $file) = @_;
+
+ # Send a status message.
+ $self->info("Searching for '$file' file");
+
+ # Look for the file. See App::Info:Utility for its interface.
+ my @paths = qw(/usr/conf /etc/conf /foo/conf);
+ my $found = $util->first_cat_path($file, @paths);
+
+ # If we didn't find it, trigger an unknown event to
+ # give a handler a chance to get the value.
+ $found ||= $self->unknown( key => "file_$file",
+ prompt => "Location of '$file' file?",
+ callback => sub { -f },
+ error => "Not a file");
+
+ # Now return the file name, regardless of whether we found it or not.
+ return $found;
+ }
+
+Note how in this method, we've tried to locate the file ourselves, but if we
+can't find it, we trigger an unknown event. This allows clients of our
+App::Info subclass to try to establish the value themselves by having an
+App::Info::Handler subclass handle the event. If a value is found by an
+App::Info::Handler subclass, it will be returned by C<unknown()> and we can
+continue. But we can't assume that the unknown event will even be handled, and
+thus must expect that an unknown value may remain unknown. This is why the
+C<_find_version()> method above simply returns if C<_find_file()> doesn't
+return a file name; there's no point in searching through a file that doesn't
+exist.
+
+Attentive readers may be left to wonder how to decide when to use C<error()>
+and when to use C<unknown()>. To a large extent, this decision must be based
+on one's own understanding of what's most appropriate. Nevertheless, I offer
+the following simple guidelines: Use C<error()> when you expect something to
+work and then it just doesn't (as when a file exists and should contain the
+information you seek, but then doesn't). Use C<unknown()> when you're less
+sure of your processes for finding the value, and also for any of the values
+that should be returned by any of the L<metadata object methods|"Metadata
+Object Methods">. And of course, C<error()> would be more appropriate when you
+encounter an unexpected condition and don't think that it could be handled in
+any other way.
+
+Now, more than likely, a method such C<_find_version()> would be called by the
+C<version()> method, which is a metadata method mandated by the App::Info
+abstract base class. This is an appropriate place to handle an unknown version
+value. Indeed, every one of your metadata methods should make use of the
+C<unknown()> method. The C<version()> method then should look something like
+this:
+
+ sub version {
+ my $self = shift;
+
+ unless (exists $self->{version}) {
+ # Try to find the version number.
+ $self->{version} = $self->_find_version ||
+ $self->unknown( key => 'version',
+ prompt => "Enter the version number");
+ }
+
+ # Now return the version number.
+ return $self->{version};
+ }
+
+Note how this method only tries to find the version number once. Any
+subsequent calls to C<version()> will return the same value that was returned
+the first time it was called. Of course, thanks to the C<key> parameter in the
+call to C<unknown()>, we could have have tried to enumerate the version number
+every time, as C<unknown()> will return the same value every time it is called
+(as, indeed, should C<_find_version()>. But by checking for the C<version> key
+in C<$self> ourselves, we save some of the overhead.
+
+But as I said before, every metadata method should make use of the
+C<unknown()> method. Thus, the C<major()> method might looks something like
+this:
+
+ sub major {
+ my $self = shift;
+
+ unless (exists $self->{major}) {
+ # Try to get the major version from the full version number.
+ ($self->{major}) = $self->version =~ /^(\d+)\./;
+ # Handle an unknown value.
+ $self->{major} = $self->unknown( key => 'major',
+ prompt => "Enter major version",
+ callback => sub { /^\d+$/ },
+ error => "Not a number")
+ unless defined $self->{major};
+ }
+
+ return $self->{version};
+ }
+
+Finally, the C<confirm()> method should be used to verify core pieces of data
+that significant numbers of other methods rely on. Typically such data are
+executables or configuration files from which will be drawn other metadata.
+Most often, such major data points will be sought in the object constructor.
+Here's an example:
+
+ sub new {
+ # Construct the object so that handlers will work properly.
+ my $self = shift->SUPER::new(@_);
+
+ # Try to find the executable.
+ $self->info("Searching for executable");
+ if (my $exe = $util->first_exe('/bin/myapp', '/usr/bin/myapp')) {
+ # Confirm it.
+ $self->{exe} =
+ $self->confirm( key => 'binary',
+ prompt => 'Path to your executable?',
+ value => $exe,
+ callback => sub { -x },
+ error => 'Not an executable');
+ } else {
+ # Handle an unknown value.
+ $self->{exe} =
+ $self->unknown( key => 'binary',
+ prompt => 'Path to your executable?',
+ callback => sub { -x },
+ error => 'Not an executable');
+ }
+
+ # We're done.
+ return $self;
+ }
+
+By now, most of what's going on here should be quite familiar. The use of the
+C<confirm()> method is quite similar to that of C<unknown()>. Really the only
+difference is that the value is known, but we need verification or a new value
+supplied if the value we found isn't correct. Such may be the case when
+multiple copies of the executable have been installed on the system, we found
+F</bin/myapp>, but the user may really be interested in F</usr/bin/myapp>.
+Thus the C<confirm()> event gives the user the chance to change the value if
+the confirm event is handled.
+
+The final thing to note about this constructor is the first line:
+
+ my $self = shift->SUPER::new(@_);
+
+The first thing an App::Info subclass should do is execute this line to allow
+the super class to construct the object first. Doing so allows any event
+handling arguments to set up the event handlers, so that when we call
+C<confirm()> or C<unknown()> the event will be handled as the client expects.
+
+If we needed our subclass constructor to take its own parameter argumente, the
+approach is to specify the same C<key => $arg> syntax as is used by
+App::Info's C<new()> method. Say we wanted to allow clients of our App::Info
+subclass to pass in a list of alternate executable locations for us to search.
+Such an argument would most make sense as an array reference. So we specify
+that the key be C<alt_paths> and allow the user to construct an object like
+this:
+
+ my $app = App::Info::Category::FooApp->new( alt_paths => \@paths );
+
+This approach allows the super class constructor arguments to pass unmolested
+(as long as we use unique keys!):
+
+ my $app = App::Info::Category::FooApp->new( on_error => \@handlers,
+ alt_paths => \@paths );
+
+Then, to retrieve these paths inside our C<new()> constructor, all we need do
+is access them directly from the object:
+
+ my $self = shift->SUPER::new(@_);
+ my $alt_paths = $self->{alt_paths};
+
+=head2 Subclassing Guidelines
+
+To summarize, here are some guidelines for subclassing App::Info.
+
+=over 4
+
+=item *
+
+Always subclass an App::Info category subclass. This will help to keep the
+App::Info namespace well-organized. New categories can be added as needed.
+
+=item *
+
+When you create the C<new()> constructor, always call C<SUPER::new(@_)>. This
+ensures that the event handling methods methods defined by the App::Info base
+classes (e.g., C<error()>) will work properly.
+
+=item *
+
+Use a package-scoped lexical App::Info::Util object to carry out common tasks.
+If you find you're doing something over and over that's not already addressed
+by an App::Info::Util method, and you think that others might find your
+solution useful, consider submitting a patch to App::Info::Util to add the
+functionality you need. See L<App::Info::Util|App::Info::Util> for complete
+documentation of its interface.
+
+=item *
+
+Use the C<info()> event triggering method to send messages to users of your
+subclass.
+
+=item *
+
+Use the C<error()> event triggering method to alert users of unexpected
+conditions. Fatal errors should still be fatal; use C<Carp::croak()> to throw
+exceptions for fatal errors.
+
+=item *
+
+Use the C<unknown()> event triggering method when a metadata or other
+important value is unknown and you want to give any event handlers the chance
+to provide the data.
+
+=item *
+
+Use the C<confirm()> event triggering method when a core piece of data is
+known (such as the location of an executable in the C<new()> constructor) and
+you need to make sure that you have the I<correct> information.
+
+=item *
+
+Be sure to implement B<all> of the abstract methods defined by App::Info and
+by your category abstract base class -- even if they don't do anything. Doing
+so ensures that all App::Info subclasses share a common interface, and can, if
+necessary, be used without regard to subclass. Any method not implemented but
+called on an object will generate a fatal exception.
+
+=back
+
+Otherwise, have fun! There are a lot of software packages for which relevant
+information might be collected and aggregated into an App::Info concrete
+subclass (witness all of the Automake macros in the world!), and folks who are
+knowledgeable about particular software packages or categories of software are
+warmly invited to contribute. As more subclasses are implemented, it will make
+sense, I think, to create separate distributions based on category -- or even,
+when necessary, on a single software package. Broader categories can then be
+aggregated in Bundle distributions.
+
+But I get ahead of myself...
+
+=head1 BUGS
+
+Report all bugs via the CPAN Request Tracker at
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Info>.
+
+=head1 AUTHOR
+
+David Wheeler <L<david@wheeler.net|"david@wheeler.net">>
+
+=head1 SEE ALSO
+
+The following classes define a few software package categories in which
+App::Info subclasses can be placed. Check them out for ideas on how to
+create new category subclasses.
+
+=over 4
+
+=item L<App::Info::HTTP|App::Info::HTTPD>
+
+=item L<App::Info::RDBMS|App::Info::RDBMS>
+
+=item L<App::Info::Lib|App::Info::Lib>
+
+=back
+
+The following classes implement the App::Info interface for various software
+packages. Check them out for examples of how to implement new App::Info
+concrete subclasses.
+
+=over
+
+=item L<App::Info::HTTPD::Apache|App::Info::HTTPD::Apache>
+
+=item L<App::Info::RDBMS::PostgreSQL|App::Info::RDBMS::PostgreSQL>
+
+=item L<App::Info::Lib::Expat|App::Info::Lib::Expat>
+
+=item L<App::Info::Lib::Iconv|App::Info::Lib::Iconv>
+
+=back
+
+L<App::Info::Util|App::Info::Util> provides utility methods for App::Info
+subclasses.
+
+L<App::Info::Handler|App::Info::Handler> defines an interface for event
+handlers to subclass. Consult its documentation for information on creating
+custom event handlers.
+
+The following classes implement the App::Info::Handler interface to offer some
+simple event handling. Check them out for examples of how to implement new
+App::Info::Handler subclasses.
+
+=over 4
+
+=item L<App::Info::Handler::Print|App::Info::Handler::Print>
+
+=item L<App::Info::Handler::Carp|App::Info::Handler::Carp>
+
+=item L<App::Info::Handler::Prompt|App::Info::Handler::Prompt>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2002, David Wheeler. All Rights Reserved.
+
+This module is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler.pm b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler.pm
new file mode 100644
index 0000000..65416a8
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler.pm
@@ -0,0 +1,305 @@
+package App::Info::Handler;
+
+# $Id: Handler.pm,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+=head1 NAME
+
+App::Info::Handler - App::Info event handler base class
+
+=head1 SYNOPSIS
+
+ use App::Info::Category::FooApp;
+ use App::Info::Handler;
+
+ my $app = App::Info::Category::FooApp->new( on_info => ['default'] );
+
+=head1 DESCRIPTION
+
+This class defines the interface for subclasses that wish to handle events
+triggered by App::Info concrete subclasses. The different types of events
+triggered by App::Info can all be handled by App::Info::Handler (indeed, by
+default they're all handled by a single App::Info::Handler object), and
+App::Info::Handler subclasses may be designed to handle whatever events they
+wish.
+
+If you're interested in I<using> an App::Info event handler, this is probably
+not the class you should look at, since all it does is define a simple handler
+that does nothing with an event. Look to the L<App::Info::Handler
+subclasses|"SEE ALSO"> included in this distribution to do more interesting
+things with App::Info events.
+
+If, on the other hand, you're interested in implementing your own event
+handlers, read on!
+
+=cut
+
+use strict;
+use vars qw($VERSION);
+$VERSION = '0.22';
+
+my %handlers;
+
+=head1 INTERFACE
+
+This section documents the public interface of App::Info::Handler.
+
+=head2 Class Method
+
+=head3 register_handler
+
+ App::Info::Handler->register_handler( $key => $code_ref );
+
+This class method may be used by App::Info::Handler subclasses to register
+themselves with App::Info::Handler. Multiple registrations are supported. The
+idea is that a subclass can define different functionality by specifying
+different strings that represent different modes of constructing an
+App::Info::Handler subclass object. The keys are case-sensitve, and should be
+unique across App::Info::Handler subclasses so that many subclasses can be
+loaded and used separately. If the C<$key> is already registered,
+C<register_handler()> will throw an exception. The values are code references
+that, when executed, return the appropriate App::Info::Handler subclass
+object.
+
+=cut
+
+sub register_handler {
+ my ($pkg, $key, $code) = @_;
+ Carp::croak("Handler '$key' already exists")
+ if $handlers{$key};
+ $handlers{$key} = $code;
+}
+
+# Register ourself.
+__PACKAGE__->register_handler('default', sub { __PACKAGE__->new } );
+
+##############################################################################
+
+=head2 Constructor
+
+=head3 new
+
+ my $handler = App::Info::Handler->new;
+ $handler = App::Info::Handler->new( key => $key);
+
+Constructs an App::Info::Handler object and returns it. If the key parameter
+is provided and has been registered by an App::Info::Handler subclass via the
+C<register_handler()> class method, then the relevant code reference will be
+executed and the resulting App::Info::Handler subclass object returned. This
+approach provides a handy shortcut for having C<new()> behave as an abstract
+factory method, returning an object of the subclass appropriate to the key
+parameter.
+
+=cut
+
+sub new {
+ my ($pkg, %p) = @_;
+ my $class = ref $pkg || $pkg;
+ $p{key} ||= 'default';
+ if ($class eq __PACKAGE__ && $p{key} ne 'default') {
+ # We were called directly! Handle it.
+ Carp::croak("No such handler '$p{key}'") unless $handlers{$p{key}};
+ return $handlers{$p{key}}->();
+ } else {
+ # A subclass called us -- just instantiate and return.
+ return bless \%p, $class;
+ }
+}
+
+=head2 Instance Method
+
+=head3 handler
+
+ $handler->handler($req);
+
+App::Info::Handler defines a single instance method that must be defined by
+its subclasses, C<handler()>. This is the method that will be executed by an
+event triggered by an App::Info concrete subclass. It takes as its single
+argument an App::Info::Request object, and returns a true value if it has
+handled the event request. Returning a false value declines the request, and
+App::Info will then move on to the next handler in the chain.
+
+The C<handler()> method implemented in App::Info::Handler itself does nothing
+more than return a true value. It thus acts as a very simple default event
+handler. See the App::Info::Handler subclasses for more interesting handling
+of events, or create your own!
+
+=cut
+
+sub handler { 1 }
+
+1;
+__END__
+
+=head1 SUBCLASSING
+
+I hatched the idea of the App::Info event model with its subclassable handlers
+as a way of separating the aggregation of application metadata from writing a
+user interface for handling certain conditions. I felt it a better idea to
+allow people to create their own user interfaces, and instead to provide only
+a few examples. The App::Info::Handler class defines the API interface for
+handling these conditions, which App::Info refers to as "events".
+
+There are various types of events defined by App::Info ("info", "error",
+"unknown", and "confirm"), but the App::Info::Handler interface is designed to
+be flexible enough to handle any and all of them. If you're interested in
+creating your own App::Info event handler, this is the place to learn how.
+
+=head2 The Interface
+
+To create an App::Info event handler, all one need do is subclass
+App::Info::Handler and then implement the C<new()> constructor and the
+C<handler()> method. The C<new()> constructor can do anything you like, and
+take any arguments you like. However, I do recommend that the first thing
+you do in your implementation is to call the super constructor:
+
+ sub new {
+ my $pkg = shift;
+ my $self = $pkg->SUPER::new(@_);
+ # ... other stuff.
+ return $self;
+ }
+
+Although the default C<new()> constructor currently doesn't do much, that may
+change in the future, so this call will keep you covered. What it does do is
+take the parameterized arguments and assign them to the App::Info::Handler
+object. Thus if you've specified a "mode" argument, where clients can
+construct objects of you class like this:
+
+ my $handler = FooHandler->new( mode => 'foo' );
+
+You can access the mode parameter directly from the object, like so:
+
+ sub new {
+ my $pkg = shift;
+ my $self = $pkg->SUPER::new(@_);
+ if ($self->{mode} eq 'foo') {
+ # ...
+ }
+ return $self;
+ }
+
+Just be sure not to use a parameter key name required by App::Info::Handler
+itself. At the moment, the only parameter accepted by App::Info::Handler is
+"key", so in general you'll be pretty safe.
+
+Next, I recommend that you take advantage of the C<register_handler()> method
+to create some shortcuts for creating handlers of your class. For example, say
+we're creating a handler subclass FooHandler. It has two modes, a default
+"foo" mode and an advanced "bar" mode. To allow both to be constructed by
+stringified shortcuts, the FooHandler class implementation might start like
+this:
+
+ package FooHandler;
+
+ use strict;
+ use App::Info::Handler;
+ use vars qw(@ISA);
+ @ISA = qw(App::Info::Handler);
+
+ foreach my $c (qw(foo bar)) {
+ App::Info::Handler->register_handler
+ ( $c => sub { __PACKAGE__->new( mode => $c) } );
+ }
+
+The strings "foo" and "bar" can then be used by clients as shortcuts to have
+App::Info objects automatically create and use handlers for certain events.
+For example, if a client wanted to use a "bar" event handler for its info
+events, it might do this:
+
+ use App::Info::Category::FooApp;
+ use FooHandler;
+
+ my $app = App::Info::Category::FooApp->new(on_info => ['bar']);
+
+Take a look at App::Info::Handler::Print and App::Info::Handler::Carp to see
+concrete examples of C<register_handler()> usage.
+
+The final step in creating a new App::Info event handler is to implement the
+C<handler()> method itself. This method takes a single argument, an
+App::Info::Request object, and is expected to return true if it handled the
+request, and false if it did not. The App::Info::Request object contains all
+the metadata relevant to a request, including the type of event that triggered
+it; see L<App::Info::Request|App::Info::Request> for its documentation.
+
+Use the App::Info::Request object however you like to handle the request
+however you like. You are, however, expected to abide by a a few guidelines:
+
+=over 4
+
+=item *
+
+For error and info events, you are expected (but not required) to somehow
+display the info or error message for the user. How your handler chooses to do
+so is up to you and the handler.
+
+=item *
+
+For unknown and confirm events, you are expected to prompt the user for a
+value. If it's a confirm event, offer the known value (found in
+C<$req-E<gt>value>) as a default.
+
+=item *
+
+For unknown and confirm events, you are expected to call C<$req-E<gt>callback>
+and pass in the new value. If C<$req-E<gt>callback> returns a false value, you
+are expected to display the error message in C<$req-E<gt>error> and prompt the
+user again. Note that C<$req-E<gt>value> calls C<$req-E<gt>callback>
+internally, and thus assigns the value and returns true if
+C<$req-E<gt>callback> returns true, and does not assign the value and returns
+false if C<$req-E<gt>callback> returns false.
+
+=item *
+
+For unknown and confirm events, if you've collected a new value and
+C<$req-E<gt>callback> returns true for that value, you are expected to assign
+the value by passing it to C<$req-E<gt>value>. This allows App::Info to give
+the value back to the calling App::Info concrete subclass.
+
+=back
+
+Probably the easiest way to get started creating new App::Info event handlers
+is to check out the simple handlers provided with the distribution and follow
+their logical examples. Consult the App::Info documentation of the L<event
+methods|App::Info/"Events"> for details on how App::Info constructs the
+App::Info::Request object for each event type.
+
+=head1 BUGS
+
+Report all bugs via the CPAN Request Tracker at
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Info>.
+
+=head1 AUTHOR
+
+David Wheeler <L<david@wheeler.net|"david@wheeler.net">>
+
+=head1 SEE ALSO
+
+L<App::Info|App::Info> thoroughly documents the client interface for setting
+event handlers, as well as the event triggering interface for App::Info
+concrete subclasses.
+
+L<App::Info::Request|App::Info::Request> documents the interface for the
+request objects passed to App::Info::Handler C<handler()> methods.
+
+The following App::Info::Handler subclasses offer examples for event handler
+authors, and, of course, provide actual event handling functionality for
+App::Info clients.
+
+=over 4
+
+=item L<App::Info::Handler::Carp|App::Info::Handler::Carp>
+
+=item L<App::Info::Handler::Print|App::Info::Handler::Print>
+
+=item L<App::Info::Handler::Prompt|App::Info::Handler::Prompt>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2002, David Wheeler. All Rights Reserved.
+
+This module is free software; you can redistribute it and/or modify it under the
+same terms as Perl itself.
+
+=cut
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler/Prompt.pm b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler/Prompt.pm
new file mode 100644
index 0000000..47edd78
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler/Prompt.pm
@@ -0,0 +1,170 @@
+package App::Info::Handler::Prompt;
+
+# $Id: Prompt.pm,v 1.1 2004-04-29 09:21:29 ivan Exp $
+
+=head1 NAME
+
+App::Info::Handler::Prompt - Prompting App::Info event handler
+
+=head1 SYNOPSIS
+
+ use App::Info::Category::FooApp;
+ use App::Info::Handler::Print;
+
+ my $prompter = App::Info::Handler::Print->new;
+ my $app = App::Info::Category::FooApp->new( on_unknown => $prompter );
+
+ # Or...
+ my $app = App::Info::Category::FooApp->new( on_confirm => 'prompt' );
+
+=head1 DESCRIPTION
+
+App::Info::Handler::Prompt objects handle App::Info events by printing their
+messages to C<STDOUT> and then accepting a new value from C<STDIN>. The new
+value is validated by any callback supplied by the App::Info concrete subclass
+that triggered the event. If the value is valid, App::Info::Handler::Prompt
+assigns the new value to the event request. If it isn't it prints the error
+message associated with the event request, and then prompts for the data
+again.
+
+Although designed with unknown and confirm events in mind,
+App::Info::Handler::Prompt handles info and error events as well. It will
+simply print info event messages to C<STDOUT> and print error event messages
+to C<STDERR>. For more interesting info and error event handling, see
+L<App::Info::Handler::Print|App::Info::Handler::Print> and
+L<App::Info::Handler::Carp|App::Info::Handler::Carp>.
+
+Upon loading, App::Info::Handler::Print registers itself with
+App::Info::Handler, setting up a single string, "prompt", that can be passed
+to an App::Info concrete subclass constructor. This string is a shortcut that
+tells App::Info how to create an App::Info::Handler::Print object for handling
+events.
+
+=cut
+
+use strict;
+use App::Info::Handler;
+use vars qw($VERSION @ISA);
+$VERSION = '0.22';
+@ISA = qw(App::Info::Handler);
+
+# Register ourselves.
+App::Info::Handler->register_handler
+ ('prompt' => sub { __PACKAGE__->new('prompt') } );
+
+=head1 INTERFACE
+
+=head2 Constructor
+
+=head3 new
+
+ my $prompter = App::Info::Handler::Prompt->new;
+
+Constructs a new App::Info::Handler::Prompt object and returns it. No special
+arguments are required.
+
+=cut
+
+sub new {
+ my $pkg = shift;
+ my $self = $pkg->SUPER::new(@_);
+ $self->{tty} = -t STDIN && ( -t STDOUT || !( -f STDOUT || -c STDOUT ) );
+ # We're done!
+ return $self;
+}
+
+my $get_ans = sub {
+ my ($prompt, $tty, $def) = @_;
+ # Print the message.
+ local $| = 1;
+ local $\;
+ print $prompt;
+
+ # Collect the answer.
+ my $ans;
+ if ($tty) {
+ $ans = <STDIN>;
+ if (defined $ans ) {
+ chomp $ans;
+ } else { # user hit ctrl-D
+ print "\n";
+ }
+ } else {
+ print "$def\n" if defined $def;
+ }
+ return $ans;
+};
+
+sub handler {
+ my ($self, $req) = @_;
+ my $ans;
+ my $type = $req->type;
+ if ($type eq 'unknown' || $type eq 'confirm') {
+ # We'll want to prompt for a new value.
+ my $val = $req->value;
+ my ($def, $dispdef) = defined $val ? ($val, " [$val] ") : ('', ' ');
+ my $msg = $req->message or Carp::croak("No message in request");
+ $msg .= $dispdef;
+
+ # Get the answer.
+ $ans = $get_ans->($msg, $self->{tty}, $def);
+ # Just return if they entered an empty string or we couldnt' get an
+ # answer.
+ return 1 unless defined $ans && $ans ne '';
+
+ # Validate the answer.
+ my $err = $req->error;
+ while (!$req->value($ans)) {
+ print "$err: '$ans'\n";
+ $ans = $get_ans->($msg, $self->{tty}, $def);
+ return 1 unless defined $ans && $ans ne '';
+ }
+
+ } elsif ($type eq 'info') {
+ # Just print the message.
+ print STDOUT $req->message, "\n";
+ } elsif ($type eq 'error') {
+ # Just print the message.
+ print STDERR $req->message, "\n";
+ } else {
+ # This shouldn't happen.
+ Carp::croak("Invalid request type '$type'");
+ }
+
+ # Return true to indicate that we've handled the request.
+ return 1;
+}
+
+1;
+__END__
+
+=head1 BUGS
+
+Report all bugs via the CPAN Request Tracker at
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Info>.
+
+=head1 AUTHOR
+
+David Wheeler <L<david@wheeler.net|"david@wheeler.net">>
+
+=head1 SEE ALSO
+
+L<App::Info|App::Info> documents the event handling interface.
+
+L<App::Info::Handler::Carp|App::Info::Handler::Carp> handles events by
+passing their messages Carp module functions.
+
+L<App::Info::Handler::Print|App::Info::Handler::Print> handles events by
+printing their messages to a file handle.
+
+L<App::Info::Handler|App::Info::Handler> describes how to implement custom
+App::Info event handlers.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2002, David Wheeler. All Rights Reserved.
+
+This module is free software; you can redistribute it and/or modify it under the
+same terms as Perl itself.
+
+=cut
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS.pm b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS.pm
new file mode 100644
index 0000000..504d570
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS.pm
@@ -0,0 +1,55 @@
+package App::Info::RDBMS;
+
+# $Id: RDBMS.pm,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+use strict;
+use App::Info;
+use vars qw(@ISA $VERSION);
+@ISA = qw(App::Info);
+$VERSION = '0.22';
+
+1;
+__END__
+
+=head1 NAME
+
+App::Info::RDBMS - Information about databases on a system
+
+=head1 DESCRIPTION
+
+This class is an abstract base class for App::Info subclasses that provide
+information about relational databases. Its subclasses are required to
+implement its interface. See L<App::Info|App::Info> for a complete description
+and L<App::Info::RDBMS::PostgreSQL|App::Info::RDBMS::PostgreSQL> for an example
+implementation.
+
+=head1 INTERFACE
+
+Currently, App::Info::RDBMS adds no more methods than those from its parent
+class, App::Info.
+
+=head1 BUGS
+
+Report all bugs via the CPAN Request Tracker at
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Info>.
+
+=head1 AUTHOR
+
+David Wheeler <L<david@wheeler.net|"david@wheeler.net">>
+
+=head1 SEE ALSO
+
+L<App::Info|App::Info>,
+L<App::Info::RDBMS::PostgreSQL|App::Info::RDBMS::PostgreSQL>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2002, David Wheeler. All Rights Reserved.
+
+This module is free software; you can redistribute it and/or modify it under the
+same terms as Perl itself.
+
+=cut
+
+
+
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS/PostgreSQL.pm b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS/PostgreSQL.pm
new file mode 100644
index 0000000..aef326c
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS/PostgreSQL.pm
@@ -0,0 +1,730 @@
+package App::Info::RDBMS::PostgreSQL;
+
+# $Id: PostgreSQL.pm,v 1.1 2004-04-29 09:21:29 ivan Exp $
+
+=head1 NAME
+
+App::Info::RDBMS::PostgreSQL - Information about PostgreSQL
+
+=head1 SYNOPSIS
+
+ use App::Info::RDBMS::PostgreSQL;
+
+ my $pg = App::Info::RDBMS::PostgreSQL->new;
+
+ if ($pg->installed) {
+ print "App name: ", $pg->name, "\n";
+ print "Version: ", $pg->version, "\n";
+ print "Bin dir: ", $pg->bin_dir, "\n";
+ } else {
+ print "PostgreSQL is not installed. :-(\n";
+ }
+
+=head1 DESCRIPTION
+
+App::Info::RDBMS::PostgreSQL supplies information about the PostgreSQL
+database server installed on the local system. It implements all of the
+methods defined by App::Info::RDBMS. Methods that trigger events will trigger
+them only the first time they're called (See L<App::Info|App::Info> for
+documentation on handling events). To start over (after, say, someone has
+installed PostgreSQL) construct a new App::Info::RDBMS::PostgreSQL object to
+aggregate new metadata.
+
+Some of the methods trigger the same events. This is due to cross-calling of
+shared subroutines. However, any one event should be triggered no more than
+once. For example, although the info event "Executing `pg_config --version`"
+is documented for the methods C<name()>, C<version()>, C<major_version()>,
+C<minor_version()>, and C<patch_version()>, rest assured that it will only be
+triggered once, by whichever of those four methods is called first.
+
+=cut
+
+use strict;
+use App::Info::RDBMS;
+use App::Info::Util;
+use vars qw(@ISA $VERSION);
+@ISA = qw(App::Info::RDBMS);
+$VERSION = '0.22';
+
+my $u = App::Info::Util->new;
+
+=head1 INTERFACE
+
+=head2 Constructor
+
+=head3 new
+
+ my $pg = App::Info::RDBMS::PostgreSQL->new(@params);
+
+Returns an App::Info::RDBMS::PostgreSQL object. See L<App::Info|App::Info> for
+a complete description of argument parameters.
+
+When it called, C<new()> searches the file system for the F<pg_config>
+application. If found, F<pg_config> will be called by the object methods below
+to gather the data necessary for each. If F<pg_config> cannot be found, then
+PostgreSQL is assumed not to be installed, and each of the object methods will
+return C<undef>.
+
+App::Info::RDBMS::PostgreSQL searches for F<pg_config> along your path, as
+defined by C<File::Spec-E<gt>path>. Failing that, it searches the following
+directories:
+
+=over 4
+
+=item /usr/local/pgsql/bin
+
+=item /usr/local/postgres/bin
+
+=item /opt/pgsql/bin
+
+=item /usr/local/bin
+
+=item /usr/local/sbin
+
+=item /usr/bin
+
+=item /usr/sbin
+
+=item /bin
+
+=back
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Looking for pg_config
+
+=item confirm
+
+Path to pg_config?
+
+=item unknown
+
+Path to pg_config?
+
+=back
+
+=cut
+
+sub new {
+ # Construct the object.
+ my $self = shift->SUPER::new(@_);
+
+ # Find pg_config.
+ $self->info("Looking for pg_config");
+ my @paths = ($u->path,
+ qw(/usr/local/pgsql/bin
+ /usr/local/postgres/bin
+ /opt/pgsql/bin
+ /usr/local/bin
+ /usr/local/sbin
+ /usr/bin
+ /usr/sbin
+ /bin));
+
+ if (my $cfg = $u->first_cat_exe('pg_config', @paths)) {
+ # We found it. Confirm.
+ $self->{pg_config} = $self->confirm( key => 'pg_config',
+ prompt => 'Path to pg_config?',
+ value => $cfg,
+ callback => sub { -x },
+ error => 'Not an executable');
+ } else {
+ # Handle an unknown value.
+ $self->{pg_config} = $self->unknown( key => 'pg_config',
+ prompt => 'Path to pg_config?',
+ callback => sub { -x },
+ error => 'Not an executable');
+ }
+
+ return $self;
+}
+
+# We'll use this code reference as a common way of collecting data.
+my $get_data = sub {
+ return unless $_[0]->{pg_config};
+ $_[0]->info("Executing `$_[0]->{pg_config} $_[1]`");
+ my $info = `$_[0]->{pg_config} $_[1]`;
+ chomp $info;
+ return $info;
+};
+
+##############################################################################
+
+=head2 Class Method
+
+=head3 key_name
+
+ my $key_name = App::Info::RDBMS::PostgreSQL->key_name;
+
+Returns the unique key name that describes this class. The value returned is
+the string "PostgreSQL".
+
+=cut
+
+sub key_name { 'PostgreSQL' }
+
+##############################################################################
+
+=head2 Object Methods
+
+=head3 installed
+
+ print "PostgreSQL is ", ($pg->installed ? '' : 'not '), "installed.\n";
+
+Returns true if PostgreSQL is installed, and false if it is not.
+App::Info::RDBMS::PostgreSQL determines whether PostgreSQL is installed based
+on the presence or absence of the F<pg_config> application on the file system
+as found when C<new()> constructed the object. If PostgreSQL does not appear
+to be installed, then all of the other object methods will return empty
+values.
+
+=cut
+
+sub installed { return $_[0]->{pg_config} ? 1 : undef }
+
+##############################################################################
+
+=head3 name
+
+ my $name = $pg->name;
+
+Returns the name of the application. App::Info::RDBMS::PostgreSQL parses the
+name from the system call C<`pg_config --version`>.
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Executing `pg_config --version`
+
+=item error
+
+Failed to find PostgreSQL version with `pg_config --version`
+
+Unable to parse name from string
+
+Unable to parse version from string
+
+Failed to parse PostgreSQL version parts from string
+
+=item unknown
+
+Enter a valid PostgreSQL name
+
+=back
+
+=cut
+
+# This code reference is used by name(), version(), major_version(),
+# minor_version(), and patch_version() to aggregate the data they need.
+my $get_version = sub {
+ my $self = shift;
+ $self->{'--version'} = 1;
+ my $data = $get_data->($self, '--version');
+ unless ($data) {
+ $self->error("Failed to find PostgreSQL version with ".
+ "`$self->{pg_config} --version");
+ return;
+ }
+
+ chomp $data;
+ my ($name, $version) = split /\s+/, $data, 2;
+
+ # Check for and assign the name.
+ $name ?
+ $self->{name} = $name :
+ $self->error("Unable to parse name from string '$data'");
+
+ # Parse the version number.
+ if ($version) {
+ my ($x, $y, $z) = $version =~ /(\d+)\.(\d+).(\d+)/;
+ if (defined $x and defined $y and defined $z) {
+ @{$self}{qw(version major minor patch)} =
+ ($version, $x, $y, $z);
+ } else {
+ $self->error("Failed to parse PostgreSQL version parts from " .
+ "string '$version'");
+ }
+ } else {
+ $self->error("Unable to parse version from string '$data'");
+ }
+};
+
+sub name {
+ my $self = shift;
+ return unless $self->{pg_config};
+
+ # Load data.
+ $get_version->($self) unless $self->{'--version'};
+
+ # Handle an unknown name.
+ $self->{name} ||= $self->unknown( key => 'name' );
+
+ # Return the name.
+ return $self->{name};
+}
+
+##############################################################################
+
+=head3 version
+
+ my $version = $pg->version;
+
+Returns the PostgreSQL version number. App::Info::RDBMS::PostgreSQL parses the
+version number from the system call C<`pg_config --version`>.
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Executing `pg_config --version`
+
+=item error
+
+Failed to find PostgreSQL version with `pg_config --version`
+
+Unable to parse name from string
+
+Unable to parse version from string
+
+Failed to parse PostgreSQL version parts from string
+
+=item unknown
+
+Enter a valid PostgreSQL version number
+
+=back
+
+=cut
+
+sub version {
+ my $self = shift;
+ return unless $self->{pg_config};
+
+ # Load data.
+ $get_version->($self) unless $self->{'--version'};
+
+ # Handle an unknown value.
+ unless ($self->{version}) {
+ # Create a validation code reference.
+ my $chk_version = sub {
+ # Try to get the version number parts.
+ my ($x, $y, $z) = /^(\d+)\.(\d+).(\d+)$/;
+ # Return false if we didn't get all three.
+ return unless $x and defined $y and defined $z;
+ # Save all three parts.
+ @{$self}{qw(major minor patch)} = ($x, $y, $z);
+ # Return true.
+ return 1;
+ };
+ $self->{version} = $self->unknown( key => 'version number',
+ callback => $chk_version);
+ }
+
+ return $self->{version};
+}
+
+##############################################################################
+
+=head3 major version
+
+ my $major_version = $pg->major_version;
+
+Returns the PostgreSQL major version number. App::Info::RDBMS::PostgreSQL
+parses the major version number from the system call C<`pg_config --version`>.
+For example, C<version()> returns "7.1.2", then this method returns "7".
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Executing `pg_config --version`
+
+=item error
+
+Failed to find PostgreSQL version with `pg_config --version`
+
+Unable to parse name from string
+
+Unable to parse version from string
+
+Failed to parse PostgreSQL version parts from string
+
+=item unknown
+
+Enter a valid PostgreSQL major version number
+
+=back
+
+=cut
+
+# This code reference is used by major_version(), minor_version(), and
+# patch_version() to validate a version number entered by a user.
+my $is_int = sub { /^\d+$/ };
+
+sub major_version {
+ my $self = shift;
+ return unless $self->{pg_config};
+ # Load data.
+ $get_version->($self) unless exists $self->{'--version'};
+ # Handle an unknown value.
+ $self->{major} = $self->unknown( key => 'major version number',
+ callback => $is_int)
+ unless $self->{major};
+ return $self->{major};
+}
+
+##############################################################################
+
+=head3 minor version
+
+ my $minor_version = $pg->minor_version;
+
+Returns the PostgreSQL minor version number. App::Info::RDBMS::PostgreSQL
+parses the minor version number from the system call C<`pg_config --version`>.
+For example, if C<version()> returns "7.1.2", then this method returns "2".
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Executing `pg_config --version`
+
+=item error
+
+Failed to find PostgreSQL version with `pg_config --version`
+
+Unable to parse name from string
+
+Unable to parse version from string
+
+Failed to parse PostgreSQL version parts from string
+
+=item unknown
+
+Enter a valid PostgreSQL minor version number
+
+=back
+
+=cut
+
+sub minor_version {
+ my $self = shift;
+ return unless $self->{pg_config};
+ # Load data.
+ $get_version->($self) unless exists $self->{'--version'};
+ # Handle an unknown value.
+ $self->{minor} = $self->unknown( key => 'minor version number',
+ callback => $is_int)
+ unless defined $self->{minor};
+ return $self->{minor};
+}
+
+##############################################################################
+
+=head3 patch version
+
+ my $patch_version = $pg->patch_version;
+
+Returns the PostgreSQL patch version number. App::Info::RDBMS::PostgreSQL
+parses the patch version number from the system call C<`pg_config --version`>.
+For example, if C<version()> returns "7.1.2", then this method returns "1".
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Executing `pg_config --version`
+
+=item error
+
+Failed to find PostgreSQL version with `pg_config --version`
+
+Unable to parse name from string
+
+Unable to parse version from string
+
+Failed to parse PostgreSQL version parts from string
+
+=item unknown
+
+Enter a valid PostgreSQL minor version number
+
+=back
+
+=cut
+
+sub patch_version {
+ my $self = shift;
+ return unless $self->{pg_config};
+ # Load data.
+ $get_version->($self) unless exists $self->{'--version'};
+ # Handle an unknown value.
+ $self->{patch} = $self->unknown( key => 'patch version number',
+ callback => $is_int)
+ unless defined $self->{patch};
+ return $self->{patch};
+}
+
+##############################################################################
+
+=head3 bin_dir
+
+ my $bin_dir = $pg->bin_dir;
+
+Returns the PostgreSQL binary directory path. App::Info::RDBMS::PostgreSQL
+gathers the path from the system call C<`pg_config --bindir`>.
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Executing `pg_config --bindir`
+
+=item error
+
+Cannot find bin directory
+
+=item unknown
+
+Enter a valid PostgreSQL bin directory
+
+=back
+
+=cut
+
+# This code reference is used by bin_dir(), lib_dir(), and so_lib_dir() to
+# validate a directory entered by the user.
+my $is_dir = sub { -d };
+
+sub bin_dir {
+ my $self = shift;
+ return unless $self->{pg_config};
+ unless (exists $self->{bin_dir} ) {
+ if (my $dir = $get_data->($self, '--bindir')) {
+ $self->{bin_dir} = $dir;
+ } else {
+ # Handle an unknown value.
+ $self->error("Cannot find bin directory");
+ $self->{bin_dir} = $self->unknown( key => 'bin directory',
+ callback => $is_dir)
+ }
+ }
+
+ return $self->{bin_dir};
+}
+
+##############################################################################
+
+=head3 inc_dir
+
+ my $inc_dir = $pg->inc_dir;
+
+Returns the PostgreSQL include directory path. App::Info::RDBMS::PostgreSQL
+gathers the path from the system call C<`pg_config --includedir`>.
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Executing `pg_config --includedir`
+
+=item error
+
+Cannot find include directory
+
+=item unknown
+
+Enter a valid PostgreSQL include directory
+
+=back
+
+=cut
+
+sub inc_dir {
+ my $self = shift;
+ return unless $self->{pg_config};
+ unless (exists $self->{inc_dir} ) {
+ if (my $dir = $get_data->($self, '--includedir')) {
+ $self->{inc_dir} = $dir;
+ } else {
+ # Handle an unknown value.
+ $self->error("Cannot find include directory");
+ $self->{inc_dir} = $self->unknown( key => 'include directory',
+ callback => $is_dir)
+ }
+ }
+
+ return $self->{inc_dir};
+}
+
+##############################################################################
+
+=head3 lib_dir
+
+ my $lib_dir = $pg->lib_dir;
+
+Returns the PostgreSQL library directory path. App::Info::RDBMS::PostgreSQL
+gathers the path from the system call C<`pg_config --libdir`>.
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Executing `pg_config --libdir`
+
+=item error
+
+Cannot find library directory
+
+=item unknown
+
+Enter a valid PostgreSQL library directory
+
+=back
+
+=cut
+
+sub lib_dir {
+ my $self = shift;
+ return unless $self->{pg_config};
+ unless (exists $self->{lib_dir} ) {
+ if (my $dir = $get_data->($self, '--libdir')) {
+ $self->{lib_dir} = $dir;
+ } else {
+ # Handle an unknown value.
+ $self->error("Cannot find library directory");
+ $self->{lib_dir} = $self->unknown( key => 'library directory',
+ callback => $is_dir)
+ }
+ }
+
+ return $self->{lib_dir};
+}
+
+##############################################################################
+
+=head3 so_lib_dir
+
+ my $so_lib_dir = $pg->so_lib_dir;
+
+Returns the PostgreSQL shared object library directory path.
+App::Info::RDBMS::PostgreSQL gathers the path from the system call
+C<`pg_config --pkglibdir`>.
+
+B<Events:>
+
+=over 4
+
+=item info
+
+Executing `pg_config --pkglibdir`
+
+=item error
+
+Cannot find shared object library directory
+
+=item unknown
+
+Enter a valid PostgreSQL shared object library directory
+
+=back
+
+=cut
+
+# Location of dynamically loadable modules.
+sub so_lib_dir {
+ my $self = shift;
+ return unless $self->{pg_config};
+ unless (exists $self->{so_lib_dir} ) {
+ if (my $dir = $get_data->($self, '--pkglibdir')) {
+ $self->{so_lib_dir} = $dir;
+ } else {
+ # Handle an unknown value.
+ $self->error("Cannot find shared object library directory");
+ $self->{so_lib_dir} =
+ $self->unknown( key => 'shared object library directory',
+ callback => $is_dir)
+ }
+ }
+
+ return $self->{so_lib_dir};
+}
+
+##############################################################################
+
+=head3 home_url
+
+ my $home_url = $pg->home_url;
+
+Returns the PostgreSQL home page URL.
+
+=cut
+
+sub home_url { "http://www.postgresql.org/" }
+
+##############################################################################
+
+=head3 download_url
+
+ my $download_url = $pg->download_url;
+
+Returns the PostgreSQL download URL.
+
+=cut
+
+sub download_url { "http://www.ca.postgresql.org/sitess.html" }
+
+1;
+__END__
+
+=head1 BUGS
+
+Report all bugs via the CPAN Request Tracker at
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Info>.
+
+=head1 AUTHOR
+
+David Wheeler <L<david@wheeler.net|"david@wheeler.net">> based on code by Sam
+Tregar <L<sam@tregar.com|"sam@tregar.com">>.
+
+=head1 SEE ALSO
+
+L<App::Info|App::Info> documents the event handling interface.
+
+L<App::Info::RDBMS|App::Info::RDBMS> is the App::Info::RDBMS::PostgreSQL
+parent class.
+
+L<DBD::Pg|DBD::Pg> is the L<DBI|DBI> driver for connecting to PostgreSQL
+databases.
+
+L<http://www.postgresql.org/> is the PostgreSQL home page.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2002, David Wheeler. All Rights Reserved.
+
+This module is free software; you can redistribute it and/or modify it under the
+same terms as Perl itself.
+
+=cut
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Request.pm b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Request.pm
new file mode 100644
index 0000000..c02c97b
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Request.pm
@@ -0,0 +1,287 @@
+package App::Info::Request;
+
+# $Id: Request.pm,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+=head1 NAME
+
+App::Info::Request - App::Info event handler request object
+
+=head1 SYNOPSIS
+
+ # In an App::Info::Handler subclass:
+ sub handler {
+ my ($self, $req) = @_;
+ print "Event Type: ", $req->type;
+ print "Message: ", $req->message;
+ print "Error: ", $req->error;
+ print "Value: ", $req->value;
+ }
+
+=head1 DESCRIPTION
+
+Objects of this class are passed to the C<handler()> method of App::Info event
+handlers. Generally, this class will be of most interest to App::Info::Handler
+subclass implementers.
+
+The L<event triggering methods|App::Info/"Events"> in App::Info each construct
+a new App::Info::Request object and initialize it with their arguments. The
+App::Info::Request object is then the sole argument passed to the C<handler()>
+method of any and all App::Info::Handler objects in the event handling chain.
+Thus, if you'd like to create your own App::Info event handler, this is the
+object you need to be familiar with. Consult the
+L<App::Info::Handler|App::Info::Handler> documentation for details on creating
+custom event handlers.
+
+Each of the App::Info event triggering methods constructs an
+App::Info::Request object with different attribute values. Be sure to consult
+the documentation for the L<event triggering methods|App::Info/"Events"> in
+App::Info, where the values assigned to the App::Info::Request object are
+documented. Then, in your event handler subclass, check the value returned by
+the C<type()> method to determine what type of event request you're handling
+to handle the request appropriately.
+
+=cut
+
+use strict;
+use vars qw($VERSION);
+$VERSION = '0.23';
+
+##############################################################################
+
+=head1 INTERFACE
+
+The following sections document the App::Info::Request interface.
+
+=head2 Constructor
+
+=head3 new
+
+ my $req = App::Info::Request->new(%params);
+
+This method is used internally by App::Info to construct new
+App::Info::Request objects to pass to event handler objects. Generally, you
+won't need to use it, other than perhaps for testing custom App::Info::Handler
+classes.
+
+The parameters to C<new()> are passed as a hash of named parameters that
+correspond to their like-named methods. The supported parameters are:
+
+=over 4
+
+=item type
+
+=item message
+
+=item error
+
+=item value
+
+=item callback
+
+=back
+
+See the object methods documentation below for details on these object
+attributes.
+
+=cut
+
+sub new {
+ my $pkg = shift;
+
+ # Make sure we've got a hash of arguments.
+ Carp::croak("Odd number of parameters in call to " . __PACKAGE__ .
+ "->new() when named parameters expected" ) if @_ % 2;
+ my %params = @_;
+
+ # Validate the callback.
+ if ($params{callback}) {
+ Carp::croak("Callback parameter '$params{callback}' is not a code ",
+ "reference")
+ unless UNIVERSAL::isa($params{callback}, 'CODE');
+ } else {
+ # Otherwise just assign a default approve callback.
+ $params{callback} = sub { 1 };
+ }
+
+ # Validate type parameter.
+ if (my $t = $params{type}) {
+ Carp::croak("Invalid handler type '$t'")
+ unless $t eq 'error' or $t eq 'info' or $t eq 'unknown'
+ or $t eq 'confirm';
+ } else {
+ $params{type} = 'info';
+ }
+
+ # Return the request object.
+ bless \%params, ref $pkg || $pkg;
+}
+
+##############################################################################
+
+=head2 Object Methods
+
+=head3 message
+
+ my $message = $req->message;
+
+Returns the message stored in the App::Info::Request object. The message is
+typically informational, or an error message, or a prompt message.
+
+=cut
+
+sub message { $_[0]->{message} }
+
+##############################################################################
+
+=head3 error
+
+ my $error = $req->error;
+
+Returns any error message associated with the App::Info::Request object. The
+error message is typically there to display for users when C<callback()>
+returns false.
+
+=cut
+
+sub error { $_[0]->{error} }
+
+##############################################################################
+
+=head3 type
+
+ my $type = $req->type;
+
+Returns a string representing the type of event that triggered this request.
+The types are the same as the event triggering methods defined in App::Info.
+As of this writing, the supported types are:
+
+=over
+
+=item info
+
+=item error
+
+=item unknown
+
+=item confirm
+
+=back
+
+Be sure to consult the App::Info documentation for more details on the event
+types.
+
+=cut
+
+sub type { $_[0]->{type} }
+
+##############################################################################
+
+=head3 callback
+
+ if ($req->callback($value)) {
+ print "Value '$value' is valid.\n";
+ } else {
+ print "Value '$value' is not valid.\n";
+ }
+
+Executes the callback anonymous subroutine supplied by the App::Info concrete
+base class that triggered the event. If the callback returns false, then
+C<$value> is invalid. If the callback returns true, then C<$value> is valid
+and can be assigned via the C<value()> method.
+
+Note that the C<value()> method itself calls C<callback()> if it was passed a
+value to assign. See its documentation below for more information.
+
+=cut
+
+sub callback {
+ my $self = shift;
+ my $code = $self->{callback};
+ local $_ = $_[0];
+ $code->(@_);
+}
+
+##############################################################################
+
+=head3 value
+
+ my $value = $req->value;
+ if ($req->value($value)) {
+ print "Value '$value' successfully assigned.\n";
+ } else {
+ print "Value '$value' not successfully assigned.\n";
+ }
+
+When called without an argument, C<value()> simply returns the value currently
+stored by the App::Info::Request object. Typically, the value is the default
+value for a confirm event, or a value assigned to an unknown event.
+
+When passed an argument, C<value()> attempts to store the the argument as a
+new value. However, C<value()> calls C<callback()> on the new value, and if
+C<callback()> returns false, then C<value()> returns false and does not store
+the new value. If C<callback()> returns true, on the other hand, then
+C<value()> goes ahead and stores the new value and returns true.
+
+=cut
+
+sub value {
+ my $self = shift;
+ if ($#_ >= 0) {
+ # grab the value.
+ my $value = shift;
+ # Validate the value.
+ if ($self->callback($value)) {
+ # The value is good. Assign it and return true.
+ $self->{value} = $value;
+ return 1;
+ } else {
+ # Invalid value. Return false.
+ return;
+ }
+ }
+ # Just return the value.
+ return $self->{value};
+}
+
+1;
+__END__
+
+=head1 BUGS
+
+Report all bugs via the CPAN Request Tracker at
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Info>.
+
+=head1 AUTHOR
+
+David Wheeler <L<david@wheeler.net|"david@wheeler.net">>
+
+=head1 SEE ALSO
+
+L<App::Info|App::Info> documents the event triggering methods and how they
+construct App::Info::Request objects to pass to event handlers.
+
+L<App::Info::Handler:|App::Info::Handler> documents how to create custom event
+handlers, which must make use of the App::Info::Request object passed to their
+C<handler()> object methods.
+
+The following classes subclass App::Info::Handler, and thus offer good
+exemplars for using App::Info::Request objects when handling events.
+
+=over 4
+
+=item L<App::Info::Handler::Carp|App::Info::Handler::Carp>
+
+=item L<App::Info::Handler::Print|App::Info::Handler::Print>
+
+=item L<App::Info::Handler::Prompt|App::Info::Handler::Prompt>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2002, David Wheeler. All Rights Reserved.
+
+This module is free software; you can redistribute it and/or modify it under the
+same terms as Perl itself.
+
+=cut
diff --git a/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Util.pm b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Util.pm
new file mode 100644
index 0000000..55bb333
--- /dev/null
+++ b/install/5.005/DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Util.pm
@@ -0,0 +1,456 @@
+package App::Info::Util;
+
+# $Id: Util.pm,v 1.1 2004-04-29 09:21:28 ivan Exp $
+
+=head1 NAME
+
+App::Info::Util - Utility class for App::Info subclasses
+
+=head1 SYNOPSIS
+
+ use App::Info::Util;
+
+ my $util = App::Info::Util->new;
+
+ # Subclasses File::Spec.
+ my @paths = $util->paths;
+
+ # First directory that exists in a list.
+ my $dir = $util->first_dir(@paths);
+
+ # First directory that exists in a path.
+ $dir = $util->first_path($ENV{PATH});
+
+ # First file that exists in a list.
+ my $file = $util->first_file('this.txt', '/that.txt', 'C:\\foo.txt');
+
+ # First file found among file base names and directories.
+ my $files = ['this.txt', 'that.txt'];
+ $file = $util->first_cat_file($files, @paths);
+
+=head1 DESCRIPTION
+
+This class subclasses L<File::Spec|File::Spec> and adds its own methods in
+order to offer utility methods to L<App::Info|App::Info> classes. Although
+intended to be used by App::Info subclasses, in truth App::Info::Util's
+utility may be considered more general, so feel free to use it elsewhere.
+
+The methods added in addition to the usual File::Spec suspects are designed to
+facilitate locating files and directories on the file system, as well as
+searching those files. The assumption is that, in order to provide useful
+metadata about a given software package, an App::Info subclass must find
+relevant files and directories and parse them with regular expressions. This
+class offers methods that simplify those tasks.
+
+=cut
+
+use strict;
+use File::Spec ();
+use vars qw(@ISA $VERSION);
+@ISA = qw(File::Spec);
+$VERSION = '0.22';
+
+my %path_dems = (MacOS => qr',',
+ MSWin32 => qr';',
+ os2 => qr';',
+ VMS => undef,
+ epoc => undef);
+
+my $path_dem = exists $path_dems{$^O} ? $path_dems{$^O} : qr':';
+
+=head1 CONSTRUCTOR
+
+=head2 new
+
+ my $util = App::Info::Util->new;
+
+This is a very simple constructor that merely returns an App::Info::Util
+object. Since, like its File::Spec super class, App::Info::Util manages no
+internal data itself, all methods may be used as class methods, if one prefers
+to. The constructor here is provided merely as a convenience.
+
+=cut
+
+sub new { bless {}, ref $_[0] || $_[0] }
+
+=head1 OBJECT METHODS
+
+In addition to all of the methods offered by its super class,
+L<File::Spec|File::Spec>, App::Info::Util offers the following methods.
+
+=head2 first_dir
+
+ my @paths = $util->paths;
+ my $dir = $util->first_dir(@dirs);
+
+Returns the first file system directory in @paths that exists on the local
+file system. Only the first item in @paths that exists as a directory will be
+returned; any other paths leading to non-directories will be ignored.
+
+=cut
+
+sub first_dir {
+ shift;
+ foreach (@_) { return $_ if -d }
+ return;
+}
+
+=head2 first_path
+
+ my $path = $ENV{PATH};
+ $dir = $util->first_path($path);
+
+Takes the $path string and splits it into a list of directory paths, based on
+the path demarcator on the local file system. Then calls C<first_dir()> to
+return the first directoy in the path list that exists on the local file
+system. The path demarcator is specified for the following file systems:
+
+=over 4
+
+=item MacOS: ","
+
+=item MSWin32: ";"
+
+=item os2: ";"
+
+=item VMS: undef
+
+This method always returns undef on VMS. Patches welcome.
+
+=item epoc: undef
+
+This method always returns undef on epoch. Patches welcome.
+
+=item Unix: ":"
+
+All other operating systems are assumed to be Unix-based.
+
+=back
+
+=cut
+
+sub first_path {
+ return unless $path_dem;
+ shift->first_dir(split /$path_dem/, shift)
+}
+
+=head2 first_file
+
+ my $file = $util->first_file(@filelist);
+
+Examines each of the files in @filelist and returns the first one that exists
+on the file system. The file must be a regular file -- directories will be
+ignored.
+
+=cut
+
+sub first_file {
+ shift;
+ foreach (@_) { return $_ if -f }
+ return;
+}
+
+=head2 first_exe
+
+ my $exe = $util->first_exe(@exelist);
+
+Examines each of the files in @exelist and returns the first one that exists
+on the file system as an executable file. Directories will be ignored.
+
+=cut
+
+sub first_exe {
+ shift;
+ foreach (@_) { return $_ if -f && -x }
+ return;
+}
+
+=head2 first_cat_path
+
+ my $file = $util->first_cat_path('ick.txt', @paths);
+ $file = $util->first_cat_path(['this.txt', 'that.txt'], @paths);
+
+The first argument to this method may be either a file or directory base name
+(that is, a file or directory name without a full path specification), or a
+reference to an array of file or directory base names. The remaining arguments
+constitute a list of directory paths. C<first_cat_path()> processes each of
+these directory paths, concatenates (by the method native to the local
+operating system) each of the file or directory base names, and returns the
+first one that exists on the file system.
+
+For example, let us say that we were looking for a file called either F<httpd>
+or F<apache>, and it could be in any of the following paths:
+F</usr/local/bin>, F</usr/bin/>, F</bin>. The method call looks like this:
+
+ my $httpd = $util->first_cat_path(['httpd', 'apache'], '/usr/local/bin',
+ '/usr/bin/', '/bin');
+
+If the OS is a Unix variant, C<first_cat_path()> will then look for the first
+file that exists in this order:
+
+=over 4
+
+=item /usr/local/bin/httpd
+
+=item /usr/local/bin/apache
+
+=item /usr/bin/httpd
+
+=item /usr/bin/apache
+
+=item /bin/httpd
+
+=item /bin/apache
+
+=back
+
+The first of these complete paths to be found will be returned. If none are
+found, then undef will be returned.
+
+=cut
+
+sub first_cat_path {
+ my $self = shift;
+ my $files = ref $_[0] ? shift() : [shift()];
+ foreach my $p (@_) {
+ foreach my $f (@$files) {
+ my $path = $self->catfile($p, $f);
+ return $path if -e $path;
+ }
+ }
+ return;
+}
+
+=head2 first_cat_dir
+
+ my $dir = $util->first_cat_dir('ick.txt', @paths);
+ $dir = $util->first_cat_dir(['this.txt', 'that.txt'], @paths);
+
+Funtionally identical to C<first_cat_path()>, except that it returns the
+directory path in which the first file was found, rather than the full
+concatenated path. Thus, in the above example, if the file found was
+F</usr/bin/httpd>, while C<first_cat_path()> would return that value,
+C<first_cat_dir()> would return F</usr/bin> instead.
+
+=cut
+
+sub first_cat_dir {
+ my $self = shift;
+ my $files = ref $_[0] ? shift() : [shift()];
+ foreach my $p (@_) {
+ foreach my $f (@$files) {
+ my $path = $self->catfile($p, $f);
+ return $p if -e $path;
+ }
+ }
+ return;
+}
+
+=head2 first_cat_exe
+
+ my $exe = $util->first_cat_exe('ick.txt', @paths);
+ $exe = $util->first_cat_exe(['this.txt', 'that.txt'], @paths);
+
+Funtionally identical to C<first_cat_path()>, except that it returns the full
+path to the first executable file found, rather than simply the first file
+found.
+
+=cut
+
+sub first_cat_exe {
+ my $self = shift;
+ my $files = ref $_[0] ? shift() : [shift()];
+ foreach my $p (@_) {
+ foreach my $f (@$files) {
+ my $path = $self->catfile($p, $f);
+ return $path if -f $path && -x $path;
+ }
+ }
+ return;
+}
+
+=head2 search_file
+
+ my $file = 'foo.txt';
+ my $regex = qr/(text\s+to\s+find)/;
+ my $value = $util->search_file($file, $regex);
+
+Opens C<$file> and executes the C<$regex> regular expression against each line
+in the file. Once the line matches and one or more values is returned by the
+match, the file is closed and the value or values returned.
+
+For example, say F<foo.txt> contains the line "Version 6.5, patch level 8",
+and you need to grab each of the three version parts. All three parts can
+be grabbed like this:
+
+ my $regex = qr/Version\s+(\d+)\.(\d+),[^\d]*(\d+)/;
+ my @nums = $util->search_file($file, $regex);
+
+Now C<@nums> will contain the values C<(6, 5, 8)>. Note that in a scalar
+context, the above search would yeild an array reference:
+
+ my $regex = qr/Version\s+(\d+)\.(\d+),[^\d]*(\d+)/;
+ my $nums = $util->search_file($file, $regex);
+
+So now C<$nums> contains C<[6, 5, 8]>. The same does not hold true if the
+match returns only one value, however. Say F<foo.txt> contains the line
+"king of the who?", and you wish to know who the king is king of. Either
+of the following two calls would get you the data you need:
+
+ my $minions = $util->search_file($file, qr/King\s+of\s+(.*)/);
+ my @minions = $util->search_file($file, qr/King\s+of\s+(.*)/);
+
+In the first case, because the regular expression contains only one set of
+parentheses, C<search_file()> will simply return that value: C<$minions>
+contains the string "the who?". In the latter case, C<@minions> of course
+contains a single element: C<("the who?")>.
+
+Note that a regular expression without parentheses -- that is, one that
+doesn't grab values and put them into $1, $2, etc., will never successfully
+match a line in this method. You must include something to parentetically
+match. If you just want to know the value of what was matched, parenthesize
+the whole thing and if the value returns, you have a match. Also, if you need
+to match patterns across lines, try using multiple regular expressions with
+C<multi_search_file()>, instead.
+
+=cut
+
+sub search_file {
+ my ($self, $file, $regex) = @_;
+ return unless $file && $regex;
+ open F, "<$file" or Carp::croak "Cannot open $file: $!\n";
+ my @ret;
+ while (<F>) {
+ # If we find a match, we're done.
+ (@ret) = /$regex/ and last;
+ }
+ close F;
+ # If the match returned an more than one value, always return the full
+ # array. Otherwise, return just the first value in a scalar context.
+ return unless @ret;
+ return wantarray ? @ret : $#ret <= 0 ? $ret[0] : \@ret;
+}
+
+=head2 multi_search_file
+
+ my @regexen = (qr/(one)/, qr/(two)\s+(three)/);
+ my @matches = $util->multi_search_file($file, @regexen);
+
+Like C<search_file()>, this mehod opens C<$file> and parses it for regular
+expresion matches. This method, however, can take a list of regular
+expressions to look for, and will return the values found for all of them.
+Regular expressions that match and return multiple values will be returned as
+array referernces, while those that match and return a single value will
+return just that single value.
+
+For example, say you are parsing a file with lines like the following:
+
+ #define XML_MAJOR_VERSION 1
+ #define XML_MINOR_VERSION 95
+ #define XML_MICRO_VERSION 2
+
+You need to get each of these numbers, but calling C<search_file()> for each
+of them would be wasteful, as each call to C<search_file()> opens the file and
+parses it. With C<multi_search_file()>, on the other hand, the file will be
+opened only once, and, once all of the regular expressions have returned
+matches, the file will be closed and the matches returned.
+
+Thus the above values can be collected like this:
+
+ my @regexen = ( qr/XML_MAJOR_VERSION\s+(\d+)$/,
+ qr/XML_MINOR_VERSION\s+(\d+)$/,
+ qr/XML_MICRO_VERSION\s+(\d+)$/ );
+
+ my @nums = $file->multi_search_file($file, @regexen);
+
+The result will be that C<@nums> contains C<(1, 95, 2)>. Note that
+C<multi_file_search()> tries to do the right thing by only parsing the file
+until all of the regular expressions have been matched. Thus, a large file
+with the values you need near the top can be parsed very quickly.
+
+As with C<search_file()>, C<multi_search_file()> can take regular expressions
+that match multiple values. These will be returned as array references. For
+example, say the file you're parsing has files like this:
+
+ FooApp Version 4
+ Subversion 2, Microversion 6
+
+To get all of the version numbers, you can either use three regular
+expressions, as in the previous example:
+
+ my @regexen = ( qr/FooApp\s+Version\s+(\d+)$/,
+ qr/Subversion\s+(\d+),/,
+ qr/Microversion\s+(\d$)$/ );
+
+ my @nums = $file->multi_search_file($file, @regexen);
+
+In which case C<@nums> will contain C<(4, 2, 6)>. Or, you can use just two
+regular expressions:
+
+ my @regexen = ( qr/FooApp\s+Version\s+(\d+)$/,
+ qr/Subversion\s+(\d+),\s+Microversion\s+(\d$)$/ );
+
+ my @nums = $file->multi_search_file($file, @regexen);
+
+In which case C<@nums> will contain C<(4, [2, 6])>. Note that the two
+parentheses that return values in the second regular expression cause the
+matches to be returned as an array reference.
+
+=cut
+
+sub multi_search_file {
+ my ($self, $file, @regexen) = @_;
+ return unless $file && @regexen;
+ my @each = @regexen;
+ open F, "<$file" or Carp::croak "Cannot open $file: $!\n";
+ my %ret;
+ while (my $line = <F>) {
+ my @splice;
+ # Process each of the regular expresssions.
+ for (my $i = 0; $i < @each; $i++) {
+ if ((my @ret) = $line =~ /$each[$i]/) {
+ # We have a match! If there's one match returned, just grab
+ # it. If there's more than one, keep it as an array ref.
+ $ret{$each[$i]} = $#ret > 0 ? \@ret : $ret[0];
+ # We got values for this regex, so not its place in the @each
+ # array.
+ push @splice, $i;
+ }
+ }
+ # Remove any regexen that have already found a match.
+ for (@splice) { splice @each, $_, 1 }
+ # If there are no more regexes, we're done -- no need to keep
+ # processing lines in the file!
+ last unless @each;
+ }
+ close F;
+ return unless %ret;
+ return wantarray ? @ret{@regexen} : \@ret{@regexen};
+}
+
+1;
+__END__
+
+=head1 BUGS
+
+Report all bugs via the CPAN Request Tracker at
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Info>.
+
+=head1 AUTHOR
+
+David Wheeler <L<david@wheeler.net|"david@wheeler.net">>
+
+=head1 SEE ALSO
+
+L<App::Info|App::Info>, L<File::Spec|File::Spec>,
+L<App::Info::HTTPD::Apache|App::Info::HTTPD::Apache>
+L<App::Info::RDBMS::PostgreSQL|App::Info::RDBMS::PostgreSQL>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2002, David Wheeler. All Rights Reserved.
+
+This module is free software; you can redistribute it and/or modify it under the
+same terms as Perl itself.
+
+=cut
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/Changes b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/Changes
new file mode 100644
index 0000000..f413bd9
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/Changes
@@ -0,0 +1,62 @@
+Revision history for Perl extension DBIx::DBSchema.
+
+0.23 Mon Feb 16 17:35:54 PST 2004
+ - Update Pg dependancy to 1.32
+ - Update the simple load test so it skips DBIx::DBSchema::DBD::Pg if
+ DBD::Pg 1.32 is not installed.
+
+0.22 Thu Oct 23 15:18:21 PDT 2003
+ - Pg reverse-engineering fix: varchar with no limit
+ - Pg needs (unreleased) DBD::Pg 1.30 (or deb 1.22-2... interesting)
+
+0.21 Thu Sep 19 05:04:18 PDT 2002
+ - Pg reverse-engineering fix: now sets default
+
+0.20 Mon Mar 4 04:58:34 2002
+ - documentation updates
+ - fix Column->new when using named params
+ - fix Pg driver reverse-engineering length of numeric columns:
+ translate 655362 to 10,2, etc.
+ - fix Pg driver reverse-engineering of text columns (don't have a
+ length)
+
+0.19 Tue Oct 23 08:49:12 2001
+ - documentation for %typemap
+ - preliminary Sybase driver from Charles Shapiro
+ <charles.shapiro@numethods.com> and Mitchell J. Friedman
+ <mitchell.friedman@numethods.com>.
+ - Fix Column::line to return a scalar as documented, not a list.
+ - Should finally eliminate the Use of uninitialized value at
+ ... DBIx/DBSchema/Column.pm line 251
+
+0.18 Fri Aug 10 17:07:28 2001
+ - Added Table::delcolumn
+ - patch from Charles Shapiro <cshapiro@numethods.com> to add
+ `ORDER BY a.attnum' to the SQL in DBIx::DBSchema::DBD::Pg::columns
+
+0.17 Sat Jul 7 17:55:33 2001
+ - Rework Table->new interface for named params
+ - Fixes for Pg blobs, yay!
+ - MySQL doesn't need non-standard index syntax anymore (since 3.22).
+ - patch from Mark Ethan Trostler <mark@zzo.com> for generating
+ tables without indices.
+
+0.16 Fri Jan 5 15:55:50 2001
+ - Don't overflow index names.
+
+0.15 Fri Nov 24 23:39:16 2000
+ - MySQL handling of BOOL type (change to TINYINT)
+
+0.14 Tue Oct 24 14:43:16 2000
+ - MySQL handling of SERIAL type (change to INTEGER AUTO_INCREMENT)
+
+0.13 Wed Oct 11 10:47:13 2000
+ - fixed up type mapping foo, added default values, added named
+ parameters to Column->new, fixed quoting of default values
+
+0.11 Sun Sep 28 02:16:25 2000
+ - oops, original verison got 0.10, so this one will get 0.11
+
+0.01 Sun Sep 17 07:57:35 2000
+ - original version; created by h2xs 1.19
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema.pm
new file mode 100644
index 0000000..fc4916d
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema.pm
@@ -0,0 +1,367 @@
+package DBIx::DBSchema;
+
+use strict;
+use vars qw(@ISA $VERSION);
+#use Exporter;
+use Carp qw(confess);
+use DBI;
+use FreezeThaw qw(freeze thaw cmpStr);
+use DBIx::DBSchema::Table;
+use DBIx::DBSchema::Column;
+use DBIx::DBSchema::ColGroup::Unique;
+use DBIx::DBSchema::ColGroup::Index;
+
+#@ISA = qw(Exporter);
+@ISA = ();
+
+$VERSION = "0.23";
+
+=head1 NAME
+
+DBIx::DBSchema - Database-independent schema objects
+
+=head1 SYNOPSIS
+
+ use DBIx::DBSchema;
+
+ $schema = new DBIx::DBSchema @dbix_dbschema_table_objects;
+ $schema = new_odbc DBIx::DBSchema $dbh;
+ $schema = new_odbc DBIx::DBSchema $dsn, $user, $pass;
+ $schema = new_native DBIx::DBSchema $dbh;
+ $schema = new_native DBIx::DBSchema $dsn, $user, $pass;
+
+ $schema->save("filename");
+ $schema = load DBIx::DBSchema "filename";
+
+ $schema->addtable($dbix_dbschema_table_object);
+
+ @table_names = $schema->tables;
+
+ $DBIx_DBSchema_table_object = $schema->table("table_name");
+
+ @sql = $schema->sql($dbh);
+ @sql = $schema->sql($dsn, $username, $password);
+ @sql = $schema->sql($dsn); #doesn't connect to database - less reliable
+
+ $perl_code = $schema->pretty_print;
+ %hash = eval $perl_code;
+ use DBI qw(:sql_types); $schema = pretty_read DBIx::DBSchema \%hash;
+
+=head1 DESCRIPTION
+
+DBIx::DBSchema objects are collections of DBIx::DBSchema::Table objects and
+represent a database schema.
+
+This module implements an OO-interface to database schemas. Using this module,
+you can create a database schema with an OO Perl interface. You can read the
+schema from an existing database. You can save the schema to disk and restore
+it a different process. Most importantly, DBIx::DBSchema can write SQL
+CREATE statements statements for different databases from a single source.
+
+Currently supported databases are MySQL and PostgreSQL. Sybase support is
+partially implemented. DBIx::DBSchema will attempt to use generic SQL syntax
+for other databases. Assistance adding support for other databases is
+welcomed. See L<DBIx::DBSchema::DBD>, "Driver Writer's Guide and Base Class".
+
+=head1 METHODS
+
+=over 4
+
+=item new TABLE_OBJECT, TABLE_OBJECT, ...
+
+Creates a new DBIx::DBSchema object.
+
+=cut
+
+sub new {
+ my($proto, @tables) = @_;
+ my %tables = map { $_->name, $_ } @tables; #check for duplicates?
+
+ my $class = ref($proto) || $proto;
+ my $self = {
+ 'tables' => \%tables,
+ };
+
+ bless ($self, $class);
+
+}
+
+=item new_odbc DATABASE_HANDLE | DATA_SOURCE USERNAME PASSWORD [ ATTR ]
+
+Creates a new DBIx::DBSchema object from an existing data source, which can be
+specified by passing an open DBI database handle, or by passing the DBI data
+source name, username, and password. This uses the experimental DBI type_info
+method to create a schema with standard (ODBC) SQL column types that most
+closely correspond to any non-portable column types. Use this to import a
+schema that you wish to use with many different database engines. Although
+primary key and (unique) index information will only be read from databases
+with DBIx::DBSchema::DBD drivers (currently MySQL and PostgreSQL), import of
+column names and attributes *should* work for any database. Note that this
+method only uses "ODBC" column types; it does not require or use an ODBC
+driver.
+
+=cut
+
+sub new_odbc {
+ my($proto, $dbh) = (shift, shift);
+ $dbh = DBI->connect( $dbh, @_ ) or die $DBI::errstr unless ref($dbh);
+ $proto->new(
+ map { new_odbc DBIx::DBSchema::Table $dbh, $_ } _tables_from_dbh($dbh)
+ );
+}
+
+=item new_native DATABASE_HANDLE | DATA_SOURCE USERNAME PASSWORD [ ATTR ]
+
+Creates a new DBIx::DBSchema object from an existing data source, which can be
+specified by passing an open DBI database handle, or by passing the DBI data
+source name, username and password. This uses database-native methods to read
+the schema, and will preserve any non-portable column types. The method is
+only available if there is a DBIx::DBSchema::DBD for the corresponding database engine (currently, MySQL and PostgreSQL).
+
+=cut
+
+sub new_native {
+ my($proto, $dbh) = (shift, shift);
+ $dbh = DBI->connect( $dbh, @_ ) or die $DBI::errstr unless ref($dbh);
+ $proto->new(
+ map { new_native DBIx::DBSchema::Table ( $dbh, $_ ) } _tables_from_dbh($dbh)
+ );
+}
+
+=item load FILENAME
+
+Loads a DBIx::DBSchema object from a file.
+
+=cut
+
+sub load {
+ my($proto,$file)=@_; #use $proto ?
+ open(FILE,"<$file") or die "Can't open $file: $!";
+ my($string)=join('',<FILE>); #can $string have newlines? pry not?
+ close FILE or die "Can't close $file: $!";
+ my($self)=thaw $string;
+ #no bless needed?
+ $self;
+}
+
+=item save FILENAME
+
+Saves a DBIx::DBSchema object to a file.
+
+=cut
+
+sub save {
+ my($self,$file)=@_;
+ my($string)=freeze $self;
+ open(FILE,">$file") or die "Can't open $file: $!";
+ print FILE $string;
+ close FILE or die "Can't close file: $!";
+ my($check_self)=thaw $string;
+ die "Verify error: Can't freeze and thaw dbdef $self"
+ if (cmpStr($self,$check_self));
+}
+
+=item addtable TABLE_OBJECT
+
+Adds the given DBIx::DBSchema::Table object to this DBIx::DBSchema.
+
+=cut
+
+sub addtable {
+ my($self,$table)=@_;
+ $self->{'tables'}->{$table->name} = $table; #check for dupliates?
+}
+
+=item tables
+
+Returns a list of the names of all tables.
+
+=cut
+
+sub tables {
+ my($self)=@_;
+ keys %{$self->{'tables'}};
+}
+
+=item table TABLENAME
+
+Returns the specified DBIx::DBSchema::Table object.
+
+=cut
+
+sub table {
+ my($self,$table)=@_;
+ $self->{'tables'}->{$table};
+}
+
+=item sql [ DATABASE_HANDLE | DATA_SOURCE [ USERNAME PASSWORD [ ATTR ] ] ]
+
+Returns a list of SQL `CREATE' statements for this schema.
+
+The data source can be specified by passing an open DBI database handle, or by
+passing the DBI data source name, username and password.
+
+Although the username and password are optional, it is best to call this method
+with a database handle or data source including a valid username and password -
+a DBI connection will be opened and the quoting and type mapping will be more
+reliable.
+
+If passed a DBI data source (or handle) such as `DBI:mysql:database' or
+`DBI:Pg:dbname=database', will use syntax specific to that database engine.
+Currently supported databases are MySQL and PostgreSQL.
+
+If not passed a data source (or handle), or if there is no driver for the
+specified database, will attempt to use generic SQL syntax.
+
+=cut
+
+sub sql {
+ my($self, $dbh) = (shift, shift);
+ my $created_dbh = 0;
+ unless ( ref($dbh) || ! @_ ) {
+ $dbh = DBI->connect( $dbh, @_ ) or die $DBI::errstr;
+ $created_dbh = 1;
+ }
+ my @r = map { $self->table($_)->sql_create_table($dbh); } $self->tables;
+ $dbh->disconnect if $created_dbh;
+ @r;
+}
+
+=item pretty_print
+
+Returns the data in this schema as Perl source, suitable for assigning to a
+hash.
+
+=cut
+
+sub pretty_print {
+ my($self) = @_;
+ join("},\n\n",
+ map {
+ my $table = $_;
+ "'$table' => {\n".
+ " 'columns' => [\n".
+ join("", map {
+ #cant because -w complains about , in qw()
+ # (also biiiig problems with empty lengths)
+ #" qw( $_ ".
+ #$self->table($table)->column($_)->type. " ".
+ #( $self->table($table)->column($_)->null ? 'NULL' : 0 ). " ".
+ #$self->table($table)->column($_)->length. " ),\n"
+ " '$_', ".
+ "'". $self->table($table)->column($_)->type. "', ".
+ "'". $self->table($table)->column($_)->null. "', ".
+ "'". $self->table($table)->column($_)->length. "', ".
+ "'". $self->table($table)->column($_)->default. "', ".
+ "'". $self->table($table)->column($_)->local. "',\n"
+ } $self->table($table)->columns
+ ).
+ " ],\n".
+ " 'primary_key' => '". $self->table($table)->primary_key. "',\n".
+ " 'unique' => [ ". join(', ',
+ map { "[ '". join("', '", @{$_}). "' ]" }
+ @{$self->table($table)->unique->lol_ref}
+ ). " ],\n".
+ " 'index' => [ ". join(', ',
+ map { "[ '". join("', '", @{$_}). "' ]" }
+ @{$self->table($table)->index->lol_ref}
+ ). " ],\n"
+ #" 'index' => [ ". " ],\n"
+ } $self->tables
+ ), "}\n";
+}
+
+=cut
+
+=item pretty_read HASHREF
+
+Creates a schema as specified by a data structure such as that created by
+B<pretty_print> method.
+
+=cut
+
+sub pretty_read {
+ my($proto, $href) = @_;
+ my $schema = $proto->new( map {
+ my(@columns);
+ while ( @{$href->{$_}{'columns'}} ) {
+ push @columns, DBIx::DBSchema::Column->new(
+ splice @{$href->{$_}{'columns'}}, 0, 6
+ );
+ }
+ DBIx::DBSchema::Table->new(
+ $_,
+ $href->{$_}{'primary_key'},
+ DBIx::DBSchema::ColGroup::Unique->new($href->{$_}{'unique'}),
+ DBIx::DBSchema::ColGroup::Index->new($href->{$_}{'index'}),
+ @columns,
+ );
+ } (keys %{$href}) );
+}
+
+# private subroutines
+
+sub _load_driver {
+ my($dbh) = @_;
+ my $driver;
+ if ( ref($dbh) ) {
+ $driver = $dbh->{Driver}->{Name};
+ } else {
+ $dbh =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i #nicked from DBI->connect
+ or '' =~ /()/; # ensure $1 etc are empty if match fails
+ $driver = $1 or confess "can't parse data source: $dbh";
+ }
+
+ #require "DBIx/DBSchema/DBD/$driver.pm";
+ #$driver;
+ eval 'require "DBIx/DBSchema/DBD/$driver.pm"' and $driver or die $@;
+}
+
+sub _tables_from_dbh {
+ my($dbh) = @_;
+ my $sth = $dbh->table_info or die $dbh->errstr;
+ #map { $_->{TABLE_NAME} } grep { $_->{TABLE_TYPE} eq 'TABLE' }
+ # @{ $sth->fetchall_arrayref({ TABLE_NAME=>1, TABLE_TYPE=>1}) };
+ map { $_->[0] } grep { $_->[1] =~ /^TABLE$/i }
+ @{ $sth->fetchall_arrayref([2,3]) };
+}
+
+=back
+
+=head1 AUTHOR
+
+Ivan Kohler <ivan-dbix-dbschema@420.am>
+
+Charles Shapiro <charles.shapiro@numethods.com> and Mitchell Friedman
+<mitchell.friedman@numethods.com> contributed the start of a Sybase driver.
+
+=head1 COPYRIGHT
+
+Copyright (c) 2000 Ivan Kohler
+Copyright (c) 2000 Mail Abuse Prevention System LLC
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 BUGS
+
+Each DBIx::DBSchema object should have a name which corresponds to its name
+within the SQL database engine (DBI data source).
+
+pretty_print is actually pretty ugly.
+
+Perhaps pretty_read should eval column types so that we can use DBI
+qw(:sql_types) here instead of externally.
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema::Table>, L<DBIx::DBSchema::ColGroup>,
+L<DBIx::DBSchema::ColGroup::Unique>, L<DBIx::DBSchema::ColGroup::Index>,
+L<DBIx::DBSchema::Column>, L<DBIx::DBSchema::DBD>,
+L<DBIx::DBSchema::DBD::mysql>, L<DBIx::DBSchema::DBD::Pg>, L<FS::Record>,
+L<DBI>
+
+=cut
+
+1;
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup.pm
new file mode 100644
index 0000000..ceeb223
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup.pm
@@ -0,0 +1,141 @@
+package DBIx::DBSchema::ColGroup;
+
+use strict;
+use vars qw(@ISA);
+#use Exporter;
+
+#@ISA = qw(Exporter);
+@ISA = qw();
+
+=head1 NAME
+
+DBIx::DBSchema::ColGroup - Column group objects
+
+=head1 SYNOPSIS
+
+ use DBIx::DBSchema::ColGroup;
+
+ $colgroup = new DBIx::DBSchema::ColGroup ( $lol_ref );
+ $colgroup = new DBIx::DBSchema::ColGroup ( \@lol );
+ $colgroup = new DBIx::DBSchema::ColGroup (
+ [
+ [ 'single_column' ],
+ [ 'multiple_columns', 'another_column', ],
+ ]
+ );
+
+ $lol_ref = $colgroup->lol_ref;
+
+ @sql_lists = $colgroup->sql_list;
+
+ @singles = $colgroup->singles;
+
+=head1 DESCRIPTION
+
+DBIx::DBSchema::ColGroup objects represent sets of sets of columns. (IOW a
+"list of lists" - see L<perllol>.)
+
+=head1 METHODS
+
+=over 4
+
+=item new [ LOL_REF ]
+
+Creates a new DBIx::DBSchema::ColGroup object. Pass a reference to a list of
+lists of column names.
+
+=cut
+
+sub new {
+ my($proto, $lol) = @_;
+
+ my $class = ref($proto) || $proto;
+ my $self = {
+ 'lol' => $lol,
+ };
+
+ bless ($self, $class);
+
+}
+
+=item lol_ref
+
+Returns a reference to a list of lists of column names.
+
+=cut
+
+sub lol_ref {
+ my($self) = @_;
+ $self->{'lol'};
+}
+
+=item sql_list
+
+Returns a flat list of comma-separated values, for SQL statements.
+
+For example:
+
+ @lol = (
+ [ 'single_column' ],
+ [ 'multiple_columns', 'another_column', ],
+ );
+
+ $colgroup = new DBIx::DBSchema::ColGroup ( \@lol );
+
+ print join("\n", $colgroup->sql_list), "\n";
+
+Will print:
+
+ single_column
+ multiple_columns, another_column
+
+=cut
+
+sub sql_list { #returns a flat list of comman-separates lists (for sql)
+ my($self)=@_;
+ grep $_ ne '', map join(', ', @{$_}), @{$self->{'lol'}};
+}
+
+=item singles
+
+Returns a flat list of all single item lists.
+
+=cut
+
+sub singles { #returns single-field groups as a flat list
+ my($self)=@_;
+ #map ${$_}[0], grep scalar(@{$_}) == 1, @{$self->{'lol'}};
+ map {
+ ${$_}[0] =~ /^(\w+)$/
+ #aah!
+ or die "Illegal column ", ${$_}[0], " in colgroup!";
+ $1;
+ } grep scalar(@{$_}) == 1, @{$self->{'lol'}};
+}
+
+=back
+
+=head1 AUTHOR
+
+Ivan Kohler <ivan-dbix-dbschema@420.am>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2000 Ivan Kohler
+Copyright (c) 2000 Mail Abuse Prevention System LLC
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema::Table>, L<DBIx::DBSchema::ColGroup::Unique>,
+L<DBIx::DBSchema::ColGroup::Index>, L<DBIx::DBSchema>, L<perllol>, L<perldsc>,
+L<DBI>
+
+=cut
+
+1;
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Index.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Index.pm
new file mode 100644
index 0000000..1a92baa
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Index.pm
@@ -0,0 +1,37 @@
+package DBIx::DBSchema::ColGroup::Index;
+
+use strict;
+use vars qw(@ISA);
+use DBIx::DBSchema::ColGroup;
+
+@ISA=qw(DBIx::DBSchema::ColGroup);
+
+=head1 NAME
+
+DBIx::DBSchema::ColGroup::Index - Index column group object
+
+=head1 SYNOPSIS
+
+ use DBIx::DBSchema::ColGroup::Index;
+
+ # see DBIx::DBSchema::ColGroup methods
+
+=head1 DESCRIPTION
+
+DBIx::DBSchema::ColGroup::Index objects represent the (non-unique) indices of a
+database table (L<DBIx::DBSchema::Table>). DBIx::DBSchema::ColGroup::Index
+inherits from DBIx::DBSchema::ColGroup.
+
+=head1 BUGS
+
+Is this empty subclass needed?
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema::ColGroup>, L<DBIx::DBSchema::ColGroup::Unique>,
+L<DBIx::DBSchema::Table>, L<DBIx::DBSchema>, L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Unique.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Unique.pm
new file mode 100644
index 0000000..450043f
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Unique.pm
@@ -0,0 +1,38 @@
+package DBIx::DBSchema::ColGroup::Unique;
+
+use strict;
+use vars qw(@ISA);
+use DBIx::DBSchema::ColGroup;
+
+@ISA=qw(DBIx::DBSchema::ColGroup);
+
+=head1 NAME
+
+DBIx::DBSchema::ColGroup::Unique - Unique column group object
+
+=head1 SYNOPSIS
+
+ use DBIx::DBSchema::ColGroup::Unique;
+
+ # see DBIx::DBSchema::ColGroup methods
+
+=head1 DESCRIPTION
+
+DBIx::DBSchema::ColGroup::Unique objects represent the unique indices of a
+database table (L<DBIx::DBSchema::Table>). DBIx::DBSchema::ColGroup:Unique
+inherits from DBIx::DBSchema::ColGroup.
+
+=head1 BUGS
+
+Is this empty subclass needed?
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema::ColGroup>, L<DBIx::DBSchema::ColGroup::Index>,
+L<DBIx::DBSchema::Table>, L<DBIx::DBSchema>, L<FS::Record>
+
+=cut
+
+1;
+
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/Column.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/Column.pm
new file mode 100644
index 0000000..4e26646
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/Column.pm
@@ -0,0 +1,300 @@
+package DBIx::DBSchema::Column;
+
+use strict;
+use vars qw(@ISA $VERSION);
+#use Carp;
+#use Exporter;
+
+#@ISA = qw(Exporter);
+@ISA = qw();
+
+$VERSION = '0.02';
+
+=head1 NAME
+
+DBIx::DBSchema::Column - Column objects
+
+=head1 SYNOPSIS
+
+ use DBIx::DBSchema::Column;
+
+ #named params with a hashref (preferred)
+ $column = new DBIx::DBSchema::Column ( {
+ 'name' => 'column_name',
+ 'type' => 'varchar'
+ 'null' => 'NOT NULL',
+ 'length' => 64,
+ 'default' => '
+ 'local' => '',
+ } );
+
+ #list
+ $column = new DBIx::DBSchema::Column ( $name, $sql_type, $nullability, $length, $default, $local );
+
+ $name = $column->name;
+ $column->name( 'name' );
+
+ $sql_type = $column->type;
+ $column->type( 'sql_type' );
+
+ $null = $column->null;
+ $column->null( 'NULL' );
+ $column->null( 'NOT NULL' );
+ $column->null( '' );
+
+ $length = $column->length;
+ $column->length( '10' );
+ $column->length( '8,2' );
+
+ $default = $column->default;
+ $column->default( 'Roo' );
+
+ $sql_line = $column->line;
+ $sql_line = $column->line($datasrc);
+
+=head1 DESCRIPTION
+
+DBIx::DBSchema::Column objects represent columns in tables (see
+L<DBIx::DBSchema::Table>).
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+=item new [ name [ , type [ , null [ , length [ , default [ , local ] ] ] ] ] ]
+
+Creates a new DBIx::DBSchema::Column object. Takes a hashref of named
+parameters, or a list. B<name> is the name of the column. B<type> is the SQL
+data type. B<null> is the nullability of the column (intrepreted using Perl's
+rules for truth, with one exception: `NOT NULL' is false). B<length> is the
+SQL length of the column. B<default> is the default value of the column.
+B<local> is reserved for database-specific information.
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+
+ my $self;
+ if ( ref($_[0]) ) {
+ $self = shift;
+ } else {
+ $self = { map { $_ => shift } qw(name type null length default local) };
+ }
+
+ #croak "Illegal name: ". $self->{'name'}
+ # if grep $self->{'name'} eq $_, @reserved_words;
+
+ $self->{'null'} =~ s/^NOT NULL$//i;
+ $self->{'null'} = 'NULL' if $self->{'null'};
+
+ bless ($self, $class);
+
+}
+
+=item name [ NAME ]
+
+Returns or sets the column name.
+
+=cut
+
+sub name {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ #croak "Illegal name: $name" if grep $name eq $_, @reserved_words;
+ $self->{'name'} = $value;
+ } else {
+ $self->{'name'};
+ }
+}
+
+=item type [ TYPE ]
+
+Returns or sets the column type.
+
+=cut
+
+sub type {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ $self->{'type'} = $value;
+ } else {
+ $self->{'type'};
+ }
+}
+
+=item null [ NULL ]
+
+Returns or sets the column null flag (the empty string is equivalent to
+`NOT NULL')
+
+=cut
+
+sub null {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ $value =~ s/^NOT NULL$//i;
+ $value = 'NULL' if $value;
+ $self->{'null'} = $value;
+ } else {
+ $self->{'null'};
+ }
+}
+
+=item length [ LENGTH ]
+
+Returns or sets the column length.
+
+=cut
+
+sub length {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ $self->{'length'} = $value;
+ } else {
+ $self->{'length'};
+ }
+}
+
+=item default [ LOCAL ]
+
+Returns or sets the default value.
+
+=cut
+
+sub default {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ $self->{'default'} = $value;
+ } else {
+ $self->{'default'};
+ }
+}
+
+
+=item local [ LOCAL ]
+
+Returns or sets the database-specific field.
+
+=cut
+
+sub local {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ $self->{'local'} = $value;
+ } else {
+ $self->{'local'};
+ }
+}
+
+=item line [ DATABASE_HANDLE | DATA_SOURCE [ USERNAME PASSWORD [ ATTR ] ] ]
+
+Returns an SQL column definition.
+
+The data source can be specified by passing an open DBI database handle, or by
+passing the DBI data source name, username and password.
+
+Although the username and password are optional, it is best to call this method
+with a database handle or data source including a valid username and password -
+a DBI connection will be opened and the quoting and type mapping will be more
+reliable.
+
+If passed a DBI data source (or handle) such as `DBI:mysql:database' or
+`DBI:Pg:dbname=database', will use syntax specific to that database engine.
+Currently supported databases are MySQL and PostgreSQL. Non-standard syntax
+for other engines (if applicable) may also be supported in the future.
+
+=cut
+
+sub line {
+ my($self,$dbh) = (shift, shift);
+
+ my $created_dbh = 0;
+ unless ( ref($dbh) || ! @_ ) {
+ $dbh = DBI->connect( $dbh, @_ ) or die $DBI::errstr;
+ my $gratuitous = $DBI::errstr; #surpress superfluous `used only once' error
+ $created_dbh = 1;
+ }
+
+ my $driver = DBIx::DBSchema::_load_driver($dbh);
+ my %typemap;
+ %typemap = eval "\%DBIx::DBSchema::DBD::${driver}::typemap" if $driver;
+ my $type = defined( $typemap{uc($self->type)} )
+ ? $typemap{uc($self->type)}
+ : $self->type;
+
+ my $null = $self->null;
+
+ my $default;
+ if ( defined($self->default) && $self->default ne ''
+ && ref($dbh)
+ # false laziness: nicked from FS::Record::_quote
+ && ( $self->default !~ /^\-?\d+(\.\d+)?$/
+ || $type =~ /(char|binary|blob|text)$/i
+ )
+ ) {
+ $default = $dbh->quote($self->default);
+ } else {
+ $default = $self->default;
+ }
+
+ #this should be a callback into the driver
+ if ( $driver eq 'mysql' ) { #yucky mysql hack
+ $null ||= "NOT NULL";
+ $self->local('AUTO_INCREMENT') if uc($self->type) eq 'SERIAL';
+ } elsif ( $driver eq 'Pg' ) { #yucky Pg hack
+ $null ||= "NOT NULL";
+ $null =~ s/^NULL$//;
+ }
+
+ my $r = join(' ',
+ $self->name,
+ $type. ( ( defined($self->length) && $self->length )
+ ? '('.$self->length.')'
+ : ''
+ ),
+ $null,
+ ( ( defined($default) && $default ne '' )
+ ? 'DEFAULT '. $default
+ : ''
+ ),
+ ( ( $driver eq 'mysql' && defined($self->local) )
+ ? $self->local
+ : ''
+ ),
+ );
+ $dbh->disconnect if $created_dbh;
+ $r;
+
+}
+
+=back
+
+=head1 AUTHOR
+
+Ivan Kohler <ivan-dbix-dbschema@420.am>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2000 Ivan Kohler
+Copyright (c) 2000 Mail Abuse Prevention System LLC
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 BUGS
+
+line() has database-specific foo that probably ought to be abstracted into
+the DBIx::DBSchema:DBD:: modules.
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema::Table>, L<DBIx::DBSchema>, L<DBIx::DBSchema::DBD>, L<DBI>
+
+=cut
+
+1;
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD.pm
new file mode 100644
index 0000000..a4c6000
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD.pm
@@ -0,0 +1,113 @@
+package DBIx::DBSchema::DBD;
+
+use strict;
+use vars qw($VERSION);
+
+$VERSION = '0.02';
+
+=head1 NAME
+
+DBIx::DBSchema::DBD - DBIx::DBSchema Driver Writer's Guide and Base Class
+
+=head1 SYNOPSIS
+
+ perldoc DBIx::DBSchema::DBD
+
+ package DBIx::DBSchema::DBD::FooBase
+ use DBIx::DBSchmea::DBD;
+ @ISA = qw(DBIx::DBSchema::DBD);
+
+=head1 DESCRIPTION
+
+Drivers should be named DBIx::DBSchema::DBD::DatabaseName, where DatabaseName
+is the same as the DBD:: driver for this database. Drivers should implement the
+following class methods:
+
+=over 4
+
+=item columns CLASS DBI_DBH TABLE
+
+Given an active DBI database handle, return a listref of listrefs (see
+L<perllol>), each containing six elements: column name, column type,
+nullability, column length, column default, and a field reserved for
+driver-specific use.
+
+=item column CLASS DBI_DBH TABLE COLUMN
+
+Same as B<columns> above, except return the listref for a single column. You
+can inherit from DBIx::DBSchema::DBD to provide this function.
+
+=cut
+
+sub column {
+ my($proto, $dbh, $table, $column) = @_;
+ #@a = grep { $_->[0] eq $column } @{ $proto->columns( $dbh, $table ) };
+ #$a[0];
+ @{ [
+ grep { $_->[0] eq $column } @{ $proto->columns( $dbh, $table ) }
+ ] }[0]; #force list context on grep, return scalar of first element
+}
+
+=item primary_key CLASS DBI_DBH TABLE
+
+Given an active DBI database handle, return the primary key for the specified
+table.
+
+=item unique CLASS DBI_DBH TABLE
+
+Given an active DBI database handle, return a hashref of unique indices. The
+keys of the hashref are index names, and the values are arrayrefs which point
+a list of column names for each. See L<perldsc/"HASHES OF LISTS"> and
+L<DBIx::DBSchema::ColGroup>.
+
+=item index CLASS DBI_DBH TABLE
+
+Given an active DBI database handle, return a hashref of (non-unique) indices.
+The keys of the hashref are index names, and the values are arrayrefs which
+point a list of column names for each. See L<perldsc/"HASHES OF LISTS"> and
+L<DBIx::DBSchema::ColGroup>.
+
+=back
+
+=head1 TYPE MAPPING
+
+You can define a %typemap array for your driver to map "standard" data
+types to database-specific types. For example, the MySQL TIMESTAMP field
+has non-standard auto-updating semantics; the MySQL DATETIME type is
+what other databases and the ODBC standard call TIMESTAMP, so one of the
+entries in the MySQL %typemap is:
+
+ 'TIMESTAMP' => 'DATETIME',
+
+Another example is the Pg %typemap which maps the standard types BLOB and
+LONG VARBINARY to the Pg-specific BYTEA:
+
+ 'BLOB' => 'BYTEA',
+ 'LONG VARBINARY' => 'BYTEA',
+
+Make sure you use all uppercase-keys.
+
+=head1 AUTHOR
+
+Ivan Kohler <ivan-dbix-dbschema@420.am>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2000 Ivan Kohler
+Copyright (c) 2000 Mail Abuse Prevention System LLC
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema>, L<DBIx::DBSchema::DBD::mysql>, L<DBIx::DBSchema::DBD::Pg>,
+L<DBIx::DBSchema::ColGroup>, L<DBI>, L<DBI::DBD>, L<perllol>,
+L<perldsc/"HASHES OF LISTS">
+
+=cut
+
+1;
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Pg.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Pg.pm
new file mode 100644
index 0000000..018b890
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Pg.pm
@@ -0,0 +1,175 @@
+package DBIx::DBSchema::DBD::Pg;
+
+use strict;
+use vars qw($VERSION @ISA %typemap);
+use DBD::Pg 1.22;
+use DBIx::DBSchema::DBD;
+
+$VERSION = '0.08';
+@ISA = qw(DBIx::DBSchema::DBD);
+
+%typemap = (
+ 'BLOB' => 'BYTEA',
+ 'LONG VARBINARY' => 'BYTEA',
+);
+
+=head1 NAME
+
+DBIx::DBSchema::DBD::Pg - PostgreSQL native driver for DBIx::DBSchema
+
+=head1 SYNOPSIS
+
+use DBI;
+use DBIx::DBSchema;
+
+$dbh = DBI->connect('dbi:Pg:dbname=database', 'user', 'pass');
+$schema = new_native DBIx::DBSchema $dbh;
+
+=head1 DESCRIPTION
+
+This module implements a PostgreSQL-native driver for DBIx::DBSchema.
+
+=cut
+
+sub columns {
+ my($proto, $dbh, $table) = @_;
+ my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
+ SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull,
+ a.atthasdef, a.attnum
+ FROM pg_class c, pg_attribute a, pg_type t
+ WHERE c.relname = '$table'
+ AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid
+ ORDER BY a.attnum
+END
+ $sth->execute or die $sth->errstr;
+
+ map {
+
+ my $default = '';
+ if ( $_->{atthasdef} ) {
+ my $attnum = $_->{attnum};
+ my $d_sth = $dbh->prepare(<<END) or die $dbh->errstr;
+ SELECT substring(d.adsrc for 128) FROM pg_attrdef d, pg_class c
+ WHERE c.relname = '$table' AND c.oid = d.adrelid AND d.adnum = $attnum
+END
+ $d_sth->execute or die $d_sth->errstr;
+
+ $default = $d_sth->fetchrow_arrayref->[0];
+ };
+
+ my $len = '';
+ if ( $_->{attlen} == -1 && $_->{atttypmod} != -1
+ && $_->{typname} ne 'text' ) {
+ $len = $_->{atttypmod} - 4;
+ if ( $_->{typname} eq 'numeric' ) {
+ $len = ($len >> 16). ','. ($len & 0xffff);
+ }
+ }
+
+ my $type = $_->{'typname'};
+ $type = 'char' if $type eq 'bpchar';
+
+ [
+ $_->{'attname'},
+ $type,
+ ! $_->{'attnotnull'},
+ $len,
+ $default,
+ '' #local
+ ];
+
+ } @{ $sth->fetchall_arrayref({}) };
+}
+
+sub primary_key {
+ my($proto, $dbh, $table) = @_;
+ my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
+ SELECT a.attname, a.attnum
+ FROM pg_class c, pg_attribute a, pg_type t
+ WHERE c.relname = '${table}_pkey'
+ AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid
+END
+ $sth->execute or die $sth->errstr;
+ my $row = $sth->fetchrow_hashref or return '';
+ $row->{'attname'};
+}
+
+sub unique {
+ my($proto, $dbh, $table) = @_;
+ my $gratuitous = { map { $_ => [ $proto->_index_fields($dbh, $_ ) ] }
+ grep { $proto->_is_unique($dbh, $_ ) }
+ $proto->_all_indices($dbh, $table)
+ };
+}
+
+sub index {
+ my($proto, $dbh, $table) = @_;
+ my $gratuitous = { map { $_ => [ $proto->_index_fields($dbh, $_ ) ] }
+ grep { ! $proto->_is_unique($dbh, $_ ) }
+ $proto->_all_indices($dbh, $table)
+ };
+}
+
+sub _all_indices {
+ my($proto, $dbh, $table) = @_;
+ my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
+ SELECT c2.relname
+ FROM pg_class c, pg_class c2, pg_index i
+ WHERE c.relname = '$table' AND c.oid = i.indrelid AND i.indexrelid = c2.oid
+END
+ $sth->execute or die $sth->errstr;
+ map { $_->{'relname'} }
+ grep { $_->{'relname'} !~ /_pkey$/ }
+ @{ $sth->fetchall_arrayref({}) };
+}
+
+sub _index_fields {
+ my($proto, $dbh, $index) = @_;
+ my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
+ SELECT a.attname, a.attnum
+ FROM pg_class c, pg_attribute a, pg_type t
+ WHERE c.relname = '$index'
+ AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid
+END
+ $sth->execute or die $sth->errstr;
+ map { $_->{'attname'} } @{ $sth->fetchall_arrayref({}) };
+}
+
+sub _is_unique {
+ my($proto, $dbh, $index) = @_;
+ my $sth = $dbh->prepare(<<END) or die $dbh->errstr;
+ SELECT i.indisunique
+ FROM pg_index i, pg_class c, pg_am a
+ WHERE i.indexrelid = c.oid AND c.relname = '$index' AND c.relam = a.oid
+END
+ $sth->execute or die $sth->errstr;
+ my $row = $sth->fetchrow_hashref or die 'guru meditation #420';
+ $row->{'indisunique'};
+}
+
+=head1 AUTHOR
+
+Ivan Kohler <ivan-dbix-dbschema@420.am>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2000 Ivan Kohler
+Copyright (c) 2000 Mail Abuse Prevention System LLC
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 BUGS
+
+Yes.
+
+columns doesn't return column default information.
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema>, L<DBIx::DBSchema::DBD>, L<DBI>, L<DBI::DBD>
+
+=cut
+
+1;
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Sybase.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Sybase.pm
new file mode 100755
index 0000000..4a74069
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Sybase.pm
@@ -0,0 +1,141 @@
+package DBIx::DBSchema::DBD::Sybase;
+
+use strict;
+use vars qw($VERSION @ISA %typemap);
+use DBIx::DBSchema::DBD;
+
+$VERSION = '0.03';
+@ISA = qw(DBIx::DBSchema::DBD);
+
+%typemap = (
+# 'empty' => 'empty'
+);
+
+=head1 NAME
+
+DBIx::DBSchema::DBD::Sybase - Sybase database driver for DBIx::DBSchema
+
+=head1 SYNOPSIS
+
+use DBI;
+use DBIx::DBSchema;
+
+$dbh = DBI->connect('dbi:Sybase:dbname=database', 'user', 'pass');
+$schema = new_native DBIx::DBSchema $dbh;
+
+=head1 DESCRIPTION
+
+This module implements a Sybase driver for DBIx::DBSchema.
+
+=cut
+
+sub columns {
+ my($proto, $dbh, $table) = @_;
+
+ my $sth = $dbh->prepare("sp_columns \@table_name=$table")
+ or die $dbh->errstr;
+
+ $sth->execute or die $sth->errstr;
+ my @cols = map {
+ [
+ $_->{'column_name'},
+ $_->{'type_name'},
+ ($_->{'nullable'} ? 1 : ''),
+ $_->{'length'},
+ '', #default
+ '' #local
+ ]
+ } @{ $sth->fetchall_arrayref({}) };
+ $sth->finish;
+
+ @cols;
+}
+
+sub primary_key {
+ return("StubbedPrimaryKey");
+}
+
+
+sub unique {
+ my($proto, $dbh, $table) = @_;
+ my $gratuitous = { map { $_ => [ $proto->_index_fields($dbh, $table, $_ ) ] }
+ grep { $proto->_is_unique($dbh, $_ ) }
+ $proto->_all_indices($dbh, $table)
+ };
+}
+
+sub index {
+ my($proto, $dbh, $table) = @_;
+ my $gratuitous = { map { $_ => [ $proto->_index_fields($dbh, $table, $_ ) ] }
+ grep { ! $proto->_is_unique($dbh, $_ ) }
+ $proto->_all_indices($dbh, $table)
+ };
+}
+
+sub _all_indices {
+ my($proto, $dbh, $table) = @_;
+
+ my $sth = $dbh->prepare_cached(<<END) or die $dbh->errstr;
+ SELECT name
+ FROM sysindexes
+ WHERE id = object_id('$table') and indid between 1 and 254
+END
+ $sth->execute or die $sth->errstr;
+ my @indices = map { $_->[0] } @{ $sth->fetchall_arrayref() };
+ $sth->finish;
+ $sth = undef;
+ @indices;
+}
+
+sub _index_fields {
+ my($proto, $dbh, $table, $index) = @_;
+
+ my @keys;
+
+ my ($indid) = $dbh->selectrow_array("select indid from sysindexes where id = object_id('$table') and name = '$index'");
+ for (1..30) {
+ push @keys, $dbh->selectrow_array("select index_col('$table', $indid, $_)") || ();
+ }
+
+ return @keys;
+}
+
+sub _is_unique {
+ my($proto, $dbh, $table, $index) = @_;
+
+ my ($isunique) = $dbh->selectrow_array("select status & 2 from sysindexes where id = object_id('$table') and name = '$index'");
+
+ return $isunique;
+}
+
+=head1 AUTHOR
+
+Charles Shapiro <charles.shapiro@numethods.com>
+(courtesy of Ivan Kohler <ivan-dbix-dbschema@420.am>)
+
+Mitchell Friedman <mitchell.friedman@numethods.com>
+
+Bernd Dulfer <bernd@widd.de>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2001 Charles Shapiro, Mitchell J. Friedman
+Copyright (c) 2001 nuMethods LLC.
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 BUGS
+
+Yes.
+
+The B<primary_key> method does not yet work.
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema>, L<DBIx::DBSchema::DBD>, L<DBI>, L<DBI::DBD>
+
+=cut
+
+1;
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/mysql.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/mysql.pm
new file mode 100644
index 0000000..f3804dd
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/mysql.pm
@@ -0,0 +1,126 @@
+package DBIx::DBSchema::DBD::mysql;
+
+use strict;
+use vars qw($VERSION @ISA %typemap);
+use DBIx::DBSchema::DBD;
+
+$VERSION = '0.03';
+@ISA = qw(DBIx::DBSchema::DBD);
+
+%typemap = (
+ 'TIMESTAMP' => 'DATETIME',
+ 'SERIAL' => 'INTEGER',
+ 'BOOL' => 'TINYINT',
+ 'LONG VARBINARY' => 'LONGBLOB',
+);
+
+=head1 NAME
+
+DBIx::DBSchema::DBD::mysql - MySQL native driver for DBIx::DBSchema
+
+=head1 SYNOPSIS
+
+use DBI;
+use DBIx::DBSchema;
+
+$dbh = DBI->connect('dbi:mysql:database', 'user', 'pass');
+$schema = new_native DBIx::DBSchema $dbh;
+
+=head1 DESCRIPTION
+
+This module implements a MySQL-native driver for DBIx::DBSchema.
+
+=cut
+
+sub columns {
+ my($proto, $dbh, $table ) = @_;
+ my $sth = $dbh->prepare("SHOW COLUMNS FROM $table") or die $dbh->errstr;
+ $sth->execute or die $sth->errstr;
+ map {
+ $_->{'Type'} =~ /^(\w+)\(?([\d\,]+)?\)?( unsigned)?$/
+ or die "Illegal type: ". $_->{'Type'}. "\n";
+ my($type, $length) = ($1, $2);
+ [
+ $_->{'Field'},
+ $type,
+ $_->{'Null'},
+ $length,
+ $_->{'Default'},
+ $_->{'Extra'}
+ ]
+ } @{ $sth->fetchall_arrayref( {} ) };
+}
+
+#sub primary_key {
+# my($proto, $dbh, $table ) = @_;
+# my $primary_key = '';
+# my $sth = $dbh->prepare("SHOW INDEX FROM $table")
+# or die $dbh->errstr;
+# $sth->execute or die $sth->errstr;
+# my @pkey = map { $_->{'Column_name'} } grep {
+# $_->{'Key_name'} eq "PRIMARY"
+# } @{ $sth->fetchall_arrayref( {} ) };
+# scalar(@pkey) ? $pkey[0] : '';
+#}
+
+sub primary_key {
+ my($proto, $dbh, $table) = @_;
+ my($pkey, $unique_href, $index_href) = $proto->_show_index($dbh, $table);
+ $pkey;
+}
+
+sub unique {
+ my($proto, $dbh, $table) = @_;
+ my($pkey, $unique_href, $index_href) = $proto->_show_index($dbh, $table);
+ $unique_href;
+}
+
+sub index {
+ my($proto, $dbh, $table) = @_;
+ my($pkey, $unique_href, $index_href) = $proto->_show_index($dbh, $table);
+ $index_href;
+}
+
+sub _show_index {
+ my($proto, $dbh, $table ) = @_;
+ my $sth = $dbh->prepare("SHOW INDEX FROM $table")
+ or die $dbh->errstr;
+ $sth->execute or die $sth->errstr;
+
+ my $pkey = '';
+ my(%index, %unique);
+ foreach my $row ( @{ $sth->fetchall_arrayref({}) } ) {
+ if ( $row->{'Key_name'} eq 'PRIMARY' ) {
+ $pkey = $row->{'Column_name'};
+ } elsif ( $row->{'Non_unique'} ) { #index
+ push @{ $index{ $row->{'Key_name'} } }, $row->{'Column_name'};
+ } else { #unique
+ push @{ $unique{ $row->{'Key_name'} } }, $row->{'Column_name'};
+ }
+ }
+
+ ( $pkey, \%unique, \%index );
+}
+
+=head1 AUTHOR
+
+Ivan Kohler <ivan-dbix-dbschema@420.am>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2000 Ivan Kohler
+Copyright (c) 2000 Mail Abuse Prevention System LLC
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema>, L<DBIx::DBSchema::DBD>, L<DBI>, L<DBI::DBD>
+
+=cut
+
+1;
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/Table.pm b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/Table.pm
new file mode 100644
index 0000000..2d6272e
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/DBSchema/Table.pm
@@ -0,0 +1,471 @@
+package DBIx::DBSchema::Table;
+
+use strict;
+use vars qw(@ISA %create_params);
+#use Carp;
+#use Exporter;
+use DBIx::DBSchema::Column 0.02;
+use DBIx::DBSchema::ColGroup::Unique;
+use DBIx::DBSchema::ColGroup::Index;
+
+#@ISA = qw(Exporter);
+@ISA = qw();
+
+=head1 NAME
+
+DBIx::DBSchema::Table - Table objects
+
+=head1 SYNOPSIS
+
+ use DBIx::DBSchema::Table;
+
+ #old style (depriciated)
+ $table = new DBIx::DBSchema::Table (
+ "table_name",
+ "primary_key",
+ $dbix_dbschema_colgroup_unique_object,
+ $dbix_dbschema_colgroup_index_object,
+ @dbix_dbschema_column_objects,
+ );
+
+ #new style (preferred), pass a hashref of parameters
+ $table = new DBIx::DBSchema::Table (
+ {
+ name => "table_name",
+ primary_key => "primary_key",
+ unique => $dbix_dbschema_colgroup_unique_object,
+ 'index' => $dbix_dbschema_colgroup_index_object,
+ columns => \@dbix_dbschema_column_objects,
+ }
+ );
+
+ $table->addcolumn ( $dbix_dbschema_column_object );
+
+ $table_name = $table->name;
+ $table->name("table_name");
+
+ $primary_key = $table->primary_key;
+ $table->primary_key("primary_key");
+
+ $dbix_dbschema_colgroup_unique_object = $table->unique;
+ $table->unique( $dbix_dbschema__colgroup_unique_object );
+
+ $dbix_dbschema_colgroup_index_object = $table->index;
+ $table->index( $dbix_dbschema_colgroup_index_object );
+
+ @column_names = $table->columns;
+
+ $dbix_dbschema_column_object = $table->column("column");
+
+ #preferred
+ @sql_statements = $table->sql_create_table( $dbh );
+ @sql_statements = $table->sql_create_table( $datasrc, $username, $password );
+
+ #possible problems
+ @sql_statements = $table->sql_create_table( $datasrc );
+ @sql_statements = $table->sql_create_table;
+
+=head1 DESCRIPTION
+
+DBIx::DBSchema::Table objects represent a single database table.
+
+=head1 METHODS
+
+=over 4
+
+=item new [ TABLE_NAME [ , PRIMARY_KEY [ , UNIQUE [ , INDEX [ , COLUMN... ] ] ] ] ]
+
+=item new HASHREF
+
+Creates a new DBIx::DBSchema::Table object. The preferred usage is to pass a
+hash reference of named parameters.
+
+ {
+ name => TABLE_NAME,
+ primary_key => PRIMARY_KEY,
+ unique => UNIQUE,
+ 'index' => INDEX,
+ columns => COLUMNS
+ }
+
+TABLE_NAME is the name of the table. PRIMARY_KEY is the primary key (may be
+empty). UNIQUE is a DBIx::DBSchema::ColGroup::Unique object (see
+L<DBIx::DBSchema::ColGroup::Unique>). INDEX is a
+DBIx::DBSchema::ColGroup::Index object (see
+L<DBIx::DBSchema::ColGroup::Index>). COLUMNS is a reference to an array of
+DBIx::DBSchema::Column objects (see L<DBIx::DBSchema::Column>).
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+
+ my $self;
+ if ( ref($_[0]) ) {
+
+ $self = shift;
+ $self->{column_order} = [ map { $_->name } @{$self->{columns}} ];
+ $self->{columns} = { map { $_->name, $_ } @{$self->{columns}} };
+
+ } else {
+
+ my($name,$primary_key,$unique,$index,@columns) = @_;
+
+ my %columns = map { $_->name, $_ } @columns;
+ my @column_order = map { $_->name } @columns;
+
+ $self = {
+ 'name' => $name,
+ 'primary_key' => $primary_key,
+ 'unique' => $unique,
+ 'index' => $index,
+ 'columns' => \%columns,
+ 'column_order' => \@column_order,
+ };
+
+ }
+
+ #check $primary_key, $unique and $index to make sure they are $columns ?
+ # (and sanity check?)
+
+ bless ($self, $class);
+
+}
+
+=item new_odbc DATABASE_HANDLE TABLE_NAME
+
+Creates a new DBIx::DBSchema::Table object from the supplied DBI database
+handle for the specified table. This uses the experimental DBI type_info
+method to create a table with standard (ODBC) SQL column types that most
+closely correspond to any non-portable column types. Use this to import a
+schema that you wish to use with many different database engines. Although
+primary key and (unique) index information will only be imported from databases
+with DBIx::DBSchema::DBD drivers (currently MySQL and PostgreSQL), import of
+column names and attributes *should* work for any database.
+
+Note: the _odbc refers to the column types used and nothing else - you do not
+have to have ODBC installed or connect to the database via ODBC.
+
+=cut
+
+%create_params = (
+# undef => sub { '' },
+ '' => sub { '' },
+ 'max length' => sub { $_[0]->{PRECISION}->[$_[1]]; },
+ 'precision,scale' =>
+ sub { $_[0]->{PRECISION}->[$_[1]]. ','. $_[0]->{SCALE}->[$_[1]]; }
+);
+
+sub new_odbc {
+ my( $proto, $dbh, $name) = @_;
+ my $driver = DBIx::DBSchema::_load_driver($dbh);
+ my $sth = _null_sth($dbh, $name);
+ my $sthpos = 0;
+ $proto->new (
+ $name,
+ scalar(eval "DBIx::DBSchema::DBD::$driver->primary_key(\$dbh, \$name)"),
+ DBIx::DBSchema::ColGroup::Unique->new(
+ $driver
+ ? [values %{eval "DBIx::DBSchema::DBD::$driver->unique(\$dbh, \$name)"}]
+ : []
+ ),
+ DBIx::DBSchema::ColGroup::Index->new(
+ $driver
+ ? [ values %{eval "DBIx::DBSchema::DBD::$driver->index(\$dbh, \$name)"} ]
+ : []
+ ),
+ map {
+ my $type_info = scalar($dbh->type_info($sth->{TYPE}->[$sthpos]))
+ or die "DBI::type_info ". $dbh->{Driver}->{Name}. " driver ".
+ "returned no results for type ". $sth->{TYPE}->[$sthpos];
+ new DBIx::DBSchema::Column
+ $_,
+ $type_info->{'TYPE_NAME'},
+ #"SQL_". uc($type_info->{'TYPE_NAME'}),
+ $sth->{NULLABLE}->[$sthpos],
+ &{ $create_params{ $type_info->{CREATE_PARAMS} } }( $sth, $sthpos++ ), $driver && #default
+ ${ [
+ eval "DBIx::DBSchema::DBD::$driver->column(\$dbh, \$name, \$_)"
+ ] }[4]
+ # DB-local
+ } @{$sth->{NAME}}
+ );
+}
+
+=item new_native DATABASE_HANDLE TABLE_NAME
+
+Creates a new DBIx::DBSchema::Table object from the supplied DBI database
+handle for the specified table. This uses database-native methods to read the
+schema, and will preserve any non-portable column types. The method is only
+available if there is a DBIx::DBSchema::DBD for the corresponding database
+engine (currently, MySQL and PostgreSQL).
+
+=cut
+
+sub new_native {
+ my( $proto, $dbh, $name) = @_;
+ my $driver = DBIx::DBSchema::_load_driver($dbh);
+ $proto->new (
+ $name,
+ scalar(eval "DBIx::DBSchema::DBD::$driver->primary_key(\$dbh, \$name)"),
+ DBIx::DBSchema::ColGroup::Unique->new(
+ [ values %{eval "DBIx::DBSchema::DBD::$driver->unique(\$dbh, \$name)"} ]
+ ),
+ DBIx::DBSchema::ColGroup::Index->new(
+ [ values %{eval "DBIx::DBSchema::DBD::$driver->index(\$dbh, \$name)"} ]
+ ),
+ map {
+ DBIx::DBSchema::Column->new( @{$_} )
+ } eval "DBIx::DBSchema::DBD::$driver->columns(\$dbh, \$name)"
+ );
+}
+
+=item addcolumn COLUMN
+
+Adds this DBIx::DBSchema::Column object.
+
+=cut
+
+sub addcolumn {
+ my($self,$column)=@_;
+ ${$self->{'columns'}}{$column->name}=$column; #sanity check?
+ push @{$self->{'column_order'}}, $column->name;
+}
+
+=item delcolumn COLUMN_NAME
+
+Deletes this column. Returns false if no column of this name was found to
+remove, true otherwise.
+
+=cut
+
+sub delcolumn {
+ my($self,$column) = @_;
+ return 0 unless exists $self->{'columns'}{$column};
+ delete $self->{'columns'}{$column};
+ @{$self->{'column_order'}}= grep { $_ ne $column } @{$self->{'column_order'}}; 1;
+}
+
+=item name [ TABLE_NAME ]
+
+Returns or sets the table name.
+
+=cut
+
+sub name {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ $self->{name} = $value;
+ } else {
+ $self->{name};
+ }
+}
+
+=item primary_key [ PRIMARY_KEY ]
+
+Returns or sets the primary key.
+
+=cut
+
+sub primary_key {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ $self->{primary_key} = $value;
+ } else {
+ #$self->{primary_key};
+ #hmm. maybe should untaint the entire structure when it comes off disk
+ # cause if you don't trust that, ?
+ $self->{primary_key} =~ /^(\w*)$/
+ #aah!
+ or die "Illegal primary key: ", $self->{primary_key};
+ $1;
+ }
+}
+
+=item unique [ UNIQUE ]
+
+Returns or sets the DBIx::DBSchema::ColGroup::Unique object.
+
+=cut
+
+sub unique {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ $self->{unique} = $value;
+ } else {
+ $self->{unique};
+ }
+}
+
+=item index [ INDEX ]
+
+Returns or sets the DBIx::DBSchema::ColGroup::Index object.
+
+=cut
+
+sub index {
+ my($self,$value)=@_;
+ if ( defined($value) ) {
+ $self->{'index'} = $value;
+ } else {
+ $self->{'index'};
+ }
+}
+
+=item columns
+
+Returns a list consisting of the names of all columns.
+
+=cut
+
+sub columns {
+ my($self)=@_;
+ #keys %{$self->{'columns'}};
+ #must preserve order
+ @{ $self->{'column_order'} };
+}
+
+=item column COLUMN_NAME
+
+Returns the column object (see L<DBIx::DBSchema::Column>) for the specified
+COLUMN_NAME.
+
+=cut
+
+sub column {
+ my($self,$column)=@_;
+ $self->{'columns'}->{$column};
+}
+
+=item sql_create_table [ DATABASE_HANDLE | DATA_SOURCE [ USERNAME PASSWORD [ ATTR ] ] ]
+
+Returns a list of SQL statments to create this table.
+
+The data source can be specified by passing an open DBI database handle, or by
+passing the DBI data source name, username and password.
+
+Although the username and password are optional, it is best to call this method
+with a database handle or data source including a valid username and password -
+a DBI connection will be opened and the quoting and type mapping will be more
+reliable.
+
+If passed a DBI data source (or handle) such as `DBI:mysql:database', will use
+MySQL- or PostgreSQL-specific syntax. Non-standard syntax for other engines
+(if applicable) may also be supported in the future.
+
+=cut
+
+sub sql_create_table {
+ my($self, $dbh) = (shift, shift);
+
+ my $created_dbh = 0;
+ unless ( ref($dbh) || ! @_ ) {
+ $dbh = DBI->connect( $dbh, @_ ) or die $DBI::errstr;
+ my $gratuitous = $DBI::errstr; #surpress superfluous `used only once' error
+ $created_dbh = 1;
+ }
+ #false laziness: nicked from DBSchema::_load_driver
+ my $driver;
+ if ( ref($dbh) ) {
+ $driver = $dbh->{Driver}->{Name};
+ } else {
+ my $discard = $dbh;
+ $discard =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i #nicked from DBI->connect
+ or '' =~ /()/; # ensure $1 etc are empty if match fails
+ $driver = $1 or die "can't parse data source: $dbh";
+ }
+ #eofalse
+
+#should be in the DBD somehwere :/
+# my $saved_pkey = '';
+# if ( $driver eq 'Pg' && $self->primary_key ) {
+# my $pcolumn = $self->column( (
+# grep { $self->column($_)->name eq $self->primary_key } $self->columns
+# )[0] );
+##AUTO-INCREMENT# $pcolumn->type('serial') if lc($pcolumn->type) eq 'integer';
+# $pcolumn->local( $pcolumn->local. ' PRIMARY KEY' );
+# #my $saved_pkey = $self->primary_key;
+# #$self->primary_key('');
+# #change it back afterwords :/
+# }
+
+ my @columns = map { $self->column($_)->line($dbh) } $self->columns;
+
+ push @columns, "PRIMARY KEY (". $self->primary_key. ")"
+ #if $self->primary_key && $driver ne 'Pg';
+ if $self->primary_key;
+
+ my $indexnum = 1;
+
+ my @r = (
+ "CREATE TABLE ". $self->name. " (\n ". join(",\n ", @columns). "\n)\n"
+ );
+
+ push @r, map {
+ #my($index) = $self->name. "__". $_ . "_idx";
+ #$index =~ s/,\s*/_/g;
+ my $index = $self->name. $indexnum++;
+ "CREATE UNIQUE INDEX $index ON ". $self->name. " ($_)\n"
+ } $self->unique->sql_list
+ if $self->unique;
+
+ push @r, map {
+ #my($index) = $self->name. "__". $_ . "_idx";
+ #$index =~ s/,\s*/_/g;
+ my $index = $self->name. $indexnum++;
+ "CREATE INDEX $index ON ". $self->name. " ($_)\n"
+ } $self->index->sql_list
+ if $self->index;
+
+ #$self->primary_key($saved_pkey) if $saved_pkey;
+ $dbh->disconnect if $created_dbh;
+ @r;
+}
+
+#
+
+sub _null_sth {
+ my($dbh, $table) = @_;
+ my $sth = $dbh->prepare("SELECT * FROM $table WHERE 1=0")
+ or die $dbh->errstr;
+ $sth->execute or die $sth->errstr;
+ $sth;
+}
+
+=back
+
+=head1 AUTHOR
+
+Ivan Kohler <ivan-dbix-dbschema@420.am>
+
+Thanks to Mark Ethan Trostler <mark@zzo.com> for a patch to allow tables
+with no indices.
+
+=head1 COPYRIGHT
+
+Copyright (c) 2000 Ivan Kohler
+Copyright (c) 2000 Mail Abuse Prevention System LLC
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 BUGS
+
+sql_create_table() has database-specific foo that probably ought to be
+abstracted into the DBIx::DBSchema::DBD:: modules.
+
+sql_create_table may change or destroy the object's data. If you need to use
+the object after sql_create_table, make a copy beforehand.
+
+Some of the logic in new_odbc might be better abstracted into Column.pm etc.
+
+=head1 SEE ALSO
+
+L<DBIx::DBSchema>, L<DBIx::DBSchema::ColGroup::Unique>,
+L<DBIx::DBSchema::ColGroup::Index>, L<DBIx::DBSchema::Column>, L<DBI>
+
+=cut
+
+1;
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/MANIFEST b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/MANIFEST
new file mode 100644
index 0000000..b04de25
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/MANIFEST
@@ -0,0 +1,19 @@
+Changes
+MANIFEST
+MANIFEST.SKIP
+README
+TODO
+Makefile.PL
+DBSchema.pm
+t/load.t
+t/load-mysql.t
+t/load-pg.t
+DBSchema/Table.pm
+DBSchema/ColGroup.pm
+DBSchema/ColGroup/Index.pm
+DBSchema/ColGroup/Unique.pm
+DBSchema/Column.pm
+DBSchema/DBD.pm
+DBSchema/DBD/mysql.pm
+DBSchema/DBD/Pg.pm
+DBSchema/DBD/Sybase.pm
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/MANIFEST.SKIP b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/MANIFEST.SKIP
new file mode 100644
index 0000000..ae335e7
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/MANIFEST.SKIP
@@ -0,0 +1 @@
+CVS/
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/Makefile.PL b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/Makefile.PL
new file mode 100644
index 0000000..a10e4da
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/Makefile.PL
@@ -0,0 +1,11 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'DBIx::DBSchema',
+ 'VERSION_FROM' => 'DBSchema.pm', # finds $VERSION
+ 'PREREQ_PM' => {
+ 'DBI' => 0,
+ 'FreezeThaw' => 0,
+ },
+);
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/README b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/README
new file mode 100644
index 0000000..8911ea4
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/README
@@ -0,0 +1,42 @@
+DBIx::DBSchema
+
+Copyright (c) 2000-2002 Ivan Kohler
+Copyright (c) 2000 Mail Abuse Prevention System LLC
+All rights reserved.
+This program is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+This module implements an OO-interface to database schemas. Using this module,
+you can create a database schema with an OO Perl interface. You can read the
+schema from an existing database. You can save the schema to disk and restore
+it from different process. Most importantly, DBIx::DBSchema can write SQL
+CREATE statements for different databases from a single source.
+
+Currently supported databases are MySQL, PostgreSQL and Sybase.
+DBIx::DBSchema will attempt to use generic SQL syntax for other databases.
+Assistance adding support for other databases is welcomed. See the
+DBIx::DBSchema::DBD manpage, "Driver Writer's Guide and Base Class".
+
+To install:
+ perl Makefile.PL
+ make
+ make test # nothing substantial yet
+ make install
+
+Documentation will then be available via `man DBIx::DBSchema' or
+`perldoc DBIx::DBSchema'.
+
+Anonymous CVS access is available:
+ $ export CVSROOT=":pserver:anonymous@cleanwhisker.420.am:/home/cvs/cvsroot"
+ $ cvs login
+ (Logging in to anonymous@cleanwhisker.420.am)
+ CVS password: anonymous
+ $ cvs checkout DBIx-DBSchema
+as well as <http://www.420.am/cgi-bin/cvsweb/DBIx-DBSchema>.
+
+A mailing list is available. Send a blank message to
+<ivan-dbix-dbschema-users-subscribe@420.am>.
+
+Homepage: <http://www.420.am/dbix-dbschema>
+
+$Id: README,v 1.1 2004-04-29 09:21:27 ivan Exp $
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/TODO b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/TODO
new file mode 100644
index 0000000..e75850b
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/TODO
@@ -0,0 +1,6 @@
+port and test with additional databases
+
+sql CREATE TABLE output should convert integers
+(i.e. use DBI qw(:sql_types);) to local types using DBI->type_info plus a hash
+to fudge things
+
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load-mysql.t b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load-mysql.t
new file mode 100644
index 0000000..78818c1
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load-mysql.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n"; }
+END {print "not ok 1\n" unless $loaded;}
+use DBIx::DBSchema::DBD::mysql;
+$loaded = 1;
+print "ok 1\n";
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load-pg.t b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load-pg.t
new file mode 100644
index 0000000..93fcf4a
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load-pg.t
@@ -0,0 +1,12 @@
+print "1..1\n";
+eval "use DBD::Pg 1.32";
+if ( length($@) ) {
+ print "ok 1 # Skipped: DBD::Pg 1.32 required for Pg";
+} else {
+ eval "use DBIx::DBSchema::DBD::Pg;";
+ if ( length($@) ) {
+ print "not ok 1\n";
+ } else {
+ print "ok 1\n";
+ }
+}
diff --git a/install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load.t b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load.t
new file mode 100644
index 0000000..67ea44b
--- /dev/null
+++ b/install/5.005/DBIx-DBSchema-0.23-5.005kludge/t/load.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n"; }
+END {print "not ok 1\n" unless $loaded;}
+use DBIx::DBSchema;
+$loaded = 1;
+print "ok 1\n";
diff --git a/install/5.005/Net-Whois-Raw/COPYRIGHT b/install/5.005/Net-Whois-Raw/COPYRIGHT
new file mode 100644
index 0000000..78fd312
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/COPYRIGHT
@@ -0,0 +1,7 @@
+Copyright 2003-2003 Walery Studennikov
+Copyright 2003-2003 Corris Randall
+Copyright 2003-2003 Gabor Szabo
+Copyright 2000-2002 Ariel Brosh
+
+This package is free software. You may redistribute it or modify it under
+the same terms as Perl itself.
diff --git a/install/5.005/Net-Whois-Raw/Changes b/install/5.005/Net-Whois-Raw/Changes
new file mode 100644
index 0000000..68310b0
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/Changes
@@ -0,0 +1,53 @@
+Revision history for Perl extension Net::Whois::Raw.
+
+0.01 Jul 05 12:35:47 2000
+ - original version; created by h2xs 1.19
+
+0.02 - 0.22 ???
+ - ???
+
+0.23 Mar 25 09:23:37 PST 2003
+ - only exports &whois by default, the other variables are exportable still.
+ - incorporated new whois servers ( thanks Toni Mueller <support@oeko.net> )
+ - now tests the main tlds
+ - added some more regexen to strip out disclaimers and such ( for $OMIT_MSG > 2 ).
+ - moved %servers to %Net::Whois::Raw::Data::servers
+
+0.24 Nov 18 2003 Walery Studennikov <despair@cpan.org>
+ - fixed whois server for .org domains and add new whois servers
+ for multilingual domains
+ - fixed recursive whois requests for .org domains
+ - new fail-check and strip patterns added
+ - more verbose error messages
+ - added support for third level domains
+ - some bugfixes
+
+0.25 Nov 21 2003 Walery Studennikov <despair@cpan.org>
+ - fixed multilingual domains whois via whois.melbourneit.com server
+ - whois_config function for setting config variables
+ (if setting imported variables $OMIT_MSG, $CHECK_FAIL etc.
+ doesn't work for some reason, for example because of
+ namespace problems in mod_perl scripts)
+
+0.26 Jan 09 2004 Walery Studennikov <despair@cpan.org>
+ - added recursive whois requests for .cc domains
+ - fixed recursive whois requests for whois.crsnic.net
+
+0.27 Feb 10 2004 Alex Kapranoff <alex@kapranoff.ru>
+ - patch to check availability of .info and .biz domains
+
+0.28 Feb 20 2004 Alex Kapranoff <alex@kapranoff.ru>
+ - fixed documentation for pwhois.PL
+
+0.29 Feb 24 2004 Walery Studennikov <despair@cpan.org>
+ - fixed extra rules which strips the copyright message or disclaimer
+ - removed pwhois.PL. "pwhois" is shipped now instead.
+ - data structures in Net/Whois/Raw/Data.pm reformatted
+ - new strip patterns for whois.crsnic.net
+
+
+0.30 Mar 15 2004 Walery Studennikov <despair@cpan.org>
+ - added strip rules for whois.dns.be
+
+0.31 Mar 19 2004 Walery Studennikov <despair@cpan.org>
+ - more robust recursive whois queries
diff --git a/install/5.005/Net-Whois-Raw/MANIFEST b/install/5.005/Net-Whois-Raw/MANIFEST
new file mode 100644
index 0000000..643f3ce
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/MANIFEST
@@ -0,0 +1,10 @@
+Changes
+MANIFEST
+Makefile.PL
+lib/Net/Whois/Raw.pm
+lib/Net/Whois/Raw/Data.pm
+t/01.t
+pwhois
+README
+COPYRIGHT
+META.yml Module meta-data (added by MakeMaker)
diff --git a/install/5.005/Net-Whois-Raw/META.yml b/install/5.005/Net-Whois-Raw/META.yml
new file mode 100644
index 0000000..56efaa6
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/META.yml
@@ -0,0 +1,11 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: Net-Whois-Raw
+version: 0.29
+version_from: lib/Net/Whois/Raw.pm
+installdirs: site
+requires:
+ IO::Socket: 1
+
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.17
diff --git a/install/5.005/Net-Whois-Raw/Makefile.PL b/install/5.005/Net-Whois-Raw/Makefile.PL
new file mode 100755
index 0000000..abd0ca3
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/Makefile.PL
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+
+sub MY::postamble {
+ package MY;
+ shift->SUPER::postamble . <<'MAKE';
+dist : README
+
+README : lib/Net/Whois/Raw.pm
+ @$(PERL) -MPod::Text -e "pod2text('$<');" > $@
+
+MAKE
+}
+
+WriteMakefile(
+ 'NAME' => 'Net::Whois::Raw',
+ 'VERSION_FROM' => 'lib/Net/Whois/Raw.pm', # finds $VERSION
+ 'PREREQ_PM' => {'IO::Socket' => 1.0},
+ 'EXE_FILES' => ['pwhois'],
+ 'dist' => {'COMPRESS' => 'gzip --best --force'},
+);
diff --git a/install/5.005/Net-Whois-Raw/README b/install/5.005/Net-Whois-Raw/README
new file mode 100644
index 0000000..916a53f
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/README
@@ -0,0 +1,129 @@
+NAME
+ Net::Whois::Raw - Perl extension for unparsed raw whois information
+
+SYNOPSIS
+ use Net::Whois::Raw qw( whois );
+
+ $s = whois('perl.com');
+ $s = whois('funet.fi');
+ $s = whois('yahoo.co.uk');
+
+ ### if you do "use Net::Whois::Raw qw( whois $OMIT_MSG $CHECK_FAIL
+ ### $CACHE_DIR $CACHE_TIME $USE_CNAMES $TIMEOUT );
+ ### you can use these:
+
+ $OMIT_MSG = 1; # This will attempt to strip several known copyright
+ messages and disclaimers sorted by servers.
+ Default is to give the whole response.
+
+ $OMIT_MSG = 2; # This will try some additional stripping rules
+ if none are known for the spcific server.
+
+ $CHECK_FAIL = 1; # This will return undef if the response matches
+ one of the known patterns for a failed search,
+ sorted by servers.
+ Default is to give the textual response.
+
+ $CHECK_FAIL = 2; # This will match against several more rules
+ if none are known for the specific server.
+
+ $CACHE_DIR = "/var/spool/pwhois/"; # Whois information will be
+ cached in this directory. Default is no cache.
+
+ $CACHE_TIME = 24; # Cache files will be cleared after not accessed
+ for a specific number of hours. Documents will not be
+ cleared if they keep get requested for, independent
+ of disk space. Default is not to clear the cache.
+
+ $USE_CNAMES = 1; # Use whois-servers.net to get the whois server
+ name when possible. Default is to use the
+ hardcoded defaults.
+
+ $TIMEOUT = 10; # Cancel the request if connection is not made within
+ a specific number of seconds.
+
+ Note: as of version 0.21, extra data will be loaded only if the
+ OMIT_MSG or CHECK_FAIL flags were used, in order to reduce memory usage.
+
+DESCRIPTION
+ Net::Whois::Raw queries NetworkSolutions and follows the Registrar:
+ answer for ORG, EDU, COM and NET domains. For other TLDs it uses the
+ whois-servers.net namespace. ($TLD.whois-servers.net).
+
+ Setting the variables $OMIT_MSG and $CHECK_FAIL will match the results
+ against a set of known patterns. The first flag will try to omit the
+ copyright message/disclaimer, the second will attempt to determine if
+ the search failed and return undef in such a case.
+
+ IMPORTANT: these checks merely use pattern matching; they will work on
+ several servers but certainly not on all of them.
+
+ (This features were contributed by Walery Studennikov despair@sama.ru)
+
+AUTHOR
+ Original author Ariel Brosh, schop@cpan.org, Inspired by jwhois.pl
+ available on the net.
+
+ Since Ariel has passed away in September 2002:
+
+ Past maintainers Gabor Szabo, gabor@perl.org.il, Corris Randall
+ corris@cpan.org
+
+ Current Maintainer: Walery Studennikov despair@cpan.org
+
+CREDITS
+ Fixed regular expression to match hyphens. (Peter Chow,
+ peter@interq.or.jp)
+
+ Added support for Tonga TLD. (.to) (Peter Chow, peter@interq.or.jp)
+
+ Added support for reverse lookup of IP addresses via the ARIN registry.
+ (Alex Withers awithers@gonzaga.edu)
+
+ This will work now for RIPE addresses as well, according to a
+ redirection from ARIN. (Philip Hands phil@uk.alcove.com, Trevor Peirce
+ trev@digitalcon.ca)
+
+ Added the pattern matching switches, (Walery Studennikov
+ despair@sama.ru)
+
+ Modified pattern matching, added cache. (Tony L. Svanstrom
+ tony@svanstrom.org)
+
+CHANGES
+ See file "Changes" in the distribution
+
+CLARIFICATION
+ As NetworkSolutions got most of the domains of InterNic as legacy, we
+ start by querying their server, as this way one whois query would be
+ sufficient for many domains. Starting at whois.internic.net or
+ whois.crsnic.net will result in always two requests in any case.
+
+NOTE
+ Some users complained that the die statements in the module make their
+ CGI scripts crash. Please consult the entries on eval and die on
+ perlfunc about exception handling in Perl.
+
+COPYRIGHT
+ Copyright 2000-2002 Ariel Brosh. Copyright 2003-2003 Gabor Szabo.
+ Copyright 2003-2003 Corris Randall. Copyright 2003-2003 Walery
+ Studennikov.
+
+ This package is free software. You may redistribute it or modify it
+ under the same terms as Perl itself.
+
+ I apologize for any misunderstandings caused by the lack of a clear
+ licence in previous versions.
+
+COMMERCIAL SUPPORT
+ Not available anymore.
+
+LEGAL
+ Notice that registrars forbid querying their whois servers as a part of
+ a search engine, or querying for a lot of domains by script. Also,
+ omitting the copyright information (that was requested by users of this
+ module) is forbidden by the registrars.
+
+SEE ALSO
+ perl(1), Net::Whois, whois.
+
diff --git a/install/5.005/Net-Whois-Raw/lib/Net/Whois/Raw.pm b/install/5.005/Net-Whois-Raw/lib/Net/Whois/Raw.pm
new file mode 100644
index 0000000..04db671
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/lib/Net/Whois/Raw.pm
@@ -0,0 +1,393 @@
+package Net::Whois::Raw;
+
+require Net::Whois::Raw::Data;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $OMIT_MSG $CHECK_FAIL
+ %notfound %strip $CACHE_DIR $CACHE_TIME $USE_CNAMES
+ $TIMEOUT);
+use IO::Socket;
+
+require Exporter;
+
+@ISA = qw(Exporter);
+
+@EXPORT = qw( whois whois_config ); ### It's bad manners to export lots.
+@EXPORT_OK = qw( $OMIT_MSG $CHECK_FAIL $CACHE_DIR $CACHE_TIME $USE_CNAMES $TIMEOUT);
+
+$VERSION = '0.31';
+
+($OMIT_MSG, $CHECK_FAIL, $CACHE_DIR, $CACHE_TIME, $USE_CNAMES, $TIMEOUT) = (0) x 6;
+
+sub whois {
+ my ($dom, $srv) = @_;
+ my $res;
+ unless ($srv) {
+ ($res, $srv) = query($dom);
+ } else {
+ $res = _whois($dom, uc($srv));
+ }
+ finish($res, $srv);
+}
+
+sub whois_config {
+ my ($par) = @_;
+ my @parnames = qw(OMIT_MSG CHECK_FAIL CACHE_DIR CACHE_TIME USE_CNAMES TIMEOUT);
+ foreach my $parname (@parnames) {
+ if (exists($par->{$parname})) {
+ eval('$'.$parname.'='.int($par->{$parname}));
+ }
+ }
+}
+
+sub query {
+ my $dom = shift;
+ my $tld;
+ if ($dom =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) {
+ $tld = "IP";
+ } else {
+ my @alltlds = keys %Net::Whois::Raw::Data::servers;
+ @alltlds = sort { dlen($b) <=> dlen($a) } @alltlds;
+ foreach my $awailtld (@alltlds) {
+ $awailtld = lc $awailtld;
+ if ($dom =~ /(.+?)\.($awailtld)$/) {
+ $tld = uc $2;
+ last;
+ }
+ }
+ unless ($tld) {
+ my @tokens = split(/\./, $dom);
+ $tld = uc($tokens[-1]);
+ }
+ }
+
+
+ $dom =~ s/.NS$//i;
+ my $cname = "$tld.whois-servers.net";
+ my $srv = $Net::Whois::Raw::Data::servers{$tld} || $cname;
+ $srv = $cname if $USE_CNAMES && gethostbyname($cname);
+ my $flag = (
+ $srv eq 'whois.crsnic.net' ||
+ $srv eq 'whois.publicinterestregistry.net' ||
+ $srv eq 'whois.nic.cc' ||
+ $tld eq 'ARPA'
+ );
+ my $res = do_whois($dom, uc($srv), $flag, [], $tld);
+ wantarray ? ($res, $srv) : $res;
+}
+
+sub do_whois {
+ my ($dom) = @_; # receives 4 parameters, do NOT shift
+ return _whois(@_) unless $CACHE_DIR;
+ mkdir $CACHE_DIR, 0644;
+ if (-f "$CACHE_DIR/$dom") {
+ if (open(I, "$CACHE_DIR/$dom")) {
+ my $res = join("", <I>);
+ close(I);
+ return $res;
+ }
+ }
+ my $res = _whois(@_);
+ return $res unless $res;
+ return $res unless open(O, ">$CACHE_DIR/$dom");
+ print O $res;
+ close(O);
+
+
+ return $res unless $CACHE_TIME;
+
+ my $now = time;
+ foreach (glob("$CACHE_DIR/*.*")) {
+ my $atime = (stat($_))[8];
+ my $elapsed = $now - $atime;
+ unlink $_ if ($elapsed / 3600 > $CACHE_TIME);
+ }
+ $res;
+}
+
+sub finish {
+ my ($text, $srv) = @_;
+ return $text unless $CHECK_FAIL || $OMIT_MSG;
+ *notfound = \%Net::Whois::Raw::Data::notfound;
+ *strip = \%Net::Whois::Raw::Data::strip;
+
+ my $notfound = $notfound{lc($srv)};
+ my @strip = $strip{lc($srv)} ? @{$strip{lc($srv)}} : ();
+ my @lines;
+ MAIN: foreach (split(/\n/, $text)) {
+ return undef if $CHECK_FAIL && $notfound && /$notfound/;
+ if ($OMIT_MSG) {
+ foreach my $re (@strip) {
+ next MAIN if (/$re/);
+ }
+ }
+ push(@lines, $_);
+ }
+ local ($_) = join("\n", @lines, "");
+
+ if ($CHECK_FAIL > 1) {
+ return undef unless check_existance($_);
+ }
+
+ if ($OMIT_MSG > 1) {
+ s/The Data.+(policy|connection)\.\n//is;
+ s/% NOTE:.+prohibited\.//is;
+ s/Disclaimer:.+\*\*\*\n?//is;
+ s/NeuLevel,.+A DOMAIN NAME\.//is;
+ s/For information about.+page=spec//is;
+ s/NOTICE: Access to.+this policy.//is;
+ s/The previous information.+completeness\.//s;
+ s/NOTICE AND TERMS OF USE:.*modify these terms at any time\.//s;
+ s/TERMS OF USE:.*?modify these terms at any time\.//s;
+ s/NOTICE:.*expiration for this registration\.//s;
+
+ s/By submitting a WHOIS query.+?DOMAIN AVAILABILITY.\n?//s;
+ s/Registration and WHOIS.+?its accuracy.\n?//s;
+ s/Disclaimer:.+?\*\*\*\n?//s;
+ s/The .COOP Registration .+ Information\.//s;
+ s/Whois Server Version \d+\.\d+.//is;
+ s/NeuStar,.+www.whois.us\.//is;
+ s/\n?Domain names in the \.com, .+ detailed information.\n?//s;
+ s/\n?The Registry database .+?Registrars\.\n//s;
+ s/\n?>>> Last update of .+? <<<\n?//;
+ s/% .+?\n//gs;
+ }
+ $_;
+}
+
+sub _whois {
+ my ($dom, $srv, $flag, $ary, $tld) = @_;
+ my $state;
+
+ my $sock;
+ eval {
+ local $SIG{'ALRM'} = sub { die "Connection timeout to $srv" };
+ alarm $TIMEOUT if $TIMEOUT;
+ $sock = new IO::Socket::INET("$srv:43") || die "$srv: $!";
+ };
+ alarm 0;
+ die $@ if $@;
+ my $israce = $dom =~ /ra--/ || $dom =~ /bq--/;
+ my $whoisquery = $dom;
+ if ($srv eq 'WHOIS.MELBOURNEIT.COM' && $israce) {
+ $whoisquery .= ' race';
+ }
+ #warn "$srv: $whoisquery ($OMIT_MSG, $CHECK_FAIL, $CACHE_DIR, $CACHE_TIME, $USE_CNAMES, $TIMEOUT)\n";
+ print $sock "$whoisquery\r\n";
+ my @lines = <$sock>;
+ close($sock);
+ my $answer = join '', @lines;
+ if ($flag) {
+ foreach (@lines) {
+ $state ||= (/Registrar:/);
+ if ( $state && /Whois Server:\s*([A-Za-z0-9\-_\.]+)/ ) {
+ my $newsrv = uc("$1");
+ next if (($newsrv) eq uc($srv));
+ return undef if (grep {$_ eq $newsrv} @$ary);
+ my $whois = eval { _whois($dom, $newsrv, $flag, [@$ary, $srv]) };
+ if ($@ && !$whois || $whois && !check_existance($whois)) {
+ return $answer;
+ }
+ return $whois;
+ }
+ if (/^\s+Maintainer:\s+RIPE\b/ && $tld eq 'ARPA') {
+ my $newsrv = uc($Net::Whois::Raw::Data::servers{'RIPE'});
+ next if ($newsrv eq $srv);
+ return undef if (grep {$_ eq $newsrv} @$ary);
+ my $whois = eval { _whois($dom, $newsrv, $flag, [@$ary, $srv]) };
+ if ($@ && !$whois) {
+ return $answer;
+ }
+ return $whois;
+ }
+ }
+ }
+ my $whois = join("", @lines);
+
+ if ($whois =~ /To single out one record, look it up with \"xxx\",/s) {
+ my $newsrv = uc('whois.networksolutions.com');
+ return _whois($dom, $newsrv, $flag, [@{$ary||[]}, $srv]);
+ }
+
+ return $whois;
+}
+
+sub dlen {
+ my ($str) = @_;
+ my $dotcount = $str =~ tr/././;
+ return length($str) * (1 + $dotcount);
+}
+
+
+sub check_existance {
+ $_ = $_[0];
+
+ return undef if
+ /is unavailable/is ||
+ /No entries found for the selected source/is ||
+ /Not found:/s ||
+ /No match\./s ||
+ /is available/is ||
+ /Not found/is &&
+ !/ your query returns "NOT FOUND"/ &&
+ !/Domain not found locally/ ||
+ /No match for/is ||
+ /No Objects Found/s ||
+ /No domain records were found/s ||
+ /No such domain/s ||
+ /No entries found in the /s ||
+ /Unable to find any information for your query/s ||
+ /is not registered and may be available for registration/s;
+ return 1;
+}
+
+
+# Preloaded methods go here.
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+# Below is the stub of documentation for your module. You better edit it!
+
+=head1 NAME
+
+Net::Whois::Raw - Perl extension for unparsed raw whois information
+
+=head1 SYNOPSIS
+
+ use Net::Whois::Raw qw( whois );
+
+ $s = whois('perl.com');
+ $s = whois('funet.fi');
+ $s = whois('yahoo.co.uk');
+
+ ### if you do "use Net::Whois::Raw qw( whois $OMIT_MSG $CHECK_FAIL
+ ### $CACHE_DIR $CACHE_TIME $USE_CNAMES $TIMEOUT );
+ ### you can use these:
+
+ $OMIT_MSG = 1; # This will attempt to strip several known copyright
+ messages and disclaimers sorted by servers.
+ Default is to give the whole response.
+
+ $OMIT_MSG = 2; # This will try some additional stripping rules
+ if none are known for the spcific server.
+
+ $CHECK_FAIL = 1; # This will return undef if the response matches
+ one of the known patterns for a failed search,
+ sorted by servers.
+ Default is to give the textual response.
+
+ $CHECK_FAIL = 2; # This will match against several more rules
+ if none are known for the specific server.
+
+ $CACHE_DIR = "/var/spool/pwhois/"; # Whois information will be
+ cached in this directory. Default is no cache.
+
+ $CACHE_TIME = 24; # Cache files will be cleared after not accessed
+ for a specific number of hours. Documents will not be
+ cleared if they keep get requested for, independent
+ of disk space. Default is not to clear the cache.
+
+ $USE_CNAMES = 1; # Use whois-servers.net to get the whois server
+ name when possible. Default is to use the
+ hardcoded defaults.
+
+
+ $TIMEOUT = 10; # Cancel the request if connection is not made within
+ a specific number of seconds.
+
+ Note: as of version 0.21, extra data will be loaded only if the
+ OMIT_MSG or CHECK_FAIL flags were used, in order to reduce memory usage.
+
+=head1 DESCRIPTION
+
+Net::Whois::Raw queries NetworkSolutions and follows the Registrar: answer
+for ORG, EDU, COM and NET domains.
+For other TLDs it uses the whois-servers.net namespace.
+(B<$TLD>.whois-servers.net).
+
+Setting the variables $OMIT_MSG and $CHECK_FAIL will match the results
+against a set of known patterns. The first flag will try to omit the
+copyright message/disclaimer, the second will attempt to determine if
+the search failed and return undef in such a case.
+
+B<IMPORTANT>: these checks merely use pattern matching; they will work
+on several servers but certainly not on all of them.
+
+(This features were contributed by Walery Studennikov B<despair@sama.ru>)
+
+=head1 AUTHOR
+
+Original author Ariel Brosh, B<schop@cpan.org>,
+Inspired by jwhois.pl available on the net.
+
+Since Ariel has passed away in September 2002:
+
+Past maintainers Gabor Szabo, B<gabor@perl.org.il>,
+Corris Randall B<corris@cpan.org>
+
+Current Maintainer: Walery Studennikov B<despair@cpan.org>
+
+=head1 CREDITS
+
+Fixed regular expression to match hyphens. (Peter Chow,
+B<peter@interq.or.jp>)
+
+Added support for Tonga TLD. (.to) (Peter Chow, B<peter@interq.or.jp>)
+
+Added support for reverse lookup of IP addresses via the ARIN registry. (Alex Withers B<awithers@gonzaga.edu>)
+
+This will work now for RIPE addresses as well, according to a redirection from ARIN. (Philip Hands B<phil@uk.alcove.com>, Trevor Peirce B<trev@digitalcon.ca>)
+
+Added the pattern matching switches, (Walery Studennikov B<despair@sama.ru>)
+
+Modified pattern matching, added cache. (Tony L. Svanstrom B<tony@svanstrom.org>)
+
+=head1 CHANGES
+
+See file "Changes" in the distribution
+
+
+=head1 CLARIFICATION
+
+As NetworkSolutions got most of the domains of InterNic as legacy, we
+start by querying their server, as this way one whois query would be
+sufficient for many domains. Starting at whois.internic.net or
+whois.crsnic.net will result in always two requests in any case.
+
+=head1 NOTE
+
+Some users complained that the B<die> statements in the module make their
+CGI scripts crash. Please consult the entries on B<eval> and
+B<die> on L<perlfunc> about exception handling in Perl.
+
+=head1 COPYRIGHT
+
+Copyright 2000-2002 Ariel Brosh.
+Copyright 2003-2003 Gabor Szabo.
+Copyright 2003-2003 Corris Randall.
+Copyright 2003-2003 Walery Studennikov.
+
+This package is free software. You may redistribute it or modify it under
+the same terms as Perl itself.
+
+I apologize for any misunderstandings caused by the lack of a clear
+licence in previous versions.
+
+=head1 COMMERCIAL SUPPORT
+
+Not available anymore.
+
+=head1 LEGAL
+
+Notice that registrars forbid querying their whois servers as a part of
+a search engine, or querying for a lot of domains by script.
+Also, omitting the copyright information (that was requested by users of this
+module) is forbidden by the registrars.
+
+=head1 SEE ALSO
+
+L<perl(1)>, L<Net::Whois>, L<whois>.
+
+=cut
diff --git a/install/5.005/Net-Whois-Raw/lib/Net/Whois/Raw/Data.pm b/install/5.005/Net-Whois-Raw/lib/Net/Whois/Raw/Data.pm
new file mode 100644
index 0000000..c505117
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/lib/Net/Whois/Raw/Data.pm
@@ -0,0 +1,509 @@
+package Net::Whois::Raw::Data;
+
+use strict;
+use vars qw(%notfound %strip %servers);
+
+%servers = qw(
+ COM whois.crsnic.net
+ NET whois.crsnic.net
+ EDU whois.educause.net
+ ORG whois.publicinterestregistry.net
+ ARPA whois.arin.net
+ RIPE whois.ripe.net
+ MIL whois.nic.mil
+ COOP whois.nic.coop
+ MUSEUM whois.museum
+
+ BIZ whois.neulevel.biz
+ INFO whois.afilias.net
+ NAME whois.nic.name
+ GOV whois.nic.gov
+ AERO whois.information.aero
+ NS whois.internic.net
+ IP whois.ripe.net
+
+ AD whois.ripe.net
+ AL whois.ripe.net
+ AM whois.ripe.net
+ AS whois.gdns.net
+ AT whois.nic.at
+ AU box2.aunic.net
+ AZ whois.ripe.net
+ BA whois.ripe.net
+ BE whois.dns.be
+ BG whois.ripe.net
+ BR whois.nic.br
+ BY whois.ripe.net
+ CA eider.cira.ca
+ CC whois.nic.cc
+ CH domex.switch.ch
+ CK whois.ck-nic.org.ck
+ CL nic.cl
+ CN log.cnnic.net.cn
+ CX whois.nic.cx
+ CY whois.ripe.net
+ CZ dc1.eunet.cz
+ DE whois.denic.de
+ DK whois.dk-hostmaster.dk
+ DO ns.nic.do
+ DZ whois.ripe.net
+ EE whois.ripe.net
+ EG whois.ripe.net
+ ES whois.ripe.net
+ FI whois.ripe.net
+ FO whois.ripe.net
+ FR winter.nic.fr
+ GA whois.ripe.net
+ GB whois.ripe.net
+ GE whois.ripe.net
+ GL whois.ripe.net
+ GM whois.ripe.net
+ GR whois.ripe.net
+ GS whois.adamsnames.tc
+ HK whois.hkdnr.net.hk
+ HR whois.ripe.net
+ HU whois.nic.hu
+ ID muara.idnic.net.id
+ IE whois.domainregistry.ie
+ IL whois.isoc.org.il
+ IN whois.ncst.ernet.in
+ IS horus.isnic.is
+ IT whois.nic.it
+ JO whois.ripe.net
+ JP whois.nic.ad.jp
+ KG whois.domain.kg
+ KH whois.nic.net.kh
+ KR whois.krnic.net
+ LA whois.nic.la
+ LI domex.switch.ch
+ LK arisen.nic.lk
+ LT ns.litnet.lt
+ LU whois.dns.lu
+ LV whois.ripe.net
+ MA whois.ripe.net
+ MC whois.ripe.net
+ MD whois.ripe.net
+ MM whois.nic.mm
+ MS whois.adamsnames.tc
+ MT whois.ripe.net
+ MX whois.nic.mx
+ NL gw.domain-registry.nl
+ NO ask.norid.no
+ NU whois.worldnames.net
+ NZ akl-iis.domainz.net.nz
+ PL nazgul.nask.waw.pl
+ PT whois.ripe.net
+ RO whois.rotld.ro
+ RU whois.ripn.net
+ SE ear.nic-se.se
+ SG qs.nic.net.sg
+ SH whois.nic.sh
+ SI whois.arnes.si
+ SK whois.ripe.net
+ SM whois.ripe.net
+ ST whois.nic.st
+ SU whois.ripn.net
+ TC whois.adamsnames.tc
+ TF whois.adamsnames.tc
+ TH whois.thnic.net
+ TJ whois.nic.tj
+ TN whois.ripe.net
+ TO whois.tonic.to
+ TR whois.ripe.net
+ TW whois.twnic.net
+ UA whois.net.ua
+ UK whois.nic.uk
+ US whois.nic.us
+ VA whois.ripe.net
+ VG whois.adamsnames.tc
+ WS whois.worldsite.ws
+ YU whois.ripe.net
+ ZA apies.frd.ac.za
+
+ RA--AQ5D4PA whois.i-dns.net
+ RA--AQ6TKQQ whois.i-dns.net
+ RA--AQ7EAMY whois.i-dns.net
+ XN--P1AG ru.whois.i-dns.net
+ XN--P1AG ru.whois.i-dns.net
+ XN--J1AEF whois.i-dns.net
+ XN--E1APQ whois.i-dns.net
+ XN--C1AVG whois.i-dns.net
+
+ NET.RU whois.ripn.net
+ ORG.RU whois.ripn.net
+ PP.RU whois.ripn.net
+ SPB.RU whois.relcom.ru
+ MSK.RU whois.relcom.ru
+ RU.NET whois.relcom.ru
+);
+
+# These do not seem to work
+# CN log.cnnic.net.cn
+# DK whois.dk-hostmaster.dk
+# US whois.isi.edu
+# These serve only several subdomains
+# ZA apies.frd.ac.za
+
+
+%notfound = (
+ 'whois.nic.cc' => '^No match for',
+ 'whois.arin.net' => '^No match for',
+ 'whois.nic.br' => 'No match for',
+ 'ear.nic-se.se' => 'No data found',
+ 'whois.nic.sh' => '^No match for',
+ 'whois.nic.mx' => '^Nombre del Dominio:',
+ 'whois.domainregistry.ie' => 'There was no match',
+ 'domex.switch.ch' => '^We do not have an entry in our database matching your',
+ 'whois.dns.lu' => 'No entries found',
+ 'whois.worldsite.ws' => 'No match for',
+ 'whois.nic.it' => '^No entries found',
+ 'whois.nic.coop' => 'No Objects Found',
+ 'whois.nic.at' => 'nothing found',
+ 'ask.norid.no' => 'no matches',
+ 'whois.nic.uk' => '^\\s*No match for',
+ 'whois.nic.ad.jp' => 'No match',
+ 'whois.arnes.si' => 'No entries found',
+ 'whois.tonic.to' => 'No match for',
+ 'whois.hkdnr.net.hk' => '^No Match for',
+ 'whois.worldnames.net' => 'NO MATCH for domain',
+ 'whois.rotld.ro' => 'No entries found',
+ 'whois.nic.st' => '^No entries found',
+ 'whois.isoc.org.il' => 'No data was found',
+ 'eider.cira.ca' => 'Status:\\s*UNAV',
+ 'whois.nic.tj' => '^No match for',
+ 'aardvark.dns.be' => 'No such domain',
+ 'nazgul.nask.waw.pl' => '^Domain name .* does not exists',
+ 'whois.ncst.ernet.in' => '^No matches',
+ 'whois.krnic.net' => 'Above domain name is not registered',
+ 'whois.museum' => '^No information for',
+ 'whois.net.ua' => 'No entries found',
+ 'apies.frd.ac.za' => 'No information is available',
+ 'gw.domain-registry.nl' => 'invalid query',
+ 'whois.denic.de' => 'No entries found',
+ 'whois.nic.mil' => '^No match for',
+ 'horus.isnic.is' => 'No entries found',
+ 'winter.nic.fr' => 'No entries found',
+ 'whois.ripe.net' => 'No entries found',
+ 'whois.ripn.net' => 'No entries found',
+ 'qs.nic.net.sg' => 'NO entry found',
+ 'whois.twnic.net' => '^NO MATCH: This domain is',
+ 'nic.cl' => 'Invalid domain name',
+ 'whois.gdns.net' => '^Domain Not Found',
+ 'box2.aunic.net' => 'No entries found',
+ 'whois.nic.cx' => '^No match for',
+ 'dc1.eunet.cz' => 'No data found',
+ 'akl-iis.domainz.net.nz' => 'domain_name_status: 00 Not Listed',
+ 'ns.litnet.lt' => 'No matches found',
+ 'whois.adamsnames.tc' => 'is not a domain controlled by',
+ 'whois.nic.la' => '^NO MATCH for',
+ 'whois.networksolutions.com' => '(?i)no match',
+ 'whois.thnic.net' => 'No entries found',
+ 'whois.neulevel.biz' => '^Not found:',
+ 'whois.afilias.net' => '^NOT FOUND',
+);
+
+%strip = (
+ 'whois.crsnic.net' => [
+ '^TERMS OF USE:',
+ '^database through',
+ '^automated except',
+ '^modify existing',
+ '^Services\' \(\"VeriSign\"\)',
+ '^information purposes only',
+ '^about or related to a',
+ '^guarantee its accuracy\.',
+ '^by the following terms',
+ '^for lawful purposes and',
+ '^to: (1) allow, enable,',
+ '^unsolicited, commercial',
+ '^or facsimile; or \(2\)',
+ '^that apply to VeriSign',
+ '^repackaging, dissemination',
+ '^prohibited without the',
+ '^use electronic processes',
+ '^query the Whois database',
+ '^domain names or modify',
+ '^to restrict your access',
+ '^operational stability\.',
+ '^Whois database for',
+ '^reserves the right',
+
+ '^NOTICE AND TERMS OF USE:',
+ '^Data in Network Solutions',
+ '^purposes only, and to assist',
+ '^to a domain name registration',
+ '^By submitting a WHOIS query,',
+ '^You agree that you may use',
+ '^circumstances will you use',
+ '^the transmission of mass',
+ '^via e-mail, telephone, or',
+ '^electronic processes that',
+ '^compilation, repackaging,',
+ '^high-volume, automated,',
+ '^database. Network Solutions',
+ '^database in its sole discretion,',
+ '^querying of the WHOIS database',
+ '^Network Solutions reserves the',
+
+ '^NOTICE: The expiration date',
+ '^registrar\'s sponsorship of',
+ '^currently set to expire\.',
+ '^date of the domain name',
+ '^registrar. Users may',
+ '^view the registrar\'s',
+ '^to: \(1\) allow, enable,',
+ '^The Registry database',
+ '^Registrars\.',
+ '^Domain not found locally,',
+ '^Local WHOIS DB must be out',
+
+ '^Whois Server Version',
+ '^Domain names in the .com',
+ '^with many different',
+ '^for detailed information\.',
+
+ '^>>> Last update of whois database',
+ '^$',
+ ],
+ 'whois.tonic.to' => [
+ '^Tonic whoisd',
+ ],
+ 'whois.net.ua' => [
+ '^%',
+ ],
+ 'whois.nic.cx' => [
+ '^ Registrar: Christmas Island',
+ '^ Whois Server: whois.nic.cx',
+ ],
+ 'gw.domain-registry.nl' => [
+ 'Rights restricted by copyright',
+ 'http://www.domain-registry.nl',
+ ],
+ 'whois.denic.de' => [
+ '^%',
+ ],
+ 'whois.gdns.net' => [
+ '^\\w+ Whois Server',
+ '^Access to .* WHOIS information is provided to',
+ '^determining the contents of a domain name',
+ '^registrar database. The data in',
+ '^informational purposes only, and',
+ '^Compilation, repackaging, dissemination,',
+ '^in its entirety, or a substantial portion',
+ 'prior written permission. By',
+ '^by this policy. All rights reserved.',
+ ],
+ 'whois.isoc.org.il' => [
+ '^%',
+ ],
+ 'whois.dns.lu' => [
+ '^%',
+ ],
+ 'whois.worldnames.net' => [
+ '^----------------------------------',
+ '^.\\w+ Domain .* Whois service',
+ '^Copyright by .* Domain LTD',
+ '^----------------------------------',
+ '^Database last updated',
+ ],
+ 'whois.nic.sh' => [
+ '^NIC Whois Server',
+ ],
+ 'whois.nic.coop' => [
+ '^%',
+ '^ The .COOP Registration',
+ '^ Please use the',
+ ],
+ 'domex.switch.ch' => [
+ '^whois: This information is subject',
+ '^See http',
+ ],
+ 'whois.twnic.net' => [
+ '^Registrar:',
+ '^URL: http://rs.twnic.net.tw',
+ ],
+ 'nic.cl' => [
+ '^cl.cl:',
+ '^Más información: http://www.nic.cl/',
+ ],
+ 'whois.nic.mx' => [
+ '^------------------',
+ '^La información que ha',
+ '^relacionados con la',
+ '^DNS administrado por el NIC-México.',
+ '^Queda absolutamente prohibido',
+ '^envío de e-mail no solicitado',
+ '^productos y servicios',
+ '^del NIC-México.',
+ '^La base de datos generada',
+ '^protegida por las leyes de',
+ '^internacionales sobre la materia.',
+ ],
+ 'whois.domainregistry.ie' => [
+ '^%',
+ ],
+ 'ns.litnet.lt' => [
+ '^%',
+ ],
+ 'dc1.eunet.cz' => [
+ '^%',
+ ],
+ 'whois.ripn.net' => [
+ '^%',
+ ],
+ 'whois.nic.uk' => [
+ '^The .* Registration Host contains information',
+ '^registrations in the .*co.uk',
+ 'and .*\\.uk second-level domains.',
+ ],
+ 'whois.nic.br' => [
+ '^%',
+ ],
+ 'whois.krnic.net' => [
+ '^Korea Internet Information Service',
+ '^20\\d\\d³â 7¿ù 2ÀϺÎÅÍ´Â °³¼±µÈ Whois',
+ '^.com, .net, .org',
+ ],
+ 'whois.arnes.si' => [
+ '^\\*',
+ ],
+ 'nazgul.nask.waw.pl' => [
+ '^%',
+ ],
+ 'whois.nic.la' => [
+ '^ WHOIS server',
+ '^ The Data in the',
+ 'for information purposes,',
+ '^ and to assist persons in obtaining',
+ '^ domain name registration record. Sterling Holdings, Limited,',
+ '^ does not guarantee its accuracy.',
+ '^ you will use this Data only for lawful',
+ '^ circumstances will you use this Data',
+ '^ \\(1\\) allow, enable, or otherwise s',
+ '^ unsolicited, commercial advertising',
+ '^ \\(spam\\); or',
+ '^ that apply to Sterling Holdings',
+ '^ Sterling Holdings .* reserves the right to modify',
+ '^ terms at any time. By submitting this',
+ '^ policy.',
+ ],
+ 'horus.isnic.is' => [
+ '^%',
+ ],
+ 'whois.rotld.ro' => [
+ '^%',
+ ],
+ 'whois.nic.st' => [
+ '^The data in the .* database is provided',
+ '^The .* Registry does not guarantee',
+ '^The data in the .* database is protected',
+ '^By submitting a .* query, you agree that you will',
+ '^The Domain Council of .* reserves the right',
+ ],
+ 'ask.norid.no' => [
+ '^%',
+ ],
+ 'whois.hkdnr.net.hk' => [
+ '^Whois server',
+ '^Domain names in the',
+ '^and .* can now be registered',
+ '^Go to http://www.hkdnr.net.hk',
+ '^---------',
+ '^The Registry contains ONLY',
+ '^.* and .*\\.HK domains.',
+ ],
+ 'whois.arin.net' => [
+ '^The ARIN Registration Services Host contains',
+ '^Network Information:.*Networks',
+ '^Please use the whois server at',
+ '^Information and .* for .* Information.',
+ ],
+ 'qs.nic.net.sg' => [
+ '^\\*',
+ ],
+ 'akl-iis.domainz.net.nz' => [
+ '^%',
+ ],
+ 'whois.nic.hu' => [
+ '^%',
+ ],
+ 'whois.worldsite.ws' => [
+ '^Welcome to the .* Whois Server',
+ '^Use of this service for any',
+ '^than determining the',
+ '^in the .* to be registered',
+ '^prohibited.',
+ ],
+ 'whois.ripe.net' => [
+ '^%',
+ ],
+ 'whois.nic.cc' => [
+ '^This information is',
+ '^The Data in eNIC',
+ '^Corporation for information',
+ '^in obtaining information',
+ '^registration record',
+ '^accuracy. By submitting',
+ '^will use this Data only',
+ '^no circumstances will',
+ '^or otherwise support',
+ '^commercial advertising',
+ '^or \\(2\\) enable high volume',
+ '^apply to eNIC Corporation',
+ '^reserves the right to',
+ '^submitting this query,',
+ ],
+ 'whois.nic.mil' => [
+ '^To single out one record',
+ '^handle, shown in parenthesis',
+ '^Please be advised that this whois',
+ '^All INTERNET Domain, IP Network Number,',
+ '^the Internet Registry, RS.INTERNIC.NET.',
+ ],
+ 'box2.aunic.net' => [
+ '^%',
+ ],
+ 'whois.nic.ad.jp' => [
+ '^[',
+ ],
+ 'winter.nic.fr' => [
+ '^Tous droits reserves par copyright.',
+ '^Voir http://www.nic.fr',
+ '^Rights restricted by copyright.',
+ '^See http://www.nic.fr/outils',
+ ],
+ 'ear.nic-se.se' => [
+ '^#',
+ ],
+ 'whois.networksolutions.com' => [
+ '^The Data in',
+ '^Solutions for information',
+ '^information about or',
+ '^Network Solutions does not guarantee',
+ '^WHOIS query, you agree that',
+ '^purposes and that, under no circumstances',
+ '^\\(1\\) allow, enable, or',
+ '^unsolicited, commercial advertising',
+ '^\\(spam\\); or',
+ '^that apply to Network',
+ '^reserves the right',
+ '^this query, you',
+ ],
+ 'aardvark.dns.be' => [
+ '^%',
+ ],
+ 'whois.dns.be' => [
+ '^%-',
+ ],
+ 'whois.nic.tj' => [
+ '^This Whois server looks up only',
+ '^Please see http://nic.tj for more',
+ '^Tajikistan, and the Public Registrar Network.',
+ ],
+ 'whois.nic.at' => [
+ '^%',
+ ],
+);
+
+
+1;
diff --git a/install/5.005/Net-Whois-Raw/pwhois b/install/5.005/Net-Whois-Raw/pwhois
new file mode 100755
index 0000000..56d9a7e
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/pwhois
@@ -0,0 +1,106 @@
+#!/usr/bin/perl -w
+
+use Net::Whois::Raw qw( whois $OMIT_MSG $CHECK_FAIL $TIMEOUT $CACHE_DIR );
+use Getopt::Std;
+use strict;
+use vars qw($opt_s $opt_c $opt_S $opt_C $opt_t $opt_T $opt_h);
+
+getopts("scSCtT:h");
+
+if ($opt_h) {
+ print <<EOM;
+ $0 [ -s | -S ] [ -c | -C ] [ -t <timeout> ] [ -T] <domain> [ <server> ]
+
+The -s switch attempts to strip the copyright message or disclaimer.
+The -S switch will attempt some exra rules for it.
+The -c switch attempts to return an empty answer for failed searches.
+The -C switch will attempt some exra rules for it.
+The -T switch takes a parameter that is used for the timeout for
+connection attempts.
+The -t switch enables caching.
+EOM
+ exit;
+}
+
+
+$OMIT_MSG = $CHECK_FAIL = 0;
+
+$OMIT_MSG = 1 if $opt_s;
+$OMIT_MSG = 2 if $opt_S;
+$CHECK_FAIL = 1 if $opt_c;
+$CHECK_FAIL = 2 if $opt_C;
+$TIMEOUT = $opt_T;
+
+$CACHE_DIR = undef;
+if ($opt_t) {
+ if ($^O =~ /Win/) {
+ $CACHE_DIR = $ENV{'TEMP'} || "C:\\temp";
+ } else {
+ $CACHE_DIR = $ENV{'TEMP'} || "/tmp";
+ my @ent = getpwuid($>);
+ if (@ent) {
+ foreach ("/tmp/$ent[0]", "$ent[7]/.pwhois") {
+ mkdir $_, 0644;
+ if (open(O, ">$_/__$$-$$.tmp")) {
+ close(O);
+ unlink "$_/__$$-$$.tmp";
+ $CACHE_DIR = $_;
+ last;
+ }
+ }
+ }
+ }
+}
+
+my $dom = $ARGV[0] || die "Usage: $0 domain";
+
+my $server = $ARGV[1];
+
+eval {
+ my $result = whois($dom, $server);
+ if ($result) {
+ print $result;
+ } else {
+ print STDERR "Failed.\n";
+ }
+};
+if ($@) {
+ my $err = $@;
+ $err =~ s/\s+at \S+ line \d+\.$//;
+ print "\nWhois information could not be fetched:\n$err\n";
+ exit -1;
+}
+
+__END__
+
+=head1 NAME
+
+pwhois - Perl written whois client
+
+=head1 SYNOPSIS
+
+ pwhois perl.com
+ pwhois gnu.org
+ pwhois -s police.co.il
+ pwhois -c there.is.no.tld.called.foobar
+ pwhois yahoo.com whois.networksolutions.com
+ pwhois -T 10 funet.fi
+
+etc etc.....
+
+=head1 DESCRIPTION
+
+Just invoke with a domain name, optionally with a whois server name.
+The B<-s> switch attempts to strip the copyright message or disclaimer.
+The B<-c> switch attempts to return an empty answer for failed searches.
+The B<-T> switch takes a parameter that is used for the timeout for
+connection attempts.
+
+=head1 AUTHOR
+
+Ariel Brosh, B<schop@cpan.org>
+
+=head1 SEE ALSO
+
+L<Net::Whois::Raw>.
+
diff --git a/install/5.005/Net-Whois-Raw/t/01.t b/install/5.005/Net-Whois-Raw/t/01.t
new file mode 100644
index 0000000..dd7ffc4
--- /dev/null
+++ b/install/5.005/Net-Whois-Raw/t/01.t
@@ -0,0 +1,22 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+use strict;
+
+use Test::More tests => 5;
+BEGIN { use_ok('Net::Whois::Raw',qw( whois )) };
+
+my @domains = qw(
+ yahoo.com
+ freshmeat.net
+ freebsd.org
+ ucsb.edu
+);
+
+print "The following tests requires internet connection...\n";
+
+foreach my $domain ( @domains ) {
+ my $txt = whois( $domain );
+ ok($txt =~ /$domain/i, "$domain resolved");
+}
+
diff --git a/install/debian/3.0/INSTALL b/install/debian/3.0/INSTALL
new file mode 100644
index 0000000..96991e8
--- /dev/null
+++ b/install/debian/3.0/INSTALL
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+echo "deb http://pouncequick.420.am/~ivan/freeside-woody/ ./" >>/etc/apt/sources.list
+
+apt-get update
+apt-get install screen zsh libapache-mod-ssl libapache-mod-perl rsync \
+ postgresql cvs fsh \
+ liburi-perl libhtml-tagset-perl libnet-perl liblocale-codes-perl \
+ libnet-whois-perl libwww-perl libbusiness-creditcard-perl \
+ libmailtools-perl libtimedate-perl libdate-manip-perl \
+ libfile-counterfile-perl libfreezethaw-perl libstring-approx-perl \
+ libtext-template-perl libdbi-perl libdbd-pg-perl \
+ libdbix-datasource-perl libdbix-dbschema-perl libnet-ssh-perl \
+ libstring-shellquote-perl libnet-scp-perl libapache-asp-perl \
+ libtie-ixhash-perl libtime-duration-perl \
+ libhtml-widgets-selectlayers-perl libstorable-perl \
+ libapache-dbi-perl libcache-cache-perl libdbd-mysql-perl
+
+useradd freeside
+su postgres -c "createuser -P freeside"
+
+su freeside -c "createdb freeside"
+
+#?
+cd ../../..
+make install-perl-modules
+make create-config
+freeside-adduser -c -h /usr/local/etc/freeside/htpasswd ivan
+su freeside -c 'freeside-setup ivan'
+su freeside -c '/home/ivan/freeside/bin/populate-msgcat ivan'
+make deploy
diff --git a/install/fedora/fc1/INSTALL b/install/fedora/fc1/INSTALL
new file mode 100755
index 0000000..c347609
--- /dev/null
+++ b/install/fedora/fc1/INSTALL
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+wget --passive-ftp --continue http://download.fedora.us/fedora/fedora/1/i386/RPMS.stable/apt-0.5.15cnc5-0.fdr.10.1.i386.rpm
+rpm -i apt*i386.rpm
+
+cp sources.list /etc/apt/sources.list
+
+apt-get update
+
+apt-get install perl-Devel-Symdump perl-BSD-Resource
+
+wget --passive-ftp --continue http://linux.reb00t.com/fedora-current/RPMS/apache-1.3.29-1.n0i.2.MPSSL.i686.rpm http://linux.reb00t.com/fedora-current/RPMS/mm-1.3.0-0.n0i.2.i686.rpm http://mirrors.kernel.org/fedora.us/fedora/fedora/1.91/i386/RPMS.os/db4-4.2.52-3.1.i386.rpm
+
+apt-get remove httpd mod_perl
+
+rpm -i mm-1.3.0-0.n0i.2.i686.rpm db4-4.2.52-3.1.i386.rpm apache-1.3.29-1.n0i.2.MPSSL.i686.rpm
+
+/sbin/chkconfig httpd on
+
+#edit /etc/httpd/conf/httpd.conf, remove mod_auth_db LoadMoudle and AddModule
+
+echo 'OPTIONS="-DHAVE_PERL -DHAVE_SSL"' >>/etc/sysconfig/apache
+
+/etc/init.d/httpd start
+
+echo 'RPM::Allow-Duplicated { "^db4$"; };' >>/etc/apt/apt.conf
+
+wget --continue http://atrpms.physik.fu-berlin.de/RPM-GPG-KEY.atrpms
+rpm --import RPM-GPG-KEY.atrpms
+wget --continue http://dag.wieers.com/packages/RPM-GPG-KEY.dag.txt
+rpm --import RPM-GPG-KEY.dag.txt
+
+apt-get install perl-DBD-MySQL perl-DBI perl-DateManip perl-HTML-Parser perl-HTML-Tagset perl-TimeDate perl-URI perl-libwww-perl perl-suidperl rsync postgresql postgresql-docs postgresql-libs postgresql-server postgresql-devel screen zsh lftp cvs gcc gd perl-GD perl-MailTools perl-FreezeThaw perl-NetAddr-IP perl-Chart
+
+perl -MCPAN -e"install Net::Whois::Raw, Business::CreditCard, \
+ File::CounterFile, String::Approx, Text::Template, \
+ DBIx::DataSource, DBIx::DBSchema, Net::SSH, \
+ String::ShellQuote, Net::SCP, Apache::ASP, \
+ Tie::IxHash, Time::Duration, \
+ HTML::Widgets::SelectLayers, Apache::DBI, \
+ Cache::Cache, IPC::ShareLite, Locale::SubCountry, \
+ DBD::Pg, Crypt::PasswdMD5 "
+
+
+#remove perl & ssl LoadModule lines from /etc/httpd/conf/httpd.conf
+#as they're statically linked (?)
+
+/usr/sbin/useradd freeside
+chsh freeside -s /bin/bash
+
+/sbin/chkconfig postgresql on
+/etc/init.d/postgresql start
+
+echo -e '\n\ny\nn" | su postgres -c "createuser -P freeside"
+
+su freeside -c "createdb freeside"
+
+#?
+cd ../../..
+make install-perl-modules
+make create-config
+freeside-adduser -c -h /usr/local/etc/freeside/htpasswd ivan
+su freeside -c 'freeside-setup ivan'
+su freeside -c '/home/ivan/freeside/bin/populate-msgcat ivan'
+make deploy
+
diff --git a/install/fedora/fc1/sources.list b/install/fedora/fc1/sources.list
new file mode 100644
index 0000000..9b36242
--- /dev/null
+++ b/install/fedora/fc1/sources.list
@@ -0,0 +1,12 @@
+# Fedora Core (Kernel.org, San Francisco California, USA)
+rpm http://mirrors.kernel.org/fedora.us/fedora fedora/1/i386 os updates
+rpm-src http://mirrors.kernel.org/fedora.us/fedora fedora/1/i386 os updates
+
+# Fedora Extras (Kernel.org, San Francisco California, USA)
+rpm http://mirrors.kernel.org/fedora.us/fedora fedora/1/i386 stable
+rpm-src http://mirrors.kernel.org/fedora.us/fedora fedora/1/i386 stable
+
+### Dag Apt Repository for Red Hat Fedora Core 1 (rhfc1)
+rpm http://apt.sw.be redhat/fc1/en/i386 dag
+
+rpm http://apt.physik.fu-berlin.de redhat/9/en/i386 at-testing
diff --git a/install/freebsd/INSTALL b/install/freebsd/INSTALL
new file mode 100755
index 0000000..53fc613
--- /dev/null
+++ b/install/freebsd/INSTALL
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+( cd /usr/ports/sysutils/portupgrade
+ make install
+)
+
+pkgdb -u
+
+portinstall -PR cvsup-without-gui
+
+cp /usr/share/examples/cvsup/ports-supfile /root
+perl -pi -e 's/CHANGE_THIS/cvsup1/;' /root/ports-supfile
+cvsup /root/ports-supfile
+
+for port in `grep -v '^ *#' ports`; do
+ #cd /usr/ports/$port
+ #make install || exit
+ portinstall -P -R $port || exit
+done
+
+for a in Net::SSH DBIx::DBSchema HTML::Widgets::SelectLayers Time::Duration Business::CreditCard; do perl -MCPAN -e"install $a"; done
+
+su -l pgsql -c initdb
+
+/usr/local/etc/rc.d/010.pgsql.sh start
+
+pw user add freeside -m
+
+su -l pgsql -c 'createuser -P freeside'
+
+su -l freeside -c 'createdb freeside'
+
+#?
+cd ../..
+make install-perl-modules
+make create-config
+make deploy
+
+#edit apache config, etc.
+
diff --git a/install/freebsd/ports b/install/freebsd/ports
new file mode 100644
index 0000000..019c5e1
--- /dev/null
+++ b/install/freebsd/ports
@@ -0,0 +1,44 @@
+shells/zsh
+misc/screen
+ftp/lftp
+www/apache13-modssl
+www/mod_perl
+net/rsync
+databases/postgresql7
+misc/p5-Array-PrintCols
+devel/p5-Term-Query
+converters/p5-MIME-Base64
+security/p5-Digest-MD5
+security/p5-MD5
+net/p5-URI
+www/p5-HTML-Tagset
+www/p5-HTML-Parser
+net/p5-Net
+misc/p5-Locale-Codes
+net/p5-Net-Whois
+www/p5-libwww
+ #misc/p5-Business-CreditCard
+devel/p5-Data-ShowTable
+mail/p5-Mail-Tools
+devel/p5-TimeDate
+devel/p5-Date-Manip
+misc/p5-File-CounterFile
+devel/p5-FreezeThaw
+devel/p5-String-Approx
+textproc/p5-Text-Template
+databases/p5-DBI
+databases/p5-DBD-Pg
+#databases/p5-DBD-mysql
+databases/p5-DBIx-DataSource
+ #database/p5-DBIx-DBSchema
+ #net/p5-Net-SSH
+textproc/p5-String-ShellQuote
+net/p5-Net-SCP
+www/p5-Apache-ASP
+ #www/p5-HTML-Mason
+devel/p5-Tie-IxHash
+ #devel/p5-Time-Duration
+ #www/p5-HTML-Widgets-SelectLayers
+devel/p5-Storable
+www/p5-Apache-DBI
+devel/p5-Cache-Cache
diff --git a/install/openbsd/INSTALL b/install/openbsd/INSTALL
new file mode 100644
index 0000000..1beef92
--- /dev/null
+++ b/install/openbsd/INSTALL
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+DIR=`pwd`
+
+#cd /usr/ports
+#cvs -q -d anoncvs@anoncvs6.usa.openbsd.org:/cvs up -r OPENBSD_`uname -r | perl -pe 's/\./_/g;'` -Pd
+
+for a in `grep -v '^ *#' $DIR/ports`
+do cd /usr/ports/$a
+ make install
+done
+
+for a in `grep -v '^ *#' $DIR/cpan`
+do perl -MCPAN -e "install $a"
+done
+
+#from /usr/local/share/doc/postgresql/README.OpenBSD
+useradd -c "PostgreSQL Admin User" -g =uid -m -d /var/postgresql -s /bin/sh postgresql
+
+su -l postgresql -c 'mkdir /var/postgresql/data'
+su -l postgresql -c 'initdb -D /var/postgresql/data'
+
+cat <<END >>/etc/rc.local
+if [ -x /usr/local/bin/pg_ctl ]; then
+ su -l postgresql -c "/usr/local/bin/pg_ctl start \
+ -D /var/postgresql/data -l /var/postgresql/logfile \
+ -o '-D /var/postgresql/data'"
+ echo -n ' postgresql'
+fi
+END
+
+cat <<END >>/etc/rc.shutdown
+if [ -f /var/postgresql/data/postmaster.pid ]; then
+ su -l postgresql -c "/usr/local/bin/pg_ctl stop -m fast \
+ -D /var/postgresql/data"
+ rm -f /var/postgresql/data/postmaster.pid
+fi
+
+su -l postgresql -c "/usr/local/bin/pg_ctl start \
+ -D /var/postgresql/data -l /var/postgresql/logfile \
+ -o '-D /var/postgresql/data'"
+
+useradd -c "Freeside" -g =uid -m freeside
+su -l postgresql -c 'createuser -P freeside'
+su -l freeside -c 'createdb freeside'
+
+#?
+cd ../..
+make install-perl-modules
+make create-config
+make deploy
+
+#edit apache config, etc.
+
diff --git a/install/openbsd/cpan b/install/openbsd/cpan
new file mode 100644
index 0000000..4304b72
--- /dev/null
+++ b/install/openbsd/cpan
@@ -0,0 +1,15 @@
+DBIx::DBSchema
+Time::Duration
+Business::CreditCard
+String::ShellQuote
+Net::SSH
+HTML::Mason
+HTML::Widgets::SelectLayers
+DBIx::DataSource
+Date::Manip
+String::Approx
+Tie::IxHash
+Date::Parse
+File::CounterFile
+Net::SCP
+Mail::Internet
diff --git a/install/openbsd/ports b/install/openbsd/ports
new file mode 100644
index 0000000..3e17d82
--- /dev/null
+++ b/install/openbsd/ports
@@ -0,0 +1,24 @@
+shells/zsh
+misc/screen
+#www/apache13-modssl
+www/mod_perl
+net/rsync
+databases/postgresql
+converters/p5-MIME-Base64
+security/p5-Digest-MD5
+security/p5-MD5
+www/p5-HTML-Tagset
+www/p5-HTML-Parser
+net/p5-libnet
+misc/p5-Locale-Codes
+net/p5-Net-Whois
+www/p5-libwww
+#mail/p5-Mail-Tools
+devel/p5-FreezeThaw
+textproc/p5-Text-Template
+databases/p5-DBI
+databases/p5-DBD-Pg
+#databases/p5-DBD-Msql-Mysql
+www/p5-Apache-ASP
+devel/p5-Storable
+www/p5-Apache-DBI
diff --git a/install/redhat/7.3/INSTALL b/install/redhat/7.3/INSTALL
new file mode 100644
index 0000000..d2f60cb
--- /dev/null
+++ b/install/redhat/7.3/INSTALL
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+wget --passive-ftp ftp://apt-rpm.tuxfamily.org/apt/redhat/7.3/en/i386/RPMS.extra/apt-*i386.rpm
+rpm -i apt*i386.rpm
+cp sources.list /etc/apt/
+apt-get update; apt-get update
+apt-get install apache mod_ssl mod_perl perl-CGI perl-CPAN perl-DBD-MySQL perl-DBD-Pg perl-DBI perl-DateManip perl-Digest-MD5 perl-HTML-Parser perl-HTML-Tagset perl-MIME-Base64 perl-Storable perl-TimeDate perl-URI perl-libnet perl-libwww-perl perl-suidperl rsync postgresql postgresql-docs postgresql-libs postgresql-server screen zsh lftp cvs #openssh
+
+wget --passive-ftp --continue http://download.atrpms.net/production/packages/redhat-7.3-i386/atrpms/atrpms-51-1.rh7.3.at.noarch.rpm http://download.atrpms.net/production/packages/redhat-7.3-i386/atrpms/atrpms-package-config-51-1.rh7.3.at.noarch.rpm http://download.atrpms.net/production/packages/redhat-7.3-i386/atrpms/gd-2.0.15-1_6.rh7.3.at.i386.rpm http://download.atrpms.net/production/packages/redhat-7.3-i386/atrpms/gd-devel-2.0.15-1_6.rh7.3.at.i386.rpm http://download.atrpms.net/production/packages/redhat-7.3-i386/atrpms/perl-GD-2.11-7.rh7.3.at.i386.rpm
+
+#rpm -i atrpms-package-config-51-1.rh7.3.at.noarch.rpm
+rpm -i atrpms-51-1.rh7.3.at.noarch.rpm
+rpm -i gd-2.0.15-1_6.rh7.3.at.i386.rpm
+rpm -i perl-GD-2.11-7.rh7.3.at.i386.rpm
+
+perl -MCPAN -e"install Locale::Country, Net::Whois, Business::CreditCard, \
+ Mail::Internet, File::CounterFile, FreezeThaw, \
+ String::Approx, Text::Template, DBIx::DataSource, \
+ DBIx::DBSchema, Net::SSH, String::ShellQuote, \
+ Net::SCP, Apache::ASP, Tie::IxHash, Time::Duration, \
+ HTML::Widgets::SelectLayers, Apache::DBI, Cache::Cache"
+
+useradd freeside
+
+chkconfig postgresql on
+/etc/init.d/postgresql start
+
+su postgres -c "createuser -P freeside"
+
+su freeside -c "createdb freeside"
+
+#?
+cd ../..
+make install-perl-modules
+make create-config
+freeside-adduser -c -h /usr/local/etc/freeside/htpasswd ivan
+su freeside -c 'freeside-setup ivan'
+su freeside -c '/home/ivan/freeside/bin/populate-msgcat ivan'
+make deploy
+
diff --git a/install/redhat/7.3/sources.list b/install/redhat/7.3/sources.list
new file mode 100644
index 0000000..9a9ad5c
--- /dev/null
+++ b/install/redhat/7.3/sources.list
@@ -0,0 +1,2 @@
+rpm ftp://apt-rpm.tuxfamily.org/apt redhat/7.3/en/i386 os updates extra
+rpm-src ftp://apt-rpm.tuxfamily.org/apt redhat/7.3/en/i386 os updates extra
diff --git a/install/redhat/9/INSTALL b/install/redhat/9/INSTALL
new file mode 100644
index 0000000..c32a235
--- /dev/null
+++ b/install/redhat/9/INSTALL
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+wget --passive-ftp --continue http://redhat.usu.edu/mirrors/apt4rpm/apt-0.5.5cnc4.1-fr1.20030325a.2.i386.rpm
+rpm -i apt*i386.rpm
+cp sources.list /etc/apt/
+apt-get update
+
+apt-get install httpd mod_perl mod_ssl perl-CGI perl-CPAN perl-DBD-MySQL perl-DateManip perl-HTML-Parser perl-HTML-Tagset perl-TimeDate perl-URI perl-libwww-perl perl-suidperl rsync postgresql postgresql-docs postgresql-libs postgresql-server screen zsh lftp cvs gcc # gd openssh
+
+wget --passive-ftp --continue http://atrpms.physik.fu-berlin.de/dist/rh9/perl-GD/perl-GD-2.11-7.rh9.at.i386.rpm http://atrpms.physik.fu-berlin.de/dist/rh9/atrpms/atrpms-54-1.rh9.at.noarch.rpm http://atrpms.physik.fu-berlin.de/dist/rh9/gd/gd-2.0.15-1_6.rh9.at.i386.rpm
+
+cp /etc/apt/apt.conf /etc/apt/apt.conf.real
+
+rpm -i gd-2.0.15-1_6.rh9.at.i386.rpm atrpms-54-1.rh9.at.noarch.rpm perl-GD-2.11-7.rh9.at.i386.rpm
+
+mv /etc/apt/apt.conf.real /etc/apt/apt.conf
+
+perl -MCPAN -e"install Locale::Country, Net::Whois, Business::CreditCard, \
+ Mail::Internet, File::CounterFile, FreezeThaw, \
+ String::Approx, Text::Template, DBIx::DataSource, \
+ DBIx::DBSchema, Net::SSH, String::ShellQuote, \
+ Net::SCP, Apache::ASP, Tie::IxHash, Time::Duration, \
+ HTML::Widgets::SelectLayers, Apache::DBI, \
+ Cache::Cache, Test::Pod, NetAddr::IP, IPC::ShareLite, \
+ Chart::LinesPoints, Net::Whois::Raw, \
+ Locale::SubCountry, Crypt::PasswdMD5, DBI, DBD::Pg"
+
+
+#apachetoolbox i guess
+
+/usr/sbin/useradd freeside
+
+/sbin/chkconfig postgresql on
+/etc/init.d/postgresql start
+
+su postgres -c "createuser -P freeside"
+
+su freeside -c "createdb freeside"
+
+#?
+cd ../../..
+make install-perl-modules
+make create-config
+freeside-adduser -c -h /usr/local/etc/freeside/htpasswd ivan
+su freeside -c 'freeside-setup ivan'
+su freeside -c '/home/ivan/freeside/bin/populate-msgcat ivan'
+make deploy
+
diff --git a/install/redhat/9/sources.list b/install/redhat/9/sources.list
new file mode 100644
index 0000000..6dcb3b4
--- /dev/null
+++ b/install/redhat/9/sources.list
@@ -0,0 +1,2 @@
+#rpm http://download.fedoralegacy.org/apt redhat/9/i386 os updates legacy-util
+rpm http://download.fedoralegacy.org/apt redhat/9/i386 os updates
diff --git a/install/suse/9.0/INSTALL b/install/suse/9.0/INSTALL
new file mode 100644
index 0000000..4e44147
--- /dev/null
+++ b/install/suse/9.0/INSTALL
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+# based on install/redhat/9/INSTALL
+
+# apt for SuSE howto: http://linux01.gwdg.de/apt4rpm/
+
+for file in ftp://ftp.gwdg.de/pub/linux/suse/apt/SuSE/9.0-i386/RPMS.suser-rbos/apt-0.5.5cnc6-rb6.i586.rpm ftp://ftp.gwdg.de/pub/linux/suse/apt/SuSE/9.0-i386/RPMS.suser-rbos/apt-libs-0.5.5cnc6-rb6.i586.rpm ftp://ftp.gwdg.de/pub/linux/suse/apt/SuSE/9.0-i386/RPMS.suser-rbos/lua-5.0-rb3.i586.rpm; do
+ curl -C - -o `basename $file` $file
+done
+
+rpm -i lua-5.0-rb3.i586.rpm
+rpm -i apt-libs-0.5.5cnc6-rb6.i586.rpm
+rpm -i apt-0.5.5cnc6-rb6.i586.rpm
+
+perl -pi.bak -e 's/386 update/386 base update/' /etc/apt/sources.list
+
+apt-get update; apt-get update
+
+apt-get install apache mod_ssl mod_perl perl-DBI perl-Msql-Mysql-modules perl-DBD-Pg perl-DateManip perl-HTML-Parser perl-HTML-Tagset perl-TimeDate perl-URI perl-libwww-perl perl-Apache-DBI perl-Apache-ASP perl-GD perl-MailTools perl-Tie-IxHash rsync postgresql postgresql-docs postgresql-libs postgresql-server postgresql-devel screen zsh lftp wget cvs make gcc
+
+perl -MCPAN -e"install DBD::Pg, Net::Whois, Business::CreditCard, \
+ File::CounterFile, FreezeThaw, String::Approx, \
+ Text::Template, DBIx::DataSource, DBIx::DBSchema, \
+ Net::SSH, String::ShellQuote, Net::SCP, \
+ Time::Duration, HTML::Widgets::SelectLayers, \
+ Cache::Cache, Test::Pod, NetAddr::IP, IPC::ShareLite, \
+ Chart::LinesPoints"
+
+/usr/sbin/useradd freeside
+
+/sbin/chkconfig postgresql on
+/etc/init.d/postgresql start
+
+/sbin/chkconfig apache on
+#/etc/init.d/apache start
+
+su postgres -c "createuser -P freeside"
+
+su freeside -c "createdb freeside"
+
+#?
+cd ../../..
+make install-perl-modules
+make create-config
+freeside-adduser -c -h /usr/local/etc/freeside/htpasswd ivan
+su freeside -c 'freeside-setup ivan'
+su freeside -c '/home/ivan/freeside/bin/populate-msgcat ivan'
+make deploy
+
+
+
+
diff --git a/rt/FREESIDE_MODIFIED b/rt/FREESIDE_MODIFIED
new file mode 100644
index 0000000..3937c30
--- /dev/null
+++ b/rt/FREESIDE_MODIFIED
@@ -0,0 +1,6 @@
+sbin/rt-setup-database
+sbin/rt-setup-database.in
+config.layout
+config.layout.in
+etc/RT_SiteConfig.pm
+lib/RT/URI/freeside.pm
diff --git a/rt/bin/rt b/rt/bin/rt
deleted file mode 100755
index d9f8a3f..0000000
--- a/rt/bin/rt
+++ /dev/null
@@ -1,1816 +0,0 @@
-#!/usr/bin/perl -w
-# BEGIN LICENSE BLOCK
-#
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-#
-# (Except where explictly superceded by other copyright notices)
-#
-# This work is made available to you under the terms of Version 2 of
-# the GNU General Public License. A copy of that license should have
-# been provided with this software, but in any event can be snarfed
-# from www.gnu.org.
-#
-# This work is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# Unless otherwise specified, all modifications, corrections or
-# extensions to this work which alter its source code become the
-# property of Best Practical Solutions, LLC when submitted for
-# inclusion in the work.
-#
-#
-# END LICENSE BLOCK
-
-use strict;
-
-# This program is intentionally written to have as few non-core module
-# dependencies as possible. It should stay that way.
-
-use Cwd;
-use LWP;
-use HTTP::Request::Common;
-
-# We derive configuration information from hardwired defaults, dotfiles,
-# and the RT* environment variables (in increasing order of precedence).
-# Session information is stored in ~/.rt_sessions.
-
-my $VERSION = 0.02;
-my $HOME = eval{(getpwuid($<))[7]}
- || $ENV{HOME} || $ENV{LOGDIR} || $ENV{HOMEPATH}
- || ".";
-my %config = (
- (
- debug => 0,
- user => eval{(getpwuid($<))[0]} || $ENV{USER} || $ENV{USERNAME},
- passwd => undef,
- server => 'http://localhost/rt/',
- ),
- config_from_file($ENV{RTCONFIG} || ".rtrc"),
- config_from_env()
-);
-my $session = new Session("$HOME/.rt_sessions");
-my $REST = "$config{server}/REST/1.0";
-
-sub whine;
-sub DEBUG { warn @_ if $config{debug} >= shift }
-
-# These regexes are used by command handlers to parse arguments.
-# (XXX: Ask Autrijus how i18n changes these definitions.)
-
-my $name = '[\w.-]+';
-my $field = '[a-zA-Z][a-zA-Z0-9_-]*';
-my $label = '[a-zA-Z0-9@_.+-]+';
-my $labels = "(?:$label,)*$label";
-my $idlist = '(?:(?:\d+-)?\d+,)*(?:\d+-)?\d+';
-
-# Our command line looks like this:
-#
-# rt <action> [options] [arguments]
-#
-# We'll parse just enough of it to decide upon an action to perform, and
-# leave the rest to per-action handlers to interpret appropriately.
-
-my %handlers = (
-# handler => [ ...aliases... ],
- version => ["version", "ver"],
- logout => ["logout"],
- help => ["help", "man"],
- show => ["show", "cat"],
- edit => ["create", "edit", "new", "ed"],
- list => ["search", "list", "ls"],
- comment => ["comment", "correspond"],
- link => ["link", "ln"],
- merge => ["merge"],
- grant => ["grant", "revoke"],
-);
-
-# Once we find and call an appropriate handler, we're done.
-
-my (%actions, $action);
-foreach my $fn (keys %handlers) {
- foreach my $alias (@{ $handlers{$fn} }) {
- $actions{$alias} = \&{"$fn"};
- }
-}
-if (@ARGV && exists $actions{$ARGV[0]}) {
- $action = shift @ARGV;
-}
-$actions{$action || "help"}->($action || ());
-exit;
-
-# Handler functions.
-# ------------------
-#
-# The following subs are handlers for each entry in %actions.
-
-sub version {
- print "rt $VERSION\n";
-}
-
-sub logout {
- submit("$REST/logout") if defined $session->cookie;
-}
-
-sub help {
- my ($action, $type) = @_;
- my (%help, $key);
-
- # What help topics do we know about?
- local $/ = undef;
- foreach my $item (@{ Form::parse(<DATA>) }) {
- my $title = $item->[2]{Title};
- my @titles = ref $title eq 'ARRAY' ? @$title : $title;
-
- foreach $title (grep $_, @titles) {
- $help{$title} = $item->[2]{Text};
- }
- }
-
- # What does the user want help with?
- undef $action if ($action && $actions{$action} eq \&help);
- unless ($action || $type) {
- # If we don't know, we'll look for clues in @ARGV.
- foreach (@ARGV) {
- if (exists $help{$_}) { $key = $_; last; }
- }
- unless ($key) {
- # Tolerate possibly plural words.
- foreach (@ARGV) {
- if ($_ =~ s/s$// && exists $help{$_}) { $key = $_; last; }
- }
- }
- }
-
- if ($type && $action) {
- $key = "$type.$action";
- }
- $key ||= $type || $action || "introduction";
-
- # Find a suitable topic to display.
- while (!exists $help{$key}) {
- if ($type && $action) {
- if ($key eq "$type.$action") { $key = $action; }
- elsif ($key eq $action) { $key = $type; }
- else { $key = "introduction"; }
- }
- else {
- $key = "introduction";
- }
- }
-
- print STDERR $help{$key}, "\n\n";
-}
-
-# Displays a list of objects that match some specified condition.
-
-sub list {
- my ($q, $type, %data, $orderby);
- my $bad = 0;
-
- while (@ARGV) {
- $_ = shift @ARGV;
-
- if (/^-t$/) {
- $bad = 1, last unless defined($type = get_type_argument());
- }
- elsif (/^-S$/) {
- $bad = 1, last unless get_var_argument(\%data);
- }
- elsif (/^-o$/) {
- $orderby = shift @ARGV;
- }
- elsif (/^-([isl])$/) {
- $data{format} = $1;
- }
- elsif (/^-f$/) {
- if ($ARGV[0] !~ /^(?:(?:$field,)*$field)$/) {
- whine "No valid field list in '-f $ARGV[0]'.";
- $bad = 1; last;
- }
- $data{fields} = shift @ARGV;
- }
- elsif (!defined $q && !/^-/) {
- $q = $_;
- }
- else {
- my $datum = /^-/ ? "option" : "argument";
- whine "Unrecognised $datum '$_'.";
- $bad = 1; last;
- }
- }
-
- $type ||= "ticket";
- unless ($type && defined $q) {
- my $item = $type ? "query string" : "object type";
- whine "No $item specified.";
- $bad = 1;
- }
- return help("list", $type) if $bad;
-
- my $r = submit("$REST/search/$type", { query => $q, %data, orderby => $orderby || "" });
- print $r->content;
-}
-
-# Displays selected information about a single object.
-
-sub show {
- my ($type, @objects, %data);
- my $slurped = 0;
- my $bad = 0;
-
- while (@ARGV) {
- $_ = shift @ARGV;
-
- if (/^-t$/) {
- $bad = 1, last unless defined($type = get_type_argument());
- }
- elsif (/^-S$/) {
- $bad = 1, last unless get_var_argument(\%data);
- }
- elsif (/^-([isl])$/) {
- $data{format} = $1;
- }
- elsif (/^-$/ && !$slurped) {
- chomp(my @lines = <STDIN>);
- foreach (@lines) {
- unless (is_object_spec($_, $type)) {
- whine "Invalid object on STDIN: '$_'.";
- $bad = 1; last;
- }
- push @objects, $_;
- }
- $slurped = 1;
- }
- elsif (/^-f$/) {
- if ($ARGV[0] !~ /^(?:(?:$field,)*$field)$/) {
- whine "No valid field list in '-f $ARGV[0]'.";
- $bad = 1; last;
- }
- $data{fields} = shift @ARGV;
- }
- elsif (my $spec = is_object_spec($_, $type)) {
- push @objects, $spec;
- }
- else {
- my $datum = /^-/ ? "option" : "argument";
- whine "Unrecognised $datum '$_'.";
- $bad = 1; last;
- }
- }
-
- unless (@objects) {
- whine "No objects specified.";
- $bad = 1;
- }
- return help("show", $type) if $bad;
-
- my $r = submit("$REST/show", { id => \@objects, %data });
- print $r->content;
-}
-
-# To create a new object, we ask the server for a form with the defaults
-# filled in, allow the user to edit it, and send the form back.
-#
-# To edit an object, we must ask the server for a form representing that
-# object, make changes requested by the user (either on the command line
-# or interactively via $EDITOR), and send the form back.
-
-sub edit {
- my ($action) = @_;
- my (%data, $type, @objects);
- my ($cl, $text, $edit, $input, $output);
-
- use vars qw(%set %add %del);
- %set = %add = %del = ();
- my $slurped = 0;
- my $bad = 0;
-
- while (@ARGV) {
- $_ = shift @ARGV;
-
- if (/^-e$/) { $edit = 1 }
- elsif (/^-i$/) { $input = 1 }
- elsif (/^-o$/) { $output = 1 }
- elsif (/^-t$/) {
- $bad = 1, last unless defined($type = get_type_argument());
- }
- elsif (/^-S$/) {
- $bad = 1, last unless get_var_argument(\%data);
- }
- elsif (/^-$/ && !($slurped || $input)) {
- chomp(my @lines = <STDIN>);
- foreach (@lines) {
- unless (is_object_spec($_, $type)) {
- whine "Invalid object on STDIN: '$_'.";
- $bad = 1; last;
- }
- push @objects, $_;
- }
- $slurped = 1;
- }
- elsif (/^set$/i) {
- my $vars = 0;
-
- while (@ARGV && $ARGV[0] =~ /^($field)([+-]?=)(.*)$/) {
- my ($key, $op, $val) = ($1, $2, $3);
- my $hash = ($op eq '=') ? \%set : ($op =~ /^\+/) ? \%add : \%del;
-
- vpush($hash, lc $key, $val);
- shift @ARGV;
- $vars++;
- }
- unless ($vars) {
- whine "No variables to set.";
- $bad = 1; last;
- }
- $cl = $vars;
- }
- elsif (/^(?:add|del)$/i) {
- my $vars = 0;
- my $hash = ($_ eq "add") ? \%add : \%del;
-
- while (@ARGV && $ARGV[0] =~ /^($field)=(.*)$/) {
- my ($key, $val) = ($1, $2);
-
- vpush($hash, lc $key, $val);
- shift @ARGV;
- $vars++;
- }
- unless ($vars) {
- whine "No variables to set.";
- $bad = 1; last;
- }
- $cl = $vars;
- }
- elsif (my $spec = is_object_spec($_, $type)) {
- push @objects, $spec;
- }
- else {
- my $datum = /^-/ ? "option" : "argument";
- whine "Unrecognised $datum '$_'.";
- $bad = 1; last;
- }
- }
-
- if ($action =~ /^ed(?:it)?$/) {
- unless (@objects) {
- whine "No objects specified.";
- $bad = 1;
- }
- }
- else {
- if (@objects) {
- whine "You shouldn't specify objects as arguments to $action.";
- $bad = 1;
- }
- unless ($type) {
- whine "What type of object do you want to create?";
- $bad = 1;
- }
- @objects = ("$type/new");
- }
- return help($action, $type) if $bad;
-
- # We need a form to make changes to. We usually ask the server for
- # one, but we can avoid that if we are fed one on STDIN, or if the
- # user doesn't want to edit the form by hand, and the command line
- # specifies only simple variable assignments.
-
- if ($input) {
- local $/ = undef;
- $text = <STDIN>;
- }
- elsif ($edit || %add || %del || !$cl) {
- my $r = submit("$REST/show", { id => \@objects, format => 'l' });
- $text = $r->content;
- }
-
- # If any changes were specified on the command line, apply them.
- if ($cl) {
- if ($text) {
- # We're updating forms from the server.
- my $forms = Form::parse($text);
-
- foreach my $form (@$forms) {
- my ($c, $o, $k, $e) = @$form;
- my ($key, $val);
-
- next if ($e || !@$o);
-
- local %add = %add;
- local %del = %del;
- local %set = %set;
-
- # Make changes to existing fields.
- foreach $key (@$o) {
- if (exists $add{lc $key}) {
- $val = delete $add{lc $key};
- vpush($k, $key, $val);
- $k->{$key} = vsplit($k->{$key}) if $val =~ /[,\n]/;
- }
- if (exists $del{lc $key}) {
- $val = delete $del{lc $key};
- my %val = map {$_=>1} @{ vsplit($val) };
- $k->{$key} = vsplit($k->{$key});
- @{$k->{$key}} = grep {!exists $val{$_}} @{$k->{$key}};
- }
- if (exists $set{lc $key}) {
- $k->{$key} = delete $set{lc $key};
- }
- }
-
- # Then update the others.
- foreach $key (keys %set) { vpush($k, $key, $set{$key}) }
- foreach $key (keys %add) {
- vpush($k, $key, $add{$key});
- $k->{$key} = vsplit($k->{$key});
- }
- push @$o, (keys %add, keys %set);
- }
-
- $text = Form::compose($forms);
- }
- else {
- # We're rolling our own set of forms.
- my @forms;
- foreach (@objects) {
- my ($type, $ids, $args) =
- m{^($name)/($idlist|$labels)(?:(/.*))?$}o;
-
- $args ||= "";
- foreach my $obj (expand_list($ids)) {
- my %set = (%set, id => "$type/$obj$args");
- push @forms, ["", [keys %set], \%set];
- }
- }
- $text = Form::compose(\@forms);
- }
- }
-
- if ($output) {
- print $text;
- exit;
- }
-
- my $synerr = 0;
-
-EDIT:
- # We'll let the user edit the form before sending it to the server,
- # unless we have enough information to submit it non-interactively.
- if ($edit || (!$input && !$cl)) {
- my $newtext = vi($text);
- # We won't resubmit a bad form unless it was changed.
- $text = ($synerr && $newtext eq $text) ? undef : $newtext;
- }
-
- if ($text) {
- my $r = submit("$REST/edit", {content => $text, %data});
- if ($r->code == 409) {
- # If we submitted a bad form, we'll give the user a chance
- # to correct it and resubmit.
- if ($edit || (!$input && !$cl)) {
- $text = $r->content;
- $synerr = 1;
- goto EDIT;
- }
- else {
- print $r->content;
- exit -1;
- }
- }
- print $r->content;
- }
-}
-
-# We roll "comment" and "correspond" into the same handler.
-
-sub comment {
- my ($action) = @_;
- my (%data, $id, @files, @bcc, @cc, $msg, $wtime, $edit);
- my $bad = 0;
-
- while (@ARGV) {
- $_ = shift @ARGV;
-
- if (/^-e$/) {
- $edit = 1;
- }
- elsif (/^-[abcmw]$/) {
- unless (@ARGV) {
- whine "No argument specified with $_.";
- $bad = 1; last;
- }
-
- if (/-a/) {
- unless (-f $ARGV[0] && -r $ARGV[0]) {
- whine "Cannot read attachment: '$ARGV[0]'.";
- exit -1;
- }
- push @files, shift @ARGV;
- }
- elsif (/-([bc])/) {
- my $a = $_ eq "-b" ? \@bcc : \@cc;
- @$a = split /\s*,\s*/, shift @ARGV;
- }
- elsif (/-m/) { $msg = shift @ARGV }
- elsif (/-w/) { $wtime = shift @ARGV }
- }
- elsif (!$id && m|^(?:ticket/)?($idlist)$|) {
- $id = $1;
- }
- else {
- my $datum = /^-/ ? "option" : "argument";
- whine "Unrecognised $datum '$_'.";
- $bad = 1; last;
- }
- }
-
- unless ($id) {
- whine "No object specified.";
- $bad = 1;
- }
- return help($action, "ticket") if $bad;
-
- my $form = [
- "",
- [ "Ticket", "Action", "Cc", "Bcc", "Attachment", "TimeWorked", "Text" ],
- {
- Ticket => $id,
- Action => $action,
- Cc => [ @cc ],
- Bcc => [ @bcc ],
- Attachment => [ @files ],
- TimeWorked => $wtime || '',
- Text => $msg || '',
- }
- ];
-
- my $text = Form::compose([ $form ]);
-
- if ($edit || !$msg) {
- my $error = 0;
- my ($c, $o, $k, $e);
-
- do {
- my $ntext = vi($text);
- exit if ($error && $ntext eq $text);
- $text = $ntext;
- $form = Form::parse($text);
- $error = 0;
-
- ($c, $o, $k, $e) = @{ $form->[0] };
- if ($e) {
- $error = 1;
- $c = "# Syntax error.";
- goto NEXT;
- }
- elsif (!@$o) {
- exit;
- }
- @files = @{ vsplit($k->{Attachment}) };
-
- NEXT:
- $text = Form::compose([[$c, $o, $k, $e]]);
- } while ($error);
- }
-
- my $i = 1;
- foreach my $file (@files) {
- $data{"attachment_$i"} = bless([ $file ], "Attachment");
- $i++;
- }
- $data{content} = $text;
-
- my $r = submit("$REST/ticket/comment/$id", \%data);
- print $r->content;
-}
-
-# Merge one ticket into another.
-
-sub merge {
- my @id;
- my $bad = 0;
-
- while (@ARGV) {
- $_ = shift @ARGV;
-
- if (/^\d+$/) {
- push @id, $_;
- }
- else {
- whine "Unrecognised argument: '$_'.";
- $bad = 1; last;
- }
- }
-
- unless (@id == 2) {
- my $evil = @id > 2 ? "many" : "few";
- whine "Too $evil arguments specified.";
- $bad = 1;
- }
- return help("merge", "ticket") if $bad;
-
- my $r = submit("$REST/ticket/merge/$id[0]", {into => $id[1]});
- print $r->content;
-}
-
-# Link one ticket to another.
-
-sub link {
- my ($bad, $del, %data) = (0, 0, ());
- my %ltypes = map { lc $_ => $_ } qw(DependsOn DependedOnBy RefersTo
- ReferredToBy HasMember MemberOf);
-
- while (@ARGV && $ARGV[0] =~ /^-/) {
- $_ = shift @ARGV;
-
- if (/^-d$/) {
- $del = 1;
- }
- else {
- whine "Unrecognised option: '$_'.";
- $bad = 1; last;
- }
- }
-
- if (@ARGV == 3) {
- my ($from, $rel, $to) = @ARGV;
- if ($from !~ /^\d+$/ || $to !~ /^\d+$/) {
- my $bad = $from =~ /^\d+$/ ? $to : $from;
- whine "Invalid ticket ID '$bad' specified.";
- $bad = 1;
- }
- unless (exists $ltypes{lc $rel}) {
- whine "Invalid relationship '$rel' specified.";
- $bad = 1;
- }
- %data = (id => $from, rel => $rel, to => $to, del => $del);
- }
- else {
- my $bad = @ARGV < 3 ? "few" : "many";
- whine "Too $bad arguments specified.";
- $bad = 1;
- }
- return help("link", "ticket") if $bad;
-
- my $r = submit("$REST/ticket/link", \%data);
- print $r->content;
-}
-
-# Grant/revoke a user's rights.
-
-sub grant {
- my ($cmd) = @_;
-
- my $revoke = 0;
- while (@ARGV) {
- }
-
- $revoke = 1 if $cmd->{action} eq 'revoke';
-}
-
-# Client <-> Server communication.
-# --------------------------------
-#
-# This function composes and sends an HTTP request to the RT server, and
-# interprets the response. It takes a request URI, and optional request
-# data (a string, or a reference to a set of key-value pairs).
-
-sub submit {
- my ($uri, $content) = @_;
- my ($req, $data);
- my $ua = new LWP::UserAgent(agent => "RT/3.0b", env_proxy => 1);
-
- # Did the caller specify any data to send with the request?
- $data = [];
- if (defined $content) {
- unless (ref $content) {
- # If it's just a string, make sure LWP handles it properly.
- # (By pretending that it's a file!)
- $content = [ content => [undef, "", Content => $content] ];
- }
- elsif (ref $content eq 'HASH') {
- my @data;
- foreach my $k (keys %$content) {
- if (ref $content->{$k} eq 'ARRAY') {
- foreach my $v (@{ $content->{$k} }) {
- push @data, $k, $v;
- }
- }
- else { push @data, $k, $content->{$k} }
- }
- $content = \@data;
- }
- $data = $content;
- }
-
- # Should we send authentication information to start a new session?
- if (!defined $session->cookie) {
- push @$data, ( user => $config{user} );
- push @$data, ( pass => $config{passwd} || read_passwd() );
- }
-
- # Now, we construct the request.
- if (@$data) {
- $req = POST($uri, $data, Content_Type => 'form-data');
- }
- else {
- $req = GET($uri);
- }
- $session->add_cookie_header($req);
-
- # Then we send the request and parse the response.
- DEBUG(3, $req->as_string);
- my $res = $ua->request($req);
- DEBUG(3, $res->as_string);
-
- if ($res->is_success) {
- # The content of the response we get from the RT server consists
- # of an HTTP-like status line followed by optional header lines,
- # a blank line, and arbitrary text.
-
- my ($head, $text) = split /\n\n/, $res->content, 2;
- my ($status, @headers) = split /\n/, $head;
- $text =~ s/\n*$/\n/;
-
- # "RT/3.0.1 401 Credentials required"
- if ($status !~ m#^RT/\d+(?:\.\d+)+(?:-?\w+)? (\d+) ([\w\s]+)$#) {
- warn "rt: Malformed RT response from $config{server}.\n";
- warn "(Rerun with RTDEBUG=3 for details.)\n" if $config{debug} < 3;
- exit -1;
- }
-
- # Our caller can pretend that the server returned a custom HTTP
- # response code and message. (Doing that directly is apparently
- # not sufficiently portable and uncomplicated.)
- $res->code($1);
- $res->message($2);
- $res->content($text);
- $session->update($res) if ($res->is_success || $res->code != 401);
-
- if (!$res->is_success) {
- # We can deal with authentication failures ourselves. Either
- # we sent invalid credentials, or our session has expired.
- if ($res->code == 401) {
- my %d = @$data;
- if (exists $d{user}) {
- warn "rt: Incorrect username or password.\n";
- exit -1;
- }
- elsif ($req->header("Cookie")) {
- # We'll retry the request with credentials, unless
- # we only wanted to logout in the first place.
- $session->delete;
- return submit(@_) unless $uri eq "$REST/logout";
- }
- }
- # Conflicts should be dealt with by the handler and user.
- # For anything else, we just die.
- elsif ($res->code != 409) {
- warn "rt: ", $res->content;
- exit;
- }
- }
- }
- else {
- warn "rt: Server error: ", $res->message, " (", $res->code, ")\n";
- exit -1;
- }
-
- return $res;
-}
-
-# Session management.
-# -------------------
-#
-# Maintains a list of active sessions in the ~/.rt_sessions file.
-{
- package Session;
- my ($s, $u);
-
- # Initialises the session cache.
- sub new {
- my ($class, $file) = @_;
- my $self = {
- file => $file || "$HOME/.rt_sessions",
- sids => { }
- };
-
- # The current session is identified by the currently configured
- # server and user.
- ($s, $u) = @config{"server", "user"};
-
- bless $self, $class;
- $self->load();
-
- return $self;
- }
-
- # Returns the current session cookie.
- sub cookie {
- my ($self) = @_;
- my $cookie = $self->{sids}{$s}{$u};
- return defined $cookie ? "RT_SID=$cookie" : undef;
- }
-
- # Deletes the current session cookie.
- sub delete {
- my ($self) = @_;
- delete $self->{sids}{$s}{$u};
- }
-
- # Adds a Cookie header to an outgoing HTTP request.
- sub add_cookie_header {
- my ($self, $request) = @_;
- my $cookie = $self->cookie();
-
- $request->header(Cookie => $cookie) if defined $cookie;
- }
-
- # Extracts the Set-Cookie header from an HTTP response, and updates
- # session information accordingly.
- sub update {
- my ($self, $response) = @_;
- my $cookie = $response->header("Set-Cookie");
-
- if (defined $cookie && $cookie =~ /^RT_SID=([0-9A-Fa-f]+);/) {
- $self->{sids}{$s}{$u} = $1;
- }
- }
-
- # Loads the session cache from the specified file.
- sub load {
- my ($self, $file) = @_;
- $file ||= $self->{file};
- local *F;
-
- open(F, $file) && do {
- $self->{file} = $file;
- my $sids = $self->{sids} = {};
- while (<F>) {
- chomp;
- next if /^$/ || /^#/;
- next unless m#^https?://[^ ]+ \w+ [0-9A-Fa-f]+$#;
- my ($server, $user, $cookie) = split / /, $_;
- $sids->{$server}{$user} = $cookie;
- }
- return 1;
- };
- return 0;
- }
-
- # Writes the current session cache to the specified file.
- sub save {
- my ($self, $file) = shift;
- $file ||= $self->{file};
- local *F;
-
- open(F, ">$file") && do {
- my $sids = $self->{sids};
- foreach my $server (keys %$sids) {
- foreach my $user (keys %{ $sids->{$server} }) {
- my $sid = $sids->{$server}{$user};
- if (defined $sid) {
- print F "$server $user $sid\n";
- }
- }
- }
- close(F);
- chmod 0600, $file;
- return 1;
- };
- return 0;
- }
-
- sub DESTROY {
- my $self = shift;
- $self->save;
- }
-}
-
-# Form handling.
-# --------------
-#
-# Forms are RFC822-style sets of (field, value) specifications with some
-# initial comments and interspersed blank lines allowed for convenience.
-# Sets of forms are separated by --\n (in a cheap parody of MIME).
-#
-# Each form is parsed into an array with four elements: commented text
-# at the start of the form, an array with the order of keys, a hash with
-# key/value pairs, and optional error text if the form syntax was wrong.
-
-# Returns a reference to an array of parsed forms.
-sub Form::parse {
- my $state = 0;
- my @forms = ();
- my @lines = split /\n/, $_[0];
- my ($c, $o, $k, $e) = ("", [], {}, "");
-
- LINE:
- while (@lines) {
- my $line = shift @lines;
-
- next LINE if $line eq '';
-
- if ($line eq '--') {
- # We reached the end of one form. We'll ignore it if it was
- # empty, and store it otherwise, errors and all.
- if ($e || $c || @$o) {
- push @forms, [ $c, $o, $k, $e ];
- $c = ""; $o = []; $k = {}; $e = "";
- }
- $state = 0;
- }
- elsif ($state != -1) {
- if ($state == 0 && $line =~ /^#/) {
- # Read an optional block of comments (only) at the start
- # of the form.
- $state = 1;
- $c = $line;
- while (@lines && $lines[0] =~ /^#/) {
- $c .= "\n".shift @lines;
- }
- $c .= "\n";
- }
- elsif ($state <= 1 && $line =~ /^($field):(?:\s+(.*))?$/) {
- # Read a field: value specification.
- my $f = $1;
- my @v = ($2 || ());
-
- # Read continuation lines, if any.
- while (@lines && ($lines[0] eq '' || $lines[0] =~ /^\s+/)) {
- push @v, shift @lines;
- }
- pop @v while (@v && $v[-1] eq '');
-
- # Strip longest common leading indent from text.
- my $ws = "";
- foreach my $ls (map {/^(\s+)/} @v[1..$#v]) {
- $ws = $ls if (!$ws || length($ls) < length($ws));
- }
- s/^$ws// foreach @v;
-
- push(@$o, $f) unless exists $k->{$f};
- vpush($k, $f, join("\n", @v));
-
- $state = 1;
- }
- elsif ($line !~ /^#/) {
- # We've found a syntax error, so we'll reconstruct the
- # form parsed thus far, and add an error marker. (>>)
- $state = -1;
- $e = Form::compose([[ "", $o, $k, "" ]]);
- $e.= $line =~ /^>>/ ? "$line\n" : ">> $line\n";
- }
- }
- else {
- # We saw a syntax error earlier, so we'll accumulate the
- # contents of this form until the end.
- $e .= "$line\n";
- }
- }
- push(@forms, [ $c, $o, $k, $e ]) if ($e || $c || @$o);
-
- foreach my $l (keys %$k) {
- $k->{$l} = vsplit($k->{$l}) if (ref $k->{$l} eq 'ARRAY');
- }
-
- return \@forms;
-}
-
-# Returns text representing a set of forms.
-sub Form::compose {
- my ($forms) = @_;
- my @text;
-
- foreach my $form (@$forms) {
- my ($c, $o, $k, $e) = @$form;
- my $text = "";
-
- if ($c) {
- $c =~ s/\n*$/\n/;
- $text = "$c\n";
- }
- if ($e) {
- $text .= $e;
- }
- elsif ($o) {
- my @lines;
-
- foreach my $key (@$o) {
- my ($line, $sp);
- my $v = $k->{$key};
- my @values = ref $v eq 'ARRAY' ? @$v : $v;
-
- $sp = " "x(length("$key: "));
- $sp = " "x4 if length($sp) > 16;
-
- foreach $v (@values) {
- if ($v =~ /\n/) {
- $v =~ s/^/$sp/gm;
- $v =~ s/^$sp//;
-
- if ($line) {
- push @lines, "$line\n\n";
- $line = "";
- }
- elsif (@lines && $lines[-1] !~ /\n\n$/) {
- $lines[-1] .= "\n";
- }
- push @lines, "$key: $v\n\n";
- }
- elsif ($line &&
- length($line)+length($v)-rindex($line, "\n") >= 70)
- {
- $line .= ",\n$sp$v";
- }
- else {
- $line = $line ? "$line, $v" : "$key: $v";
- }
- }
-
- $line = "$key:" unless @values;
- if ($line) {
- if ($line =~ /\n/) {
- if (@lines && $lines[-1] !~ /\n\n$/) {
- $lines[-1] .= "\n";
- }
- $line .= "\n";
- }
- push @lines, "$line\n";
- }
- }
-
- $text .= join "", @lines;
- }
- else {
- chomp $text;
- }
- push @text, $text;
- }
-
- return join "\n--\n\n", @text;
-}
-
-# Configuration.
-# --------------
-
-# Returns configuration information from the environment.
-sub config_from_env {
- my %env;
-
- foreach my $k ("DEBUG", "USER", "PASSWD", "SERVER") {
- if (exists $ENV{"RT$k"}) {
- $env{lc $k} = $ENV{"RT$k"};
- }
- }
-
- return %env;
-}
-
-# Finds a suitable configuration file and returns information from it.
-sub config_from_file {
- my ($rc) = @_;
-
- if ($rc =~ m#^/#) {
- # We'll use an absolute path if we were given one.
- return parse_config_file($rc);
- }
- else {
- # Otherwise we'll use the first file we can find in the current
- # directory, or in one of its (increasingly distant) ancestors.
-
- my @dirs = split /\//, cwd;
- while (@dirs) {
- my $file = join('/', @dirs, $rc);
- if (-r $file) {
- return parse_config_file($file);
- }
-
- # Remove the last directory component each time.
- pop @dirs;
- }
-
- # Still nothing? We'll fall back to some likely defaults.
- for ("$HOME/$rc", "/etc/rt.conf") {
- return parse_config_file($_) if (-r $_);
- }
- }
-
- return ();
-}
-
-# Makes a hash of the specified configuration file.
-sub parse_config_file {
- my %cfg;
- my ($file) = @_;
-
- open(CFG, $file) && do {
- while (<CFG>) {
- chomp;
- next if (/^#/ || /^\s*$/);
-
- if (/^(user|passwd|server)\s+([^ ]+)$/) {
- $cfg{$1} = $2;
- }
- else {
- die "rt: $file:$.: unknown configuration directive.\n";
- }
- }
- };
-
- return %cfg;
-}
-
-# Helper functions.
-# -----------------
-
-sub whine {
- my $sub = (caller(1))[3];
- $sub =~ s/^main:://;
- warn "rt: $sub: @_\n";
- return;
-}
-
-sub read_passwd {
- eval 'require Term::ReadKey';
- if ($@) {
- die "No password specified (and Term::ReadKey not installed).\n";
- }
-
- print "Password: ";
- Term::ReadKey::ReadMode('noecho');
- chomp(my $passwd = Term::ReadKey::ReadLine(0));
- Term::ReadKey::ReadMode('restore');
- print "\n";
-
- return $passwd;
-}
-
-sub vi {
- my ($text) = @_;
- my $file = "/tmp/rt.form.$$";
- my $editor = $ENV{EDITOR} || $ENV{VISUAL} || "vi";
-
- local *F;
- local $/ = undef;
-
- open(F, ">$file") || die "$file: $!\n"; print F $text; close(F);
- system($editor, $file) && die "Couldn't run $editor.\n";
- open(F, $file) || die "$file: $!\n"; $text = <F>; close(F);
- unlink($file);
-
- return $text;
-}
-
-# Add a value to a (possibly multi-valued) hash key.
-sub vpush {
- my ($hash, $key, $val) = @_;
- my @val = ref $val eq 'ARRAY' ? @$val : $val;
-
- if (exists $hash->{$key}) {
- unless (ref $hash->{$key} eq 'ARRAY') {
- my @v = $hash->{$key} ne '' ? $hash->{$key} : ();
- $hash->{$key} = \@v;
- }
- push @{ $hash->{$key} }, @val;
- }
- else {
- $hash->{$key} = $val;
- }
-}
-
-# "Normalise" a hash key that's known to be multi-valued.
-sub vsplit {
- my ($val) = @_;
- my ($word, @words);
- my @values = ref $val eq 'ARRAY' ? @$val : $val;
-
- foreach my $line (map {split /\n/} @values) {
- # XXX: This should become a real parser, à la Text::ParseWords.
- $line =~ s/^\s+//;
- $line =~ s/\s+$//;
- push @words, split /\s*,\s*/, $line;
- }
-
- return \@words;
-}
-
-sub expand_list {
- my ($list) = @_;
- my ($elt, @elts, %elts);
-
- foreach $elt (split /,/, $list) {
- if ($elt =~ /^(\d+)-(\d+)$/) { push @elts, ($1..$2) }
- else { push @elts, $elt }
- }
-
- @elts{@elts}=();
- return sort {$a<=>$b} keys %elts;
-}
-
-sub get_type_argument {
- my $type;
-
- if (@ARGV) {
- $type = shift @ARGV;
- unless ($type =~ /^[A-Za-z0-9_.-]+$/) {
- # We want whine to mention our caller, not us.
- @_ = ("Invalid type '$type' specified.");
- goto &whine;
- }
- }
- else {
- @_ = ("No type argument specified with -t.");
- goto &whine;
- }
-
- $type =~ s/s$//; # "Plural". Ugh.
- return $type;
-}
-
-sub get_var_argument {
- my ($data) = @_;
-
- if (@ARGV) {
- my $kv = shift @ARGV;
- if (my ($k, $v) = $kv =~ /^($field)=(.*)$/) {
- push @{ $data->{$k} }, $v;
- }
- else {
- @_ = ("Invalid variable specification: '$kv'.");
- goto &whine;
- }
- }
- else {
- @_ = ("No variable argument specified with -S.");
- goto &whine;
- }
-}
-
-sub is_object_spec {
- my ($spec, $type) = @_;
-
- $spec =~ s|^(?:$type/)?|$type/| if defined $type;
- return $spec if ($spec =~ m{^$name/(?:$idlist|$labels)(?:/.*)?$}o);
- return;
-}
-
-__DATA__
-
-Title: intro
-Title: introduction
-Text:
-
- ** THIS IS AN UNSUPPORTED PREVIEW RELEASE **
- ** PLEASE REPORT BUGS TO rt-bugs@fsck.com **
-
- This is a command-line interface to RT 3.
-
- It allows you to interact with an RT server over HTTP, and offers an
- interface to RT's functionality that is better-suited to automation
- and integration with other tools.
-
- In general, each invocation of this program should specify an action
- to perform on one or more objects, and any other arguments required
- to complete the desired action.
-
- For more information:
-
- - rt help actions (a list of possible actions)
- - rt help objects (how to specify objects)
- - rt help usage (syntax information)
-
- - rt help config (configuration details)
- - rt help examples (a few useful examples)
- - rt help topics (a list of help topics)
-
---
-
-Title: usage
-Title: syntax
-Text:
-
- Syntax:
-
- rt <action> [options] [arguments]
-
- Each invocation of this program must specify an action (e.g. "edit",
- "create"), options to modify behaviour, and other arguments required
- by the specified action. (For example, most actions expect a list of
- numeric object IDs to act upon.)
-
- The details of the syntax and arguments for each action are given by
- "rt help <action>". Some actions may be referred to by more than one
- name ("create" is the same as "new", for example).
-
- Objects are identified by a type and an ID (which can be a name or a
- number, depending on the type). For some actions, the object type is
- implied (you can only comment on tickets); for others, the user must
- specify it explicitly. See "rt help objects" for details.
-
- In syntax descriptions, mandatory arguments that must be replaced by
- appropriate value are enclosed in <>, and optional arguments are
- indicated by [] (for example, <action> and [options] above).
-
- For more information:
-
- - rt help objects (how to specify objects)
- - rt help actions (a list of actions)
- - rt help types (a list of object types)
-
---
-
-Title: conf
-Title: config
-Title: configuration
-Text:
-
- This program has two major sources of configuration information: its
- configuration files, and the environment.
-
- The program looks for configuration directives in a file named .rtrc
- (or $RTCONFIG; see below) in the current directory, and then in more
- distant ancestors, until it reaches /. If no suitable configuration
- files are found, it will also check for ~/.rtrc and /etc/rt.conf.
-
- Configuration directives:
-
- The following directives may occur, one per line:
-
- - server <URL> URL to RT server.
- - user <username> RT username.
- - passwd <passwd> RT user's password.
-
- Blank and #-commented lines are ignored.
-
- Environment variables:
-
- The following environment variables override any corresponding
- values defined in configuration files:
-
- - RTUSER
- - RTPASSWD
- - RTSERVER
- - RTDEBUG Numeric debug level. (Set to 3 for full logs.)
- - RTCONFIG Specifies a name other than ".rtrc" for the
- configuration file.
-
---
-
-Title: objects
-Text:
-
- Syntax:
-
- <type>/<id>[/<attributes>]
-
- Every object in RT has a type (e.g. "ticket", "queue") and a numeric
- ID. Some types of objects can also be identified by name (like users
- and queues). Furthermore, objects may have named attributes (such as
- "ticket/1/history").
-
- An object specification is like a path in a virtual filesystem, with
- object types as top-level directories, object IDs as subdirectories,
- and named attributes as further subdirectories.
-
- A comma-separated list of names, numeric IDs, or numeric ranges can
- be used to specify more than one object of the same type. Note that
- the list must be a single argument (i.e., no spaces). For example,
- "user/root,1-3,5,7-10,ams" is a list of ten users; the same list
- can also be written as "user/ams,root,1,2,3,5,7,8-20".
-
- Examples:
-
- ticket/1
- ticket/1/attachments
- ticket/1/attachments/3
- ticket/1/attachments/3/content
- ticket/1-3/links
- ticket/1-3,5-7/history
-
- user/ams
- user/ams/rights
- user/ams,rai,1/rights
-
- For more information:
-
- - rt help <action> (action-specific details)
- - rt help <type> (type-specific details)
-
---
-
-Title: actions
-Title: commands
-Text:
-
- You can currently perform the following actions on all objects:
-
- - list (list objects matching some condition)
- - show (display object details)
- - edit (edit object details)
- - create (create a new object)
-
- Each type may define actions specific to itself; these are listed in
- the help item about that type.
-
- For more information:
-
- - rt help <action> (action-specific details)
- - rt help types (a list of possible types)
-
---
-
-Title: types
-Text:
-
- You can currently operate on the following types of objects:
-
- - tickets
- - users
- - groups
- - queues
-
- For more information:
-
- - rt help <type> (type-specific details)
- - rt help objects (how to specify objects)
- - rt help actions (a list of possible actions)
-
---
-
-Title: ticket
-Text:
-
- Tickets are identified by a numeric ID.
-
- The following generic operations may be performed upon tickets:
-
- - list
- - show
- - edit
- - create
-
- In addition, the following ticket-specific actions exist:
-
- - link
- - merge
- - comment
- - correspond
-
- Attributes:
-
- The following attributes can be used with "rt show" or "rt edit"
- to retrieve or edit other information associated with tickets:
-
- links A ticket's relationships with others.
- history All of a ticket's transactions.
- history/type/<type> Only a particular type of transaction.
- history/id/<id> Only the transaction of the specified id.
- attachments A list of attachments.
- attachments/<id> The metadata for an individual attachment.
- attachments/<id>/content The content of an individual attachment.
-
---
-
-Title: user
-Title: group
-Text:
-
- Users and groups are identified by name or numeric ID.
-
- The following generic operations may be performed upon them:
-
- - list
- - show
- - edit
- - create
-
- In addition, the following type-specific actions exist:
-
- - grant
- - revoke
-
- Attributes:
-
- The following attributes can be used with "rt show" or "rt edit"
- to retrieve or edit other information associated with users and
- groups:
-
- rights Global rights granted to this user.
- rights/<queue> Queue rights for this user.
-
---
-
-Title: queue
-Text:
-
- Queues are identified by name or numeric ID.
-
- Currently, they can be subjected to the following actions:
-
- - show
- - edit
- - create
-
---
-
-Title: logout
-Text:
-
- Syntax:
-
- rt logout
-
- Terminates the currently established login session. You will need to
- provide authentication credentials before you can continue using the
- server. (See "rt help config" for details about authentication.)
-
---
-
-Title: ls
-Title: list
-Title: search
-Text:
-
- Syntax:
-
- rt <ls|list|search> [options] "query string"
-
- Displays a list of objects matching the specified conditions.
- ("ls", "list", and "search" are synonyms.)
-
- Conditions are expressed in the SQL-like syntax used internally by
- RT3. (For more information, see "rt help query".) The query string
- must be supplied as one argument.
-
- (Right now, the server doesn't support listing anything but tickets.
- Other types will be supported in future; this client will be able to
- take advantage of that support without any changes.)
-
- Options:
-
- The following options control how much information is displayed
- about each matching object:
-
- -i Numeric IDs only. (Useful for |rt edit -; see examples.)
- -s Short description.
- -l Longer description.
-
- In addition,
-
- -o +/-<field> Orders the returned list by the specified field.
- -S var=val Submits the specified variable with the request.
- -t type Specifies the type of object to look for. (The
- default is "ticket".)
-
- Examples:
-
- rt ls "Priority > 5 and Status='new'"
- rt ls -o +Subject "Priority > 5 and Status='new'"
- rt ls -o -Created "Priority > 5 and Status='new'"
- rt ls -i "Priority > 5"|rt edit - set status=resolved
- rt ls -t ticket "Subject like '[PATCH]%'"
-
---
-
-Title: show
-Text:
-
- Syntax:
-
- rt show [options] <object-ids>
-
- Displays details of the specified objects.
-
- For some types, object information is further classified into named
- attributes (for example, "1-3/links" is a valid ticket specification
- that refers to the links for tickets 1-3). Consult "rt help <type>"
- and "rt help objects" for further details.
-
- This command writes a set of forms representing the requested object
- data to STDOUT.
-
- Options:
-
- - Read IDs from STDIN instead of the command-line.
- -t type Specifies object type.
- -f a,b,c Restrict the display to the specified fields.
- -S var=val Submits the specified variable with the request.
-
- Examples:
-
- rt show -t ticket -f id,subject,status 1-3
- rt show ticket/3/attachments/29
- rt show ticket/3/attachments/29/content
- rt show ticket/1-3/links
- rt show -t user 2
-
---
-
-Title: new
-Title: edit
-Title: create
-Text:
-
- Syntax:
-
- rt edit [options] <object-ids> set field=value [field=value] ...
- add field=value [field=value] ...
- del field=value [field=value] ...
-
- Edits information corresponding to the specified objects.
-
- If, instead of "edit", an action of "new" or "create" is specified,
- then a new object is created. In this case, no numeric object IDs
- may be specified, but the syntax and behaviour remain otherwise
- unchanged.
-
- This command typically starts an editor to allow you to edit object
- data in a form for submission. If you specified enough information
- on the command-line, however, it will make the submission directly.
-
- The command line may specify field-values in three different ways.
- "set" sets the named field to the given value, "add" adds a value
- to a multi-valued field, and "del" deletes the corresponding value.
- Each "field=value" specification must be given as a single argument.
-
- For some types, object information is further classified into named
- attributes (for example, "1-3/links" is a valid ticket specification
- that refers to the links for tickets 1-3). These attributes may also
- be edited. Consult "rt help <type>" and "rt help object" for further
- details.
-
- Options:
-
- - Read numeric IDs from STDIN instead of the command-line.
- (Useful with rt ls ... | rt edit -; see examples below.)
- -i Read a completed form from STDIN before submitting.
- -o Dump the completed form to STDOUT instead of submitting.
- -e Allows you to edit the form even if the command-line has
- enough information to make a submission directly.
- -S var=val
- Submits the specified variable with the request.
- -t type Specifies object type.
-
- Examples:
-
- # Interactive (starts $EDITOR with a form).
- rt edit ticket/3
- rt create -t ticket
-
- # Non-interactive.
- rt edit ticket/1-3 add cc=foo@example.com set priority=3
- rt ls -t tickets -i 'Priority > 5' | rt edit - set status=resolved
- rt edit ticket/4 set priority=3 owner=bar@example.com \
- add cc=foo@example.com bcc=quux@example.net
- rt create -t ticket subject='new ticket' priority=10 \
- add cc=foo@example.com
-
---
-
-Title: comment
-Title: correspond
-Text:
-
- Syntax:
-
- rt <comment|correspond> [options] <ticket-id>
-
- Adds a comment (or correspondence) to the specified ticket (the only
- difference being that comments aren't sent to the requestors.)
-
- This command will typically start an editor and allow you to type a
- comment into a form. If, however, you specified all the necessary
- information on the command line, it submits the comment directly.
-
- (See "rt help forms" for more information about forms.)
-
- Options:
-
- -m <text> Specify comment text.
- -a <file> Attach a file to the comment. (May be used more
- than once to attach multiple files.)
- -c <addrs> A comma-separated list of Cc addresses.
- -b <addrs> A comma-separated list of Bcc addresses.
- -w <time> Specify the time spent working on this ticket.
- -e Starts an editor before the submission, even if
- arguments from the command line were sufficient.
-
- Examples:
-
- rt comment -t 'Not worth fixing.' -a stddisclaimer.h 23
-
---
-
-Title: merge
-Text:
-
- Syntax:
-
- rt merge <from-id> <to-id>
-
- Merges the two specified tickets.
-
---
-
-Title: link
-Text:
-
- Syntax:
-
- rt link [-d] <id-A> <relationship> <id-B>
-
- Creates (or, with -d, deletes) a link between the specified tickets.
- The relationship can (irrespective of case) be any of:
-
- DependsOn/DependedOnBy: A depends upon B (or vice versa).
- RefersTo/ReferredToBy: A refers to B (or vice versa).
- MemberOf/HasMember: A is a member of B (or vice versa).
-
- To view a ticket's relationships, use "rt show ticket/3/links". (See
- "rt help ticket" and "rt help show".)
-
- Options:
-
- -d Deletes the specified link.
-
- Examples:
-
- rt link 2 dependson 3
- rt link -d 4 referredtoby 6 # 6 no longer refers to 4
-
---
-
-Title: grant
-Title: revoke
-Text:
-
---
-
-Title: query
-Text:
-
- RT3 uses an SQL-like syntax to specify object selection constraints.
- See the <RT:...> documentation for details.
-
- (XXX: I'm going to have to write it, aren't I?)
-
---
-
-Title: form
-Title: forms
-Text:
-
- This program uses RFC822 header-style forms to represent object data
- in a form that's suitable for processing both by humans and scripts.
-
- A form is a set of (field, value) specifications, with some initial
- commented text and interspersed blank lines allowed for convenience.
- Field names may appear more than once in a form; a comma-separated
- list of multiple field values may also be specified directly.
-
- Field values can be wrapped as in RFC822, with leading whitespace.
- The longest sequence of leading whitespace common to all the lines
- is removed (preserving further indentation). There is no limit on
- the length of a value.
-
- Multiple forms are separated by a line containing only "--\n".
-
- (XXX: A more detailed specification will be provided soon. For now,
- the server-side syntax checking will suffice.)
-
---
-
-Title: topics
-Text:
-
- Use "rt help <topic>" for help on any of the following subjects:
-
- - tickets, users, groups, queues.
- - show, edit, ls/list/search, new/create.
-
- - query (search query syntax)
- - forms (form specification)
-
- - objects (how to specify objects)
- - types (a list of object types)
- - actions/commands (a list of actions)
- - usage/syntax (syntax details)
- - conf/config/configuration (configuration details)
- - examples (a few useful examples)
-
---
-
-Title: example
-Title: examples
-Text:
-
- This section will be filled in with useful examples, once it becomes
- more clear what examples may be useful.
-
- For the moment, please consult examples provided with each action.
-
---
diff --git a/rt/config.layout b/rt/config.layout.in
index 23a7775..a08f489 100644
--- a/rt/config.layout
+++ b/rt/config.layout.in
@@ -102,3 +102,26 @@
customlexdir: ${customdir}/po
customlibdir: ${customdir}/lib
</Layout>
+
+<Layout Freeside>
+ prefix: /opt/rt3
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ sysconfdir: ${prefix}/etc
+ mandir: ${prefix}/man
+ libdir: ${prefix}/lib
+ datadir: ${prefix}/share
+ htmldir: %%%FREESIDE_DOCUMENT_ROOT%%%/rt
+ manualdir: ${datadir}/doc
+ localstatedir: ${prefix}/var
+ logfiledir: ${localstatedir}/log
+ masonstatedir: %%%MASONDATA%%%
+ sessionstatedir: ${localstatedir}/session_data
+ customdir: ${prefix}/local
+ custometcdir: ${customdir}/etc
+ customhtmldir: ${customdir}/html
+ customlexdir: ${customdir}/po
+ customlibdir: ${customdir}/lib
+</Layout>
+
diff --git a/rt/etc/RT_SiteConfig.pm b/rt/etc/RT_SiteConfig.pm
index 0afc604..572a2ba 100644
--- a/rt/etc/RT_SiteConfig.pm
+++ b/rt/etc/RT_SiteConfig.pm
@@ -1 +1,13 @@
+$RT::rtname = '%%%RT_DOMAIN%%%';
+$RT::Organization = '%%%RT_DOMAIN%%%';
+
+$RT::Timezone = '%%%RT_TIMEZONE%%%';
+
+$RT::WebBaseURL = '';
+$RT::WebPath = '/freeside/rt';
+
+$RT::WebExternalAuth = 1;
+$RT::WebFallbackToInternal = 1; #no
+$RT::WebExternalAuto = 1;
+
1;
diff --git a/rt/etc/schema.Oracle b/rt/etc/schema.Oracle
deleted file mode 100644
index 95cfda2..0000000
--- a/rt/etc/schema.Oracle
+++ /dev/null
@@ -1,354 +0,0 @@
-CREATE SEQUENCE ATTACHMENTS_seq;
-CREATE TABLE Attachments (
- id NUMBER(11,0)
- CONSTRAINT Attachments_Key PRIMARY KEY,
- TransactionId NUMBER(11,0) NOT NULL,
- Parent NUMBER(11,0) DEFAULT 0 NOT NULL,
- MessageId VARCHAR2(160),
- Subject VARCHAR2(255),
- Filename VARCHAR2(255),
- ContentType VARCHAR2(80),
- ContentEncoding VARCHAR2(80),
- Content CLOB,
- Headers CLOB,
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE
-);
-CREATE INDEX Attachments2 ON Attachments (TransactionId);
-CREATE INDEX Attachments3 ON Attachments (Parent, TransactionId);
-
-
-CREATE SEQUENCE QUEUES_seq;
-CREATE TABLE Queues (
- id NUMBER(11,0)
- CONSTRAINT Queues_Key PRIMARY KEY,
- Name VARCHAR2(200) CONSTRAINT Queues_Name_Unique UNIQUE NOT NULL,
- Description VARCHAR2(255),
- CorrespondAddress VARCHAR2(120),
- CommentAddress VARCHAR2(120),
- InitialPriority NUMBER(11,0) DEFAULT 0 NOT NULL,
- FinalPriority NUMBER(11,0) DEFAULT 0 NOT NULL,
- DefaultDueIn NUMBER(11,0) DEFAULT 0 NOT NULL,
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE,
- Disabled NUMBER(11,0) DEFAULT 0 NOT NULL
-);
- CREATE INDEX Queues1 ON Queues (lower(Name));
-CREATE INDEX Queues2 ON Queues (Disabled);
-
-
-CREATE SEQUENCE LINKS_seq;
-CREATE TABLE Links (
- id NUMBER(11,0)
- CONSTRAINT Links_Key PRIMARY KEY,
- Base VARCHAR2(240),
- Target VARCHAR2(240),
- Type VARCHAR2(20) NOT NULL,
- LocalTarget NUMBER(11,0) DEFAULT 0 NOT NULL,
- LocalBase NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE,
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE
-);
-CREATE UNIQUE INDEX Links1 ON Links (Base, Target, Type);
-CREATE INDEX Links2 ON Links (Base, Type);
-CREATE INDEX Links3 ON Links (Target, Type);
-CREATE INDEX Links4 ON Links(Type,LocalBase);
-
-
-CREATE SEQUENCE PRINCIPALS_seq;
-CREATE TABLE Principals (
- id NUMBER(11,0)
- CONSTRAINT Principals_Key PRIMARY KEY,
- PrincipalType VARCHAR2(16),
- ObjectId NUMBER(11,0),
- Disabled NUMBER(11,0) DEFAULT 0 NOT NULL
-);
-CREATE UNIQUE INDEX Principals2 ON Principals (ObjectId);
-
-
-CREATE SEQUENCE GROUPS_seq;
-CREATE TABLE Groups (
- id NUMBER(11,0)
- CONSTRAINT Groups_Key PRIMARY KEY,
- Name VARCHAR2(200),
- Description VARCHAR2(255),
- Domain VARCHAR2(64),
- Type VARCHAR2(64),
- Instance NUMBER(11,0) DEFAULT 0 -- NOT NULL
--- Instance VARCHAR2(64)
-);
-CREATE INDEX Groups1 ON Groups (lower( Domain), Instance, lower(Type), id);
-CREATE INDEX Groups2 ON Groups (lower(Type), Instance, lower(Domain));
-
-
-CREATE SEQUENCE SCRIPCONDITIONS_seq;
-CREATE TABLE ScripConditions (
- id NUMBER(11, 0)
- CONSTRAINT ScripConditions_Key PRIMARY KEY,
- Name VARCHAR2(200),
- Description VARCHAR2(255),
- ExecModule VARCHAR2(60),
- Argument VARCHAR2(255),
- ApplicableTransTypes VARCHAR2(60),
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE
-);
-
-
-CREATE SEQUENCE TRANSACTIONS_seq;
-CREATE TABLE Transactions (
- id NUMBER(11,0)
- CONSTRAINT Transactions_Key PRIMARY KEY,
- EffectiveTicket NUMBER(11,0) DEFAULT 0 NOT NULL,
- Ticket NUMBER(11,0) DEFAULT 0 NOT NULL,
- TimeTaken NUMBER(11,0) DEFAULT 0 NOT NULL,
- Type VARCHAR2(20),
- Field VARCHAR2(40),
- OldValue VARCHAR2(255),
- NewValue VARCHAR2(255),
- Data VARCHAR2(255),
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE
-);
-CREATE INDEX Transactions1 ON Transactions (Ticket);
-CREATE INDEX Transactions2 ON Transactions (EffectiveTicket);
-
-
-CREATE SEQUENCE SCRIPS_seq;
-CREATE TABLE Scrips (
- id NUMBER(11,0)
- CONSTRAINT Scrips_Key PRIMARY KEY,
- Description VARCHAR2(255),
- ScripCondition NUMBER(11,0) DEFAULT 0 NOT NULL,
- ScripAction NUMBER(11,0) DEFAULT 0 NOT NULL,
- ConditionRules CLOB,
- ActionRules CLOB,
- CustomIsApplicableCode CLOB,
- CustomPrepareCode CLOB,
- CustomCommitCode CLOB,
- Stage VARCHAR2(32),
- Queue NUMBER(11,0) DEFAULT 0 NOT NULL,
- Template NUMBER(11,0) DEFAULT 0 NOT NULL,
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE
-);
-
-
-CREATE SEQUENCE ACL_seq;
-CREATE TABLE ACL (
- id NUMBER(11,0)
- CONSTRAINT ACL_Key PRIMARY KEY,
- PrincipalType VARCHAR2(25) NOT NULL,
- PrincipalId NUMBER(11,0) NOT NULL,
- RightName VARCHAR2(25) NOT NULL,
- ObjectType VARCHAR2(25) NOT NULL,
- ObjectId NUMBER(11,0) DEFAULT 0 NOT NULL,
- DelegatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- DelegatedFrom NUMBER(11,0) DEFAULT 0 NOT NULL
-);
-CREATE INDEX ACL1 ON ACL(RightName, ObjectType, ObjectId, PrincipalType, PrincipalId);
-
-
-CREATE SEQUENCE GROUPMEMBERS_seq;
-CREATE TABLE GroupMembers (
- id NUMBER(11,0)
- CONSTRAINT GroupMembers_Key PRIMARY KEY,
- GroupId NUMBER(11,0) DEFAULT 0 NOT NULL,
- MemberId NUMBER(11,0) DEFAULT 0 NOT NULL
-);
-CREATE UNIQUE INDEX GroupMembers1 ON GroupMembers (GroupId, MemberId);
-
-
-CREATE SEQUENCE CachedGroupMembers_seq;
-CREATE TABLE CachedGroupMembers (
- id NUMBER(11,0)
- CONSTRAINT CachedGroupMembers_Key PRIMARY KEY,
- GroupId NUMBER(11,0),
- MemberId NUMBER(11,0),
- Via NUMBER(11,0),
- ImmediateParentId NUMBER(11,0),
- Disabled NUMBER(11,0) DEFAULT 0 NOT NULL
-);
-CREATE INDEX DisGrouMem ON CachedGroupMembers (GroupId, MemberId, Disabled);
-CREATE INDEX GrouMem ON CachedGroupMembers (GroupId, MemberId);
-
-
-CREATE SEQUENCE USERS_seq;
-CREATE TABLE Users (
- id NUMBER(11,0)
- CONSTRAINT Users_Key PRIMARY KEY,
- Name VARCHAR2(200) CONSTRAINT Users_Name_Unique
- unique NOT NULL,
- Password VARCHAR2(40),
- Comments CLOB,
- Signature CLOB,
- EmailAddress VARCHAR2(120),
- FreeFormContactInfo CLOB,
- Organization VARCHAR2(200),
- RealName VARCHAR2(120),
- NickName VARCHAR2(16),
- Lang VARCHAR2(16),
- EmailEncoding VARCHAR2(16),
- WebEncoding VARCHAR2(16),
- ExternalContactInfoId VARCHAR2(100),
- ContactInfoSystem VARCHAR2(30),
- ExternalAuthId VARCHAR2(100),
- AuthSystem VARCHAR2(30),
- Gecos VARCHAR2(16),
- HomePhone VARCHAR2(30),
- WorkPhone VARCHAR2(30),
- MobilePhone VARCHAR2(30),
- PagerPhone VARCHAR2(30),
- Address1 VARCHAR2(200),
- Address2 VARCHAR2(200),
- City VARCHAR2(100),
- State VARCHAR2(100),
- Zip VARCHAR2(16),
- Country VARCHAR2(50),
- Timezone VARCHAR2(50),
- PGPKey CLOB,
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE
-);
--- CREATE UNIQUE INDEX Users1 ON Users (Name);
-
-CREATE INDEX Users2 ON Users( LOWER(name));
-CREATE INDEX Users4 ON Users (lower(EmailAddress));
-
-
-CREATE SEQUENCE TICKETS_seq;
-CREATE TABLE Tickets (
- id NUMBER(11, 0)
- CONSTRAINT Tickets_Key PRIMARY KEY,
- EffectiveId NUMBER(11,0) DEFAULT 0 NOT NULL,
- Queue NUMBER(11,0) DEFAULT 0 NOT NULL,
- Type VARCHAR2(16),
- IssueStatement NUMBER(11,0) DEFAULT 0 NOT NULL,
- Resolution NUMBER(11,0) DEFAULT 0 NOT NULL,
- Owner NUMBER(11,0) DEFAULT 0 NOT NULL,
- Subject VARCHAR2(200) DEFAULT '[no subject]',
- InitialPriority NUMBER(11,0) DEFAULT 0 NOT NULL,
- FinalPriority NUMBER(11,0) DEFAULT 0 NOT NULL,
- Priority NUMBER(11,0) DEFAULT 0 NOT NULL,
- TimeEstimated NUMBER(11,0) DEFAULT 0 NOT NULL,
- TimeWorked NUMBER(11,0) DEFAULT 0 NOT NULL,
- Status VARCHAR2(10),
- TimeLeft NUMBER(11,0) DEFAULT 0 NOT NULL,
- Told DATE,
- Starts DATE,
- Started DATE,
- Due DATE,
- Resolved DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE,
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE,
- Disabled NUMBER(11,0) DEFAULT 0 NOT NULL
-);
-CREATE INDEX Tickets1 ON Tickets (Queue, Status);
-CREATE INDEX Tickets2 ON Tickets (Owner);
-CREATE INDEX Tickets4 ON Tickets (id, Status);
-CREATE INDEX Tickets5 ON Tickets (id, EffectiveId);
-CREATE INDEX Tickets6 ON Tickets (EffectiveId, Type);
-
-
-CREATE SEQUENCE SCRIPACTIONS_seq;
-CREATE TABLE ScripActions (
- id NUMBER(11,0)
- CONSTRAINT ScripActions_Key PRIMARY KEY,
- Name VARCHAR2(200),
- Description VARCHAR2(255),
- ExecModule VARCHAR2(60),
- Argument VARCHAR2(255),
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE
-);
-
-
-CREATE SEQUENCE TEMPLATES_seq;
-CREATE TABLE Templates (
- id NUMBER(11,0)
- CONSTRAINT Templates_Key PRIMARY KEY,
- Queue NUMBER(11,0) DEFAULT 0 NOT NULL,
- Name VARCHAR2(200) NOT NULL,
- Description VARCHAR2(255),
- Type VARCHAR2(16),
- Language VARCHAR2(16),
- TranslationOf NUMBER(11,0) DEFAULT 0 NOT NULL,
- Content CLOB,
- LastUpdated DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE
-);
-
-
-CREATE SEQUENCE TICKETCUSTOMFIELDVALUES_seq;
-CREATE TABLE TicketCustomFieldValues (
- id NUMBER(11,0)
- CONSTRAINT TicketCustomFieldValues_Key PRIMARY KEY,
- Ticket NUMBER(11,0),
- CustomField NUMBER(11,0) NOT NULL,
- Content VARCHAR2(255),
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE
-);
-
-CREATE INDEX TicketCustomFieldValues1 ON TicketCustomFieldValues (CustomField,Ticket,Content);
-CREATE INDEX TicketCustomFieldValues2 ON TicketCustomFieldValues (CustomField,Ticket);
-
-CREATE SEQUENCE CUSTOMFIELDS_seq;
-CREATE TABLE CustomFields (
- id NUMBER(11,0)
- CONSTRAINT CustomFields_Key PRIMARY KEY,
- Name VARCHAR2(200),
- Type VARCHAR2(200),
- Queue NUMBER(11,0) DEFAULT 0 NOT NULL,
- Description VARCHAR2(255),
- SortOrder NUMBER(11,0) DEFAULT 0 NOT NULL,
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE,
- Disabled NUMBER(11,0) DEFAULT 0 NOT NULL
-);
-CREATE INDEX CustomFields1 ON CustomFields (Disabled, Queue);
-
-
-CREATE SEQUENCE CUSTOMFIELDVALUES_seq;
-CREATE TABLE CustomFieldValues (
- id NUMBER(11,0)
- CONSTRAINT CustomFieldValues_Key PRIMARY KEY,
- CustomField NUMBER(11,0),
- Name VARCHAR2(200),
- Description VARCHAR2(255),
- SortOrder NUMBER(11,0) DEFAULT 0 NOT NULL,
- Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
- Created DATE,
- LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
- LastUpdated DATE
-);
-
-CREATE INDEX CustomFieldValues1 ON CustomFieldValues (CustomField);
-
-CREATE TABLE sessions (
- id VARCHAR2(32)
- CONSTRAINT Sessions_Key PRIMARY KEY,
- a_session CLOB,
- LastUpdated DATE
-);
-
diff --git a/rt/lib/RT/URI/freeside.pm b/rt/lib/RT/URI/freeside.pm
new file mode 100644
index 0000000..bfb514d
--- /dev/null
+++ b/rt/lib/RT/URI/freeside.pm
@@ -0,0 +1,188 @@
+# BEGIN LICENSE BLOCK
+#
+# Copyright (c) 2004 Kristian Hoffmann <khoff@fire2wire.com>
+# Based on the original RT::URI::base and RT::URI::fsck_com_rt.
+#
+# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+#
+# (Except where explictly superceded by other copyright notices)
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# Unless otherwise specified, all modifications, corrections or
+# extensions to this work which alter its source code become the
+# property of Best Practical Solutions, LLC when submitted for
+# inclusion in the work.
+#
+#
+# END LICENSE BLOCK
+package RT::URI::freeside;
+
+use RT::URI::base;
+use strict;
+use vars qw(@ISA);
+
+@ISA = qw/RT::URI::base/;
+
+
+=head1 NAME
+
+RT::URI::base
+
+=head1 DESCRIPTION
+
+URI handler for freeside URIs. See http://www.sisd.com/freeside/ for
+more information on freeside.
+
+=cut
+
+
+sub FreesideURIPrefix {
+
+ my $self = shift;
+ return($self->Scheme . '://freeside');
+
+}
+
+sub FreesideURILabel {
+
+ my $self = shift;
+
+ return(undef) unless (exists($self->{'fstable'}) and
+ exists($self->{'fspkey'}));
+
+ my $label;
+ my ($table, $pkey) = ($self->{'fstable'}, $self->{'fspkey'});
+
+ eval {
+ use FS::UID qw(dbh);
+ use FS::Record qw(qsearchs qsearch dbdef);
+ eval "use FS::$table;";
+ use FS::cust_svc;
+
+ my $dbdef = dbdef or die "No dbdef";
+ my $pkeyfield = $dbdef->table($table)->primary_key
+ or die "No primary key for table $table";
+
+ my $rec = qsearchs($table, { $pkeyfield => $pkey })
+ or die "Record with $pkeyfield == $pkey does not exist in table $table";
+
+ if ($table =~ /^svc_/) {
+ if ($rec->can('cust_svc')) {
+ my $cust_svc = $rec->cust_svc or die '$rec->cust_svc failed';
+ my ($svc, $tag, $svcdb) = $cust_svc->label;
+ $label = "Freeside service ${svc}: ${tag}";
+ }
+ } elsif ($table eq 'cust_main') {
+ my ($last, $first, $company) = map { $rec->getfield($_) }
+ qw(last first company);
+ $label = "Freeside customer ${last}, ${first}";
+ $label .= ($company ne '') ? " with ${company}" : '';
+ } else {
+ $label = "Freeside ${table}, ${pkeyfield} == ${pkey}";
+ }
+
+ #... other cases
+
+ };
+
+ if ($label and !$@) {
+ return($label);
+ } else {
+ return(undef);
+ }
+
+
+}
+
+sub ParseURI {
+ my $self = shift;
+ my $uri = shift;
+ my ($table, $pkey);
+
+ my $uriprefix = $self->FreesideURIPrefix;
+ if ($uri =~ /^$uriprefix\/(\w+)\/(\d+)$/) {
+ $table = $1;
+ $pkey = $2;
+ $self->{'scheme'} = $self->Scheme;
+ } else {
+ return(undef);
+ }
+
+ $self->{'uri'} = "${uriprefix}/${table}/${pkey}";
+ $self->{'fstable'} = $table;
+ $self->{'fspkey'} = $pkey;
+
+ my $p;
+
+ eval {
+ use FS::UID qw(dbh);
+ use FS::CGI qw(popurl);
+
+ if (dbh) {
+ $p = popurl(3);
+ }
+
+ };
+
+ if ($@ or (!$p)) {
+ $self->{'href'} = $self->{'uri'};
+ } else {
+ $self->{'href'} = "${p}view/${table}.cgi?${pkey}";
+ }
+
+ $self->{'uri'};
+
+}
+
+sub Scheme {
+ my $self = shift;
+ return('freeside');
+
+}
+
+sub HREF {
+ my $self = shift;
+ return($self->{'href'} || $self->{'uri'});
+}
+
+sub IsLocal {
+ my $self = shift;
+ return undef;
+}
+
+=head2 AsString
+
+Return a "pretty" string representing the URI object.
+
+This is meant to be used like this:
+
+ % $re = $uri->Resolver;
+ <A HREF="<% $re->HREF %>"><% $re->AsString %></A>
+
+=cut
+
+sub AsString {
+ my $self = shift;
+ my $prettystring;
+ if ($prettystring = $self->FreesideURILabel) {
+ return $prettystring;
+ } else {
+ return $self->URI;
+ }
+}
+
+eval "require RT::URI::base_Vendor";
+die $@ if ($@ && $@ !~ qr{^Can't locate RT/URI/base_Vendor.pm});
+eval "require RT::URI::base_Local";
+die $@ if ($@ && $@ !~ qr{^Can't locate RT/URI/base_Local.pm});
+
+1;
diff --git a/rt/sbin/rt-setup-database b/rt/sbin/rt-setup-database
index 58f882f..1781988 100644
--- a/rt/sbin/rt-setup-database
+++ b/rt/sbin/rt-setup-database
@@ -110,6 +110,9 @@ elsif ( $args{'action'} eq 'drop' ) {
}
drop_db();
}
+elsif ( $args{'action'} eq 'insert_initial' ) {
+ insert_initial_data();
+}
elsif ( $args{'action'} eq 'insert' ) {
insert_data( $args{'datafile'} );
}
@@ -589,6 +592,8 @@ $0: Set up RT's database
--action init Initialize the database
drop Drop the database.
This will ERASE ALL YOUR DATA
+ insert_initial
+ Insert RT's core system objects
insert Insert data into RT's database.
By default, will use RT's installation data.
To use a local or supplementary datafile, specify it
diff --git a/rt/sbin/rt-setup-database.in b/rt/sbin/rt-setup-database.in
index 9e990e5..56f4e87 100644
--- a/rt/sbin/rt-setup-database.in
+++ b/rt/sbin/rt-setup-database.in
@@ -110,6 +110,9 @@ elsif ( $args{'action'} eq 'drop' ) {
}
drop_db();
}
+elsif ( $args{'action'} eq 'insert_initial' ) {
+ insert_initial_data();
+}
elsif ( $args{'action'} eq 'insert' ) {
insert_data( $args{'datafile'} );
}
@@ -589,6 +592,8 @@ $0: Set up RT's database
--action init Initialize the database
drop Drop the database.
This will ERASE ALL YOUR DATA
+ insert_initial
+ Insert RT's core system objects
insert Insert data into RT's database.
By default, will use RT's installation data.
To use a local or supplementary datafile, specify it
diff --git a/sql-ledger/SL/AM.pm b/sql-ledger/SL/AM.pm
new file mode 100644
index 0000000..d691b3c
--- /dev/null
+++ b/sql-ledger/SL/AM.pm
@@ -0,0 +1,694 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Administration module
+# Chart of Accounts
+# template routines
+# preferences
+#
+#======================================================================
+
+package AM;
+
+
+sub get_account {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT accno, description, charttype, gifi_accno,
+ category, link
+ FROM chart
+ WHERE id = $form->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+
+ foreach my $key (keys %$ref) {
+ $form->{"$key"} = $ref->{"$key"};
+ }
+
+ $sth->finish;
+
+
+ # get default accounts
+ $query = qq|SELECT inventory_accno_id, income_accno_id, expense_accno_id
+ FROM defaults|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+
+ map { $form->{$_} = $ref->{$_} } keys %ref;
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub save_account {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn off AutoCommit
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # sanity check, can't have AR with AR_...
+ if ($form->{AR} || $form->{AP} || $form->{IC}) {
+ map { delete $form->{$_} } qw(AR_amount AR_tax AR_paid AP_amount AP_tax AP_paid IC_sale IC_cogs IC_taxpart IC_income IC_expense IC_taxservice);
+ }
+
+ $form->{link} = "";
+ foreach my $item ($form->{AR},
+ $form->{AR_amount},
+ $form->{AR_tax},
+ $form->{AR_paid},
+ $form->{AP},
+ $form->{AP_amount},
+ $form->{AP_tax},
+ $form->{AP_paid},
+ $form->{IC},
+ $form->{IC_sale},
+ $form->{IC_cogs},
+ $form->{IC_taxpart},
+ $form->{IC_income},
+ $form->{IC_expense},
+ $form->{IC_taxservice},
+ $form->{CT_tax}
+ ) {
+ $form->{link} .= "${item}:" if ($item);
+ }
+ chop $form->{link};
+
+ # if we have an id then replace the old record
+ $form->{description} =~ s/'/''/g;
+
+ # strip blanks from accno
+ map { $form->{$_} =~ s/ //g; } qw(accno gifi_accno);
+
+ my ($query, $sth);
+
+ if ($form->{id}) {
+ $query = qq|UPDATE chart SET
+ accno = '$form->{accno}',
+ description = '$form->{description}',
+ charttype = '$form->{charttype}',
+ gifi_accno = '$form->{gifi_accno}',
+ category = '$form->{category}',
+ link = '$form->{link}'
+ WHERE id = $form->{id}|;
+ } else {
+ $query = qq|INSERT INTO chart
+ (accno, description, charttype, gifi_accno, category, link)
+ VALUES ('$form->{accno}', '$form->{description}',
+ '$form->{charttype}', '$form->{gifi_accno}',
+ '$form->{category}', '$form->{link}')|;
+ }
+ $dbh->do($query) || $form->dberror($query);
+
+
+ if ($form->{IC_taxpart} || $form->{IC_taxservice} || $form->{CT_tax}) {
+
+ my $chart_id = $form->{id};
+
+ unless ($form->{id}) {
+ # get id from chart
+ $query = qq|SELECT id
+ FROM chart
+ WHERE accno = '$form->{accno}'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($chart_id) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+
+ # add account if it doesn't exist in tax
+ $query = qq|SELECT chart_id
+ FROM tax
+ WHERE chart_id = $chart_id|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my ($tax_id) = $sth->fetchrow_array;
+ $sth->finish;
+
+ # add tax if it doesn't exist
+ unless ($tax_id) {
+ $query = qq|INSERT INTO tax (chart_id, rate)
+ VALUES ($chart_id, 0)|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ } else {
+ # remove tax
+ if ($form->{id}) {
+ $query = qq|DELETE FROM tax
+ WHERE chart_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+
+ # commit
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub delete_account {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn off AutoCommit
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # delete chart of account record
+ $query = qq|DELETE FROM chart
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # set inventory_accno_id, income_accno_id, expense_accno_id to defaults
+ $query = qq|UPDATE parts
+ SET inventory_accno_id =
+ (SELECT inventory_accno_id FROM defaults)
+ WHERE inventory_accno_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|UPDATE parts
+ SET income_accno_id =
+ (SELECT income_accno_id FROM defaults)
+ WHERE income_accno_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|UPDATE parts
+ SET expense_accno_id =
+ (SELECT expense_accno_id FROM defaults)
+ WHERE expense_accno_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ foreach my $table (qw(partstax customertax vendortax tax)) {
+ $query = qq|DELETE FROM $table
+ WHERE chart_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ # commit and redirect
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+sub gifi_accounts {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT accno, description
+ FROM gifi
+ ORDER BY accno|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{ALL} }, $ref;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+
+sub get_gifi {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT accno, description
+ FROM gifi
+ WHERE accno = '$form->{accno}'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub save_gifi {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ $form->{description} =~ s/'/''/g;
+ $form->{accno} =~ s/ //g;
+
+ # id is the old account number!
+ if ($form->{id}) {
+ $query = qq|UPDATE gifi SET
+ accno = '$form->{accno}',
+ description = '$form->{description}'
+ WHERE accno = '$form->{id}'|;
+ } else {
+ $query = qq|INSERT INTO gifi
+ (accno, description)
+ VALUES ('$form->{accno}', '$form->{description}')|;
+ }
+ $dbh->do($query) || $form->dberror($query);
+
+ $dbh->disconnect;
+
+}
+
+
+sub delete_gifi {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # id is the old account number!
+ $query = qq|DELETE FROM gifi
+ WHERE accno = '$form->{id}'|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $dbh->disconnect;
+
+}
+
+
+sub load_template {
+ my ($self, $form) = @_;
+
+ open(TEMPLATE, "$form->{file}") or $form->error("$form->{file} : $!");
+
+ while (<TEMPLATE>) {
+ $form->{body} .= $_;
+ }
+
+ close(TEMPLATE);
+
+}
+
+
+sub save_template {
+ my ($self, $form) = @_;
+
+ open(TEMPLATE, ">$form->{file}") or $form->error("$form->{file} : $!");
+
+ # strip
+ $form->{body} =~ s/\r\n/\n/g;
+ print TEMPLATE $form->{body};
+
+ close(TEMPLATE);
+
+}
+
+
+
+sub save_preferences {
+ my ($self, $myconfig, $form, $memberfile, $userspath) = @_;
+
+ map { ($form->{$_}) = split /--/, $form->{$_} } qw(inventory_accno income_accno expense_accno fxgain_accno fxloss_accno);
+
+ my @a;
+ $form->{curr} =~ s/ //g;
+ map { push(@a, uc pack "A3", $_) if $_ } split /:/, $form->{curr};
+ $form->{curr} = join ':', @a;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # these defaults are database wide
+ # user specific variables are in myconfig
+ # save defaults
+ my $query = qq|UPDATE defaults SET
+ inventory_accno_id =
+ (SELECT id FROM chart
+ WHERE accno = '$form->{inventory_accno}'),
+ income_accno_id =
+ (SELECT id FROM chart
+ WHERE accno = '$form->{income_accno}'),
+ expense_accno_id =
+ (SELECT id FROM chart
+ WHERE accno = '$form->{expense_accno}'),
+ fxgain_accno_id =
+ (SELECT id FROM chart
+ WHERE accno = '$form->{fxgain_accno}'),
+ fxloss_accno_id =
+ (SELECT id FROM chart
+ WHERE accno = '$form->{fxloss_accno}'),
+ invnumber = '$form->{invnumber}',
+ sonumber = '$form->{sonumber}',
+ ponumber = '$form->{ponumber}',
+ yearend = '$form->{yearend}',
+ curr = '$form->{curr}',
+ weightunit = '$form->{weightunit}',
+ businessnumber = '$form->{businessnumber}'
+ |;
+ $dbh->do($query) || $form->dberror($query);
+
+ # update name
+ my $name = $form->{name};
+ $name =~ s/'/''/g;
+ $query = qq|UPDATE employee
+ SET name = '$name'
+ WHERE login = '$form->{login}'|;
+ $dbh->do($query) || $form->dberror($query);
+
+ foreach my $item (split / /, $form->{taxaccounts}) {
+ $query = qq|UPDATE tax
+ SET rate = |.($form->{$item} / 100).qq|,
+ taxnumber = '$form->{"taxnumber_$item"}'
+ WHERE chart_id = $item|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ # save first currency in myconfig
+ $form->{currency} = substr($form->{curr},0,3);
+
+ my $myconfig = new User "$memberfile", "$form->{login}";
+
+ foreach my $item (keys %$form) {
+ $myconfig->{$item} = $form->{$item};
+ }
+
+ $myconfig->save_member($memberfile, $userspath);
+
+ $rc;
+
+}
+
+
+sub defaultaccounts {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # get defaults from defaults table
+ my $query = qq|SELECT * FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $form->{defaults} = $sth->fetchrow_hashref(NAME_lc);
+ $form->{defaults}{IC} = $form->{defaults}{inventory_accno_id};
+ $form->{defaults}{IC_income} = $form->{defaults}{income_accno_id};
+ $form->{defaults}{IC_expense} = $form->{defaults}{expense_accno_id};
+ $form->{defaults}{FX_gain} = $form->{defaults}{fxgain_accno_id};
+ $form->{defaults}{FX_loss} = $form->{defaults}{fxloss_accno_id};
+
+
+ $sth->finish;
+
+
+ $query = qq|SELECT id, accno, description, link
+ FROM chart
+ WHERE link LIKE '%IC%'
+ ORDER BY accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ foreach my $key (split(/:/, $ref->{link})) {
+ if ($key =~ /IC/) {
+ $nkey = $key;
+ if ($key =~ /cogs/) {
+ $nkey = "IC_expense";
+ }
+ if ($key =~ /sale/) {
+ $nkey = "IC_income";
+ }
+ %{ $form->{IC}{$nkey}{$ref->{accno}} } = ( id => $ref->{id},
+ description => $ref->{description} );
+ }
+ }
+ }
+ $sth->finish;
+
+
+ $query = qq|SELECT id, accno, description
+ FROM chart
+ WHERE category = 'I'
+ AND charttype = 'A'
+ ORDER BY accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ %{ $form->{IC}{FX_gain}{$ref->{accno}} } = ( id => $ref->{id},
+ description => $ref->{description} );
+ }
+ $sth->finish;
+
+ $query = qq|SELECT id, accno, description
+ FROM chart
+ WHERE category = 'E'
+ AND charttype = 'A'
+ ORDER BY accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ %{ $form->{IC}{FX_loss}{$ref->{accno}} } = ( id => $ref->{id},
+ description => $ref->{description} );
+ }
+ $sth->finish;
+
+
+ # now get the tax rates and numbers
+ $query = qq|SELECT chart.id, chart.accno, chart.description,
+ tax.rate * 100 AS rate, tax.taxnumber
+ FROM chart, tax
+ WHERE chart.id = tax.chart_id|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $form->{taxrates}{$ref->{accno}}{id} = $ref->{id};
+ $form->{taxrates}{$ref->{accno}}{description} = $ref->{description};
+ $form->{taxrates}{$ref->{accno}}{taxnumber} = $ref->{taxnumber} if $ref->{taxnumber};
+ $form->{taxrates}{$ref->{accno}}{rate} = $ref->{rate} if $ref->{rate};
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub backup {
+ my ($self, $myconfig, $form, $userspath) = @_;
+
+ my ($tmpfile, $out, $mail);
+
+ if ($form->{media} eq 'email') {
+
+ my $boundary = time;
+ $tmpfile = "$userspath/$boundary.$myconfig->{dbname}-$form->{dbversion}.sql";
+ $out = $form->{OUT};
+ $form->{OUT} = ">$tmpfile";
+
+ use SL::Mailer;
+ $mail = new Mailer;
+
+ $mail->{to} = qq|"$myconfig->{name}" <$myconfig->{email}>|;
+ $mail->{from} = qq|"$myconfig->{name}" <$myconfig->{email}>|;
+ $mail->{subject} = "SQL-Ledger Backup / $myconfig->{dbname}-$form->{dbversion}.sql";
+ @{ $mail->{attachments} } = ($tmpfile);
+ $mail->{version} = $form->{version};
+ $mail->{fileid} = "$boundary.";
+
+ $myconfig->{signature} =~ s/\\n/\r\n/g;
+ $mail->{message} = "--\n$myconfig->{signature}";
+
+ }
+
+ if ($form->{OUT}) {
+ open(OUT, "$form->{OUT}") or $form->error("$form->{OUT} : $!");
+ } else {
+ open(OUT, ">-") or $form->error("STDOUT : $!");
+ }
+
+ if ($form->{media} eq 'file') {
+ print OUT qq|Content-Type: Application/File;
+Content-Disposition: filename="$myconfig->{dbname}-$form->{dbversion}.sql"\n\n|;
+ }
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # get all the tables
+ my @tables = $dbh->tables;
+
+ my $today = scalar localtime;
+
+
+ $myconfig->{dbhost} = 'localhost' unless $myconfig->{dbhost};
+
+ print OUT qq|-- SQL-Ledger Backup
+-- Dataset: $myconfig->{dbname}
+-- Version: $form->{dbversion}
+-- Host: $myconfig->{dbhost}
+-- Login: $form->{login}
+-- User: $myconfig->{name}
+-- Date: $today
+--
+-- set options
+$myconfig->{dboptions};
+--
+|;
+
+ foreach $table (@tables) {
+ my $query = qq|SELECT * FROM $table|;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $query = qq|INSERT INTO $table (|;
+ map { $query .= qq|$sth->{NAME}->[$_],| } (0 .. $sth->{NUM_OF_FIELDS} - 1);
+ chop $query;
+
+ $query .= qq|) VALUES|;
+
+ print OUT qq|--
+DELETE FROM $table;
+|;
+ while (my @arr = $sth->fetchrow_array) {
+
+ $fields = "(";
+ foreach my $item (@arr) {
+ if (defined $item) {
+ $item =~ s/'/''/g;
+ $fields .= qq|'$item',|;
+ } else {
+ $fields .= 'NULL,';
+ }
+ }
+
+ chop $fields;
+ $fields .= ")";
+
+ print OUT qq|$query $fields;\n|;
+ }
+
+ $sth->finish;
+ }
+
+ $query = qq|SELECT last_value FROM id|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my ($id) = $sth->fetchrow_array;
+ $sth->finish;
+
+ print OUT qq|--
+DROP SEQUENCE id;
+CREATE SEQUENCE id START $id;
+|;
+
+ close(OUT);
+
+ $dbh->disconnect;
+
+ if ($form->{media} eq 'email') {
+ my $err = $mail->send($out);
+ $_ = $tmpfile;
+ unlink;
+ }
+
+}
+
+
+sub closedto {
+ my ($self, $myconfig, $form) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT closedto, revtrans FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{closedto}, $form->{revtrans}) = $sth->fetchrow_array;
+
+ $sth->finish;
+
+ $dbh->disconnect;
+
+}
+
+
+sub closebooks {
+ my ($self, $myconfig, $form) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+
+ if ($form->{revtrans}) {
+
+ $query = qq|UPDATE defaults SET closedto = NULL,
+ revtrans = '1'|;
+ } else {
+ if ($form->{closedto}) {
+
+ $query = qq|UPDATE defaults SET closedto = '$form->{closedto}',
+ revtrans = '0'|;
+ } else {
+
+ $query = qq|UPDATE defaults SET closedto = NULL,
+ revtrans = '0'|;
+ }
+ }
+
+ # set close in defaults
+ $dbh->do($query) || $form->dberror($query);
+
+ $dbh->disconnect;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/AP.pm b/sql-ledger/SL/AP.pm
new file mode 100644
index 0000000..e1870f8
--- /dev/null
+++ b/sql-ledger/SL/AP.pm
@@ -0,0 +1,381 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Accounts Payables database backend routines
+#
+#======================================================================
+
+
+package AP;
+
+
+sub post_transaction {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my ($null, $taxrate, $amount);
+ my $exchangerate = 0;
+
+ # split and store id numbers in link accounts
+ ($form->{AP}{payables}) = split(/--/, $form->{AP});
+ map { ($form->{AP}{"amount_$_"}) = split(/--/, $form->{"AP_amount_$_"}) } (1 .. $form->{rowcount});
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ $form->{exchangerate} = 1;
+ } else {
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'sell');
+
+ $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate});
+ }
+
+ # reverse and parse amounts
+ for my $i (1 .. $form->{rowcount}) {
+ $form->{"amount_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"amount_$i"}) * $form->{exchangerate} * -1, 2);
+ $amount += ($form->{"amount_$i"} * -1);
+ }
+
+ # this is for ap
+ $form->{amount} = $amount;
+
+ # taxincluded doesn't make sense if there is no amount
+ $form->{taxincluded} = 0 if ($form->{amount} == 0);
+
+ for my $item (split / /, $form->{taxaccounts}) {
+ $form->{AP}{"tax_$item"} = $item;
+
+ $amount = $form->round_amount($form->parse_amount($myconfig, $form->{"tax_$item"}), 2);
+
+ $form->{"tax_$item"} = $form->round_amount($amount * $form->{exchangerate}, 2) * -1;
+ $form->{total_tax} += ($form->{"tax_$item"} * -1);
+ }
+
+
+ # adjust paidaccounts if there is no date in the last row
+ $form->{paidaccounts}-- unless ($form->{"datepaid_$form->{paidaccounts}"});
+
+ $form->{invpaid} = 0;
+ # add payments
+ for my $i (1 .. $form->{paidaccounts}) {
+ $form->{"paid_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"paid_$i"}), 2);
+
+ $form->{invpaid} += $form->{"paid_$i"};
+ $form->{datepaid} = $form->{"datepaid_$i"};
+
+ }
+
+ $form->{invpaid} = $form->round_amount($form->{invpaid} * $form->{exchangerate}, 2);
+
+ if ($form->{taxincluded} *= 1) {
+ for $i (1 .. $form->{rowcount}) {
+ $tax = $form->{total_tax} * $form->{"amount_$i"} / $form->{amount};
+ $amount = $form->{"amount_$i"} - $tax;
+ $form->{"amount_$i"} = $form->round_amount($amount, 2);
+ $diff += $amount - $form->{"amount_$i"};
+ }
+
+ # deduct taxes from amount
+ $form->{amount} -= $form->{total_tax};
+ # deduct difference from amount_1
+ $form->{amount_1} += $form->round_amount($diff, 2);
+ }
+
+ $form->{netamount} = $form->{amount};
+
+ # store invoice total, this goes into ap table
+ $form->{invtotal} = $form->{amount} + $form->{total_tax};
+
+ # amount for total AP
+ $form->{payables} = $form->{invtotal};
+
+
+ my ($query, $sth);
+
+ # if we have an id delete old records
+ if ($form->{id}) {
+
+ # delete detail records
+ $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|;
+
+ $dbh->do($query) || $form->dberror($query);
+
+ } else {
+ my $uid = time;
+ $uid .= $form->{login};
+
+ $query = qq|INSERT INTO ap (invnumber, employee_id)
+ VALUES ('$uid', (SELECT id FROM employee
+ WHERE login = '$form->{login}') )|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM ap
+ WHERE invnumber = '$uid'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{id}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ }
+
+ # escape '
+ $form->{notes} =~ s/'/''/g;
+
+ $form->{datepaid} = $form->{transdate} unless ($form->{datepaid});
+ my $datepaid = ($form->{invpaid} != 0) ? qq|'$form->{datepaid}'| : 'NULL';
+
+ $query = qq|UPDATE ap SET
+ invnumber = '$form->{invnumber}',
+ transdate = '$form->{transdate}',
+ ordnumber = '$form->{ordnumber}',
+ vendor_id = $form->{vendor_id},
+ taxincluded = '$form->{taxincluded}',
+ amount = $form->{invtotal},
+ duedate = '$form->{duedate}',
+ paid = $form->{invpaid},
+ datepaid = $datepaid,
+ netamount = $form->{netamount},
+ curr = '$form->{currency}',
+ notes = '$form->{notes}'
+ WHERE id = $form->{id}
+ |;
+ $dbh->do($query) || $form->dberror($query);
+
+
+ # update exchangerate
+ if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, 0, $form->{exchangerate});
+ }
+
+ # add individual transactions
+ foreach my $item (keys %{ $form->{AP} }) {
+ if ($form->{$item} != 0) {
+ $project_id = 'NULL';
+ if ($item =~ /amount_/) {
+ if ($form->{"project_id_$'"} && $form->{"projectnumber_$'"}) {
+ $project_id = $form->{"project_id_$'"};
+ }
+ }
+
+ # insert detail records in acc_trans
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
+ project_id)
+ VALUES ($form->{id}, (SELECT id FROM chart
+ WHERE accno = '$form->{AP}{$item}'),
+ $form->{$item}, '$form->{transdate}', $project_id)|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+ # if there is no amount but a payment record a payable
+ if ($form->{amount} == 0 && $form->{invtotal} == 0) {
+ $form->{payables} = $form->{invpaid};
+ }
+
+ # add paid transactions
+ for my $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"} != 0) {
+
+ $exchangerate = 0;
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ $form->{"exchangerate_$i"} = 1;
+ } else {
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'sell');
+
+ $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
+ }
+
+
+ # get paid account
+ ($form->{AP}{"paid_$i"}) = split(/--/, $form->{"AP_paid_$i"});
+ $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"});
+
+ # if there is no amount and invtotal is zero there is no exchangerate
+ if ($form->{amount} == 0 && $form->{invtotal} == 0) {
+ $form->{exchangerate} = $form->{"exchangerate_$i"};
+ }
+
+ $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} * -1, 2);
+ if ($form->{payables}) {
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate)
+ VALUES ($form->{id},
+ (SELECT id FROM chart
+ WHERE accno = '$form->{AP}{payables}'),
+ $amount, '$form->{"datepaid_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ $form->{payables} = $amount;
+
+ # add payment
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate, source)
+ VALUES ($form->{id},
+ (SELECT id FROM chart
+ WHERE accno = '$form->{AP}{"paid_$i"}'),
+ $form->{"paid_$i"}, '$form->{"datepaid_$i"}',
+ '$form->{"source_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # add exchange rate difference
+ $amount = $form->round_amount($form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1), 2);
+ if ($amount != 0) {
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate, fx_transaction, cleared)
+ VALUES ($form->{id},
+ (SELECT id FROM chart
+ WHERE accno = '$form->{AP}{"paid_$i"}'),
+ $amount, '$form->{"datepaid_$i"}', '1', '0')|;
+
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ # exchangerate gain/loss
+ $amount = $form->round_amount($form->{"paid_$i"} * ($form->{exchangerate} - $form->{"exchangerate_$i"}), 2);
+
+ if ($amount != 0) {
+ $accno = ($amount > 0) ? $form->{fxgain_accno} : $form->{fxloss_accno};
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate, fx_transaction, cleared)
+ VALUES ($form->{id}, (SELECT id FROM chart
+ WHERE accno = '$accno'),
+ $amount, '$form->{"datepaid_$i"}', '1', '0')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ # update exchange rate record
+ if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{"datepaid_$i"}, 0, $form->{"exchangerate_$i"});
+ }
+ }
+ }
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+
+sub delete_transaction {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # check for other foreign currency transactions
+ $form->delete_exchangerate($dbh) if ($form->{currency} ne $form->{defaultcurrency});
+
+ my $query = qq|DELETE FROM ap WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # commit and redirect
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+
+sub ap_transactions {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $incemp = qq|, (SELECT e.name FROM employee e
+ WHERE a.employee_id = e.id) AS employee
+ | if ($form->{l_employee});
+
+ my $query = qq|SELECT a.id, a.invnumber, a.transdate, a.duedate,
+ a.amount, a.paid, a.ordnumber, v.name, a.invoice,
+ a.netamount, a.datepaid, a.notes
+
+ $incemp
+
+ FROM ap a, vendor v
+ WHERE a.vendor_id = v.id|;
+
+ if ($form->{vendor_id}) {
+ $query .= " AND a.vendor_id = $form->{vendor_id}";
+ } else {
+ if ($form->{vendor}) {
+ my $vendor = $form->like(lc $form->{vendor});
+ $query .= " AND lower(v.name) LIKE '$vendor'";
+ }
+ }
+ if ($form->{invnumber}) {
+ my $invnumber = $form->like(lc $form->{invnumber});
+ $query .= " AND lower(a.invnumber) LIKE '$invnumber'";
+ }
+ if ($form->{ordnumber}) {
+ my $ordnumber = $form->like(lc $form->{ordnumber});
+ $query .= " AND lower(a.ordnumber) LIKE '$ordnumber'";
+ }
+ if ($form->{notes}) {
+ my $notes = $form->like(lc $form->{notes});
+ $query .= " AND lower(a.notes) LIKE '$notes'";
+ }
+
+ $query .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom};
+ $query .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto};
+ if ($form->{open} || $form->{closed}) {
+ unless ($form->{open} && $form->{closed}) {
+ $query .= " AND a.amount <> a.paid" if ($form->{open});
+ $query .= " AND a.amount = a.paid" if ($form->{closed});
+ }
+ }
+
+ my @a = (transdate, invnumber, name);
+ push @a, "employee" if $self->{l_employee};
+ my $sortorder = join ', ', $form->sort_columns(@a);
+ $sortorder = $form->{sort} unless $sortorder;
+
+ $query .= " ORDER by $sortorder";
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ap = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{AP} }, $ap;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/AR.pm b/sql-ledger/SL/AR.pm
new file mode 100644
index 0000000..4ea3d82
--- /dev/null
+++ b/sql-ledger/SL/AR.pm
@@ -0,0 +1,381 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Accounts Receivable module backend routines
+#
+#======================================================================
+
+package AR;
+
+
+sub post_transaction {
+ my ($self, $myconfig, $form) = @_;
+
+ my ($null, $taxrate, $amount, $tax, $diff);
+ my $exchangerate = 0;
+ my $i;
+
+ # split and store id numbers in link accounts
+ map { ($form->{AR}{"amount_$_"}) = split(/--/, $form->{"AR_amount_$_"}) } (1 .. $form->{rowcount});
+ ($form->{AR}{receivables}) = split(/--/, $form->{AR});
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ $form->{exchangerate} = 1;
+ } else {
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'buy');
+ }
+
+ $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate});
+
+ for $i (1 .. $form->{rowcount}) {
+ $form->{"amount_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"amount_$i"}) * $form->{exchangerate}, 2);
+ $amount += $form->{"amount_$i"};
+ }
+
+ # this is for ar
+ $form->{amount} = $amount;
+
+ # taxincluded doesn't make sense if there is no amount
+ $form->{taxincluded} = 0 if ($form->{amount} == 0);
+
+ foreach my $item (split / /, $form->{taxaccounts}) {
+ $form->{AR}{"tax_$item"} = $item;
+
+ $amount = $form->round_amount($form->parse_amount($myconfig, $form->{"tax_$item"}), 2);
+
+ $form->{"tax_$item"} = $form->round_amount($amount * $form->{exchangerate}, 2);
+ $form->{total_tax} += $form->{"tax_$item"};
+
+ }
+
+ # adjust paidaccounts if there is no date in the last row
+ $form->{paidaccounts}-- unless ($form->{"datepaid_$form->{paidaccounts}"});
+
+ $form->{invpaid} = 0;
+ # add payments
+ for $i (1 .. $form->{paidaccounts}) {
+ $form->{"paid_$i"} = $form->round_amount($form->parse_amount($myconfig, $form->{"paid_$i"}), 2);
+
+ $form->{invpaid} += $form->{"paid_$i"};
+ $form->{datepaid} = $form->{"datepaid_$i"};
+
+ # reverse payment
+ $form->{"paid_$i"} *= -1;
+
+ }
+
+ $form->{invpaid} = $form->round_amount($form->{invpaid} * $form->{exchangerate}, 2);
+
+ if ($form->{taxincluded} *= 1) {
+ for $i (1 .. $form->{rowcount}) {
+ $tax = $form->{total_tax} * $form->{"amount_$i"} / $form->{amount};
+ $amount = $form->{"amount_$i"} - $tax;
+ $form->{"amount_$i"} = $form->round_amount($amount, 2);
+ $diff += $amount - $form->{"amount_$i"};
+ }
+
+ $form->{amount} -= $form->{total_tax};
+ # deduct difference from amount_1
+ $form->{amount_1} += $form->round_amount($diff, 2);
+ }
+
+ # store invoice total, this goes into ar table
+ $form->{invtotal} = $form->{amount} + $form->{total_tax};
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my ($query, $sth);
+
+ # if we have an id delete old records
+ if ($form->{id}) {
+
+ # delete detail records
+ $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ } else {
+ my $uid = time;
+ $uid .= $form->{login};
+
+ $query = qq|INSERT INTO ar (invnumber, employee_id)
+ VALUES ('$uid', (SELECT id FROM employee
+ WHERE login = '$form->{login}') )|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM ar
+ WHERE invnumber = '$uid'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{id}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ }
+
+ # escape '
+ $form->{notes} =~ s/'/''/g;
+
+ # record last payment date in ar table
+ $form->{datepaid} = $form->{transdate} unless $form->{datepaid};
+ my $datepaid = ($form->{invpaid} != 0) ? qq|'$form->{datepaid}'| : 'NULL';
+
+ $query = qq|UPDATE ar set
+ invnumber = '$form->{invnumber}',
+ ordnumber = '$form->{ordnumber}',
+ transdate = '$form->{transdate}',
+ customer_id = $form->{customer_id},
+ taxincluded = '$form->{taxincluded}',
+ amount = $form->{invtotal},
+ duedate = '$form->{duedate}',
+ paid = $form->{invpaid},
+ datepaid = $datepaid,
+ netamount = $form->{amount},
+ curr = '$form->{currency}',
+ notes = '$form->{notes}'
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+
+ # amount for AR account
+ $form->{receivables} = $form->round_amount($form->{invtotal} * -1, 2);
+
+
+ # update exchangerate
+ if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{transdate}, $form->{exchangerate}, 0);
+ }
+
+ # add individual transactions for AR, amount and taxes
+ foreach my $item (keys %{ $form->{AR} }) {
+ if ($form->{$item} != 0) {
+ $project_id = 'NULL';
+ if ($item =~ /amount_/) {
+ if ($form->{"project_id_$'"} && $form->{"projectnumber_$'"}) {
+ $project_id = $form->{"project_id_$'"};
+ }
+ }
+
+ # insert detail records in acc_trans
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
+ project_id)
+ VALUES ($form->{id}, (SELECT id FROM chart
+ WHERE accno = '$form->{AR}{$item}'),
+ $form->{$item}, '$form->{transdate}', $project_id)|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+ # if there is no amount but a payment record a receivables
+ if ($form->{amount} == 0 && $form->{invtotal} == 0) {
+ $form->{receivables} = $form->{invpaid} * -1;
+ }
+
+ # add paid transactions
+ for my $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"} != 0) {
+
+ ($form->{AR}{"paid_$i"}) = split(/--/, $form->{"AR_paid_$i"});
+ $form->{"datepaid_$i"} = $form->{transdate} unless ($form->{"datepaid_$i"});
+
+ $exchangerate = 0;
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ $form->{"exchangerate_$i"} = 1;
+ } else {
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy');
+
+ $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
+ }
+
+
+ # if there is no amount and invtotal is zero there is no exchangerate
+ if ($form->{amount} == 0 && $form->{invtotal} == 0) {
+ $form->{exchangerate} = $form->{"exchangerate_$i"};
+ }
+
+ # receivables amount
+ $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} * -1, 2);
+
+ if ($form->{receivables} != 0) {
+ # add receivable
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate)
+ VALUES ($form->{id},
+ (SELECT id FROM chart
+ WHERE accno = '$form->{AR}{receivables}'),
+ $amount, '$form->{"datepaid_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ $form->{receivables} = $amount;
+
+ # add payment
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate, source)
+ VALUES ($form->{id},
+ (SELECT id FROM chart
+ WHERE accno = '$form->{AR}{"paid_$i"}'),
+ $form->{"paid_$i"}, '$form->{"datepaid_$i"}',
+ '$form->{"source_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+
+
+ # exchangerate difference for payment
+ $amount = $form->round_amount($form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1), 2);
+
+ if ($amount != 0) {
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate, fx_transaction, cleared)
+ VALUES ($form->{id},
+ (SELECT id FROM chart
+ WHERE accno = '$form->{AR}{"paid_$i"}'),
+ $amount, '$form->{"datepaid_$i"}', '1', '0')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ # exchangerate gain/loss
+ $amount = $form->round_amount($form->{"paid_$i"} * ($form->{exchangerate} - $form->{"exchangerate_$i"}), 2);
+
+ if ($amount != 0) {
+ $accno = ($amount > 0) ? $form->{fxgain_accno} : $form->{fxloss_accno};
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate, fx_transaction, cleared)
+ VALUES ($form->{id}, (SELECT id FROM chart
+ WHERE accno = '$accno'),
+ $amount, '$form->{"datepaid_$i"}', '1', '0')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ # update exchangerate record
+ if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{"datepaid_$i"}, $form->{"exchangerate_$i"}, 0);
+ }
+ }
+ }
+
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub delete_transaction {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn AutoCommit off
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # check for other foreign currency transactions
+ $form->delete_exchangerate($dbh) if ($form->{currency} ne $form->{defaultcurrency});
+
+ my $query = qq|DELETE FROM ar WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # commit
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub ar_transactions {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $incemp = qq|, (SELECT e.name FROM employee e
+ WHERE a.employee_id = e.id) AS employee
+ | if ($form->{l_employee});
+
+ my $query = qq|SELECT a.id, a.invnumber, a.ordnumber, a.transdate,
+ a.duedate, a.netamount, a.amount, a.paid, c.name,
+ a.invoice, a.datepaid, a.terms, a.notes, a.shippingpoint
+
+ $incemp
+
+ FROM ar a, customer c
+ WHERE a.customer_id = c.id|;
+
+ if ($form->{customer_id}) {
+ $query .= " AND a.customer_id = $form->{customer_id}";
+ } else {
+ if ($form->{customer}) {
+ my $customer = $form->like(lc $form->{customer});
+ $query .= " AND lower(c.name) LIKE '$customer'";
+ }
+ }
+ if ($form->{invnumber}) {
+ my $invnumber = $form->like(lc $form->{invnumber});
+ $query .= " AND lower(a.invnumber) LIKE '$invnumber'";
+ }
+ if ($form->{ordnumber}) {
+ my $ordnumber = $form->like(lc $form->{ordnumber});
+ $query .= " AND lower(a.ordnumber) LIKE '$ordnumber'";
+ }
+ if ($form->{notes}) {
+ my $notes = $form->like(lc $form->{notes});
+ $query .= " AND lower(a.notes) LIKE '$notes'";
+ }
+
+ $query .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom};
+ $query .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto};
+ if ($form->{open} || $form->{closed}) {
+ unless ($form->{open} && $form->{closed}) {
+ $query .= " AND a.amount <> a.paid" if ($form->{open});
+ $query .= " AND a.amount = a.paid" if ($form->{closed});
+ }
+ }
+
+ my @a = (transdate, invnumber, name);
+ push @a, "employee" if $form->{l_employee};
+ my $sortorder = join ', ', $form->sort_columns(@a);
+ $sortorder = $form->{sort} unless $sortorder;
+
+ $query .= " ORDER by $sortorder";
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ar = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{AR} }, $ar;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/CA.pm b/sql-ledger/SL/CA.pm
new file mode 100644
index 0000000..b71749d
--- /dev/null
+++ b/sql-ledger/SL/CA.pm
@@ -0,0 +1,262 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+# chart of accounts
+#
+# CHANGE LOG:
+# DS. 2000-07-04 Created
+#
+#======================================================================
+
+
+package CA;
+
+
+sub all_accounts {
+ my ($self, $myconfig, $form) = @_;
+
+ my $amount = ();
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT accno,
+ SUM(acc_trans.amount) AS amount
+ FROM chart, acc_trans
+ WHERE chart.id = acc_trans.chart_id
+ GROUP BY accno|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $amount{$ref->{accno}} = $ref->{amount}
+ }
+ $sth->finish;
+
+ $query = qq|SELECT accno, description
+ FROM gifi|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $gifi = ();
+ while (my ($accno, $description) = $sth->fetchrow_array) {
+ $gifi{$accno} = $description;
+ }
+ $sth->finish;
+
+ $query = qq|SELECT c.id, c.accno, c.description, c.charttype, c.gifi_accno,
+ c.category, c.link
+ FROM chart c
+ ORDER BY accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ca = $sth->fetchrow_hashref(NAME_lc)) {
+ $ca->{amount} = $amount{$ca->{accno}};
+ $ca->{gifi_description} = $gifi{$ca->{gifi_accno}};
+ if ($ca->{amount} < 0) {
+ $ca->{debit} = $ca->{amount} * -1;
+ } else {
+ $ca->{credit} = $ca->{amount};
+ }
+ push @{ $form->{CA} }, $ca;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub all_transactions {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # get chart_id
+ my $query = qq|SELECT id FROM chart
+ WHERE accno = '$form->{accno}'|;
+ if ($form->{accounttype} eq 'gifi') {
+ $query = qq|SELECT id FROM chart
+ WHERE gifi_accno = '$form->{gifi_accno}'|;
+ }
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my @id = ();
+ while (my ($id) = $sth->fetchrow_array) {
+ push @id, $id;
+ }
+
+ $sth->finish;
+
+ my $where = '1 = 1';
+ # build WHERE clause from dates if any
+ if ($form->{fromdate}) {
+ $where .= " AND ac.transdate >= '$form->{fromdate}'";
+ }
+ if ($form->{todate}) {
+ $where .= " AND ac.transdate <= '$form->{todate}'";
+ }
+
+ my $sortorder = join ', ', $form->sort_columns(qw(transdate reference description));
+ my $false = ($myconfig->{dbdriver} eq 'Pg') ? FALSE : q|'0'|;
+
+ # Oracle workaround, use ordinal positions
+ my %ordinal = ( transdate => 4,
+ reference => 2,
+ description => 3 );
+ map { $sortorder =~ s/$_/$ordinal{$_}/ } keys %ordinal;
+
+
+ if ($form->{accno}) {
+ # get category for account
+ $query = qq|SELECT category
+ FROM chart
+ WHERE accno = '$form->{accno}'|;
+ $sth = $dbh->prepare($query);
+
+ $sth->execute || $form->dberror($query);
+ ($form->{category}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ if ($form->{fromdate}) {
+ # get beginning balance
+ $query = qq|SELECT SUM(ac.amount)
+ FROM acc_trans ac, chart c
+ WHERE ac.chart_id = c.id
+ AND c.accno = '$form->{accno}'
+ AND ac.transdate < date '$form->{fromdate}'
+ |;
+ $sth = $dbh->prepare($query);
+
+ $sth->execute || $form->dberror($query);
+ ($form->{balance}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+ }
+
+ if ($form->{accounttype} eq 'gifi' && $form->{gifi_accno}) {
+ # get category for account
+ $query = qq|SELECT category
+ FROM chart
+ WHERE gifi_accno = '$form->{gifi_accno}'|;
+ $sth = $dbh->prepare($query);
+
+ $sth->execute || $form->dberror($query);
+ ($form->{category}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ if ($form->{fromdate}) {
+ # get beginning balance
+ $query = qq|SELECT SUM(ac.amount)
+ FROM acc_trans ac, chart c
+ WHERE ac.chart_id = c.id
+ AND c.gifi_accno = '$form->{gifi_accno}'
+ AND ac.transdate < date '$form->{fromdate}'
+ |;
+ $sth = $dbh->prepare($query);
+
+ $sth->execute || $form->dberror($query);
+ ($form->{balance}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+ }
+
+ $query = "";
+
+ foreach my $id (@id) {
+
+ # get all transactions
+ $query .= qq|
+ SELECT g.id, g.reference, g.description, ac.transdate,
+ $false AS invoice,
+ ac.amount, 'gl' as charttype
+ FROM gl g, acc_trans ac
+ WHERE $where
+ AND ac.chart_id = $id
+ AND ac.trans_id = g.id
+ UNION ALL
+ SELECT a.id, a.invnumber, c.name, ac.transdate,
+ a.invoice,
+ ac.amount, 'ar' as charttype
+ FROM ar a, acc_trans ac, customer c
+ WHERE $where
+ AND ac.chart_id = $id
+ AND ac.trans_id = a.id
+ AND a.customer_id = c.id
+ UNION ALL
+ SELECT a.id, a.invnumber, v.name, ac.transdate,
+ a.invoice,
+ ac.amount, 'ap' as charttype
+ FROM ap a, acc_trans ac, vendor v
+ WHERE $where
+ AND ac.chart_id = $id
+ AND ac.trans_id = a.id
+ AND a.vendor_id = v.id
+ UNION ALL|;
+ }
+
+ $query =~ s/UNION ALL$//;
+ $query .= qq|
+ ORDER BY $sortorder|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ca = $sth->fetchrow_hashref(NAME_lc)) {
+
+ # gl
+ if ($ca->{charttype} eq "gl") {
+ $ca->{module} = "gl";
+ }
+
+ # ap
+ if ($ca->{charttype} eq "ap") {
+ $ca->{module} = ($ca->{invoice}) ? 'ir' : 'ap';
+ }
+
+ # ar
+ if ($ca->{charttype} eq "ar") {
+ $ca->{module} = ($ca->{invoice}) ? 'is' : 'ar';
+ }
+
+ if ($ca->{amount} < 0) {
+ $ca->{debit} = $ca->{amount} * -1;
+ $ca->{credit} = 0;
+ } else {
+ $ca->{credit} = $ca->{amount};
+ $ca->{debit} = 0;
+ }
+
+ push @{ $form->{CA} }, $ca;
+
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+1;
+
diff --git a/sql-ledger/SL/CP.pm b/sql-ledger/SL/CP.pm
new file mode 100644
index 0000000..f84bd15
--- /dev/null
+++ b/sql-ledger/SL/CP.pm
@@ -0,0 +1,308 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Check and receipt printing payment module backend routines
+# Number to text conversion routines are in
+# locale/{countrycode}/Num2text
+#
+#======================================================================
+
+package CP;
+
+
+sub new {
+ my ($type, $countrycode) = @_;
+
+ $self = {};
+
+ if ($countrycode) {
+ if (-f "locale/$countrycode/Num2text") {
+ require "locale/$countrycode/Num2text";
+ } else {
+ use SL::Num2text;
+ }
+ } else {
+ use SL::Num2text;
+ }
+
+ bless $self, $type;
+
+}
+
+
+sub paymentaccounts {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT accno, description
+ FROM chart
+ WHERE link LIKE '%$form->{arap}_paid%'
+ ORDER BY accno|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{PR} }, $ref;
+ }
+ $sth->finish;
+
+ # get currencies and closedto
+ $query = qq|SELECT curr, closedto
+ FROM defaults|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{currencies}, $form->{closedto}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ $dbh->disconnect;
+
+}
+
+
+sub get_openvc {
+ my ($self, $myconfig, $form) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $arap = ($form->{vc} eq 'customer') ? 'ar' : 'ap';
+
+ my $query = qq|SELECT count(*)
+ FROM $form->{vc} ct, $arap a
+ WHERE a.$form->{vc}_id = ct.id
+ AND a.amount != a.paid|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+ my ($count) = $sth->fetchrow_array;
+ $sth->finish;
+
+ # build selection list
+ if ($count < $myconfig->{vclimit}) {
+ $query = qq|SELECT DISTINCT ct.id, ct.name
+ FROM $form->{vc} ct, $arap a
+ WHERE a.$form->{vc}_id = ct.id
+ AND a.amount != a.paid
+ ORDER BY name|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{"all_$form->{vc}"} }, $ref;
+ }
+
+ $sth->finish;
+
+ }
+
+ $dbh->disconnect;
+
+}
+
+
+sub get_openinvoices {
+ my ($self, $myconfig, $form) = @_;
+
+ return unless $form->{"$form->{vc}_id"};
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $where = qq|WHERE $form->{vc}_id = $form->{"$form->{vc}_id"}
+ AND curr = '$form->{currency}'
+ AND NOT amount = paid|;
+
+ if ($form->{transdatefrom}) {
+ $where .= " AND transdate >= '$form->{transdatefrom}'";
+ }
+ if ($form->{transdateto}) {
+ $where .= " AND transdate <= '$form->{transdateto}'";
+ }
+
+ my ($arap, $buysell);
+ if ($form->{vc} eq 'customer') {
+ $arap = "ar";
+ $buysell = "buy";
+ } else {
+ $arap = "ap";
+ $buysell = "sell";
+ }
+
+ my $query = qq|SELECT id, invnumber, transdate, amount, paid, curr
+ FROM $arap
+ $where
+ ORDER BY id|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ # if this is a foreign currency transaction get exchangerate
+ $ref->{exchangerate} = $form->get_exchangerate($dbh, $ref->{curr}, $ref->{transdate}, $buysell) if ($form->{currency} ne $form->{defaultcurrency});
+ push @{ $form->{PR} }, $ref;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+
+sub process_payment {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn AutoCommit off
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my ($paymentaccno) = split /--/, $form->{account};
+
+ # if currency ne defaultcurrency update exchangerate
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ $form->{exchangerate} = $form->parse_amount($myconfig, $form->{exchangerate});
+
+ if ($form->{vc} eq 'customer') {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{datepaid}, $form->{exchangerate}, 0);
+ } else {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{datepaid}, 0, $form->{exchangerate});
+ }
+ } else {
+ $form->{exchangerate} = 1;
+ }
+
+ my $query = qq|SELECT fxgain_accno_id, fxloss_accno_id
+ FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my ($fxgain_accno_id, $fxloss_accno_id) = $sth->fetchrow_array;
+ $sth->finish;
+
+ my ($ARAP, $arap, $buysell);
+
+ if ($form->{vc} eq 'customer') {
+ $ARAP = "AR";
+ $arap = "ar";
+ $buysell = "buy";
+ } else {
+ $ARAP = "AP";
+ $arap = "ap";
+ $buysell = "sell";
+ }
+
+ # go through line by line
+ for my $i (1 .. $form->{rowcount}) {
+
+ if ($form->{"paid_$i"}) {
+
+ $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
+
+ # get exchangerate for original
+ $query = qq|SELECT $buysell FROM exchangerate e, $arap a
+ WHERE e.curr = '$form->{currency}'
+ AND a.transdate = e.transdate
+ AND a.id = $form->{"id_$i"}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my ($exchangerate) = $sth->fetchrow_array;
+ $sth->finish;
+
+ $exchangerate = 1 unless $exchangerate;
+
+ $query = qq|SELECT c.id FROM chart c, acc_trans a
+ WHERE a.chart_id = c.id
+ AND c.link = '$ARAP'
+ AND a.trans_id = $form->{"id_$i"}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my ($id) = $sth->fetchrow_array;
+ $sth->finish;
+
+ my $amount = $form->round_amount($form->{"paid_$i"} * $exchangerate * -1, 2);
+ $ml = ($ARAP eq 'AR') ? -1 : 1;
+ # add AR/AP
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, amount)
+ VALUES ($form->{"id_$i"}, $id,
+ '$form->{datepaid}', $amount * $ml)|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # add payment
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate, amount,
+ source)
+ VALUES ($form->{"id_$i"},
+ (SELECT id FROM chart
+ WHERE accno = '$paymentaccno'),
+ '$form->{datepaid}', $form->{"paid_$i"} * $ml,
+ '$form->{source}')|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # add exchangerate difference if currency ne defaultcurrency
+ $amount = $form->round_amount($form->{"paid_$i"} * ($form->{exchangerate} - 1), 2);
+
+ if ($amount != 0) {
+ # exchangerate difference
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
+ amount, cleared, fx_transaction)
+ VALUES ($form->{"id_$i"},
+ (SELECT id FROM chart
+ WHERE accno = '$paymentaccno'),
+ '$form->{datepaid}', $amount * $ml, '0', '1')|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # gain/loss
+
+ $amount = $form->round_amount($form->{"paid_$i"} * ($exchangerate - $form->{exchangerate}) * $ml, 2);
+ if ($amount != 0) {
+ my $accno_id = ($amount > 0) ? $fxgain_accno_id : $fxloss_accno_id;
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, transdate,
+ amount, cleared, fx_transaction)
+ VALUES ($form->{"id_$i"}, $accno_id,
+ '$form->{datepaid}', $amount, '0', '1')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+ $form->{"paid_$i"} = $form->round_amount($form->{"paid_$i"} * $exchangerate, 2);
+
+ # update AR/AP transaction
+ $query = qq|UPDATE $arap set
+ paid = paid + $form->{"paid_$i"},
+ datepaid = '$form->{datepaid}'
+ WHERE id = $form->{"id_$i"}|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/CT.pm b/sql-ledger/SL/CT.pm
new file mode 100644
index 0000000..7c42cb8
--- /dev/null
+++ b/sql-ledger/SL/CT.pm
@@ -0,0 +1,447 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# backend code for customers and vendors
+#
+# CHANGE LOG:
+# DS. 2000-07-04 Created
+#
+#======================================================================
+
+package CT;
+
+
+sub get_tuple {
+ my ($self, $myconfig, $form) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+ my $query = qq|SELECT *
+ FROM $form->{db}
+ WHERE id = $form->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+
+ $sth->finish;
+
+
+ # get ship to
+ $query = qq|SELECT *
+ FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+
+ $sth->finish;
+
+
+ # get tax labels
+ $query = qq|SELECT accno, description
+ FROM chart, tax
+ WHERE link LIKE '%CT_tax%'
+ AND chart.id = tax.chart_id
+ ORDER BY accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $form->{taxaccounts} .= "$ref->{accno} ";
+ $form->{tax}{$ref->{accno}}{description} = $ref->{description};
+ }
+ $sth->finish;
+ chop $form->{taxaccounts};
+
+ # get taxes for customer/vendor
+ $query = qq|SELECT chart_id, accno
+ FROM $form->{db}tax, chart
+ WHERE chart_id = chart.id
+ AND $form->{db}_id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $form->{tax}{$ref->{accno}}{taxable} = 1;
+ }
+ $sth->finish;
+
+
+ $dbh->disconnect;
+
+}
+
+
+sub taxaccounts {
+ my ($self, $myconfig, $form) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+
+ # get tax labels
+ my $query = qq|SELECT accno, description
+ FROM chart, tax
+ WHERE link LIKE '%CT_tax%'
+ AND chart.id = tax.chart_id
+ ORDER BY accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $taxref = $sth->fetchrow_hashref(NAME_lc)) {
+ $form->{taxaccounts} .= "$taxref->{accno} ";
+ $form->{tax}{$taxref->{accno}}{description} = $taxref->{description};
+ }
+ $sth->finish;
+ chop $form->{taxaccounts};
+
+ $dbh->disconnect;
+
+}
+
+
+sub delete_customer {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn AutoCommit off
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my $query = qq|SELECT id FROM ar
+ WHERE customer_id = $form->{id}
+ UNION
+ SELECT id FROM oe
+ WHERE customer_id = $form->{id}|;
+ my $sth = $dbh->prepare($query) || $form->dberror($query);
+ $sth->execute;
+
+ my ($rc) = $sth->fetchrow_array;
+ $sth->finish;
+
+ if ($rc) {
+ $dbh->disconnect;
+ $rc = -1;
+ } else {
+
+ # delete customer
+ $query = qq|DELETE FROM customer
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM customertax
+ WHERE customer_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # commit and redirect
+ $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ }
+
+ $rc;
+
+}
+
+
+sub save_customer {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # escape '
+ map { $form->{$_} =~ s/'/''/g } qw(customernumber name addr1 addr2 addr3 addr4 contact notes);
+
+ # assign value discount, terms, creditlimit
+ $form->{discount} /= 100;
+ $form->{terms} *= 1;
+ $form->{taxincluded} *= 1;
+ $form->{creditlimit} = $form->parse_amount($myconfig, $form->{creditlimit});
+
+ my ($query, $sth);
+
+ if ($form->{id}) {
+ $query = qq|DELETE FROM customertax
+ WHERE customer_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+ } else {
+ my $uid = time;
+ $uid .= $form->{login};
+
+ $query = qq|INSERT INTO customer (name)
+ VALUES ('$uid')|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM customer
+ WHERE name = '$uid'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{id}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ }
+
+ $query = qq|UPDATE customer SET
+ customernumber = '$form->{customernumber}',
+ name = '$form->{name}',
+ addr1 = '$form->{addr1}',
+ addr2 = '$form->{addr2}',
+ addr3 = '$form->{addr3}',
+ addr4 = '$form->{addr4}',
+ contact = '$form->{contact}',
+ phone = '$form->{phone}',
+ fax = '$form->{fax}',
+ email = '$form->{email}',
+ cc = '$form->{cc}',
+ bcc = '$form->{bcc}',
+ notes = '$form->{notes}',
+ discount = $form->{discount},
+ creditlimit = $form->{creditlimit},
+ terms = $form->{terms},
+ taxincluded = '$form->{taxincluded}'
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # save taxes
+ foreach $item (split / /, $form->{taxaccounts}) {
+ if ($form->{"tax_$item"}) {
+ $query = qq|INSERT INTO customertax (customer_id, chart_id)
+ VALUES ($form->{id}, (SELECT id
+ FROM chart
+ WHERE accno = '$item'))|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+ # add shipto
+ $form->add_shipto($dbh, $form->{id});
+
+ $dbh->disconnect;
+
+}
+
+
+sub save_vendor {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # escape '
+ map { $form->{$_} =~ s/'/''/g } qw(vendornumber name addr1 addr2 addr3 addr4 contact notes);
+
+ $form->{terms} *= 1;
+ $form->{taxincluded} *= 1;
+
+ my $query;
+
+ if ($form->{id}) {
+ $query = qq|DELETE FROM vendortax
+ WHERE vendor_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+ } else {
+ my $uid = time;
+ $uid .= $form->{login};
+
+ $query = qq|INSERT INTO vendor (name)
+ VALUES ('$uid')|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM vendor
+ WHERE name = '$uid'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{id}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ }
+
+
+ $query = qq|UPDATE vendor SET
+ vendornumber = '$form->{vendornumber}',
+ name = '$form->{name}',
+ addr1 = '$form->{addr1}',
+ addr2 = '$form->{addr2}',
+ addr3 = '$form->{addr3}',
+ addr4 = '$form->{addr4}',
+ contact = '$form->{contact}',
+ phone = '$form->{phone}',
+ fax = '$form->{fax}',
+ email = '$form->{email}',
+ cc = '$form->{cc}',
+ bcc = '$form->{bcc}',
+ notes = '$form->{notes}',
+ terms = $form->{terms},
+ taxincluded = '$form->{taxincluded}'
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # save taxes
+ foreach $item (split / /, $form->{taxaccounts}) {
+ if ($form->{"tax_$item"}) {
+ $query = qq|INSERT INTO vendortax (vendor_id, chart_id)
+ VALUES ($form->{id}, (SELECT id
+ FROM chart
+ WHERE accno = '$item'))|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+ # add shipto
+ $form->add_shipto($dbh, $form->{id});
+
+ $dbh->disconnect;
+
+}
+
+
+
+sub delete_vendor {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn AutoCommit off
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # check if there are any transactions on file
+ my $query = qq|SELECT id FROM ap
+ WHERE vendor_id = $form->{id}
+ UNION
+ SELECT id FROM oe
+ WHERE vendor_id = $form->{id}|;
+ my $sth = $dbh->prepare($query) || $form->dberror($query);
+ $sth->execute;
+
+ my ($rc) = $sth->fetchrow_array;
+ $sth->finish;
+
+ if ($rc) {
+ $dbh->disconnect;
+ $rc = -1;
+ } else {
+
+ # delete vendor
+ $query = qq|DELETE FROM vendor
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM vendortax
+ WHERE vendor_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # commit and redirect
+ $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ }
+
+ $rc;
+
+}
+
+
+sub search {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $where = "1 = 1";
+ $form->{sort} = "name" unless ($form->{sort});
+
+ if ($form->{"$form->{db}number"}) {
+ my $companynumber = $form->like(lc $form->{"$form->{db}number"});
+ $where .= " AND lower($form->{db}number) LIKE '$companynumber'";
+ }
+ if ($form->{name}) {
+ my $name = $form->like(lc $form->{name});
+ $where .= " AND lower(name) LIKE '$name'";
+ }
+ if ($form->{contact}) {
+ my $contact = $form->like(lc $form->{contact});
+ $where .= " AND lower(contact) LIKE '$contact'";
+ }
+ if ($form->{email}) {
+ my $email = $form->like(lc $form->{email});
+ $where .= " AND lower(email) LIKE '$email'";
+ }
+
+ if ($form->{status} eq 'orphaned') {
+ $where .= qq| AND id NOT IN (SELECT o.$form->{db}_id
+ FROM oe o, $form->{db} ct
+ WHERE ct.id = o.$form->{db}_id)|;
+ if ($form->{db} eq 'customer') {
+ $where .= qq| AND id NOT IN (SELECT a.customer_id
+ FROM ar a, customer ct
+ WHERE ct.id = a.customer_id)|;
+ }
+ if ($form->{db} eq 'vendor') {
+ $where .= qq| AND id NOT IN (SELECT a.vendor_id
+ FROM ap a, vendor ct
+ WHERE ct.id = a.vendor_id)|;
+ }
+ }
+
+ my $query = qq~SELECT id, name, $form->{db}number,
+ addr1 || ' ' || addr2 || ' ' || addr3 || ' ' || addr4 AS address,
+ contact, phone, fax, email, cc, terms
+ FROM $form->{db}
+ WHERE $where
+ ORDER BY $form->{sort}~;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{CT} }, $ref;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/Form.pm b/sql-ledger/SL/Form.pm
new file mode 100644
index 0000000..ef5f2ca
--- /dev/null
+++ b/sql-ledger/SL/Form.pm
@@ -0,0 +1,1397 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 1998-2003
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors: Thomas Bayen <bayen@gmx.de>
+# Antti Kaihola <akaihola@siba.fi>
+# Moritz Bunkus (tex code)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+# Utilities for parsing forms
+# and supporting routines for linking account numbers
+# used in AR, AP and IS, IR modules
+#
+#======================================================================
+
+package Form;
+
+
+sub new {
+ my $type = shift;
+
+ my $self = {};
+
+ read(STDIN, $_, $ENV{CONTENT_LENGTH});
+
+ if ($ENV{QUERY_STRING}) {
+ $_ = $ENV{QUERY_STRING};
+ }
+
+ if ($ARGV[0]) {
+ $_ = $ARGV[0];
+ }
+
+ foreach $item (split(/&/)) {
+ ($key, $value) = split(/=/, $item);
+ $self->{$key} = &unescape("",$value);
+ }
+
+ $self->{action} = lc $self->{action};
+ $self->{action} =~ s/( |-|,)/_/g;
+
+ $self->{version} = "2.0.8";
+ $self->{dbversion} = "2.0.8";
+
+ bless $self, $type;
+
+}
+
+
+sub debug {
+ my ($self) = @_;
+
+ print "\n";
+
+ map { print "$_ = $self->{$_}\n" } (sort keys %{$self});
+
+}
+
+
+sub escape {
+ my ($self, $str, $beenthere) = @_;
+
+ # for Apache 2 we escape strings twice
+ if (($ENV{SERVER_SOFTWARE} =~ /Apache\/2/) && !$beenthere) {
+ $str = $self->escape($str, 1);
+ }
+
+ $str =~ s/([^a-zA-Z0-9_.-])/sprintf("%%%02x", ord($1))/ge;
+ $str;
+
+}
+
+
+sub unescape {
+ my ($self, $str) = @_;
+
+ $str =~ tr/+/ /;
+ $str =~ s/\\$//;
+
+ $str =~ s/%([0-9a-fA-Z]{2})/pack("c",hex($1))/eg;
+
+ $str;
+
+}
+
+
+sub error {
+ my ($self, $msg) = @_;
+
+ if ($ENV{HTTP_USER_AGENT}) {
+ $msg =~ s/\n/<br>/g;
+
+ print qq|Content-Type: text/html
+
+ <body bgcolor=ffffff>
+
+ <h2><font color=red>Error!</font></h2>
+
+ <p><b>$msg</b>
+
+ </body>
+ </html>
+ |;
+
+ die "Error: $msg\n";
+
+ } else {
+
+ if ($self->{error_function}) {
+ &{ $self->{error_function} }($msg);
+ } else {
+ die "Error: $msg\n";
+ }
+ }
+
+}
+
+
+
+sub info {
+ my ($self, $msg) = @_;
+
+ if ($ENV{HTTP_USER_AGENT}) {
+ $msg =~ s/\n/<br>/g;
+
+ if (!$self->{header}) {
+ $self->header;
+ print qq|
+ <body>|;
+ }
+
+ print qq|
+
+ <p><b>$msg</b>
+ |;
+
+ } else {
+
+ if ($self->{info_function}) {
+ &{ $self->{info_function} }($msg);
+ } else {
+ print "$msg\n";
+ }
+ }
+
+}
+
+
+sub numtextrows {
+ my ($self, $str, $cols, $maxrows) = @_;
+
+ my $rows;
+
+ map { $rows += int ((length $_)/$cols) + 1 } (split /\r/, $str);
+
+ $rows = $maxrows if (defined $maxrows && ($rows > $maxrows));
+
+ $rows;
+
+}
+
+
+sub dberror {
+ my ($self, $msg) = @_;
+
+ $self->error("$msg\n".$DBI::errstr);
+
+}
+
+
+sub isblank {
+ my ($self, $name, $msg) = @_;
+
+ if ($self->{$name} =~ /^\s*$/) {
+ $self->error($msg);
+ }
+}
+
+
+sub header {
+ my ($self) = @_;
+
+ my ($nocache, $stylesheet, $charset);
+
+ # use expire tag to prevent caching
+# $nocache = qq|<META HTTP-EQUIV="Expires" CONTENT="Tue, 01 Jan 1980 1:00:00 GMT">
+# <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
+#|;
+
+ if ($self->{stylesheet} && (-f "css/$self->{stylesheet}")) {
+ $stylesheet = qq|<LINK REL="stylesheet" HREF="css/$self->{stylesheet}" TYPE="text/css" TITLE="SQL-Ledger style sheet">
+|;
+ }
+
+ if ($self->{charset}) {
+ $charset = qq|<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=$self->{charset}">
+|;
+ }
+
+ $self->{titlebar} = ($self->{title}) ? "$self->{title} - $self->{titlebar}" : $self->{titlebar};
+
+ print qq|Content-Type: text/html
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<head>
+ <title>$self->{titlebar}</title>
+ $nocache
+ $stylesheet
+ $charset
+</head>
+
+|;
+
+}
+
+
+sub redirect {
+ my ($self, $msg) = @_;
+
+ if ($self->{callback}) {
+
+ ($script, $argv) = split(/\?/, $self->{callback});
+
+ exec ("perl", "$script", $argv);
+
+ } else {
+
+ if ($ENV{HTTP_USER_AGENT}) {
+ $msg =~ s/\n/<br>/g;
+
+ print qq|Content-Type: text/html
+
+<body bgcolor=ffffff>
+
+<h2>$msg</h2>
+
+</body>
+</html>
+|;
+
+ } else {
+ print "$msg\n";
+ }
+
+ exit;
+
+ }
+
+}
+
+
+sub sort_columns {
+ my ($self, @columns) = @_;
+
+ @columns = grep !/^$self->{sort}$/, @columns;
+ splice @columns, 0, 0, $self->{sort};
+
+ @columns;
+
+}
+
+
+sub format_amount {
+ my ($self, $myconfig, $amount, $places, $dash) = @_;
+
+ if ($places =~ /\d/) {
+ $amount = $self->round_amount($amount, $places);
+ }
+
+ # is the amount negative
+ my $negative = ($amount < 0);
+
+ if ($amount != 0) {
+ if ($myconfig->{numberformat} && ($myconfig->{numberformat} ne '1000.00')) {
+ my ($whole, $dec) = split /\./, "$amount";
+ $whole =~ s/-//;
+ $amount = join '', reverse split //, $whole;
+
+ if ($myconfig->{numberformat} eq '1,000.00') {
+ $amount =~ s/\d{3,}?/$&,/g;
+ $amount =~ s/,$//;
+ $amount = join '', reverse split //, $amount;
+ $amount .= "\.$dec" if ($dec ne "");
+ }
+
+ if ($myconfig->{numberformat} eq '1.000,00') {
+ $amount =~ s/\d{3,}?/$&./g;
+ $amount =~ s/\.$//;
+ $amount = join '', reverse split //, $amount;
+ $amount .= ",$dec" if ($dec ne "");
+ }
+
+ if ($myconfig->{numberformat} eq '1000,00') {
+ $amount = "$whole";
+ $amount .= ",$dec" if ($dec ne "");
+ }
+
+ if ($dash =~ /-/) {
+ $amount = ($negative) ? "($amount)" : "$amount";
+ } elsif ($dash =~ /DRCR/) {
+ $amount = ($negative) ? "$amount DR" : "$amount CR";
+ } else {
+ $amount = ($negative) ? "-$amount" : "$amount";
+ }
+ }
+ } else {
+ if ($dash eq "0" && $places) {
+ if ($myconfig->{numberformat} eq '1.000,00') {
+ $amount = "0".","."0" x $places;
+ } else {
+ $amount = "0"."."."0" x $places;
+ }
+ } else {
+ $amount = ($dash ne "") ? "$dash" : "";
+ }
+ }
+
+ $amount;
+
+}
+
+
+sub parse_amount {
+ my ($self, $myconfig, $amount) = @_;
+
+ if (($myconfig->{numberformat} eq '1.000,00') ||
+ ($myconfig->{numberformat} eq '1000,00')) {
+ $amount =~ s/\.//g;
+ $amount =~ s/,/\./;
+ }
+
+ $amount =~ s/,//g;
+
+ return ($amount * 1);
+
+}
+
+
+sub round_amount {
+ my ($self, $amount, $places) = @_;
+
+# $places = 3 if $places == 2;
+
+ if (($places * 1) >= 0) {
+ # compensate for perl behaviour, add 1/10^$places+3
+ sprintf("%.${places}f", $amount + (1 / (10 ** ($places + 3))) * (($amount > 0) ? 1 : -1));
+ } else {
+ $places *= -1;
+ sprintf("%.f", $amount / (10 ** $places) + (($amount > 0) ? 0.1 : -0.1)) * (10 ** $places);
+ }
+
+}
+
+
+sub parse_template {
+ my ($self, $myconfig, $userspath) = @_;
+
+ # { Moritz Bunkus
+ # Some variables used for page breaks
+ my ($chars_per_line, $lines_on_first_page, $lines_on_second_page) = (0, 0, 0);
+ my ($current_page, $current_line) = (1, 1);
+ my $pagebreak = "";
+ my $sum = 0;
+ # } Moritz Bunkus
+
+ open(IN, "$self->{templates}/$self->{IN}") or $self->error("$self->{IN} : $!");
+
+ @_ = <IN>;
+ close(IN);
+
+ $self->{copies} = 1 if (($self->{copies} *= 1) <= 0);
+
+ # OUT is used for the media, screen, printer, email
+ # for postscript we store a copy in a temporary file
+ my $fileid = time;
+ $self->{tmpfile} = "$userspath/${fileid}.$self->{IN}";
+ if ($self->{format} =~ /(postscript|pdf)/ || $self->{media} eq 'email') {
+ $out = $self->{OUT};
+ $self->{OUT} = ">$self->{tmpfile}";
+ }
+
+
+ if ($self->{OUT}) {
+ open(OUT, "$self->{OUT}") or $self->error("$self->{OUT} : $!");
+ } else {
+ open(OUT, ">-") or $self->error("STDOUT : $!");
+ $self->header;
+ }
+
+
+ # first we generate a tmpfile
+ # read file and replace <%variable%>
+ while ($_ = shift) {
+
+ $par = "";
+ $var = $_;
+
+
+ # { Moritz Bunkus
+ # detect pagebreak block and its parameters
+ if (/<%pagebreak ([0-9]+) ([0-9]+) ([0-9]+)%>/) {
+ $chars_per_line = $1;
+ $lines_on_first_page = $2;
+ $lines_on_second_page = $3;
+
+ while ($_ = shift) {
+ last if (/<\%end pagebreak%>/);
+ $pagebreak .= $_;
+ }
+ }
+ # } Moritz Bunkus
+
+
+ if (/<%foreach /) {
+
+ # this one we need for the count
+ chomp $var;
+ $var =~ s/<%foreach (.+?)%>/$1/;
+ while ($_ = shift) {
+ last if (/<%end /);
+
+ # store line in $par
+ $par .= $_;
+ }
+
+ # display contents of $self->{number}[] array
+ for $i (0 .. $#{ $self->{$var} }) {
+
+ # { Moritz Bunkus
+ # Try to detect whether a manual page break is necessary
+ # but only if there was a <%pagebreak ...%> block before
+
+ if ($chars_per_line) {
+ my $lines = int(length($self->{"description"}[$i]) / $chars_per_line + 0.95);
+ my $lpp;
+
+ if ($current_page == 1) {
+ $lpp = $lines_on_first_page;
+ } else {
+ $lpp = $lines_on_second_page;
+ }
+
+ # Yes we need a manual page break
+ if (($current_line + $lines) > $lpp) {
+ my $pb = $pagebreak;
+
+ # replace the special variables <%sumcarriedforward%>
+ # and <%lastpage%>
+
+ my $psum = $self->format_amount($myconfig, $sum, 2);
+ $pb =~ s/<%sumcarriedforward%>/$psum/g;
+ $pb =~ s/<%lastpage%>/$current_page/g;
+
+ # only "normal" variables are supported here
+ # (no <%if, no <%foreach, no <%include)
+
+ $pb =~ s/<%(.+?)%>/$self->{$1}/g;
+
+ # page break block is ready to rock
+ print(OUT $pb);
+ $current_page++;
+ $current_line = 1;
+ }
+ $current_line += $lines;
+ }
+ $sum += $self->parse_amount($myconfig, $self->{"linetotal"}[$i]);
+ # } Moritz Bunkus
+
+
+ # don't parse par, we need it for each line
+ $_ = $par;
+ s/<%(.+?)%>/$self->{$1}[$i]/mg;
+ print OUT;
+ }
+ next;
+ }
+
+ # if not comes before if!
+ if (/<%if not /) {
+ # check if it is not set and display
+ chop;
+ s/<%if not (.+?)%>/$1/;
+
+ unless ($self->{$_}) {
+ while ($_ = shift) {
+ last if (/<%end /);
+
+ # store line in $par
+ $par .= $_;
+ }
+
+ $_ = $par;
+
+ } else {
+ while ($_ = shift) {
+ last if (/<%end /);
+ }
+ next;
+ }
+ }
+
+ if (/<%if /) {
+ # check if it is set and display
+ chop;
+ s/<%if (.+?)%>/$1/;
+
+ if ($self->{$_}) {
+ while ($_ = shift) {
+ last if (/<%end /);
+
+ # store line in $par
+ $par .= $_;
+ }
+
+ $_ = $par;
+
+ } else {
+ while ($_ = shift) {
+ last if (/<%end /);
+ }
+ next;
+ }
+ }
+
+ # check for <%include filename%>
+ if (/<%include /) {
+
+ # get the filename
+ chomp $var;
+ $var =~ s/<%include (.+?)%>/$1/;
+
+ # mangle filename if someone tries to be cute
+ $var =~ s/\///g;
+
+ # prevent the infinite loop!
+ next if ($self->{"$var"});
+
+ open(INC, "$self->{templates}/$var") or $self->error($self->cleanup."$self->{templates}/$var : $!");
+ unshift(@_, <INC>);
+ close(INC);
+
+ $self->{"$var"} = 1;
+
+ next;
+ }
+
+ s/<%(.+?)%>/$self->{$1}/g;
+ print OUT;
+ }
+
+ close(OUT);
+
+
+ # { Moritz Bunkus
+ # Convert the tex file to postscript
+ if ($self->{format} =~ /(postscript|pdf)/) {
+
+ use Cwd;
+ $self->{cwd} = cwd();
+ chdir("$userspath") or $self->error($self->cleanup."chdir : $!");
+
+ $self->{tmpfile} =~ s/$userspath\///g;
+
+ # DS. added screen and email option in addition to printer
+ # screen
+ if ($self->{format} eq 'postscript') {
+ system("latex --interaction=nonstopmode $self->{tmpfile} > $self->{tmpfile}.err");
+ $self->error($self->cleanup) if ($?);
+
+ $self->{tmpfile} =~ s/tex$/dvi/;
+
+ system("dvips $self->{tmpfile} -o -q > /dev/null");
+ $self->error($self->cleanup."dvips : $!") if ($?);
+ $self->{tmpfile} =~ s/dvi$/ps/;
+ }
+ if ($self->{format} eq 'pdf') {
+ system("pdflatex --interaction=nonstopmode $self->{tmpfile} > $self->{tmpfile}.err");
+ $self->error($self->cleanup) if ($?);
+ $self->{tmpfile} =~ s/tex$/pdf/;
+ }
+
+ }
+
+ if ($self->{format} =~ /(postscript|pdf)/ || $self->{media} eq 'email') {
+
+ if ($self->{media} eq 'email') {
+
+ use SL::Mailer;
+
+ my $mail = new Mailer;
+
+ $self->{email} =~ s/,/>,</g;
+
+ map { $mail->{$_} = $self->{$_} } qw(cc bcc subject message version format charset);
+ $mail->{to} = qq|"$self->{name}" <$self->{email}>|;
+ $mail->{from} = qq|"$myconfig->{name}" <$myconfig->{email}>|;
+ $mail->{fileid} = "$fileid.";
+
+ # if we send html or plain text inline
+ if (($self->{format} eq 'html') && ($self->{sendmode} eq 'inline')) {
+ $mail->{contenttype} = "text/html";
+
+ $mail->{message} =~ s/\r\n/<br>\n/g;
+ $myconfig->{signature} =~ s/\\n/<br>\n/g;
+ $mail->{message} .= "<br>\n--<br>\n$myconfig->{signature}\n<br>";
+
+ open(IN, $self->{tmpfile}) or $self->error($self->cleanup."$self->{tmpfile} : $!");
+ while (<IN>) {
+ $mail->{message} .= $_;
+ }
+
+ close(IN);
+
+ } else {
+
+ @{ $mail->{attachments} } = ($self->{tmpfile});
+
+ $myconfig->{signature} =~ s/\\n/\r\n/g;
+ $mail->{message} .= "\r\n--\r\n$myconfig->{signature}";
+
+ }
+
+ my $err = $mail->send($out);
+ $self->error($self->cleanup."$err") if ($err);
+
+ } else {
+
+ $self->{OUT} = $out;
+ open(IN, $self->{tmpfile}) or $self->error($self->cleanup."$self->{tmpfile} : $!");
+
+ $self->{copies} = 1 unless $self->{media} eq 'printer';
+
+ for my $i (1 .. $self->{copies}) {
+
+ if ($self->{OUT}) {
+ open(OUT, $self->{OUT}) or $self->error($self->cleanup."$self->{OUT} : $!");
+ } else {
+ open(OUT, ">-") or $self->error($self->cleanup."$!: STDOUT");
+
+ # launch application
+ print qq|Content-Type: application/$self->{format}; name="$self->{tmpfile}"
+ Content-Disposition: filename="$self->{tmpfile}"
+
+ |;
+ }
+
+ while (<IN>) {
+ print OUT $_;
+ }
+ close(OUT);
+ seek IN, 0, 0;
+ }
+
+ close(IN);
+ }
+
+ $self->cleanup;
+
+ }
+ # } Moritz Bunkus
+
+}
+
+
+sub cleanup {
+ my $self = shift;
+
+ my @err = ();
+ if (-f "$self->{tmpfile}.err") {
+ open(FH, "$self->{tmpfile}.err");
+ @err = <FH>;
+ close(FH);
+ }
+
+ if ($self->{tmpfile}) {
+ # strip extension
+ $self->{tmpfile} =~ s/\.\w+$//g;
+ my $tmpfile = $self->{tmpfile};
+ unlink(<$tmpfile.*>);
+ }
+
+
+ chdir("$self->{cwd}");
+
+ "@err";
+
+}
+
+
+sub format_string {
+ my ($self, @fields) = @_;
+
+ my $format = $self->{format};
+ if ($self->{format} =~ /(postscript|pdf)/) {
+ $format = 'tex';
+ }
+
+ my %replace = ( 'order' => { 'html' => [ quotemeta('\n'), ' ' ],
+ 'tex' => [ '&', quotemeta('\n'), ' ',
+ '\$', '%', '_', '#', quotemeta('^'),
+ '{', '}', '<', '>', '£' ] },
+ 'html' => {
+ quotemeta('\n') => '<br>', ' ' => '<br>'
+ },
+ 'tex' => {
+ '&' => '\&', '\$' => '\$', '%' => '\%', '_' => '\_',
+ '#' => '\#', quotemeta('^') => '\^\\', '{' => '\{', '}' => '\}',
+ '<' => '$<$', '>' => '$>$',
+ quotemeta('\n') => '\newline ', ' ' => '\newline ',
+ '£' => '\pounds ',
+ }
+ );
+
+ foreach my $key (@{ $replace{order}{$format} }) {
+ map { $self->{$_} =~ s/$key/$replace{$format}{$key}/g; } @fields;
+ }
+
+}
+
+
+sub datetonum {
+ my ($self, $date, $myconfig) = @_;
+
+ if ($date) {
+ # get separator
+ my $spc = $myconfig->{dateformat};
+ $spc =~ s/\w//g;
+ $spc = substr($spc, 1, 1);
+
+ if ($spc eq '.') {
+ $spc = '\.';
+ }
+ if ($spc eq '/') {
+ $spc = '\/';
+ }
+
+ if ($myconfig->{dateformat} =~ /^yy/) {
+ ($yy, $mm, $dd) = split /$spc/, $date;
+ }
+ if ($myconfig->{dateformat} =~ /^mm/) {
+ ($mm, $dd, $yy) = split /$spc/, $date;
+ }
+ if ($myconfig->{dateformat} =~ /^dd/) {
+ ($dd, $mm, $yy) = split /$spc/, $date;
+ }
+
+ $dd *= 1;
+ $mm *= 1;
+ $yy = ($yy < 70) ? $yy + 2000 : $yy;
+ $yy = ($yy >= 70 && $yy <= 99) ? $yy + 1900 : $yy;
+
+ $dd = "0$dd" if ($dd < 10);
+ $mm = "0$mm" if ($mm < 10);
+
+ $date = "$yy$mm$dd";
+ }
+
+ $date;
+
+}
+
+
+
+# Database routines used throughout
+
+sub dbconnect {
+ my ($self, $myconfig) = @_;
+
+ # connect to database
+ my $dbh = DBI->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}) or $self->dberror;
+
+ # set db options
+ if ($myconfig->{dboptions}) {
+ $dbh->do($myconfig->{dboptions}) || $self->dberror($myconfig->{dboptions});
+ }
+
+ $dbh;
+
+}
+
+
+sub dbconnect_noauto {
+ my ($self, $myconfig) = @_;
+
+ # connect to database
+ $dbh = DBI->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}, {AutoCommit => 0}) or $self->dberror;
+
+ # set db options
+ if ($myconfig->{dboptions}) {
+ $dbh->do($myconfig->{dboptions}) || $self->dberror($myconfig->{dboptions});
+ }
+
+ $dbh;
+
+}
+
+
+sub update_balance {
+ my ($self, $dbh, $table, $field, $where, $value) = @_;
+
+ # if we have a value, go do it
+ if ($value != 0) {
+ # retrieve balance from table
+ my $query = "SELECT $field FROM $table WHERE $where";
+ my $sth = $dbh->prepare($query);
+
+ $sth->execute || $self->dberror($query);
+ my ($balance) = $sth->fetchrow_array;
+ $sth->finish;
+
+ $balance += $value;
+ # update balance
+ $query = "UPDATE $table SET $field = $balance WHERE $where";
+ $dbh->do($query) || $self->dberror($query);
+ }
+}
+
+
+
+sub update_exchangerate {
+ my ($self, $dbh, $curr, $transdate, $buy, $sell) = @_;
+
+ # some sanity check for currency
+ return if ($curr eq '');
+
+ my $query = qq|SELECT curr FROM exchangerate
+ WHERE curr = '$curr'
+ AND transdate = '$transdate'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ my $set;
+ if ($buy != 0 && $sell != 0) {
+ $set = "buy = $buy, sell = $sell";
+ } elsif ($buy != 0) {
+ $set = "buy = $buy";
+ } elsif ($sell != 0) {
+ $set = "sell = $sell";
+ }
+
+ if ($sth->fetchrow_array) {
+ $query = qq|UPDATE exchangerate
+ SET $set
+ WHERE curr = '$curr'
+ AND transdate = '$transdate'|;
+ } else {
+ $query = qq|INSERT INTO exchangerate (curr, buy, sell, transdate)
+ VALUES ('$curr', $buy, $sell, '$transdate')|;
+ }
+ $sth->finish;
+ $dbh->do($query) || $self->dberror($query);
+
+}
+
+
+sub get_exchangerate {
+ my ($self, $dbh, $curr, $transdate, $fld) = @_;
+
+ my $query = qq|SELECT $fld FROM exchangerate
+ WHERE curr = '$curr'
+ AND transdate = '$transdate'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ my ($exchangerate) = $sth->fetchrow_array;
+ $sth->finish;
+
+ $exchangerate;
+
+}
+
+
+sub delete_exchangerate {
+ my ($self, $dbh) = @_;
+
+ my @transdate = ();
+ my $transdate;
+
+ my $query = qq|SELECT DISTINCT transdate
+ FROM acc_trans
+ WHERE trans_id = $self->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ while ($transdate = $sth->fetchrow_array) {
+ push @transdate, $transdate;
+ }
+ $sth->finish;
+
+ $query = qq|SELECT transdate FROM acc_trans
+ WHERE ar.id = trans_id
+ AND ar.curr = '$self->{currency}'
+ AND transdate IN
+ (SELECT transdate FROM acc_trans
+ WHERE trans_id = $self->{id})
+ AND trans_id != $self->{id}
+ UNION SELECT transdate FROM acc_trans
+ WHERE ap.id = trans_id
+ AND ap.curr = '$self->{currency}'
+ AND transdate IN
+ (SELECT transdate FROM acc_trans
+ WHERE trans_id = $self->{id})
+ AND trans_id != $self->{id}
+ UNION SELECT transdate FROM oe
+ WHERE oe.curr = '$self->{currency}'
+ AND transdate IN
+ (SELECT transdate FROM acc_trans
+ WHERE trans_id = $self->{id})|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ while ($transdate = $sth->fetchrow_array) {
+ @transdate = grep !/^$transdate$/, @transdate;
+ }
+ $sth->finish;
+
+ foreach $transdate (@transdate) {
+ $query = qq|DELETE FROM exchangerate
+ WHERE curr = '$self->{currency}'
+ AND transdate = '$transdate'|;
+ $dbh->do($query) || $self->dberror($query);
+ }
+
+}
+
+
+sub check_exchangerate {
+ my ($self, $myconfig, $currency, $transdate, $fld) = @_;
+
+ return "" unless $transdate;
+
+ my $dbh = $self->dbconnect($myconfig);
+
+ my $query = qq|SELECT $fld FROM exchangerate
+ WHERE curr = '$currency'
+ AND transdate = '$transdate'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ my ($exchangerate) = $sth->fetchrow_array;
+ $sth->finish;
+ $dbh->disconnect;
+
+ $exchangerate;
+
+}
+
+
+sub add_shipto {
+ my ($self, $dbh, $id) = @_;
+
+ my $shipto;
+ foreach my $item (qw(name addr1 addr2 addr3 addr4 contact phone fax email)) {
+ if ($self->{"shipto$item"}) {
+ $shipto = 1 if ($self->{$item} ne $self->{"shipto$item"});
+ }
+ $self->{"shipto$item"} =~ s/'/''/g;
+ }
+
+ if ($shipto) {
+ my $query = qq|INSERT INTO shipto (trans_id, shiptoname, shiptoaddr1,
+ shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact,
+ shiptophone, shiptofax, shiptoemail) VALUES ($id,
+ '$self->{shiptoname}', '$self->{shiptoaddr1}',
+ '$self->{shiptoaddr2}', '$self->{shiptoaddr3}',
+ '$self->{shiptoaddr4}', '$self->{shiptocontact}',
+ '$self->{shiptophone}', '$self->{shiptofax}',
+ '$self->{shiptoemail}')|;
+ $dbh->do($query) || $self->dberror($query);
+ }
+
+}
+
+
+sub get_employee {
+ my ($self, $dbh) = @_;
+
+ my $query = qq|SELECT name FROM employee
+ WHERE login = '$self->{login}'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ ($self->{employee}) = $sth->fetchrow_array;
+ $sth->finish;
+
+}
+
+
+# this sub gets the id and name from $table
+sub get_name {
+ my ($self, $myconfig, $table) = @_;
+
+ # connect to database
+ my $dbh = $self->dbconnect($myconfig);
+
+ my $name = $self->like(lc $self->{$table});
+ my $query = qq~SELECT id, name,
+ addr1 || ' ' || addr2 || ' ' || addr3 || ' ' || addr4 AS address
+ FROM $table
+ WHERE lower(name) LIKE '$name'
+ ORDER BY name~;
+ my $sth = $dbh->prepare($query);
+
+ $sth->execute || $self->dberror($query);
+
+ my $i = 0;
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push(@{ $self->{name_list} }, $ref);
+ $i++;
+ }
+ $sth->finish;
+ $dbh->disconnect;
+
+ $i;
+
+}
+
+
+# the selection sub is used in the AR, AP, IS, IR and OE module
+#
+sub all_vc {
+ my ($self, $myconfig, $table) = @_;
+
+ my $dbh = $self->dbconnect($myconfig);
+
+ my $query = qq|SELECT count(*) FROM $table|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+ my ($count) = $sth->fetchrow_array;
+ $sth->finish;
+
+ # build selection list
+ if ($count < $myconfig->{vclimit}) {
+ $query = qq|SELECT id, name
+ FROM $table
+ ORDER BY name|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $self->{"all_$table"} }, $ref;
+ }
+
+ $sth->finish;
+
+ }
+
+ $dbh->disconnect;
+
+}
+
+
+sub create_links {
+ my ($self, $module, $myconfig, $table) = @_;
+
+ $self->all_vc($myconfig, $table);
+
+ # get last customers or vendors
+ my ($query, $sth);
+
+ my $dbh = $self->dbconnect($myconfig);
+
+ my %xkeyref = ();
+
+
+ # now get the account numbers
+ $query = qq|SELECT accno, description, link
+ FROM chart
+ WHERE link LIKE '%$module%'
+ ORDER BY accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ $self->{accounts} = "";
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+
+ foreach my $key (split(/:/, $ref->{link})) {
+ if ($key =~ /$module/) {
+ # cross reference for keys
+ $xkeyref{$ref->{accno}} = $key;
+
+ push @{ $self->{"${module}_links"}{$key} }, { accno => $ref->{accno},
+ description => $ref->{description} };
+
+ $self->{accounts} .= "$ref->{accno} " unless $key =~ /tax/;
+ }
+ }
+ }
+ $sth->finish;
+
+
+ if ($self->{id}) {
+ my $arap = ($table eq 'customer') ? 'ar' : 'ap';
+
+ $query = qq|SELECT a.invnumber, a.transdate,
+ a.${table}_id, a.datepaid, a.duedate, a.ordnumber,
+ a.taxincluded, a.curr AS currency, a.notes, c.name AS $table,
+ a.amount AS oldinvtotal, a.paid AS oldtotalpaid
+ FROM $arap a, $table c
+ WHERE a.${table}_id = c.id
+ AND a.id = $self->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ foreach $key (keys %$ref) {
+ $self->{$key} = $ref->{$key};
+ }
+ $sth->finish;
+
+ # get amounts from individual entries
+ $query = qq|SELECT c.accno, c.description, a.source, a.amount,
+ a.transdate, a.cleared, a.project_id, p.projectnumber
+ FROM acc_trans a
+ JOIN chart c ON (c.id = a.chart_id)
+ LEFT JOIN project p ON (a.project_id = p.id)
+ WHERE a.trans_id = $self->{id}
+ AND a.fx_transaction = '0'
+ ORDER BY transdate|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ my $fld = ($table eq 'customer') ? 'buy' : 'sell';
+ # get exchangerate for currency
+ $self->{exchangerate} = $self->get_exchangerate($dbh, $self->{currency}, $self->{transdate}, $fld);
+
+ # store amounts in {acc_trans}{$key} for multiple accounts
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $ref->{exchangerate} = $self->get_exchangerate($dbh, $self->{currency}, $ref->{transdate}, $fld);
+
+ push @{ $self->{acc_trans}{$xkeyref{$ref->{accno}}} }, $ref;
+ }
+
+ $sth->finish;
+
+ $query = qq|SELECT d.curr AS currencies, d.closedto, d.revtrans,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxloss_accno_id = c.id) AS fxloss_accno
+ FROM defaults d|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $self->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ } else {
+
+ # get date
+ $query = qq|SELECT current_date AS transdate,
+ d.curr AS currencies, d.closedto, d.revtrans,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxloss_accno_id = c.id) AS fxloss_accno
+ FROM defaults d|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $self->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ if ($self->{"$self->{vc}_id"}) {
+ # only setup currency
+ ($self->{currency}) = split /:/, $self->{currencies};
+
+ } else {
+
+ $self->lastname_used($dbh, $myconfig, $table, $module);
+
+ my $fld = ($table eq 'customer') ? 'buy' : 'sell';
+ # get exchangerate for currency
+ $self->{exchangerate} = $self->get_exchangerate($dbh, $self->{currency}, $self->{transdate}, $fld);
+
+ }
+
+ }
+
+ $dbh->disconnect;
+
+}
+
+
+sub lastname_used {
+ my ($self, $dbh, $myconfig, $table, $module) = @_;
+
+ my $arap = ($table eq 'customer') ? "ar" : "ap";
+ $arap = 'oe' if ($self->{type} =~ /_order/);
+
+ my $query = qq|SELECT id FROM $arap
+ WHERE id IN (SELECT MAX(id) FROM $arap
+ WHERE ${table}_id > 0)|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ my ($trans_id) = $sth->fetchrow_array;
+ $sth->finish;
+
+ $trans_id *= 1;
+ $query = qq|SELECT ct.name, a.curr, a.${table}_id,
+ current_date + ct.terms AS duedate
+ FROM $arap a
+ JOIN $table ct ON (a.${table}_id = ct.id)
+ WHERE a.id = $trans_id|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ ($self->{$table}, $self->{currency}, $self->{"${table}_id"}, $self->{duedate}) = $sth->fetchrow_array;
+ $sth->finish;
+
+}
+
+
+
+sub current_date {
+ my ($self, $myconfig, $thisdate, $days) = @_;
+
+ my $dbh = $self->dbconnect($myconfig);
+ my ($sth, $query);
+
+ $days *= 1;
+ if ($thisdate) {
+ my $dateformat = $myconfig->{dateformat};
+ $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;
+
+ $query = qq|SELECT to_date('$thisdate', '$dateformat') + $days AS thisdate
+ FROM defaults|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+ } else {
+ $query = qq|SELECT current_date AS thisdate
+ FROM defaults|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+ }
+
+ ($thisdate) = $sth->fetchrow_array;
+ $sth->finish;
+
+ $dbh->disconnect;
+
+ $thisdate;
+
+}
+
+
+sub like {
+ my ($self, $string) = @_;
+
+ unless ($string =~ /%/) {
+ $string = "%$string%";
+ }
+
+ $string =~ s/'/''/g;
+ $string;
+
+}
+
+
+sub redo_rows {
+ my ($self, $flds, $new, $count, $numrows) = @_;
+
+ my @ndx = ();
+
+ map { push @ndx, { num => $new->[$_-1]->{runningnumber}, ndx => $_ } } (1 .. $count);
+
+ my $i = 0;
+ # fill rows
+ foreach my $item (sort { $a->{num} <=> $b->{num} } @ndx) {
+ $i++;
+ $j = $item->{ndx} - 1;
+ map { $self->{"${_}_$i"} = $new->[$j]->{$_} } @{$flds};
+ }
+
+ # delete empty rows
+ for $i ($count + 1 .. $numrows) {
+ map { delete $self->{"${_}_$i"} } @{$flds};
+ }
+
+}
+
+
+package Locale;
+
+
+sub new {
+ my ($type, $country, $NLS_file) = @_;
+ my $self = {};
+
+ %self = ();
+ if ($country && -d "locale/$country") {
+ $self->{countrycode} = $country;
+ eval { require "locale/$country/$NLS_file"; };
+ }
+
+ $self->{NLS_file} = $NLS_file;
+
+ push @{ $self->{LONG_MONTH} }, ("January", "February", "March", "April", "May ", "June", "July", "August", "September", "October", "November", "December");
+ push @{ $self->{SHORT_MONTH} }, (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec));
+
+ bless $self, $type;
+
+}
+
+
+sub text {
+ my ($self, $text) = @_;
+
+ return (exists $self{texts}{$text}) ? $self{texts}{$text} : $text;
+
+}
+
+
+sub findsub {
+ my ($self, $text) = @_;
+
+ if (exists $self{subs}{$text}) {
+ $text = $self{subs}{$text};
+ } else {
+ if ($self->{countrycode} && $self->{NLS_file}) {
+ Form->error("$text not defined in locale/$self->{countrycode}/$self->{NLS_file}");
+ }
+ }
+
+ $text;
+
+}
+
+
+sub date {
+ my ($self, $myconfig, $date, $longformat) = @_;
+
+ my $longdate = "";
+ my $longmonth = ($longformat) ? 'LONG_MONTH' : 'SHORT_MONTH';
+
+ if ($date) {
+ # get separator
+ $spc = $myconfig->{dateformat};
+ $spc =~ s/\w//g;
+ $spc = substr($spc, 1, 1);
+
+ if ($spc eq '.') {
+ $spc = '\.';
+ }
+ if ($spc eq '/') {
+ $spc = '\/';
+ }
+
+ if ($myconfig->{dateformat} =~ /^yy/) {
+ ($yy, $mm, $dd) = split /$spc/, $date;
+ }
+ if ($myconfig->{dateformat} =~ /^mm/) {
+ ($mm, $dd, $yy) = split /$spc/, $date;
+ }
+ if ($myconfig->{dateformat} =~ /^dd/) {
+ ($dd, $mm, $yy) = split /$spc/, $date;
+ }
+
+ $dd *= 1;
+ $mm--;
+ $yy = ($yy < 70) ? $yy + 2000 : $yy;
+ $yy = ($yy >= 70 && $yy <= 99) ? $yy + 1900 : $yy;
+
+ if ($myconfig->{dateformat} =~ /^dd/) {
+ $longdate = "$dd. ".&text($self, $self->{$longmonth}[$mm])." $yy";
+ } else {
+ $longdate = &text($self, $self->{$longmonth}[$mm])." $dd, $yy";
+ }
+
+ }
+
+ $longdate;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/GL.pm b/sql-ledger/SL/GL.pm
new file mode 100644
index 0000000..5bceb07
--- /dev/null
+++ b/sql-ledger/SL/GL.pm
@@ -0,0 +1,462 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# General ledger backend code
+#
+# CHANGE LOG:
+# DS. 2000-07-04 Created
+# DS. 2001-06-12 Changed relations from accno to chart_id
+#
+#======================================================================
+
+package GL;
+
+
+sub delete_transaction {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my $query = qq|DELETE FROM gl WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM acc_trans WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # commit and redirect
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+sub post_transaction {
+ my ($self, $myconfig, $form) = @_;
+
+ my ($debit, $credit) = (0, 0);
+ my $project_id;
+
+ my $i;
+ # check if debit and credit balances
+ for $i (1 .. $form->{rowcount}) {
+ if ($form->{"debit_$i"} && $form->{"credit_$i"}) {
+ return -1;
+ }
+
+ $form->{"debit_$i"} = $form->parse_amount($myconfig, $form->{"debit_$i"});
+ $form->{"credit_$i"} = $form->parse_amount($myconfig, $form->{"credit_$i"});
+
+ $debit += $form->{"debit_$i"};
+ $credit += $form->{"credit_$i"};
+ }
+
+ $debit = $form->round_amount($debit, 2);
+ $credit = $form->round_amount($credit, 2);
+
+ if ($debit != $credit) {
+ return -2;
+ }
+
+ if (($debit + $credit) == 0) {
+ return -3;
+ }
+
+ # connect to database, turn off AutoCommit
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # post the transaction
+ # make up a unique handle and store in reference field
+ # then retrieve the record based on the unique handle to get the id
+ # replace the reference field with the actual variable
+ # add records to acc_trans
+
+ # if there is a $form->{id} replace the old transaction
+ # delete all acc_trans entries and add the new ones
+
+ # escape '
+ map { $form->{$_} =~ s/'/''/g } qw(reference description);
+
+
+ my ($query, $sth);
+
+ if ($form->{id}) {
+ # delete individual transactions
+ $query = qq|DELETE FROM acc_trans
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ } else {
+ my $uid = time;
+ $uid .= $form->{login};
+
+ $query = qq|INSERT INTO gl (reference, employee_id)
+ VALUES ('$uid', (SELECT id FROM employee
+ WHERE login = '$form->{login}'))|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM gl
+ WHERE reference = '$uid'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{id}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ }
+
+ $query = qq|UPDATE gl SET
+ reference = '$form->{reference}',
+ description = '$form->{description}',
+ notes = '$form->{notes}',
+ transdate = '$form->{transdate}'
+ WHERE id = $form->{id}|;
+
+ $dbh->do($query) || $form->dberror($query);
+
+
+ # insert acc_trans transactions
+ for $i (1 .. $form->{rowcount}) {
+ # extract accno
+ ($accno) = split(/--/, $form->{"accno_$i"});
+ my $amount = 0;
+
+ if ($form->{"credit_$i"} != 0) {
+ $amount = $form->{"credit_$i"};
+ }
+ if ($form->{"debit_$i"} != 0) {
+ $amount = $form->{"debit_$i"} * -1;
+ }
+
+
+ # if there is an amount, add the record
+ if ($amount != 0) {
+ $project_id = ($form->{"project_id_$i"}) ? $form->{"project_id_$i"} : 'NULL';
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
+ source, project_id)
+ VALUES
+ ($form->{id}, (SELECT id
+ FROM chart
+ WHERE accno = '$accno'),
+ $amount, '$form->{transdate}', '$form->{reference}',
+ $project_id)|;
+
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+ # commit and redirect
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub all_transactions {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+ my $query;
+ my $sth;
+
+ my ($glwhere, $arwhere, $apwhere) = ("1 = 1", "1 = 1", "1 = 1");
+
+ if ($form->{reference}) {
+ my $source = $form->like(lc $form->{reference});
+ $glwhere .= " AND lower(g.reference) LIKE '$source'";
+ $arwhere .= " AND lower(a.invnumber) LIKE '$source'";
+ $apwhere .= " AND lower(a.invnumber) LIKE '$source'";
+ }
+ if ($form->{source}) {
+ my $source = $form->like(lc $form->{source});
+ $glwhere .= " AND lower(ac.source) LIKE '$source'";
+ $arwhere .= " AND lower(ac.source) LIKE '$source'";
+ $apwhere .= " AND lower(ac.source) LIKE '$source'";
+ }
+ if ($form->{datefrom}) {
+ $glwhere .= " AND ac.transdate >= '$form->{datefrom}'";
+ $arwhere .= " AND ac.transdate >= '$form->{datefrom}'";
+ $apwhere .= " AND ac.transdate >= '$form->{datefrom}'";
+ }
+ if ($form->{dateto}) {
+ $glwhere .= " AND ac.transdate <= '$form->{dateto}'";
+ $arwhere .= " AND ac.transdate <= '$form->{dateto}'";
+ $apwhere .= " AND ac.transdate <= '$form->{dateto}'";
+ }
+ if ($form->{description}) {
+ my $description = $form->like(lc $form->{description});
+ $glwhere .= " AND lower(g.description) LIKE '$description'";
+ $arwhere .= " AND lower(ct.name) LIKE '$description'";
+ $apwhere .= " AND lower(ct.name) LIKE '$description'";
+ }
+ if ($form->{notes}) {
+ my $notes = $form->like(lc $form->{notes});
+ $glwhere .= " AND lower(g.notes) LIKE '$notes'";
+ $arwhere .= " AND lower(a.notes) LIKE '$notes'";
+ $apwhere .= " AND lower(a.notes) LIKE '$notes'";
+ }
+ if ($form->{accno}) {
+ $glwhere .= " AND c.accno = '$form->{accno}'";
+ $arwhere .= " AND c.accno = '$form->{accno}'";
+ $apwhere .= " AND c.accno = '$form->{accno}'";
+ }
+ if ($form->{gifi_accno}) {
+ $glwhere .= " AND c.gifi_accno = '$form->{gifi_accno}'";
+ $arwhere .= " AND c.gifi_accno = '$form->{gifi_accno}'";
+ $apwhere .= " AND c.gifi_accno = '$form->{gifi_accno}'";
+ }
+ if ($form->{category} ne 'X') {
+ $glwhere .= " AND c.category = '$form->{category}'";
+ $arwhere .= " AND c.category = '$form->{category}'";
+ $apwhere .= " AND c.category = '$form->{category}'";
+ }
+
+ if ($form->{accno}) {
+ # get category for account
+ $query = qq|SELECT category
+ FROM chart
+ WHERE accno = '$form->{accno}'|;
+ $sth = $dbh->prepare($query);
+
+ $sth->execute || $form->dberror($query);
+ ($form->{ml}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ if ($form->{datefrom}) {
+ $query = qq|SELECT SUM(ac.amount)
+ FROM acc_trans ac, chart c
+ WHERE ac.chart_id = c.id
+ AND c.accno = '$form->{accno}'
+ AND ac.transdate < date '$form->{datefrom}'
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{balance}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+ }
+
+ if ($form->{gifi_accno}) {
+ # get category for account
+ $query = qq|SELECT category
+ FROM chart
+ WHERE gifi_accno = '$form->{gifi_accno}'|;
+ $sth = $dbh->prepare($query);
+
+ $sth->execute || $form->dberror($query);
+ ($form->{ml}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ if ($form->{datefrom}) {
+ $query = qq|SELECT SUM(ac.amount)
+ FROM acc_trans ac, chart c
+ WHERE ac.chart_id = c.id
+ AND c.gifi_accno = '$form->{gifi_accno}'
+ AND ac.transdate < date '$form->{datefrom}'
+ |;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{balance}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+ }
+
+ my $false = ($myconfig->{dbdriver} eq 'Pg') ? FALSE : q|'0'|;
+
+ my $sortorder = join ', ', $form->sort_columns(qw(transdate reference source description accno));
+ my %ordinal = ( transdate => 6,
+ reference => 4,
+ source => 7,
+ description => 5 );
+ map { $sortorder =~ s/$_/$ordinal{$_}/ } keys %ordinal;
+
+ my $query = qq|SELECT g.id, 'gl' AS type, $false AS invoice, g.reference,
+ g.description, ac.transdate, ac.source,
+ ac.amount, c.accno, c.gifi_accno, g.notes
+ FROM gl g, acc_trans ac, chart c
+ WHERE $glwhere
+ AND ac.chart_id = c.id
+ AND g.id = ac.trans_id
+ UNION ALL
+ SELECT a.id, 'ar' AS type, a.invoice, a.invnumber,
+ ct.name, ac.transdate, ac.source,
+ ac.amount, c.accno, c.gifi_accno, a.notes
+ FROM ar a, acc_trans ac, chart c, customer ct
+ WHERE $arwhere
+ AND ac.chart_id = c.id
+ AND a.customer_id = ct.id
+ AND a.id = ac.trans_id
+ UNION ALL
+ SELECT a.id, 'ap' AS type, a.invoice, a.invnumber,
+ ct.name, ac.transdate, ac.source,
+ ac.amount, c.accno, c.gifi_accno, a.notes
+ FROM ap a, acc_trans ac, chart c, vendor ct
+ WHERE $apwhere
+ AND ac.chart_id = c.id
+ AND a.vendor_id = ct.id
+ AND a.id = ac.trans_id
+ ORDER BY $sortorder|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+
+ # gl
+ if ($ref->{type} eq "gl") {
+ $ref->{module} = "gl";
+ }
+
+ # ap
+ if ($ref->{type} eq "ap") {
+ if ($ref->{invoice}) {
+ $ref->{module} = "ir";
+ } else {
+ $ref->{module} = "ap";
+ }
+ }
+
+ # ar
+ if ($ref->{type} eq "ar") {
+ if ($ref->{invoice}) {
+ $ref->{module} = "is";
+ } else {
+ $ref->{module} = "ar";
+ }
+ }
+
+ if ($ref->{amount} < 0) {
+ $ref->{debit} = $ref->{amount} * -1;
+ $ref->{credit} = 0;
+ } else {
+ $ref->{credit} = $ref->{amount};
+ $ref->{debit} = 0;
+ }
+
+ push @{ $form->{GL} }, $ref;
+
+ }
+
+ $sth->finish;
+
+ if ($form->{accno}) {
+ $query = qq|SELECT description FROM chart WHERE accno = '$form->{accno}'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{account_description}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+ if ($form->{gifi_accno}) {
+ $query = qq|SELECT description FROM gifi WHERE accno = '$form->{gifi_accno}'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{gifi_account_description}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+
+ $dbh->disconnect;
+
+}
+
+
+sub transaction {
+ my ($self, $myconfig, $form) = @_;
+
+ my ($query, $sth);
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ if ($form->{id}) {
+ $query = "SELECT closedto, revtrans
+ FROM defaults";
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{closedto}, $form->{revtrans}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ $query = "SELECT reference, description, notes, transdate
+ FROM gl
+ WHERE id = $form->{id}";
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{reference}, $form->{description}, $form->{notes}, $form->{transdate}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ # retrieve individual rows
+ $query = "SELECT c.accno, a.amount, project_id,
+ (SELECT p.projectnumber FROM project p
+ WHERE a.project_id = p.id) AS projectnumber
+ FROM acc_trans a, chart c
+ WHERE a.chart_id = c.id
+ AND a.trans_id = $form->{id}
+ ORDER BY accno";
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{GL} }, $ref;
+ }
+ } else {
+ $query = "SELECT current_date AS transdate, closedto, revtrans
+ FROM defaults";
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{transdate}, $form->{closedto}, $form->{revtrans}) = $sth->fetchrow_array;
+ }
+
+ $sth->finish;
+
+ # get chart of accounts
+ $query = qq|SELECT accno,description
+ FROM chart
+ WHERE charttype = 'A'
+ ORDER by accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+ $form->{chart} = "";
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{chart} }, $ref;
+ }
+ $sth->finish;
+
+ $dbh->disconnect;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/IC.pm b/sql-ledger/SL/IC.pm
new file mode 100644
index 0000000..f4a2f75
--- /dev/null
+++ b/sql-ledger/SL/IC.pm
@@ -0,0 +1,936 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Inventory Control backend
+#
+#======================================================================
+
+package IC;
+
+
+sub get_part {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to db
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT p.*,
+ c1.accno AS inventory_accno,
+ c2.accno AS income_accno,
+ c3.accno AS expense_accno,
+ pg.partsgroup
+ FROM parts p
+ LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
+ LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
+ LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE p.id = $form->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+
+ # copy to $form variables
+ map { $form->{$_} = $ref->{$_} } ( keys %{ $ref } );
+
+ $sth->finish;
+
+ my %oid = ('Pg' => 'a.oid',
+ 'Oracle' => 'a.rowid'
+ );
+
+
+ # part or service item
+ $form->{item} = ($form->{inventory_accno}) ? 'part' : 'service';
+ if ($form->{assembly}) {
+ $form->{item} = 'assembly';
+
+ # retrieve assembly items
+ $query = qq|SELECT p.id, p.partnumber, p.description,
+ p.sellprice, p.weight, a.qty, a.bom, p.unit,
+ pg.partsgroup
+ FROM parts p
+ JOIN assembly a ON (a.parts_id = p.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE a.id = $form->{id}
+ ORDER BY $oid{$myconfig->{dbdriver}}|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $form->{assembly_rows} = 0;
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $form->{assembly_rows}++;
+ foreach my $key ( keys %{ $ref } ) {
+ $form->{"${key}_$form->{assembly_rows}"} = $ref->{$key};
+ }
+ }
+ $sth->finish;
+
+ }
+
+ # setup accno hash for <option checked> {amount} is used in create_links
+ $form->{amount}{IC} = $form->{inventory_accno};
+ $form->{amount}{IC_income} = $form->{income_accno};
+ $form->{amount}{IC_sale} = $form->{income_accno};
+ $form->{amount}{IC_expense} = $form->{expense_accno};
+ $form->{amount}{IC_cogs} = $form->{expense_accno};
+
+
+ if ($form->{item} ne 'service') {
+ # get makes
+ if ($form->{makemodel}) {
+ $query = qq|SELECT name FROM makemodel
+ WHERE parts_id = $form->{id}|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $i = 1;
+ while (($form->{"make_$i"}, $form->{"model_$i"}) = split(/:/, $sth->fetchrow_array)) {
+ $i++;
+ }
+ $sth->finish;
+ $form->{makemodel_rows} = $i - 1;
+
+ }
+ }
+
+ # now get accno for taxes
+ $query = qq|SELECT c.accno
+ FROM chart c, partstax pt
+ WHERE pt.chart_id = c.id
+ AND pt.parts_id = $form->{id}|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (($key) = $sth->fetchrow_array) {
+ $form->{amount}{$key} = $key;
+ }
+
+ $sth->finish;
+
+ # is it an orphan
+ $query = qq|SELECT parts_id
+ FROM invoice
+ WHERE parts_id = $form->{id}
+ UNION
+ SELECT parts_id
+ FROM orderitems
+ WHERE parts_id = $form->{id}
+ UNION
+ SELECT parts_id
+ FROM assembly
+ WHERE parts_id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{orphaned}) = $sth->fetchrow_array;
+ $form->{orphaned} = !$form->{orphaned};
+ $sth->finish;
+
+ $dbh->disconnect;
+
+}
+
+
+
+sub save {
+ my ($self, $myconfig, $form) = @_;
+
+ ($form->{inventory_accno}) = split(/--/, $form->{IC});
+ ($form->{expense_accno}) = split(/--/, $form->{IC_expense});
+ ($form->{income_accno}) = split(/--/, $form->{IC_income});
+
+ # connect to database, turn off AutoCommit
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # save the part
+ # make up a unique handle and store in partnumber field
+ # then retrieve the record based on the unique handle to get the id
+ # replace the partnumber field with the actual variable
+ # add records for makemodel
+
+ # if there is a $form->{id} then replace the old entry
+ # delete all makemodel entries and add the new ones
+
+ # escape '
+ map { $form->{$_} =~ s/'/''/g } qw(partnumber description notes unit bin);
+
+ # undo amount formatting
+ map { $form->{$_} = $form->parse_amount($myconfig, $form->{$_}) } qw(rop weight listprice sellprice lastcost stock);
+
+ # set date to NULL if nothing entered
+ $form->{priceupdate} = ($form->{priceupdate}) ? qq|'$form->{priceupdate}'| : "NULL";
+
+ $form->{makemodel} = (($form->{make_1}) || ($form->{model_1})) ? 1 : 0;
+
+ $form->{alternate} = 0;
+ $form->{assembly} = ($form->{item} eq 'assembly') ? 1 : 0;
+ $form->{obsolete} *= 1;
+ $form->{onhand} *= 1;
+
+ my ($query, $sth);
+
+ if ($form->{id}) {
+
+ # get old price
+ $query = qq|SELECT sellprice, weight
+ FROM parts
+ WHERE id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my ($sellprice, $weight) = $sth->fetchrow_array;
+ $sth->finish;
+
+ # if item is part of an assembly adjust all assemblies
+ $query = qq|SELECT id, qty
+ FROM assembly
+ WHERE parts_id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my ($id, $qty) = $sth->fetchrow_array) {
+ &update_assembly($dbh, $form, $id, $qty * 1, $sellprice * 1, $weight * 1);
+ }
+ $sth->finish;
+
+
+ if ($form->{item} ne 'service') {
+ # delete makemodel records
+ $query = qq|DELETE FROM makemodel
+ WHERE parts_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ if ($form->{item} eq 'assembly') {
+ if ($form->{onhand} != 0) {
+ &adjust_inventory($dbh, $form, $form->{id}, $form->{onhand} * -1);
+ }
+
+ if ($form->{orphaned}) {
+ # delete assembly records
+ $query = qq|DELETE FROM assembly
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+ } else {
+ # update BOM only
+ $query = qq|UPDATE assembly
+ SET bom = ?
+ WHERE id = ?
+ AND parts_id = ?|;
+ $sth = $dbh->prepare($query);
+
+ for $i (1 .. $form->{assembly_rows} - 1) {
+ $sth->execute(($form->{"bom_$i"}) ? '1' : '0', $form->{id}, $form->{"id_$i"}) || $form->dberror($query);
+ }
+ $sth->finish;
+ }
+
+ $form->{onhand} += $form->{stock};
+ }
+
+ # delete tax records
+ $query = qq|DELETE FROM partstax
+ WHERE parts_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ } else {
+ my $uid = time;
+ $uid .= $form->{login};
+
+ $query = qq|INSERT INTO parts (partnumber)
+ VALUES ('$uid')|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM parts
+ WHERE partnumber = '$uid'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{id}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ $form->{orphaned} = 1;
+ $form->{onhand} = ($form->{stock} * 1) if $form->{item} eq 'assembly';
+
+ }
+
+ my $partsgroup_id = 0;
+ if ($form->{partsgroup}) {
+ my $partsgroup = lc $form->{partsgroup};
+ $query = qq|SELECT DISTINCT id FROM partsgroup
+ WHERE lower(partsgroup) = '$partsgroup'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($partsgroup_id) = $sth->fetchrow_array;
+ $sth->finish;
+
+ if (!$partsgroup_id) {
+ $query = qq|INSERT INTO partsgroup (partsgroup)
+ VALUES ('$form->{partsgroup}')|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM partsgroup
+ WHERE partsgroup = '$form->{partsgroup}'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($partsgroup_id) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+ }
+
+
+ $query = qq|UPDATE parts SET
+ partnumber = '$form->{partnumber}',
+ description = '$form->{description}',
+ makemodel = '$form->{makemodel}',
+ alternate = '$form->{alternate}',
+ assembly = '$form->{assembly}',
+ listprice = $form->{listprice},
+ sellprice = $form->{sellprice},
+ lastcost = $form->{lastcost},
+ weight = $form->{weight},
+ priceupdate = $form->{priceupdate},
+ unit = '$form->{unit}',
+ notes = '$form->{notes}',
+ rop = $form->{rop},
+ bin = '$form->{bin}',
+ inventory_accno_id = (SELECT id FROM chart
+ WHERE accno = '$form->{inventory_accno}'),
+ income_accno_id = (SELECT id FROM chart
+ WHERE accno = '$form->{income_accno}'),
+ expense_accno_id = (SELECT id FROM chart
+ WHERE accno = '$form->{expense_accno}'),
+ obsolete = '$form->{obsolete}',
+ image = '$form->{image}',
+ drawing = '$form->{drawing}',
+ microfiche = '$form->{microfiche}',
+ partsgroup_id = $partsgroup_id
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+
+ # insert makemodel records
+ unless ($form->{item} eq 'service') {
+ for my $i (1 .. $form->{makemodel_rows}) {
+ # put make and model together
+ if (($form->{"make_$i"}) || ($form->{"model_$i"})) {
+ map { $form->{"${_}_$i"} =~ s/'/''/g } qw(make model);
+
+ $query = qq|INSERT INTO makemodel (parts_id, name)
+ VALUES ($form->{id},
+ '$form->{"make_$i"}:$form->{"model_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+ }
+
+
+ # insert taxes
+ foreach $item (split / /, $form->{taxaccounts}) {
+ if ($form->{"IC_tax_$item"}) {
+ $query = qq|INSERT INTO partstax (parts_id, chart_id)
+ VALUES ($form->{id},
+ (SELECT id
+ FROM chart
+ WHERE accno = '$item'))|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+ # add assembly records
+ if ($form->{item} eq 'assembly') {
+
+ if ($form->{orphaned}) {
+ for my $i (1 .. $form->{assembly_rows}) {
+ $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
+
+ if ($form->{"qty_$i"} != 0) {
+ $form->{"bom_$i"} *= 1;
+ $query = qq|INSERT INTO assembly (id, parts_id, qty, bom)
+ VALUES ($form->{id}, $form->{"id_$i"},
+ $form->{"qty_$i"}, '$form->{"bom_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+ }
+
+ # adjust onhand for the assembly
+ if ($form->{onhand} != 0) {
+ &adjust_inventory($dbh, $form, $form->{id}, $form->{onhand});
+ }
+
+ }
+
+
+ # commit
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub update_assembly {
+ my ($dbh, $form, $id, $qty, $sellprice, $weight) = @_;
+
+ my $query = qq|SELECT id, qty
+ FROM assembly
+ WHERE parts_id = $id|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my ($pid, $aqty) = $sth->fetchrow_array) {
+ &update_assembly($dbh, $form, $pid, $aqty * $qty, $sellprice, $weight);
+ }
+ $sth->finish;
+
+ $query = qq|UPDATE parts
+ SET sellprice = sellprice +
+ $qty * ($form->{sellprice} - $sellprice),
+ weight = weight +
+ $qty * ($form->{weight} - $weight)
+ WHERE id = $id|;
+ $dbh->do($query) || $form->dberror($query);
+
+}
+
+
+
+sub retrieve_assemblies {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $where = '1 = 1';
+
+ if ($form->{partnumber}) {
+ my $partnumber = $form->like(lc $form->{partnumber});
+ $where .= " AND lower(p.partnumber) LIKE '$partnumber'";
+ }
+
+ if ($form->{description}) {
+ my $description = $form->like(lc $form->{description});
+ $where .= " AND lower(p.description) LIKE '$description'";
+ }
+ $where .= " AND NOT p.obsolete = '1'";
+
+ # retrieve assembly items
+ my $query = qq|SELECT p.id, p.partnumber, p.description,
+ p.bin, p.onhand, p.rop,
+ (SELECT sum(p2.inventory_accno_id)
+ FROM parts p2, assembly a
+ WHERE p2.id = a.parts_id
+ AND a.id = p.id) AS inventory
+ FROM parts p
+ WHERE $where
+ AND assembly = '1'|;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{assembly_items} }, $ref if $ref->{inventory};
+ }
+ $sth->finish;
+
+ $dbh->disconnect;
+
+}
+
+
+sub restock_assemblies {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ for my $i (1 .. $form->{rowcount}) {
+
+ $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
+
+ if ($form->{"qty_$i"} != 0) {
+ &adjust_inventory($dbh, $form, $form->{"id_$i"}, $form->{"qty_$i"});
+ }
+
+ }
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+sub adjust_inventory {
+ my ($dbh, $form, $id, $qty) = @_;
+
+ my $query = qq|SELECT p.id, p.inventory_accno_id, p.assembly, a.qty
+ FROM parts p
+ JOIN assembly a ON (a.parts_id = p.id)
+ WHERE a.id = $id|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+
+ my $allocate = $qty * $ref->{qty};
+
+ # is it a service item, then loop
+ $ref->{inventory_accno_id} *= 1;
+ next if (($ref->{inventory_accno_id} == 0) && !$ref->{assembly});
+
+ # adjust parts onhand
+ $form->update_balance($dbh,
+ "parts",
+ "onhand",
+ qq|id = $ref->{id}|,
+ $allocate * -1);
+ }
+
+ $sth->finish;
+
+ # update assembly
+ $form->update_balance($dbh,
+ "parts",
+ "onhand",
+ qq|id = $id|,
+ $qty);
+
+}
+
+
+sub delete {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn off AutoCommit
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ if ($form->{item} eq 'assembly' && $form->{onhand} != 0) {
+ # adjust onhand for the assembly
+ &adjust_inventory($dbh, $form, $form->{id}, $form->{onhand} * -1);
+ }
+
+ my $query = qq|DELETE FROM parts
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM partstax
+ WHERE parts_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # check if it is a part, assembly or service
+ if ($form->{item} eq 'part') {
+ $query = qq|DELETE FROM makemodel
+ WHERE parts_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ if ($form->{item} eq 'assembly') {
+ $query = qq|DELETE FROM assembly
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ if ($form->{item} eq 'alternate') {
+ $query = qq|DELETE FROM alternate
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ # commit
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+sub assembly_item {
+ my ($self, $myconfig, $form) = @_;
+
+ my $i = $form->{assembly_rows};
+ my $var;
+ my $where = "1 = 1";
+
+ if ($form->{"partnumber_$i"}) {
+ $var = $form->like(lc $form->{"partnumber_$i"});
+ $where .= " AND lower(p.partnumber) LIKE '$var'";
+ }
+ if ($form->{"description_$i"}) {
+ $var = $form->like(lc $form->{"description_$i"});
+ $where .= " AND lower(p.description) LIKE '$var'";
+ }
+ if ($form->{"partsgroup_$i"}) {
+ $var = $form->like(lc $form->{"partsgroup_$i"});
+ $where .= " AND lower(pg.partsgroup) LIKE '$var'";
+ }
+
+ if ($form->{id}) {
+ $where .= " AND NOT p.id = $form->{id}";
+ }
+
+ if ($partnumber) {
+ $where .= " ORDER BY p.partnumber";
+ } else {
+ $where .= " ORDER BY p.description";
+ }
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT p.id, p.partnumber, p.description, p.sellprice,
+ p.weight, p.onhand, p.unit,
+ pg.partsgroup
+ FROM parts p
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE $where|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{item_list} }, $ref;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub all_parts {
+ my ($self, $myconfig, $form) = @_;
+
+ my $where = '1 = 1';
+ my $var;
+
+ foreach my $item (qw(partnumber drawing microfiche)) {
+ if ($form->{$item}) {
+ $var = $form->like(lc $form->{$item});
+ $where .= " AND lower(p.$item) LIKE '$var'";
+ }
+ }
+ # special case for description
+ if ($form->{description}) {
+ unless ($form->{bought} || $form->{sold} || $form->{onorder} || $form->{ordered}) {
+ $var = $form->like(lc $form->{description});
+ $where .= " AND lower(p.description) LIKE '$var'";
+ }
+ }
+
+ if ($form->{searchitems} eq 'part') {
+ $where .= " AND p.inventory_accno_id > 0";
+ }
+ if ($form->{searchitems} eq 'assembly') {
+ $form->{bought} = "";
+ $where .= " AND p.assembly = '1'";
+ }
+ if ($form->{searchitems} eq 'service') {
+ $where .= " AND p.inventory_accno_id IS NULL AND NOT p.assembly = '1'";
+ # irrelevant for services
+ $form->{make} = $form->{model} = "";
+ }
+
+ # items which were never bought, sold or on an order
+ if ($form->{itemstatus} eq 'orphaned') {
+ $form->{onhand} = $form->{short} = 0;
+ $form->{bought} = $form->{sold} = 0;
+ $form->{onorder} = $form->{ordered} = 0;
+ $form->{transdatefrom} = $form->{transdateto} = "";
+
+ $where .= " AND p.onhand = 0
+ AND p.id NOT IN (SELECT p.id FROM parts p, invoice i
+ WHERE p.id = i.parts_id)
+ AND p.id NOT IN (SELECT p.id FROM parts p, assembly a
+ WHERE p.id = a.parts_id)
+ AND p.id NOT IN (SELECT p.id FROM parts p, orderitems o
+ WHERE p.id = o.parts_id)";
+ }
+
+ if ($form->{itemstatus} eq 'active') {
+ $where .= " AND p.obsolete = '0'";
+ }
+ if ($form->{itemstatus} eq 'obsolete') {
+ $where .= " AND p.obsolete = '1'";
+ $form->{onhand} = $form->{short} = 0;
+ }
+ if ($form->{itemstatus} eq 'onhand') {
+ $where .= " AND p.onhand > 0";
+ }
+ if ($form->{itemstatus} eq 'short') {
+ $where .= " AND p.onhand < 0";
+ }
+
+ if ($form->{make}) {
+ $var = $form->like(lc $form->{make}).":%";
+ $where .= " AND p.id IN (SELECT DISTINCT ON (m.parts_id) m.parts_id
+ FROM makemodel m WHERE lower(m.name) LIKE '$var')";
+ }
+ if ($form->{model}) {
+ $var = "%:".$form->like($form->{model});
+ $where .= " AND p.id IN (SELECT DISTINCT ON (m.parts_id) m.parts_id
+ FROM makemodel m WHERE lower(m.name) LIKE '$var')";
+ }
+ if ($form->{partsgroup}) {
+ $var = $form->like(lc $form->{partsgroup});
+ $where .= " AND lower(pg.partsgroup) LIKE '$var'";
+
+ }
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+
+ my $sortorder = join ', ', $form->sort_columns(qw(partnumber description bin priceupdate partsgroup));
+ $sortorder = $form->{sort} unless $sortorder;
+
+ my $query = qq|SELECT p.id, p.partnumber, p.description, p.onhand, p.unit,
+ p.bin, p.sellprice, p.listprice, p.lastcost, p.rop, p.weight,
+ p.priceupdate, p.image, p.drawing, p.microfiche,
+ pg.partsgroup
+ FROM parts p
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE $where
+ ORDER BY $sortorder|;
+
+ # rebuild query for bought and sold items
+ if ($form->{bought} || $form->{sold} || $form->{onorder} || $form->{ordered}) {
+
+ my $union = "";
+ $query = "";
+
+ if ($form->{bought} || $form->{sold}) {
+
+ my $invwhere = "$where";
+ $invwhere .= " AND i.assemblyitem = '0'";
+ $invwhere .= " AND a.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom};
+ $invwhere .= " AND a.transdate <= '$form->{transdateto}'" if $form->{transdateto};
+
+ if ($form->{description}) {
+ $var = $form->like(lc $form->{description});
+ $invwhere .= " AND lower(i.description) LIKE '$var'";
+ }
+
+ my $flds = qq|p.id, p.partnumber, i.description,
+ i.qty AS onhand, i.unit, p.bin, i.sellprice,
+ p.listprice, p.lastcost, p.rop, p.weight,
+ p.priceupdate, p.image, p.drawing, p.microfiche,
+ pg.partsgroup,
+ a.invnumber, a.ordnumber, i.trans_id|;
+
+ if ($form->{bought}) {
+ $query = qq|
+ SELECT $flds, 'ir' AS module, '' AS type,
+ 1 AS exchangerate
+ FROM parts p
+ JOIN invoice i ON (i.parts_id = p.id)
+ JOIN ap a ON (i.trans_id = a.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE $invwhere|;
+ $union = "
+ UNION";
+ }
+
+ if ($form->{sold}) {
+ $query .= qq|$union
+ SELECT $flds, 'is' AS module, '' AS type,
+ 1 As exchangerate
+ FROM parts p
+ JOIN invoice i ON (i.parts_id = p.id)
+ JOIN ar a ON (i.trans_id = a.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE $invwhere|;
+ $union = "
+ UNION";
+ }
+ }
+
+ if ($form->{onorder} || $form->{ordered}) {
+ my $ordwhere = "$where";
+ $ordwhere .= " AND o.closed = '0'" unless $form->{closed};
+
+ $ordwhere .= " AND o.transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom};
+ $ordwhere .= " AND o.transdate <= '$form->{transdateto}'" if $form->{transdateto};
+
+ if ($form->{description}) {
+ $var = $form->like(lc $form->{description});
+ $ordwhere .= " AND lower(oi.description) LIKE '$var'";
+ }
+
+ $flds = qq|p.id, p.partnumber, oi.description,
+ oi.qty AS onhand, oi.unit, p.bin, oi.sellprice,
+ p.listprice, p.lastcost, p.rop, p.weight,
+ p.priceupdate, p.image, p.drawing, p.microfiche,
+ pg.partsgroup,
+ '' AS invnumber, o.ordnumber, oi.trans_id|;
+
+ if ($form->{ordered}) {
+ $query .= qq|$union
+ SELECT $flds, 'oe' AS module, 'sales_order' AS type,
+ (SELECT buy FROM exchangerate ex
+ WHERE ex.curr = o.curr
+ AND ex.transdate = o.transdate) AS exchangerate
+ FROM parts p
+ JOIN orderitems oi ON (oi.parts_id = p.id)
+ JOIN oe o ON (oi.trans_id = o.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE $ordwhere
+ AND o.customer_id > 0|;
+ $union = "
+ UNION";
+ }
+
+ if ($form->{onorder}) {
+ $flds = qq|p.id, p.partnumber, oi.description,
+ oi.qty * -1 AS onhand, oi.unit, p.bin, oi.sellprice,
+ p.listprice, p.lastcost, p.rop, p.weight,
+ p.priceupdate, p.image, p.drawing, p.microfiche,
+ pg.partsgroup,
+ '' AS invnumber, o.ordnumber, oi.trans_id|;
+
+ $query .= qq|$union
+ SELECT $flds, 'oe' AS module, 'purchase_order' AS type,
+ (SELECT sell FROM exchangerate ex
+ WHERE ex.curr = o.curr
+ AND ex.transdate = o.transdate) AS exchangerate
+ FROM parts p
+ JOIN orderitems oi ON (oi.parts_id = p.id)
+ JOIN oe o ON (oi.trans_id = o.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE $ordwhere
+ AND o.vendor_id > 0|;
+ }
+
+ }
+
+ $query .= qq|
+ ORDER BY $sortorder|;
+
+ }
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{parts} }, $ref;
+ }
+
+ $sth->finish;
+
+
+ # include individual items for assemblies
+ if ($form->{searchitems} eq 'assembly' && $form->{bom}) {
+ foreach $item (@{ $form->{parts} }) {
+ push @assemblies, $item;
+ $query = qq|SELECT p.id, p.partnumber, p.description, a.qty AS onhand,
+ p.unit, p.bin,
+ p.sellprice, p.listprice, p.lastcost,
+ p.rop, p.weight, p.priceupdate,
+ p.image, p.drawing, p.microfiche
+ FROM parts p
+ JOIN assembly a ON (p.id = a.parts_id)
+ WHERE a.id = $item->{id}|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $ref->{assemblyitem} = 1;
+ push @assemblies, $ref;
+ }
+ $sth->finish;
+
+ push @assemblies, {id => $item->{id}};
+
+ }
+
+ # copy assemblies to $form->{parts}
+ @{ $form->{parts} } = @assemblies;
+
+ }
+
+ $dbh->disconnect;
+
+}
+
+
+sub create_links {
+ my ($self, $module, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT accno, description, link
+ FROM chart
+ WHERE link LIKE '%$module%'
+ ORDER BY accno|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ foreach my $key (split(/:/, $ref->{link})) {
+ if ($key =~ /$module/) {
+ push @{ $form->{"${module}_links"}{$key} }, { accno => $ref->{accno},
+ description => $ref->{description} };
+ }
+ }
+ }
+
+ $sth->finish;
+
+ if ($form->{id}) {
+ $query = qq|SELECT weightunit
+ FROM defaults|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{weightunit}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ } else {
+ $query = qq|SELECT weightunit, current_date
+ FROM defaults|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{weightunit}, $form->{priceupdate}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+
+ $dbh->disconnect;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/IR.pm b/sql-ledger/SL/IR.pm
new file mode 100644
index 0000000..357533e
--- /dev/null
+++ b/sql-ledger/SL/IR.pm
@@ -0,0 +1,995 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Inventory received module
+#
+#======================================================================
+
+package IR;
+
+
+sub post_invoice {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn off autocommit
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my ($query, $sth, $null, $project_id);
+ my $exchangerate = 0;
+
+ if ($form->{id}) {
+
+ &reverse_invoice($dbh, $form);
+
+ } else {
+ my $uid = time;
+ $uid .= $form->{login};
+
+ $query = qq|INSERT INTO ap (invnumber, employee_id)
+ VALUES ('$uid', (SELECT id FROM employee
+ WHERE login = '$form->{login}'))|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM ap
+ WHERE invnumber = '$uid'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{id}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+
+ map { $form->{$_} =~ s/'/''/g } qw(invnumber ordnumber);
+
+ my ($amount, $linetotal, $lastinventoryaccno, $lastexpenseaccno);
+ my ($netamount, $invoicediff, $expensediff) = (0, 0, 0);
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ $form->{exchangerate} = 1;
+ } else {
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'sell');
+ }
+
+ $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate});
+
+
+ for my $i (1 .. $form->{rowcount}) {
+ $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
+
+ if ($form->{"qty_$i"} != 0) {
+
+ map { $form->{"${_}_$i"} =~ s/'/''/g } qw(partnumber description unit);
+
+ my ($allocated, $taxrate) = (0, 0);
+ my $taxamount;
+
+ $form->{"sellprice_$i"} = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
+ my $fxsellprice = $form->{"sellprice_$i"};
+
+ my ($dec) = ($fxsellprice =~ /\.(\d+)/);
+ $dec = length $dec;
+ my $decimalplaces = ($dec > 2) ? $dec : 2;
+
+
+ map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{"taxaccounts_$i"};
+
+ if ($form->{"inventory_accno_$i"}) {
+
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
+
+ if ($form->{taxincluded}) {
+ $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
+ $form->{"sellprice_$i"} = $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
+ } else {
+ $taxamount = $linetotal * $taxrate;
+ }
+
+ $netamount += $linetotal;
+
+ if ($taxamount != 0) {
+ map { $form->{amount}{$form->{id}}{$_} -= $taxamount * $form->{"${_}_rate"} / $taxrate } split / /, $form->{"taxaccounts_$i"};
+ }
+
+ # add purchase to inventory, this one is without the tax!
+ $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate};
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2) * $form->{exchangerate};
+ $linetotal = $form->round_amount($linetotal, 2);
+
+ # this is the difference for the inventory
+ $invoicediff += ($amount - $linetotal);
+
+ $form->{amount}{$form->{id}}{$form->{"inventory_accno_$i"}} -= $linetotal;
+
+ # adjust and round sellprice
+ $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate}, $decimalplaces);
+
+
+ # update parts table
+ $query = qq|UPDATE parts SET
+ lastcost = $form->{"sellprice_$i"},
+ onhand = onhand + $form->{"qty_$i"}
+ WHERE id = $form->{"id_$i"}|;
+ $dbh->do($query) || $form->dberror($query);
+
+
+ # check if we sold the item already and
+ # make an entry for the expense and inventory
+ $query = qq|SELECT i.id, i.qty, i.allocated, i.trans_id,
+ p.inventory_accno_id, p.expense_accno_id, a.transdate
+ FROM invoice i, ar a, parts p
+ WHERE i.parts_id = p.id
+ AND i.parts_id = $form->{"id_$i"}
+ AND (i.qty + i.allocated) > 0
+ AND i.trans_id = a.id
+ ORDER BY transdate|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+
+ my $totalqty = $form->{"qty_$i"};
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+
+ my $qty = $ref->{qty} + $ref->{allocated};
+
+ if (($qty - $totalqty) > 0) {
+ $qty = $totalqty;
+ }
+
+
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} * $qty, 2);
+
+ if ($ref->{allocated} < 0) {
+ # we have an entry for it already, adjust amount
+ $form->update_balance($dbh,
+ "acc_trans",
+ "amount",
+ qq|trans_id = $ref->{trans_id} AND chart_id = $ref->{inventory_accno_id} AND transdate = '$ref->{transdate}'|,
+ $linetotal);
+
+ $form->update_balance($dbh,
+ "acc_trans",
+ "amount",
+ qq|trans_id = $ref->{trans_id} AND chart_id = $ref->{expense_accno_id} AND transdate = '$ref->{transdate}'|,
+ $linetotal * -1);
+
+ } else {
+ # add entry for inventory, this one is for the sold item
+ if ($linetotal != 0) {
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate)
+ VALUES ($ref->{trans_id}, $ref->{inventory_accno_id},
+ $linetotal, '$ref->{transdate}')|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # add expense
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate)
+ VALUES ($ref->{trans_id}, $ref->{expense_accno_id},
+ |. ($linetotal * -1) .qq|, '$ref->{transdate}')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+
+ # update allocated for sold item
+ $form->update_balance($dbh,
+ "invoice",
+ "allocated",
+ qq|id = $ref->{id}|,
+ $qty * -1);
+
+ $allocated += $qty;
+
+ last if (($totalqty -= $qty) <= 0);
+ }
+
+ $sth->finish;
+
+ $lastinventoryaccno = $form->{"inventory_accno_$i"};
+
+ } else {
+
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
+
+ if ($form->{taxincluded}) {
+ $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
+
+ $form->{"sellprice_$i"} = $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
+ } else {
+ $taxamount = $linetotal * $taxrate;
+ }
+
+ $netamount += $linetotal;
+
+ if ($taxamount != 0) {
+ map { $form->{amount}{$form->{id}}{$_} -= $taxamount * $form->{"${_}_rate"} / $taxrate } split / /, $form->{"taxaccounts_$i"};
+ }
+
+ $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate};
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2) * $form->{exchangerate};
+ $linetotal = $form->round_amount($linetotal, 2);
+
+ # this is the difference for expense
+ $expensediff += ($amount - $linetotal);
+
+ # add amount to expense
+ $form->{amount}{$form->{id}}{$form->{"expense_accno_$i"}} -= $linetotal;
+
+ $lastexpenseaccno = $form->{"expense_accno_$i"};
+
+ # adjust and round sellprice
+ $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate}, $decimalplaces);
+
+ # update lastcost
+ $query = qq|UPDATE parts SET
+ lastcost = $form->{"sellprice_$i"}
+ WHERE id = $form->{"id_$i"}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ }
+
+ $project_id = 'NULL';
+ if ($form->{"project_id_$i"}) {
+ $project_id = $form->{"project_id_$i"};
+ }
+ $deliverydate = ($form->{"deliverydate_$i"}) ? qq|'$form->{"deliverydate_$i"}'| : "NULL";
+
+ # save detail record in invoice table
+ $query = qq|INSERT INTO invoice (trans_id, parts_id, description, qty,
+ sellprice, fxsellprice, allocated, unit, deliverydate)
+ VALUES ($form->{id}, $form->{"id_$i"},
+ '$form->{"description_$i"}', |. ($form->{"qty_$i"} * -1) .qq|,
+ $form->{"sellprice_$i"}, $fxsellprice, $allocated,
+ '$form->{"unit_$i"}', $deliverydate)|;
+ $dbh->do($query) || $form->dberror($query);
+
+ }
+ }
+
+
+ $form->{datepaid} = $form->{invdate};
+
+ # all amounts are in natural state, netamount includes the taxes
+ # if tax is included, netamount is rounded to 2 decimal places,
+ # taxes are not
+
+ # total payments
+ for my $i (1 .. $form->{paidaccounts}) {
+ $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
+ $form->{paid} += $form->{"paid_$i"};
+ $form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"});
+ }
+
+ my ($tax, $paiddiff) = (0, 0);
+
+ $netamount = $form->round_amount($netamount, 2);
+
+ # figure out rounding errors for amount paid and total amount
+ if ($form->{taxincluded}) {
+
+ $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
+ $paiddiff = $amount - $netamount * $form->{exchangerate};
+ $netamount = $amount;
+
+ foreach my $item (split / /, $form->{taxaccounts}) {
+ $amount = $form->{amount}{$form->{id}}{$item} * $form->{exchangerate};
+ $form->{amount}{$form->{id}}{$item} = $form->round_amount($amount, 2);
+ $amount = $form->{amount}{$form->{id}}{$item} * -1;
+ $tax += $amount;
+ $netamount -= $amount;
+ }
+
+ $invoicediff += $paiddiff;
+ $expensediff += $paiddiff;
+
+ ######## this only applies to tax included
+ if ($lastinventoryaccno) {
+ $form->{amount}{$form->{id}}{$lastinventoryaccno} -= $invoicediff;
+ }
+ if ($lastexpenseaccno) {
+ $form->{amount}{$form->{id}}{$lastexpenseaccno} -= $expensediff;
+ }
+
+ } else {
+ $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
+ $paiddiff = $amount - $netamount * $form->{exchangerate};
+ $netamount = $amount;
+ foreach my $item (split / /, $form->{taxaccounts}) {
+ $form->{amount}{$form->{id}}{$item} = $form->round_amount($form->{amount}{$form->{id}}{$item}, 2);
+ $amount = $form->round_amount($form->{amount}{$form->{id}}{$item} * $form->{exchangerate} * -1, 2);
+ $paiddiff += $amount - $form->{amount}{$form->{id}}{$item} * $form->{exchangerate} * -1;
+ $form->{amount}{$form->{id}}{$item} = $form->round_amount($amount * -1, 2);
+ $amount = $form->{amount}{$form->{id}}{$item} * -1;
+ $tax += $amount;
+ }
+ }
+
+
+ $form->{amount}{$form->{id}}{$form->{AP}} = $netamount + $tax;
+
+ if ($form->{paid} != 0) {
+ $form->{paid} = $form->round_amount($form->{paid} * $form->{exchangerate} + $paiddiff, 2);
+ }
+
+
+ # update exchangerate
+ if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate}, 0, $form->{exchangerate});
+ }
+
+ # record acc_trans transactions
+ foreach my $trans_id (keys %{$form->{amount}}) {
+ foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
+ if (($form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2)) != 0) {
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate)
+ VALUES ($trans_id, (SELECT id FROM chart
+ WHERE accno = '$accno'),
+ $form->{amount}{$trans_id}{$accno}, '$form->{invdate}')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+ }
+
+ # deduct payment differences from paiddiff
+ for my $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"} != 0) {
+ $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2);
+ $paiddiff -= $amount - $form->{"paid_$i"} * $form->{exchangerate};
+ }
+ }
+
+ # force AP entry if 0
+ $form->{amount}{$form->{id}}{$form->{AP}} = $form->{paid} if ($form->{amount}{$form->{id}}{$form->{AP}} == 0);
+
+ # record payments and offsetting AP
+ for my $i (1 .. $form->{paidaccounts}) {
+
+ if ($form->{"paid_$i"} != 0) {
+ my ($accno) = split /--/, $form->{"AP_paid_$i"};
+ $form->{"datepaid_$i"} = $form->{invdate} unless ($form->{"datepaid_$i"});
+ $form->{datepaid} = $form->{"datepaid_$i"};
+
+ $amount = ($form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $paiddiff, 2)) * -1;
+
+ # record AP
+
+ if ($form->{amount}{$form->{id}}{$form->{AP}} != 0) {
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate)
+ VALUES ($form->{id}, (SELECT id FROM chart
+ WHERE accno = '$form->{AP}'),
+ $amount, '$form->{"datepaid_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ # record payment
+
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
+ source)
+ VALUES ($form->{id}, (SELECT id FROM chart
+ WHERE accno = '$accno'),
+ $form->{"paid_$i"}, '$form->{"datepaid_$i"}',
+ '$form->{"source_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+
+
+ $exchangerate = 0;
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ $form->{"exchangerate_$i"} = 1;
+ } else {
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'sell');
+
+ $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
+ }
+
+
+ # exchangerate difference
+ $form->{fx}{$accno}{$form->{"datepaid_$i"}} += $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $paiddiff;
+
+
+ # gain/loss
+ $amount = ($form->{"paid_$i"} * $form->{exchangerate}) - ($form->{"paid_$i"} * $form->{"exchangerate_$i"});
+ if ($amount > 0) {
+ $form->{fx}{$form->{fxgain_accno}}{$form->{"datepaid_$i"}} += $amount;
+ } else {
+ $form->{fx}{$form->{fxloss_accno}}{$form->{"datepaid_$i"}} += $amount;
+ }
+
+ $paiddiff = 0;
+
+ # update exchange rate
+ if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{"datepaid_$i"}, 0, $form->{"exchangerate_$i"});
+ }
+ }
+ }
+
+ # record exchange rate differences and gains/losses
+ foreach my $accno (keys %{$form->{fx}}) {
+ foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
+ if (($form->{fx}{$accno}{$transdate} = $form->round_amount($form->{fx}{$accno}{$transdate}, 2)) != 0) {
+
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate, cleared, fx_transaction)
+ VALUES ($form->{id}, (SELECT id FROM chart
+ WHERE accno = '$accno'),
+ $form->{fx}{$accno}{$transdate}, '$transdate', '0', '1')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+ }
+
+
+ $amount = $netamount + $tax;
+
+ # set values which could be empty
+ $form->{taxincluded} *= 1;
+ my $datepaid = ($form->{paid}) ? qq|'$form->{datepaid}'| : "NULL";
+ my $duedate = ($form->{duedate}) ? qq|'$form->{duedate}'| : "NULL";
+
+ # save AP record
+ $query = qq|UPDATE ap set
+ invnumber = '$form->{invnumber}',
+ ordnumber = '$form->{ordnumber}',
+ transdate = '$form->{invdate}',
+ vendor_id = $form->{vendor_id},
+ amount = $amount,
+ netamount = $netamount,
+ paid = $form->{paid},
+ datepaid = $datepaid,
+ duedate = $duedate,
+ invoice = '1',
+ taxincluded = '$form->{taxincluded}',
+ notes = '$form->{notes}',
+ curr = '$form->{currency}'
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # add shipto
+ $form->{name} = $form->{vendor};
+ $form->{name} =~ s/--$form->{vendor_id}//;
+ $form->add_shipto($dbh, $form->{id});
+
+ # delete zero entries
+ $query = qq|DELETE FROM acc_trans
+ WHERE amount = 0|;
+ $dbh->do($query) || $form->dberror($query);
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+ $rc;
+
+}
+
+
+
+sub reverse_invoice {
+ my ($dbh, $form) = @_;
+
+ # reverse inventory items
+ my $query = qq|SELECT i.parts_id, p.inventory_accno_id, p.expense_accno_id,
+ i.qty, i.allocated, i.sellprice
+ FROM invoice i, parts p
+ WHERE i.parts_id = p.id
+ AND i.trans_id = $form->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $netamount = 0;
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $netamount += $form->round_amount($ref->{sellprice} * $ref->{qty} * -1, 2);
+
+ if ($ref->{inventory_accno_id}) {
+ # update onhand
+ $form->update_balance($dbh,
+ "parts",
+ "onhand",
+ qq|id = $ref->{parts_id}|,
+ $ref->{qty});
+
+ # if $ref->{allocated} > 0 than we sold that many items
+ if ($ref->{allocated} > 0) {
+
+ # get references for sold items
+ $query = qq|SELECT i.id, i.trans_id, i.allocated, a.transdate
+ FROM invoice i, ar a
+ WHERE i.parts_id = $ref->{parts_id}
+ AND i.allocated < 0
+ AND i.trans_id = a.id
+ ORDER BY transdate DESC|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $pthref = $sth->fetchrow_hashref(NAME_lc)) {
+ my $qty = $ref->{allocated};
+ if (($ref->{allocated} + $pthref->{allocated}) > 0) {
+ $qty = $pthref->{allocated} * -1;
+ }
+
+ my $amount = $form->round_amount($ref->{sellprice} * $qty, 2);
+
+ #adjust allocated
+ $form->update_balance($dbh,
+ "invoice",
+ "allocated",
+ qq|id = $pthref->{id}|,
+ $qty);
+
+ $form->update_balance($dbh,
+ "acc_trans",
+ "amount",
+ qq|trans_id = $pthref->{trans_id} AND chart_id = $ref->{expense_accno_id} AND transdate = '$pthref->{transdate}'|,
+ $amount);
+
+ $form->update_balance($dbh,
+ "acc_trans",
+ "amount",
+ qq|trans_id = $pthref->{trans_id} AND chart_id = $ref->{inventory_accno_id} AND transdate = '$pthref->{transdate}'|,
+ $amount * -1);
+
+ last if (($ref->{allocated} -= $qty) <= 0);
+ }
+ $sth->finish;
+ }
+ }
+ }
+ $sth->finish;
+
+ # delete acc_trans
+ $query = qq|DELETE FROM acc_trans
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # delete invoice entries
+ $query = qq|DELETE FROM invoice
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+}
+
+
+
+sub delete_invoice {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # check for other foreign currency transactions
+ $form->delete_exchangerate($dbh) if ($form->{currency} ne $form->{defaultcurrency});
+
+ &reverse_invoice($dbh, $form);
+
+ # delete zero entries
+ my $query = qq|DELETE FROM acc_trans
+ WHERE amount = 0|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # delete AP record
+ my $query = qq|DELETE FROM ap
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub retrieve_invoice {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my $query;
+
+ if ($form->{id}) {
+ # get default accounts and last invoice number
+ $query = qq|SELECT (SELECT c.accno FROM chart c
+ WHERE d.inventory_accno_id = c.id) AS inventory_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.income_accno_id = c.id) AS income_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.expense_accno_id = c.id) AS expense_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
+ d.curr AS currencies
+ FROM defaults d|;
+ } else {
+ $query = qq|SELECT (SELECT c.accno FROM chart c
+ WHERE d.inventory_accno_id = c.id) AS inventory_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.income_accno_id = c.id) AS income_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.expense_accno_id = c.id) AS expense_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
+ d.ponumber AS invnumber, d.curr AS currencies,
+ current_date AS invdate
+ FROM defaults d|;
+ }
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+
+ if ($form->{id}) {
+
+ # retrieve invoice
+ $query = qq|SELECT a.invnumber, a.transdate AS invdate, a.duedate,
+ a.ordnumber, a.paid, a.taxincluded, a.notes, a.curr AS currency
+ FROM ap a
+ WHERE id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "sell");
+
+ # get shipto
+ $query = qq|SELECT * FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ # retrieve individual items
+ $query = qq|SELECT c1.accno AS inventory_accno,
+ c2.accno AS income_accno,
+ c3.accno AS expense_accno,
+ p.partnumber, i.description, i.qty, i.fxsellprice AS sellprice,
+ i.parts_id AS id, i.unit, p.bin, i.deliverydate,
+ pr.projectnumber,
+ i.project_id,
+ pg.partsgroup
+ FROM invoice i
+ JOIN parts p ON (i.parts_id = p.id)
+ LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
+ LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
+ LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
+ LEFT JOIN project pr ON (i.project_id = pr.id)
+ LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
+ WHERE trans_id = $form->{id}
+ ORDER BY i.id|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+
+ # get tax rates for part
+ $query = qq|SELECT c.accno
+ FROM chart c, partstax pt
+ WHERE pt.chart_id = c.id
+ AND pt.parts_id = $ref->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref->{taxaccounts} = "";
+ my $taxrate = 0;
+
+ while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) {
+ $ref->{taxaccounts} .= "$ptref->{accno} ";
+ $taxrate += $form->{"$ptref->{accno}_rate"};
+ }
+
+ $sth->finish;
+ chop $ref->{taxaccounts};
+
+ $ref->{qty} *= -1;
+
+ push @{ $form->{invoice_details} }, $ref;
+
+ }
+
+ $sth->finish;
+
+ } else {
+
+ # up invoice number by 1
+ $form->{invnumber}++;
+
+ # save the new number
+ $query = qq|UPDATE defaults
+ SET ponumber = '$form->{invnumber}'|;
+ $dbh->do($query) || $form->dberror($query);
+
+ }
+
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub get_vendor {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $dateformat = $myconfig->{dateformat};
+ $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;
+
+ my $duedate = ($form->{invdate}) ? "to_date('$form->{invdate}', '$dateformat')" : "current_date";
+
+ $form->{vendor_id} *= 1;
+ # get vendor
+ my $query = qq|SELECT taxincluded, terms, email, cc, bcc,
+ addr1, addr2, addr3, addr4,
+ $duedate + terms AS duedate
+ FROM vendor
+ WHERE id = $form->{vendor_id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ # get shipto if we do not convert an order or invoice
+ if (!$form->{shipto}) {
+ map { delete $form->{$_} } qw(shiptoname shiptoaddr1 shiptoaddr2 shiptoaddr3 shiptoaddr4 shiptocontact shiptophone shiptofax shiptoemail);
+
+ $query = qq|SELECT * FROM shipto
+ WHERE trans_id = $form->{vendor_id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+ }
+
+ # get taxes for vendor
+ $query = qq|SELECT c.accno
+ FROM chart c, vendortax v
+ WHERE v.chart_id = c.id
+ AND v.vendor_id = $form->{vendor_id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $vendortax = ();
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $vendortax{$ref->{accno}} = 1;
+ }
+ $sth->finish;
+
+
+ # get tax rates and description
+ $query = qq|SELECT c.accno, c.description, c.link, t.rate
+ FROM chart c, tax t
+ WHERE c.id = t.chart_id
+ AND c.link LIKE '%CT_tax%'
+ ORDER BY accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $form->{taxaccounts} = "";
+ $form->{taxpart} = "";
+ $form->{taxservice} = "";
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ if ($vendortax{$ref->{accno}}) {
+ $form->{"$ref->{accno}_rate"} = $ref->{rate};
+ $form->{"$ref->{accno}_description"} = $ref->{description};
+ $form->{taxaccounts} .= "$ref->{accno} ";
+ }
+
+ foreach my $item (split /:/, $ref->{link}) {
+ if ($item =~ /IC_taxpart/) {
+ $form->{taxpart} .= "$ref->{accno} ";
+ }
+
+ if ($item =~ /IC_taxservice/) {
+ $form->{taxservice} .= "$ref->{accno} ";
+ }
+ }
+ }
+ $sth->finish;
+ chop $form->{taxaccounts};
+ chop $form->{taxpart};
+ chop $form->{taxservice};
+
+ if (!$form->{id} && $form->{type} !~ /_order/) {
+ # setup last accounts used
+ $query = qq|SELECT c.accno, c.description, c.link, c.category
+ FROM chart c
+ JOIN acc_trans ac ON (ac.chart_id = c.id)
+ JOIN ap a ON (a.id = ac.trans_id)
+ WHERE a.vendor_id = $form->{vendor_id}
+ AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%')
+ AND a.id IN (SELECT max(id) FROM ap
+ WHERE vendor_id = $form->{vendor_id})|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $i = 0;
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ if ($ref->{category} eq 'E') {
+ $i++;
+ $form->{"AP_amount_$i"} = "$ref->{accno}--$ref->{description}";
+ }
+ if ($ref->{category} eq 'L') {
+ $form->{AP} = $form->{AP_1} = "$ref->{accno}--$ref->{description}";
+ }
+ }
+ $sth->finish;
+ $form->{rowcount} = $i if ($i && !$form->{type});
+ }
+
+ $dbh->disconnect;
+
+}
+
+
+sub retrieve_item {
+ my ($self, $myconfig, $form) = @_;
+
+ my $i = $form->{rowcount};
+ my $var;
+
+ # don't include assemblies or obsolete parts
+ my $where = "NOT p.assembly = '1' AND NOT p.obsolete = '1'";
+
+ if ($form->{"partnumber_$i"}) {
+ $var = $form->like(lc $form->{"partnumber_$i"});
+ $where .= " AND lower(p.partnumber) LIKE '$var'";
+ }
+
+ if ($form->{"description_$i"}) {
+ $var = $form->like(lc $form->{"description_$i"});
+ $where .= " AND lower(p.description) LIKE '$var'";
+ }
+
+ if ($form->{"partsgroup_$i"}) {
+ $var = $form->like(lc $form->{"partsgroup_$i"});
+ $where .= " AND lower(pg.partsgroup) LIKE '$var'";
+ }
+
+ if ($form->{"description_$i"}) {
+ $where .= " ORDER BY description";
+ } else {
+ $where .= " ORDER BY partnumber";
+ }
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT p.id, p.partnumber, p.description,
+ c1.accno AS inventory_accno,
+ c2.accno AS income_accno,
+ c3.accno AS expense_accno,
+ pg.partsgroup
+ FROM parts p
+ LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
+ LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
+ LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
+ LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
+ WHERE $where|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ # get tax rates for part
+ $query = qq|SELECT c.accno
+ FROM chart c
+ JOIN partstax pt ON (pt.chart_id = c.id)
+ WHERE pt.parts_id = $ref->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref->{taxaccounts} = "";
+ while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) {
+ $ref->{taxaccounts} .= "$ptref->{accno} ";
+ }
+ $sth->finish;
+ chop $ref->{taxaccounts};
+
+ push @{ $form->{item_list} }, $ref;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+
+sub vendor_details {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # get rest for the vendor
+ my $query = qq|SELECT vendornumber, name, addr1, addr2, addr3, addr4,
+ contact, phone as vendorphone, fax as vendorfax, vendornumber
+ FROM vendor
+ WHERE id = $form->{vendor_id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub item_links {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT accno, description, link
+ FROM chart
+ WHERE link LIKE '%IC%'
+ ORDER BY accno|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ foreach my $key (split(/:/, $ref->{link})) {
+ if ($key =~ /IC/) {
+ push @{ $form->{IC_links}{$key} }, { accno => $ref->{accno},
+ description => $ref->{description} };
+ }
+ }
+ }
+
+ $sth->finish;
+}
+
+1;
+
diff --git a/sql-ledger/SL/IS.pm b/sql-ledger/SL/IS.pm
new file mode 100644
index 0000000..dc11e36
--- /dev/null
+++ b/sql-ledger/SL/IS.pm
@@ -0,0 +1,1231 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Inventory invoicing module
+#
+#======================================================================
+
+package IS;
+
+
+sub invoice_details {
+ my ($self, $myconfig, $form) = @_;
+
+ $form->{duedate} = $form->{invdate} unless ($form->{duedate});
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT date '$form->{duedate}' - date '$form->{invdate}'
+ AS terms
+ FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{terms}) = $sth->fetchrow_array;
+ $sth->finish;
+
+ my $tax = 0;
+ my $item;
+ my $i;
+ my @partsgroup = ();
+ my $partsgroup;
+ my %oid = ( 'Pg' => 'oid',
+ 'Oracle' => 'rowid' );
+
+ # sort items by partsgroup
+ for $i (1 .. $form->{rowcount}) {
+ $partsgroup = "";
+ if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
+ $form->format_string("partsgroup_$i");
+ $partsgroup = $form->{"partsgroup_$i"};
+ }
+ push @partsgroup, [ $i, $partsgroup ];
+ }
+
+ my $sameitem = "";
+ foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
+ $i = $item->[0];
+
+ if ($item->[1] ne $sameitem) {
+ push(@{ $form->{description} }, qq|$item->[1]|);
+ $sameitem = $item->[1];
+
+ map { push(@{ $form->{$_} }, "") } qw(runningnumber number bin qty unit deliverydate sellprice listprice netprice discount linetotal);
+ }
+
+ $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
+
+ if ($form->{"qty_$i"} != 0) {
+
+ # add number, description and qty to $form->{number}, ....
+ push(@{ $form->{runningnumber} }, $i);
+ push(@{ $form->{number} }, qq|$form->{"partnumber_$i"}|);
+ push(@{ $form->{bin} }, qq|$form->{"bin_$i"}|);
+ push(@{ $form->{description} }, qq|$form->{"description_$i"}|);
+ push(@{ $form->{qty} }, $form->format_amount($myconfig, $form->{"qty_$i"}));
+ push(@{ $form->{unit} }, qq|$form->{"unit_$i"}|);
+ push(@{ $form->{deliverydate} }, qq|$form->{"deliverydate_$i"}|);
+
+ push(@{ $form->{sellprice} }, $form->{"sellprice_$i"});
+
+ # listprice
+ push(@{ $form->{listprice} }, $form->{"listprice_$i"});
+
+ my $sellprice = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
+ my ($dec) = ($sellprice =~ /\.(\d+)/);
+ $dec = length $dec;
+ my $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ my $discount = $form->round_amount($sellprice * $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100, $decimalplaces);
+
+ # keep a netprice as well, (sellprice - discount)
+ $form->{"netprice_$i"} = $sellprice - $discount;
+ push(@{ $form->{netprice} }, ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : " ");
+
+
+ my $linetotal = $form->round_amount($form->{"qty_$i"} * $form->{"netprice_$i"}, 2);
+
+ $discount = ($discount != 0) ? $form->format_amount($myconfig, $discount * -1, $decimalplaces) : " ";
+ $linetotal = ($linetotal != 0) ? $linetotal : " ";
+
+ push(@{ $form->{discount} }, $discount);
+
+ $form->{total} += $linetotal;
+
+ push(@{ $form->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2));
+
+ my $taxrate = 0;
+ my ($taxamount, $taxbase);
+
+ map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{"taxaccounts_$i"};
+
+ if ($form->{taxincluded}) {
+ # calculate tax
+ $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
+ $taxbase = $linetotal - $taxamount;
+ } else {
+ $taxamount = $linetotal * $taxrate;
+ $taxbase = $linetotal;
+ }
+
+ if ($taxamount != 0) {
+ foreach my $item (split / /, $form->{"taxaccounts_$i"}) {
+ $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate;
+ $taxbase{$item} += $taxbase;
+ }
+ }
+
+ if ($form->{"assembly_$i"}) {
+ $sameitem = "";
+
+ # get parts and push them onto the stack
+ my $sortorder = "";
+ if ($form->{groupitems}) {
+ $sortorder = qq|ORDER BY pg.partsgroup, a.$oid{$myconfig->{dbdriver}}|;
+ } else {
+ $sortorder = qq|ORDER BY a.$oid{$myconfig->{dbdriver}}|;
+ }
+
+ $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty,
+ pg.partsgroup
+ FROM assembly a
+ JOIN parts p ON (a.parts_id = p.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE a.bom = '1'
+ AND a.id = '$form->{"id_$i"}'
+ $sortorder|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
+ map { push(@{ $form->{$_} }, "") } qw(runningnumber number unit qty bin sellprice listprice netprice discount linetotal);
+ $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
+ push(@{ $form->{description} }, $sameitem);
+ }
+
+ push(@{ $form->{number} }, qq|$ref->{partnumber}|);
+ push(@{ $form->{description} }, qq|$ref->{description}|);
+ push(@{ $form->{unit} }, qq|$ref->{unit}|);
+ push(@{ $form->{qty} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}));
+
+ map { push(@{ $form->{$_} }, "") } qw(runningnumber bin sellprice listprice netprice discount linetotal);
+
+ }
+ $sth->finish;
+ }
+
+ }
+ }
+
+
+ foreach my $item (sort keys %taxaccounts) {
+ if ($form->round_amount($taxaccounts{$item}, 2) != 0) {
+ push(@{ $form->{taxbase} }, $form->format_amount($myconfig, $taxbase{$item}, 2));
+
+ $tax += $taxamount = $form->round_amount($taxaccounts{$item}, 2);
+
+ push(@{ $form->{tax} }, $form->format_amount($myconfig, $taxamount));
+ push(@{ $form->{taxdescription} }, $form->{"${item}_description"});
+ push(@{ $form->{taxrate} }, $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
+ push(@{ $form->{taxnumber} }, $form->{"${item}_taxnumber"});
+ }
+ }
+
+
+ for my $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"}) {
+ push(@{ $form->{payment} }, $form->{"paid_$i"});
+ my ($accno, $description) = split /--/, $form->{"AR_paid_$i"};
+ push(@{ $form->{paymentaccount} }, $description);
+ push(@{ $form->{paymentdate} }, $form->{"datepaid_$i"});
+ push(@{ $form->{paymentsource} }, $form->{"source_$i"});
+
+ $form->{paid} += $form->parse_amount($myconfig, $form->{"paid_$i"});
+ }
+ }
+
+ $form->{subtotal} = $form->format_amount($myconfig, $form->{total}, 2);
+ $form->{invtotal} = ($form->{taxincluded}) ? $form->{total} : $form->{total} + $tax;
+ $form->{total} = $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2);
+ $form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2);
+
+ $form->{paid} = $form->format_amount($myconfig, $form->{paid}, 2);
+
+ # myconfig variables
+ map { $form->{$_} = $myconfig->{$_} } (qw(company address tel fax signature businessnumber));
+ $form->{username} = $myconfig->{name};
+
+ $dbh->disconnect;
+
+}
+
+
+sub project_description {
+ my ($self, $dbh, $id) = @_;
+
+ my $query = qq|SELECT description
+ FROM project
+ WHERE id = $id|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($_) = $sth->fetchrow_array;
+
+ $sth->finish;
+
+ $_;
+
+}
+
+
+sub customer_details {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # get rest for the customer
+ my $query = qq|SELECT customernumber, name, addr1, addr2, addr3, addr4,
+ phone as customerphone, fax as customerfax, contact
+ FROM customer
+ WHERE id = $form->{customer_id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub post_invoice {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn off autocommit
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my ($query, $sth, $null, $project_id, $deliverydate);
+ my $exchangerate = 0;
+
+ if ($form->{id}) {
+
+ &reverse_invoice($dbh, $form);
+
+ } else {
+ my $uid = time;
+ $uid .= $form->{login};
+
+ $query = qq|INSERT INTO ar (invnumber, employee_id)
+ VALUES ('$uid', (SELECT id FROM employee
+ WHERE login = '$form->{login}') )|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM ar
+ WHERE invnumber = '$uid'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{id}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+
+
+ map { $form->{$_} =~ s/'/''/g } (qw(invnumber shippingpoint notes message));
+
+ my ($netamount, $invoicediff) = (0, 0);
+ my ($amount, $linetotal, $lastincomeaccno);
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ $form->{exchangerate} = 1;
+ } else {
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'buy');
+ }
+
+ $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate});
+
+
+ foreach my $i (1 .. $form->{rowcount}) {
+ $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
+
+ if ($form->{"qty_$i"} != 0) {
+
+ map { $form->{"${_}_$i"} =~ s/'/''/g } (qw(partnumber description unit));
+
+ # undo discount formatting
+ $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
+
+ my ($allocated, $taxrate) = (0, 0);
+ my $taxamount;
+
+ # keep entered selling price
+ my $fxsellprice = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
+
+ my ($dec) = ($fxsellprice =~ /\.(\d+)/);
+ $dec = length $dec;
+ my $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ # deduct discount
+ my $discount = $form->round_amount($fxsellprice * $form->{"discount_$i"}, $decimalplaces);
+ $form->{"sellprice_$i"} = $fxsellprice - $discount;
+
+ # add tax rates
+ map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{"taxaccounts_$i"};
+
+ # round linetotal to 2 decimal places
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
+
+ if ($form->{taxincluded}) {
+ $taxamount = $linetotal * ($taxrate / (1 + $taxrate));
+ $form->{"sellprice_$i"} = $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
+ } else {
+ $taxamount = $linetotal * $taxrate;
+ }
+
+ $netamount += $linetotal;
+
+ if ($taxamount != 0) {
+ map { $form->{amount}{$form->{id}}{$_} += $taxamount * $form->{"${_}_rate"} / $taxrate } split / /, $form->{"taxaccounts_$i"};
+ }
+
+
+ # add amount to income, $form->{amount}{trans_id}{accno}
+ $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * $form->{exchangerate};
+
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2) * $form->{exchangerate};
+ $linetotal = $form->round_amount($linetotal, 2);
+
+ # this is the difference from the inventory
+ $invoicediff += ($amount - $linetotal);
+
+ $form->{amount}{$form->{id}}{$form->{"income_accno_$i"}} += $linetotal;
+
+ $lastincomeaccno = $form->{"income_accno_$i"};
+
+
+ # adjust and round sellprice
+ $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} * $form->{exchangerate}, $decimalplaces);
+
+ if ($form->{"inventory_accno_$i"} || $form->{"assembly_$i"}) {
+ # adjust parts onhand quantity
+
+ if ($form->{"assembly_$i"}) {
+ # do not update if assembly consists of all services
+ $query = qq|SELECT sum(p.inventory_accno_id)
+ FROM parts p, assembly a
+ WHERE a.parts_id = p.id
+ AND a.id = $form->{"id_$i"}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ if ($sth->fetchrow_array) {
+ $form->update_balance($dbh,
+ "parts",
+ "onhand",
+ qq|id = $form->{"id_$i"}|,
+ $form->{"qty_$i"} * -1);
+ }
+ $sth->finish;
+
+ # record assembly item as allocated
+ &process_assembly($dbh, $form, $form->{"id_$i"}, $form->{"qty_$i"});
+ } else {
+ $form->update_balance($dbh,
+ "parts",
+ "onhand",
+ qq|id = $form->{"id_$i"}|,
+ $form->{"qty_$i"} * -1);
+
+ $allocated = &cogs($dbh, $form, $form->{"id_$i"}, $form->{"qty_$i"});
+ }
+ }
+
+ $project_id = 'NULL';
+ if ($form->{"project_id_$i"}) {
+ $project_id = $form->{"project_id_$i"};
+ }
+ $deliverydate = ($form->{"deliverydate_$i"}) ? qq|'$form->{"deliverydate_$i"}'| : "NULL";
+
+ # save detail record in invoice table
+ $query = qq|INSERT INTO invoice (trans_id, parts_id, description, qty,
+ sellprice, fxsellprice, discount, allocated, assemblyitem,
+ unit, deliverydate, project_id)
+ VALUES ($form->{id}, $form->{"id_$i"},
+ '$form->{"description_$i"}', $form->{"qty_$i"},
+ $form->{"sellprice_$i"}, $fxsellprice,
+ $form->{"discount_$i"}, $allocated, 'f',
+ '$form->{"unit_$i"}', $deliverydate, $project_id)|;
+ $dbh->do($query) || $form->dberror($query);
+
+ }
+ }
+
+
+ $form->{datepaid} = $form->{invdate};
+
+ # total payments, don't move we need it here
+ for my $i (1 .. $form->{paidaccounts}) {
+ $form->{"paid_$i"} = $form->parse_amount($myconfig, $form->{"paid_$i"});
+ $form->{paid} += $form->{"paid_$i"};
+ $form->{datepaid} = $form->{"datepaid_$i"} if ($form->{"datepaid_$i"});
+ }
+
+ my ($tax, $diff) = (0, 0);
+
+ $netamount = $form->round_amount($netamount, 2);
+
+ # figure out rounding errors for total amount vs netamount + taxes
+ if ($form->{taxincluded}) {
+
+ $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
+ $diff += $amount - $netamount * $form->{exchangerate};
+ $netamount = $amount;
+
+ foreach my $item (split / /, $form->{taxaccounts}) {
+ $amount = $form->{amount}{$form->{id}}{$item} * $form->{exchangerate};
+ $form->{amount}{$form->{id}}{$item} = $form->round_amount($amount, 2);
+ $tax += $form->{amount}{$form->{id}}{$item};
+ $netamount -= $form->{amount}{$form->{id}}{$item};
+ }
+
+ $invoicediff += $diff;
+ ######## this only applies to tax included
+ if ($lastincomeaccno) {
+ $form->{amount}{$form->{id}}{$lastincomeaccno} += $invoicediff;
+ }
+
+ } else {
+ $amount = $form->round_amount($netamount * $form->{exchangerate}, 2);
+ $diff = $amount - $netamount * $form->{exchangerate};
+ $netamount = $amount;
+ foreach my $item (split / /, $form->{taxaccounts}) {
+ $form->{amount}{$form->{id}}{$item} = $form->round_amount($form->{amount}{$form->{id}}{$item}, 2);
+ $amount = $form->round_amount($form->{amount}{$form->{id}}{$item} * $form->{exchangerate}, 2);
+ $diff += $amount - $form->{amount}{$form->{id}}{$item} * $form->{exchangerate};
+ $form->{amount}{$form->{id}}{$item} = $form->round_amount($amount, 2);
+ $tax += $form->{amount}{$form->{id}}{$item};
+ }
+ }
+
+
+ $form->{amount}{$form->{id}}{$form->{AR}} = $netamount + $tax;
+
+ if ($form->{paid} != 0) {
+ $form->{paid} = $form->round_amount($form->{paid} * $form->{exchangerate} + $diff, 2);
+ }
+
+ # reverse AR
+ $form->{amount}{$form->{id}}{$form->{AR}} *= -1;
+
+
+ # update exchangerate
+ if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{invdate}, $form->{exchangerate}, 0);
+ }
+
+ foreach my $trans_id (keys %{$form->{amount}}) {
+ foreach my $accno (keys %{ $form->{amount}{$trans_id} }) {
+ if (($form->{amount}{$trans_id}{$accno} = $form->round_amount($form->{amount}{$trans_id}{$accno}, 2)) != 0) {
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate)
+ VALUES ($trans_id, (SELECT id FROM chart
+ WHERE accno = '$accno'),
+ $form->{amount}{$trans_id}{$accno}, '$form->{invdate}')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+ }
+
+ # deduct payment differences from diff
+ for my $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"} != 0) {
+ $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate}, 2);
+ $diff -= $amount - $form->{"paid_$i"} * $form->{exchangerate};
+ }
+ }
+
+ # force AR entry if 0
+ $form->{amount}{$form->{id}}{$form->{AR}} = 1 if ($form->{amount}{$form->{id}}{$form->{AR}} == 0);
+
+ # record payments and offsetting AR
+ for my $i (1 .. $form->{paidaccounts}) {
+
+ if ($form->{"paid_$i"} != 0) {
+ my ($accno) = split /--/, $form->{"AR_paid_$i"};
+ $form->{"datepaid_$i"} = $form->{invdate} unless ($form->{"datepaid_$i"});
+ $form->{datepaid} = $form->{"datepaid_$i"};
+
+ # record AR
+ $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} + $diff, 2);
+
+ if ($form->{amount}{$form->{id}}{$form->{AR}} != 0) {
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate)
+ VALUES ($form->{id}, (SELECT id FROM chart
+ WHERE accno = '$form->{AR}'),
+ $amount, '$form->{"datepaid_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+
+ # record payment
+ $form->{"paid_$i"} *= -1;
+
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
+ source)
+ VALUES ($form->{id}, (SELECT id FROM chart
+ WHERE accno = '$accno'),
+ $form->{"paid_$i"}, '$form->{"datepaid_$i"}',
+ '$form->{"source_$i"}')|;
+ $dbh->do($query) || $form->dberror($query);
+
+
+ $exchangerate = 0;
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ $form->{"exchangerate_$i"} = 1;
+ } else {
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy');
+
+ $form->{"exchangerate_$i"} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{"exchangerate_$i"});
+ }
+
+
+ # exchangerate difference
+ $form->{fx}{$accno}{$form->{"datepaid_$i"}} += $form->{"paid_$i"} * ($form->{"exchangerate_$i"} - 1) + $diff;
+
+
+ # gain/loss
+ $amount = $form->{"paid_$i"} * $form->{exchangerate} - $form->{"paid_$i"} * $form->{"exchangerate_$i"};
+ if ($amount > 0) {
+ $form->{fx}{$form->{fxgain_accno}}{$form->{"datepaid_$i"}} += $amount;
+ } else {
+ $form->{fx}{$form->{fxloss_accno}}{$form->{"datepaid_$i"}} += $amount;
+ }
+
+ $diff = 0;
+
+ # update exchange rate
+ if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{"datepaid_$i"}, $form->{"exchangerate_$i"}, 0);
+ }
+ }
+ }
+
+
+ # record exchange rate differences and gains/losses
+ foreach my $accno (keys %{$form->{fx}}) {
+ foreach my $transdate (keys %{ $form->{fx}{$accno} }) {
+ if (($form->{fx}{$accno}{$transdate} = $form->round_amount($form->{fx}{$accno}{$transdate}, 2)) != 0) {
+
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount,
+ transdate, cleared, fx_transaction)
+ VALUES ($form->{id},
+ (SELECT id FROM chart
+ WHERE accno = '$accno'),
+ $form->{fx}{$accno}{$transdate}, '$transdate', '0', '1')|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+ }
+
+
+ $amount = $netamount + $tax;
+
+ # set values which could be empty to 0
+ $form->{terms} *= 1;
+ $form->{taxincluded} *= 1;
+ my $datepaid = ($form->{paid}) ? qq|'$form->{datepaid}'| : "NULL";
+ my $duedate = ($form->{duedate}) ? qq|'$form->{duedate}'| : "NULL";
+
+ # fill in subject if there is none
+ $form->{subject} = qq|$form->{label} $form->{invnumber}| unless $form->{subject};
+ # if there is a message stuff it into the notes
+ my $cc = "Cc: $form->{cc}\\r\n" if $form->{cc};
+ my $bcc = "Bcc: $form->{bcc}\\r\n" if $form->{bcc};
+ $form->{notes} .= qq|\r
+\r
+[email]\r
+To: $form->{email}\r
+$cc${bcc}Subject: $form->{subject}\r
+\r
+Message: $form->{message}\r| if $form->{message};
+
+ # save AR record
+ $query = qq|UPDATE ar set
+ invnumber = '$form->{invnumber}',
+ ordnumber = '$form->{ordnumber}',
+ transdate = '$form->{invdate}',
+ customer_id = $form->{customer_id},
+ amount = $amount,
+ netamount = $netamount,
+ paid = $form->{paid},
+ datepaid = $datepaid,
+ duedate = $duedate,
+ invoice = '1',
+ shippingpoint = '$form->{shippingpoint}',
+ terms = $form->{terms},
+ notes = '$form->{notes}',
+ taxincluded = '$form->{taxincluded}',
+ curr = '$form->{currency}'
+ WHERE id = $form->{id}
+ |;
+ $dbh->do($query) || $form->dberror($query);
+
+ # add shipto
+ $form->{name} = $form->{customer};
+ $form->{name} =~ s/--$form->{customer_id}//;
+ $form->add_shipto($dbh, $form->{id});
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+sub process_assembly {
+ my ($dbh, $form, $id, $totalqty) = @_;
+
+ my $query = qq|SELECT a.parts_id, a.qty, p.assembly,
+ p.partnumber, p.description, p.unit,
+ p.inventory_accno_id, p.income_accno_id,
+ p.expense_accno_id
+ FROM assembly a, parts p
+ WHERE a.parts_id = p.id
+ AND a.id = $id|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+
+ my $allocated = 0;
+
+ $ref->{inventory_accno_id} *= 1;
+ $ref->{expense_accno_id} *= 1;
+
+ map { $ref->{$_} =~ s/'/''/g } (qw(partnumber description unit));
+
+ # multiply by number of assemblies
+ $ref->{qty} *= $totalqty;
+
+ if ($ref->{assembly}) {
+ &process_assembly($dbh, $form, $ref->{parts_id}, $ref->{qty});
+ next;
+ } else {
+ if ($ref->{inventory_accno_id}) {
+ $allocated = &cogs($dbh, $form, $ref->{parts_id}, $ref->{qty});
+ }
+ }
+
+ # save detail record for individual assembly item in invoice table
+ $query = qq|INSERT INTO invoice (trans_id, description, parts_id, qty,
+ sellprice, fxsellprice, allocated, assemblyitem, unit)
+ VALUES
+ ($form->{id}, '$ref->{description}',
+ $ref->{parts_id}, $ref->{qty}, 0, 0, $allocated, 't',
+ '$ref->{unit}')|;
+ $dbh->do($query) || $form->dberror($query);
+
+ }
+
+ $sth->finish;
+
+}
+
+
+sub cogs {
+ my ($dbh, $form, $id, $totalqty) = @_;
+
+ my $query = qq|SELECT i.id, i.trans_id, i.qty, i.allocated, i.sellprice,
+ (SELECT c.accno FROM chart c
+ WHERE p.inventory_accno_id = c.id)
+ AS inventory_accno,
+ (SELECT c.accno FROM chart c
+ WHERE p.expense_accno_id = c.id)
+ AS expense_accno
+ FROM invoice i, parts p
+ WHERE i.parts_id = p.id
+ AND i.parts_id = $id
+ AND (i.qty + i.allocated) < 0
+ ORDER BY trans_id|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $allocated = 0;
+ my $qty;
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ if (($qty = (($ref->{qty} * -1) - $ref->{allocated})) > $totalqty) {
+ $qty = $totalqty;
+ }
+
+ $form->update_balance($dbh,
+ "invoice",
+ "allocated",
+ qq|id = $ref->{id}|,
+ $qty);
+
+ # total expenses and inventory
+ # sellprice is the cost of the item
+ $linetotal = $form->round_amount($ref->{sellprice} * $qty, 2);
+
+ # add to expense
+ $form->{amount}{$form->{id}}{$ref->{expense_accno}} += -$linetotal;
+
+ # deduct inventory
+ $form->{amount}{$form->{id}}{$ref->{inventory_accno}} -= -$linetotal;
+
+ # add allocated
+ $allocated += -$qty;
+
+ last if (($totalqty -= $qty) <= 0);
+ }
+
+ $sth->finish;
+
+ $allocated;
+
+}
+
+
+
+sub reverse_invoice {
+ my ($dbh, $form) = @_;
+
+ # reverse inventory items
+ my $query = qq|SELECT i.id, i.parts_id, i.qty, i.assemblyitem, p.assembly,
+ p.inventory_accno_id
+ FROM invoice i, parts p
+ WHERE i.parts_id = p.id
+ AND i.trans_id = $form->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+
+ if ($ref->{inventory_accno_id} || $ref->{assembly}) {
+
+ # if the invoice item is not an assemblyitem adjust parts onhand
+ unless ($ref->{assemblyitem}) {
+ # adjust onhand in parts table
+ $form->update_balance($dbh,
+ "parts",
+ "onhand",
+ qq|id = $ref->{parts_id}|,
+ $ref->{qty});
+ }
+
+ # loop if it is an assembly
+ next if ($ref->{assembly});
+
+ # de-allocated purchases
+ $query = qq|SELECT id, trans_id, allocated
+ FROM invoice
+ WHERE parts_id = $ref->{parts_id}
+ AND allocated > 0
+ ORDER BY trans_id DESC|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $inhref = $sth->fetchrow_hashref(NAME_lc)) {
+ $qty = $ref->{qty};
+ if (($ref->{qty} - $inhref->{allocated}) > 0) {
+ $qty = $inhref->{allocated};
+ }
+
+ # update invoice
+ $form->update_balance($dbh,
+ "invoice",
+ "allocated",
+ qq|id = $inhref->{id}|,
+ $qty * -1);
+
+ last if (($ref->{qty} -= $qty) <= 0);
+ }
+ $sth->finish;
+ }
+ }
+
+ $sth->finish;
+
+ # delete acc_trans
+ $query = qq|DELETE FROM acc_trans
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # delete invoice entries
+ $query = qq|DELETE FROM invoice
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+}
+
+
+
+sub delete_invoice {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ # check for other foreign currency transactions
+ $form->delete_exchangerate($dbh) if ($form->{currency} ne $form->{defaultcurrency});
+
+ &reverse_invoice($dbh, $form);
+
+ # delete AR record
+ my $query = qq|DELETE FROM ar
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub retrieve_invoice {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my $query;
+
+ if ($form->{id}) {
+ # get default accounts and last invoice number
+ $query = qq|SELECT (SELECT c.accno FROM chart c
+ WHERE d.inventory_accno_id = c.id) AS inventory_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.income_accno_id = c.id) AS income_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.expense_accno_id = c.id) AS expense_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
+ d.curr AS currencies
+ FROM defaults d|;
+ } else {
+ $query = qq|SELECT (SELECT c.accno FROM chart c
+ WHERE d.inventory_accno_id = c.id) AS inventory_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.income_accno_id = c.id) AS income_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.expense_accno_id = c.id) AS expense_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
+ d.invnumber, d.curr AS currencies, current_date AS invdate
+ FROM defaults d|;
+ }
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+
+ if ($form->{id}) {
+
+ # retrieve invoice
+ $query = qq|SELECT a.invnumber, a.ordnumber, a.transdate AS invdate, a.paid,
+ a.shippingpoint, a.terms, a.notes, a.duedate, a.taxincluded,
+ a.curr AS currency, (SELECT e.name FROM employee e
+ WHERE e.id = a.employee_id) AS employee
+ FROM ar a
+ WHERE a.id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "buy");
+
+ # get shipto
+ $query = qq|SELECT * FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ # retrieve individual items
+ $query = qq|SELECT c1.accno AS inventory_accno,
+ c2.accno AS income_accno,
+ c3.accno AS expense_accno,
+ i.description, i.qty, i.fxsellprice AS sellprice,
+ i.discount, i.parts_id AS id, i.unit, i.deliverydate,
+ pr.projectnumber,
+ i.project_id,
+ p.partnumber, p.assembly, p.bin,
+ pg.partsgroup
+ FROM invoice i
+ JOIN parts p ON (i.parts_id = p.id)
+ LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
+ LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
+ LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
+ LEFT JOIN project pr ON (i.project_id = pr.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE i.trans_id = $form->{id}
+ AND NOT i.assemblyitem = '1'
+ ORDER BY i.id|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ # get taxes
+ $query = qq|SELECT c.accno
+ FROM chart c, partstax pt
+ WHERE pt.chart_id = c.id
+ AND pt.parts_id = $ref->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref->{taxaccounts} = "";
+ my $taxrate = 0;
+
+ while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) {
+ $ref->{taxaccounts} .= "$ptref->{accno} ";
+ $taxrate += $form->{"$ptref->{accno}_rate"};
+ }
+ $sth->finish;
+ chop $ref->{taxaccounts};
+
+ push @{ $form->{invoice_details} }, $ref;
+ }
+ $sth->finish;
+
+ } else {
+
+ $form->{shippingpoint} = $myconfig->{shippingpoint} unless $form->{shippingpoint};
+
+ # up invoice number by 1
+ $form->{invnumber}++;
+
+ # save the new number
+ $query = qq|UPDATE defaults
+ SET invnumber = '$form->{invnumber}'|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $form->get_employee($dbh);
+
+ }
+
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+sub get_customer {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $dateformat = $myconfig->{dateformat};
+ $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;
+
+ my $duedate = ($form->{invdate}) ? "to_date('$form->{invdate}', '$dateformat')" : "current_date";
+
+ $form->{customer_id} *= 1;
+ # get customer
+ my $query = qq|SELECT c.name AS customer, c.discount, c.creditlimit, c.terms,
+ c.email, c.cc, c.bcc, c.taxincluded,
+ c.addr1, c.addr2, c.addr3, c.addr4,
+ $duedate + c.terms AS duedate
+ FROM customer c
+ WHERE c.id = $form->{customer_id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ $form->{creditremaining} = $form->{creditlimit};
+ $query = qq|SELECT SUM(amount - paid)
+ FROM ar
+ WHERE customer_id = $form->{customer_id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{creditremaining}) -= $sth->fetchrow_array;
+
+ $sth->finish;
+
+ $query = qq|SELECT o.amount,
+ (SELECT e.buy FROM exchangerate e
+ WHERE e.curr = o.curr
+ AND e.transdate = o.transdate)
+ FROM oe o
+ WHERE o.customer_id = $form->{customer_id}
+ AND o.closed = '0'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my ($amount, $exch) = $sth->fetchrow_array) {
+ $exch = 1 unless $exch;
+ $form->{creditremaining} -= $amount * $exch;
+ }
+ $sth->finish;
+
+
+ # get shipto if we did not converted an order or invoice
+ if (!$form->{shipto}) {
+ map { delete $form->{$_} } qw(shiptoname shiptoaddr1 shiptoaddr2 shiptoaddr3 shiptoaddr4 shiptocontact shiptophone shiptofax shiptoemail);
+
+ $query = qq|SELECT * FROM shipto
+ WHERE trans_id = $form->{customer_id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+ }
+
+ # get taxes we charge for this customer
+ $query = qq|SELECT c.accno
+ FROM chart c, customertax ct
+ WHERE ct.chart_id = c.id
+ AND ct.customer_id = $form->{customer_id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $customertax = ();
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $customertax{$ref->{accno}} = 1;
+ }
+ $sth->finish;
+
+ # get tax rates and description
+ $query = qq|SELECT c.accno, c.description, t.rate, t.taxnumber
+ FROM chart c, tax t
+ WHERE c.id = t.chart_id
+ AND c.link LIKE '%CT_tax%'
+ ORDER BY accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $form->{taxaccounts} = "";
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ if ($customertax{$ref->{accno}}) {
+ $form->{"$ref->{accno}_rate"} = $ref->{rate};
+ $form->{"$ref->{accno}_description"} = $ref->{description};
+ $form->{"$ref->{accno}_taxnumber"} = $ref->{taxnumber};
+ $form->{taxaccounts} .= "$ref->{accno} ";
+ }
+ }
+ $sth->finish;
+ chop $form->{taxaccounts};
+
+ # setup last accounts used for this customer
+ if (!$form->{id} && $form->{type} !~ /_order/) {
+ $query = qq|SELECT c.accno, c.description, c.link, c.category
+ FROM chart c
+ JOIN acc_trans ac ON (ac.chart_id = c.id)
+ JOIN ar a ON (a.id = ac.trans_id)
+ WHERE a.customer_id = $form->{customer_id}
+ AND NOT (c.link LIKE '%_tax%' OR c.link LIKE '%_paid%')
+ AND a.id IN (SELECT max(id) FROM ar
+ WHERE customer_id = $form->{customer_id})|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $i = 0;
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ if ($ref->{category} eq 'I') {
+ $i++;
+ $form->{"AR_amount_$i"} = "$ref->{accno}--$ref->{description}";
+ }
+ if ($ref->{category} eq 'A') {
+ $form->{AR} = $form->{AR_1} = "$ref->{accno}--$ref->{description}";
+ }
+ }
+ $sth->finish;
+ $form->{rowcount} = $i if ($i && !$form->{type});
+ }
+
+ $dbh->disconnect;
+
+}
+
+
+
+sub retrieve_item {
+ my ($self, $myconfig, $form) = @_;
+
+ my $i = $form->{rowcount};
+ my $var;
+ my $where = "NOT obsolete = '1'";
+
+ if ($form->{"partnumber_$i"}) {
+ $var = $form->like(lc $form->{"partnumber_$i"});
+ $where .= " AND lower(p.partnumber) LIKE '$var'";
+ }
+ if ($form->{"description_$i"}) {
+ $var = $form->like(lc $form->{"description_$i"});
+ $where .= " AND lower(p.description) LIKE '$var'";
+ }
+
+ if ($form->{"partsgroup_$i"}) {
+ $var = $form->like(lc $form->{"partsgroup_$i"});
+ $where .= " AND lower(pg.partsgroup) LIKE '$var'";
+ }
+
+ if ($form->{"description_$i"}) {
+ $where .= " ORDER BY description";
+ } else {
+ $where .= " ORDER BY partnumber";
+ }
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT p.id, p.partnumber, p.description, p.sellprice,
+ p.listprice,
+ c1.accno AS inventory_accno,
+ c2.accno AS income_accno,
+ c3.accno AS expense_accno,
+ p.unit, p.assembly, p.bin, p.onhand, p.makemodel,
+ pg.partsgroup
+ FROM parts p
+ LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
+ LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
+ LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
+ LEFT JOIN partsgroup pg ON (pg.id = p.partsgroup_id)
+ WHERE $where|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+
+ # get taxes for part
+ $query = qq|SELECT c.accno
+ FROM chart c
+ JOIN partstax pt ON (c.id = pt.chart_id)
+ WHERE pt.parts_id = $ref->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref->{taxaccounts} = "";
+ while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) {
+ $ref->{taxaccounts} .= "$ptref->{accno} ";
+ }
+ $sth->finish;
+ chop $ref->{taxaccounts};
+
+ # get makemodel
+ if ($ref->{makemodel}) {
+ $query = qq|SELECT name
+ FROM makemodel
+ WHERE parts_id = $ref->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref->{makemodel} = "";
+ while (my $ptref = $sth->fetchrow_hashref(NAME_lc)) {
+ $ref->{makemodel} .= "$ptref->{name}:";
+ }
+ $sth->finish;
+ chop $ref->{makemodel};
+ }
+
+ push @{ $form->{item_list} }, $ref;
+
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/Inifile.pm b/sql-ledger/SL/Inifile.pm
new file mode 100644
index 0000000..e9de47a
--- /dev/null
+++ b/sql-ledger/SL/Inifile.pm
@@ -0,0 +1,87 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#=====================================================================
+#
+# routines to retrieve / manipulate win ini style files
+# ORDER is used to keep the elements in the order they appear in .ini
+#
+#=====================================================================
+
+package Inifile;
+
+
+sub new {
+ my ($type, $file, $level) = @_;
+
+ my $id = "";
+ my $skip;
+
+ $type = ref($self) || $self;
+
+ open FH, "$file" or Form->error("$file : $!");
+
+ while (<FH>) {
+ next if /^(#|;|\s)/;
+ last if /^\./;
+
+ chop;
+
+ # strip comments
+ s/\s*(#|;).*//g;
+
+ # remove any trailing whitespace
+ s/^\s*(.*?)\s*$/$1/;
+
+ if (/^\[/) {
+ s/(\[|\])//g;
+
+ $id = $_;
+
+ # if there is a level skip
+ if ($skip = ($id !~ /^$level/)) {
+ next;
+ }
+
+ push @{$self->{ORDER}}, $_;
+
+ next;
+
+ }
+
+ if (!$skip) {
+ # add key=value to $id
+ my ($key, $value) = split /=/, $_, 2;
+
+ $self->{$id}{$key} = $value;
+ }
+
+ }
+ close FH;
+
+ bless $self, $type;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/Mailer.pm b/sql-ledger/SL/Mailer.pm
new file mode 100644
index 0000000..934ad36
--- /dev/null
+++ b/sql-ledger/SL/Mailer.pm
@@ -0,0 +1,147 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+
+package Mailer;
+
+sub new {
+ my ($type) = @_;
+ my $self = {};
+
+ bless $self, $type;
+}
+
+
+sub send {
+ my ($self, $out) = @_;
+
+ my $boundary = time;
+ $boundary = "SL-$self->{version}-$boundary";
+ my $domain = $self->{from};
+ $domain =~ s/(.*?\@|>)//g;
+ my $msgid = "$boundary\@$domain";
+
+ $self->{charset} = "ISO-8859-1" unless $self->{charset};
+
+ if ($out) {
+ open(OUT, $out) or return "$out : $!";
+ } else {
+ open(OUT, ">-") or return "STDOUT : $!";
+ }
+
+ $self->{contenttype} = "text/plain" unless $self->{contenttype};
+
+ my ($cc, $bcc);
+ $cc = "Cc: $self->{cc}\n" if $self->{cc};
+ $bcc = "Bcc: $self->{bcc}\n" if $self->{bcc};
+
+ print OUT qq|From: $self->{from}
+To: $self->{to}
+${cc}${bcc}Subject: $self->{subject}
+Message-ID: <$msgid>
+X-Mailer: SQL-Ledger $self->{version}
+MIME-Version: 1.0
+|;
+
+
+ if ($self->{attachments}) {
+ print OUT qq|Content-Type: multipart/mixed; boundary="$boundary"
+
+--${boundary}
+Content-Type: $self->{contenttype}; charset="$self->{charset}"
+
+$self->{message}
+
+|;
+
+ foreach my $attachment (@{ $self->{attachments} }) {
+
+ my $application = ($attachment =~ /(^\w+$)|\.(html|text|txt|sql)$/) ? "text" : "application";
+
+ open(IN, $attachment);
+ if ($?) {
+ close(OUT);
+ return "$attachment : $!";
+ }
+
+ my $filename = $attachment;
+ # strip path
+ $filename =~ s/(.*\/|$self->{fileid})//g;
+
+ print OUT qq|--${boundary}
+Content-Type: $application/$self->{format}; name="$filename"; charset="$self->{charset}"
+Content-Transfer-Encoding: BASE64
+Content-Disposition: attachment; filename="$filename"\n\n|;
+
+ my $msg = "";
+ while (<IN>) {;
+ $msg .= $_;
+ }
+ print OUT &encode_base64($msg);
+
+ close(IN);
+
+ }
+ print OUT qq|--${boundary}--\n|;
+
+ } else {
+ print OUT qq|Content-Type: $self->{contenttype}; charset="$self->{charset}"
+
+$self->{message}
+|;
+ }
+
+ close(OUT);
+
+ return "";
+
+}
+
+
+sub encode_base64 ($;$) {
+
+ # this code is from the MIME-Base64-2.12 package
+ # Copyright 1995-1999,2001 Gisle Aas <gisle@ActiveState.com>
+
+ my $res = "";
+ my $eol = $_[1];
+ $eol = "\n" unless defined $eol;
+ pos($_[0]) = 0; # ensure start at the beginning
+
+ $res = join '', map( pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs));
+
+ $res =~ tr|` -_|AA-Za-z0-9+/|; # `# help emacs
+ # fix padding at the end
+ my $padding = (3 - length($_[0]) % 3) % 3;
+ $res =~ s/.{$padding}$/'=' x $padding/e if $padding;
+ # break encoded string into lines of no more than 60 characters each
+ if (length $eol) {
+ $res =~ s/(.{1,60})/$1$eol/g;
+ }
+ return $res;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/Menu.pm b/sql-ledger/SL/Menu.pm
new file mode 100644
index 0000000..661d354
--- /dev/null
+++ b/sql-ledger/SL/Menu.pm
@@ -0,0 +1,117 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#=====================================================================
+#
+# routines for menu items
+#
+#=====================================================================
+
+package Menu;
+
+
+sub new {
+ my ($type, $menufile, $level) = @_;
+
+ use SL::Inifile;
+ my $self = Inifile->new($menufile, $level);
+
+ bless $self, $type;
+
+}
+
+
+sub menuitem {
+ my ($self, $myconfig, $form, $item) = @_;
+
+ my $module = $form->{script};
+ my $action = "section_menu";
+ my $target = "";
+
+ if ($self->{$item}{module}) {
+ $module = $self->{$item}{module};
+ }
+ if ($self->{$item}{action}) {
+ $action = $self->{$item}{action};
+ }
+ if ($self->{$item}{target}) {
+ $target = $self->{$item}{target};
+ }
+
+ my $level = $form->escape($item);
+ my $str = qq|<a href=$module?path=$form->{path}&action=$action&level=$level&login=$form->{login}&password=$form->{password}|;
+ my @vars = qw(module action target href);
+
+ if ($self->{$item}{href}) {
+ $str = qq|<a href=$self->{$item}{href}|;
+ @vars = qw(module target href);
+ }
+
+ map { delete $self->{$item}{$_} } @vars;
+
+
+ # add other params
+ foreach my $key (keys %{ $self->{$item} }) {
+ $str .= "&".$form->escape($key,1)."=";
+ ($value, $conf) = split /=/, $self->{$item}{$key}, 2;
+ $value = $myconfig->{$value}."/$conf" if ($conf);
+ $str .= $form->escape($value, 1);
+ }
+
+ if ($target) {
+ $str .= qq| target=$target|;
+ }
+
+ $str .= ">";
+
+}
+
+
+sub access_control {
+ my ($self, $myconfig, $menulevel) = @_;
+
+ my @menu = ();
+
+ if ($menulevel eq "") {
+ @menu = grep { !/--/ } @{ $self->{ORDER} };
+ } else {
+ @menu = grep { /^${menulevel}--/ } @{ $self->{ORDER} };
+ }
+
+ my @a = split /;/, $myconfig->{acs};
+ my $excl = ();
+
+ # remove --AR, --AP from array
+ grep { ($a, $b) = split /--/; s/--$a$//; } @a;
+
+ map { $excl{$_} = 1 } @a;
+
+ @a = ();
+ map { push @a, $_ unless $excl{$_} } (@menu);
+
+ @a;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/Num2text.pm b/sql-ledger/SL/Num2text.pm
new file mode 100644
index 0000000..f09121c
--- /dev/null
+++ b/sql-ledger/SL/Num2text.pm
@@ -0,0 +1,162 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#=====================================================================
+#
+# this is the default code for the Check package
+#
+#=====================================================================
+
+
+sub init {
+ my $self = shift;
+
+ %{ $self->{numbername} } =
+ (0 => 'Zero',
+ 1 => 'One',
+ 2 => 'Two',
+ 3 => 'Three',
+ 4 => 'Four',
+ 5 => 'Five',
+ 6 => 'Six',
+ 7 => 'Seven',
+ 8 => 'Eight',
+ 9 => 'Nine',
+ 10 => 'Ten',
+ 11 => 'Eleven',
+ 12 => 'Twelve',
+ 13 => 'Thirteen',
+ 14 => 'Fourteen',
+ 15 => 'Fifteen',
+ 16 => 'Sixteen',
+ 17 => 'Seventeen',
+ 18 => 'Eighteen',
+ 19 => 'Nineteen',
+ 20 => 'Twenty',
+ 30 => 'Thirty',
+ 40 => 'Forty',
+ 50 => 'Fifty',
+ 60 => 'Sixty',
+ 70 => 'Seventy',
+ 80 => 'Eighty',
+ 90 => 'Ninety',
+ 10**2 => 'Hundred',
+ 10**3 => 'Thousand',
+ 10**6 => 'Million',
+ 10**9 => 'Billion',
+ 10**12 => 'Trillion',
+ );
+
+}
+
+
+sub num2text {
+ my ($self, $amount) = @_;
+
+ return $self->{numbername}{0} unless $amount;
+
+ my @textnumber = ();
+
+ # split amount into chunks of 3
+ my @num = reverse split //, $amount;
+ my @numblock = ();
+ my @a;
+ my $i;
+
+ while (@num) {
+ @a = ();
+ for (1 .. 3) {
+ push @a, shift @num;
+ }
+ push @numblock, join / /, reverse @a;
+ }
+
+ while (@numblock) {
+
+ $i = $#numblock;
+ @num = split //, $numblock[$i];
+
+ if ($numblock[$i] == 0) {
+ pop @numblock;
+ next;
+ }
+
+ if ($numblock[$i] > 99) {
+ # the one from hundreds
+ push @textnumber, $self->{numbername}{$num[0]};
+
+ # add hundred designation
+ push @textnumber, $self->{numbername}{10**2};
+
+ # reduce numblock
+ $numblock[$i] -= $num[0] * 100;
+
+ }
+
+ $numblock[$i] *= 1;
+
+ if ($numblock[$i] > 9) {
+ # tens
+ push @textnumber, $self->format_ten($numblock[$i]);
+ } elsif ($numblock[$i] > 0) {
+ # ones
+ push @textnumber, $self->{numbername}{$numblock[$i]};
+ }
+
+ # add thousand, million
+ if ($i) {
+ $num = 10**($i * 3);
+ push @textnumber, $self->{numbername}{$num};
+ }
+
+ pop @numblock;
+
+ }
+
+ join ' ', @textnumber;
+
+}
+
+
+sub format_ten {
+ my ($self, $amount) = @_;
+
+ my $textnumber = "";
+ my @num = split //, $amount;
+
+ if ($amount > 20) {
+ $textnumber = $self->{numbername}{$num[0]*10};
+ $amount = $num[1];
+ } else {
+ $textnumber = $self->{numbername}{$amount};
+ $amount = 0;
+ }
+
+ $textnumber .= " ".$self->{numbername}{$amount} if $amount;
+
+ $textnumber;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/OE.pm b/sql-ledger/SL/OE.pm
new file mode 100644
index 0000000..a742ca7
--- /dev/null
+++ b/sql-ledger/SL/OE.pm
@@ -0,0 +1,674 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Order entry module
+#
+#======================================================================
+
+package OE;
+
+
+sub transactions {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query;
+
+ my $rate = ($form->{vc} eq 'customer') ? 'buy' : 'sell';
+
+ my $query = qq|SELECT o.id, o.ordnumber, o.transdate, o.reqdate,
+ o.amount, ct.name, o.netamount, o.$form->{vc}_id,
+ (SELECT $rate FROM exchangerate ex
+ WHERE ex.curr = o.curr
+ AND ex.transdate = o.transdate) AS exchangerate,
+ o.closed
+ FROM oe o, $form->{vc} ct
+ WHERE o.$form->{vc}_id = ct.id|;
+
+ my $ordnumber = $form->like(lc $form->{ordnumber});
+
+ if ($form->{"$form->{vc}_id"}) {
+ $query .= qq| AND o.$form->{vc}_id = $form->{"$form->{vc}_id"}|;
+ } else {
+ if ($form->{$form->{vc}}) {
+ my $name = $form->like(lc $form->{$form->{vc}});
+ $query .= " AND lower(name) LIKE '$name'";
+ }
+ }
+ unless ($form->{open} && $form->{closed}) {
+ $query .= ($form->{open}) ? " AND o.closed = '0'" : " AND o.closed = '1'";
+ }
+
+ my $sortorder = join ', ', $form->sort_columns(qw(transdate ordnumber name));
+ $sortorder = $form->{sort} unless $sortorder;
+
+ $query .= " AND lower(ordnumber) LIKE '$ordnumber'" if $form->{ordnumber};
+ $query .= " AND transdate >= '$form->{transdatefrom}'" if $form->{transdatefrom};
+ $query .= " AND transdate <= '$form->{transdateto}'" if $form->{transdateto};
+ $query .= " ORDER by $sortorder";
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $oe = $sth->fetchrow_hashref(NAME_lc)) {
+ $oe->{exchangerate} = 1 unless $oe->{exchangerate};
+ push @{ $form->{OE} }, $oe;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub save_order {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn off autocommit
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my ($query, $sth);
+ my $exchangerate = 0;
+
+ if ($form->{id}) {
+
+ $query = qq|DELETE FROM orderitems
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ } else {
+ my $uid = time;
+ $uid .= $form->{login};
+
+ $query = qq|INSERT INTO oe (ordnumber, employee_id)
+ VALUES ('$uid', (SELECT id FROM employee
+ WHERE login = '$form->{login}') )|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|SELECT id FROM oe
+ WHERE ordnumber = '$uid'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{id}) = $sth->fetchrow_array;
+ $sth->finish;
+ }
+
+ map { $form->{$_} =~ s/'/''/g } qw(ordnumber shippingpoint notes message);
+
+ my ($amount, $linetotal, $discount, $project_id, $reqdate);
+ my ($taxrate, $taxamount, $fxsellprice);
+ my %taxbase = ();
+ my %taxaccounts = ();
+ my ($netamount, $tax) = (0, 0);
+
+ for my $i (1 .. $form->{rowcount}) {
+
+ $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
+
+ if ($form->{"qty_$i"} != 0) {
+
+ map { $form->{"${_}_$i"} =~ s/'/''/g } qw(partnumber description unit);
+
+ # set values to 0 if nothing entered
+ $form->{"discount_$i"} = $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100;
+
+ $form->{"sellprice_$i"} = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
+ $fxsellprice = $form->{"sellprice_$i"};
+
+ my ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
+ $dec = length $dec;
+ my $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ $discount = $form->round_amount($form->{"sellprice_$i"} * $form->{"discount_$i"}, $decimalplaces);
+ $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"} - $discount, $decimalplaces);
+
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
+ $taxrate = 0;
+ map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{"taxaccounts_$i"};
+
+ if ($form->{taxincluded}) {
+ $taxamount = $linetotal * $taxrate / (1 + $taxrate);
+ $taxbase = $linetotal - $taxamount;
+ # we are not keeping a natural price, do not round
+ $form->{"sellprice_$i"} = $form->{"sellprice_$i"} * (1 / (1 + $taxrate));
+ } else {
+ $taxamount = $linetotal * $taxrate;
+ $taxbase = $linetotal;
+ }
+
+ if ($taxamount != 0) {
+ foreach my $item (split / /, $form->{"taxaccounts_$i"}) {
+ $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate;
+ $taxbase{$item} += $taxbase;
+ }
+ }
+
+ $netamount += $form->{"sellprice_$i"} * $form->{"qty_$i"};
+
+ $project_id = 'NULL';
+ if ($form->{"project_id_$i"}) {
+ $project_id = $form->{"project_id_$i"};
+ }
+ $reqdate = ($form->{"reqdate_$i"}) ? qq|'$form->{"reqdate_$i"}'| : "NULL";
+
+ # save detail record in orderitems table
+ $query = qq|INSERT INTO orderitems
+ (trans_id, parts_id, description, qty, sellprice, discount,
+ unit, reqdate, project_id) VALUES (
+ $form->{id}, $form->{"id_$i"}, '$form->{"description_$i"}',
+ $form->{"qty_$i"}, $fxsellprice, $form->{"discount_$i"},
+ '$form->{"unit_$i"}', $reqdate, $project_id)|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $form->{"sellprice_$i"} = $fxsellprice;
+ $form->{"discount_$i"} *= 100;
+ }
+ }
+
+
+ # set values which could be empty
+ map { $form->{$_} *= 1 } qw(vendor_id customer_id taxincluded closed);
+
+ $reqdate = ($form->{reqdate}) ? qq|'$form->{reqdate}'| : "NULL";
+
+ # add up the tax
+ foreach my $item (sort keys %taxaccounts) {
+ $taxamount = $form->round_amount($taxaccounts{$item}, 2);
+ $tax += $taxamount;
+ }
+
+ $amount = $form->round_amount($netamount + $tax, 2);
+ $netamount = $form->round_amount($netamount, 2);
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ $form->{exchangerate} = 1;
+ } else {
+ $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, ($form->{vc} eq 'customer') ? 'buy' : 'sell');
+ }
+
+ $form->{exchangerate} = ($exchangerate) ? $exchangerate : $form->parse_amount($myconfig, $form->{exchangerate});
+
+ # fill in subject if there is none
+ $form->{subject} = qq|$form->{label} $form->{ordnumber}| unless $form->{subject};
+ # if there is a message stuff it into the notes
+ my $cc = "Cc: $form->{cc}\\r\n" if $form->{cc};
+ my $bcc = "Bcc: $form->{bcc}\\r\n" if $form->{bcc};
+ $form->{notes} .= qq|\r
+\r
+[email]\r
+To: $form->{email}\r
+$cc${bcc}Subject: $form->{subject}\r
+\r
+Message: $form->{message}\r| if $form->{message};
+
+ # save OE record
+ $query = qq|UPDATE oe set
+ ordnumber = '$form->{ordnumber}',
+ transdate = '$form->{orddate}',
+ vendor_id = $form->{vendor_id},
+ customer_id = $form->{customer_id},
+ amount = $amount,
+ netamount = $netamount,
+ reqdate = $reqdate,
+ taxincluded = '$form->{taxincluded}',
+ shippingpoint = '$form->{shippingpoint}',
+ notes = '$form->{notes}',
+ curr = '$form->{currency}',
+ closed = '$form->{closed}'
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $form->{ordtotal} = $amount;
+
+ # add shipto
+ $form->{name} = $form->{$form->{vc}};
+ $form->{name} =~ s/--$form->{"$form->{vc}_id"}//;
+ $form->add_shipto($dbh, $form->{id});
+
+ if (($form->{currency} ne $form->{defaultcurrency}) && !$exchangerate) {
+ if ($form->{vc} eq 'customer') {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{orddate}, $form->{exchangerate}, 0);
+ }
+ if ($form->{vc} eq 'vendor') {
+ $form->update_exchangerate($dbh, $form->{currency}, $form->{orddate}, 0, $form->{exchangerate});
+ }
+ }
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub delete_order {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my $query;
+
+ # can't use $form->delete_exchangerate
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ $query = qq|SELECT transdate FROM acc_trans
+ WHERE ar.id = trans_id
+ AND ar.curr = '$form->{currency}'
+ AND transdate = '$form->{orddate}'
+ UNION SELECT transdate FROM acc_trans
+ WHERE ap.id = trans_id
+ AND ap.curr = '$form->{currency}'
+ AND transdate = '$form->{orddate}'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my ($transdate) = $sth->fetchrow_array;
+ $sth->finish;
+
+ if (!$transdate) {
+ $query = qq|DELETE FROM exchangerate
+ WHERE curr = '$form->{currency}'
+ AND transdate = '$form->{orddate}'|;
+ $dbh->do($query) || $self->dberror($query);
+ }
+ }
+
+
+ # delete OE record
+ $query = qq|DELETE FROM oe
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # delete individual entries
+ $query = qq|DELETE FROM orderitems
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $query = qq|DELETE FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub retrieve_order {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my $query;
+
+ if ($form->{id}) {
+ # get default accounts and last order number
+ $query = qq|SELECT (SELECT c.accno FROM chart c
+ WHERE d.inventory_accno_id = c.id) AS inventory_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.income_accno_id = c.id) AS income_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.expense_accno_id = c.id) AS expense_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
+ d.curr AS currencies
+ FROM defaults d|;
+ } else {
+ my $ordnumber = ($form->{vc} eq 'customer') ? 'sonumber' : 'ponumber';
+ $query = qq|SELECT (SELECT c.accno FROM chart c
+ WHERE d.inventory_accno_id = c.id) AS inventory_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.income_accno_id = c.id) AS income_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.expense_accno_id = c.id) AS expense_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
+ (SELECT c.accno FROM chart c
+ WHERE d.fxloss_accno_id = c.id) AS fxloss_accno,
+ $ordnumber AS ordnumber, d.curr AS currencies,
+ current_date AS orddate, current_date AS reqdate
+ FROM defaults d|;
+ }
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ ($form->{currency}) = split /:/, $form->{currencies};
+
+ if ($form->{id}) {
+
+ # retrieve order
+ $query = qq|SELECT o.ordnumber, o.transdate AS orddate, o.reqdate,
+ o.taxincluded, o.shippingpoint, o.notes, o.curr AS currency,
+ (SELECT name FROM employee e
+ WHERE e.id = o.employee_id) AS employee,
+ o.$form->{vc}_id, cv.name AS $form->{vc}, o.amount AS invtotal,
+ o.closed, o.reqdate
+ FROM oe o, $form->{vc} cv
+ WHERE o.$form->{vc}_id = cv.id
+ AND o.id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+
+ $query = qq|SELECT * FROM shipto
+ WHERE trans_id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $ref = $sth->fetchrow_hashref(NAME_lc);
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+ $sth->finish;
+
+ my %oid = ( 'Pg' => 'oid',
+ 'Oracle' => 'rowid',
+ 'DB2' => '' );
+
+ # retrieve individual items
+ $query = qq|SELECT c1.accno AS inventory_accno,
+ c2.accno AS income_accno,
+ c3.accno AS expense_accno,
+ p.partnumber, p.assembly, o.description, o.qty,
+ o.sellprice, o.parts_id AS id, o.unit, o.discount, p.bin,
+ o.reqdate, o.project_id,
+ pr.projectnumber,
+ pg.partsgroup
+ FROM orderitems o
+ JOIN parts p ON (o.parts_id = p.id)
+ LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
+ LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
+ LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
+ LEFT JOIN project pr ON (o.project_id = pr.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE trans_id = $form->{id}
+ ORDER BY o.$oid{$myconfig->{dbdriver}}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+
+ # get tax rates for part
+ $query = qq|SELECT c.accno
+ FROM chart c, partstax pt
+ WHERE pt.chart_id = c.id
+ AND pt.parts_id = $ref->{id}|;
+ my $pth = $dbh->prepare($query);
+ $pth->execute || $form->dberror($query);
+
+ $ref->{taxaccounts} = "";
+ my $taxrate = 0;
+
+ while (my $ptref = $pth->fetchrow_hashref(NAME_lc)) {
+ $ref->{taxaccounts} .= "$ptref->{accno} ";
+ $taxrate += $form->{"$ptref->{accno}_rate"};
+ }
+ $pth->finish;
+ chop $ref->{taxaccounts};
+
+ push @{ $form->{order_details} }, $ref;
+
+ }
+ $sth->finish;
+
+ } else {
+
+ my $ordnumber = ($form->{vc} eq 'customer') ? 'sonumber' : 'ponumber';
+ # up order number by 1
+ $form->{ordnumber}++;
+
+ # save the new number
+ $query = qq|UPDATE defaults
+ SET $ordnumber = '$form->{ordnumber}'|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $form->get_employee($dbh);
+
+ # get last name used
+ $form->lastname_used($dbh, $myconfig, $form->{vc}) unless $form->{"$form->{vc}_id"};
+
+ }
+
+ $form->{exchangerate} = $form->get_exchangerate($dbh, $form->{currency}, $form->{orddate}, ($form->{vc} eq 'customer') ? "buy" : "sell");
+
+ my $rc = $dbh->commit;
+ $dbh->disconnect;
+
+ $rc;
+
+}
+
+
+
+sub order_details {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $tax = 0;
+ my $item;
+ my $i;
+ my @partsgroup = ();
+ my $partsgroup;
+ my %oid = ( 'Pg' => 'oid',
+ 'Oracle' => 'rowid' );
+
+ # sort items by partsgroup
+ for $i (1 .. $form->{rowcount}) {
+ $partsgroup = "";
+ if ($form->{"partsgroup_$i"} && $form->{groupitems}) {
+ $form->format_string("partsgroup_$i");
+ $partsgroup = $form->{"partsgroup_$i"};
+ }
+ push @partsgroup, [ $i, $partsgroup ];
+ }
+
+ my $sameitem = "";
+ foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
+ $i = $item->[0];
+
+ if ($item->[1] ne $sameitem) {
+ push(@{ $form->{description} }, qq|$item->[1]|);
+ $sameitem = $item->[1];
+
+ map { push(@{ $form->{$_} }, "") } qw(runningnumber number bin qty unit reqdate sellprice listprice netprice discount linetotal);
+ }
+
+ $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
+
+ if ($form->{"qty_$i"} != 0) {
+
+ # add number, description and qty to $form->{number}, ....
+ push(@{ $form->{runningnumber} }, $i);
+ push(@{ $form->{number} }, qq|$form->{"partnumber_$i"}|);
+ push(@{ $form->{description} }, qq|$form->{"description_$i"}|);
+ push(@{ $form->{qty} }, $form->format_amount($myconfig, $form->{"qty_$i"}));
+ push(@{ $form->{unit} }, qq|$form->{"unit_$i"}|);
+ push(@{ $form->{reqdate} }, qq|$form->{"reqdate_$i"}|);
+
+ push(@{ $form->{sellprice} }, $form->{"sellprice_$i"});
+
+ push(@{ $form->{listprice} }, $form->{"listprice_$i"});
+
+ my $sellprice = $form->parse_amount($myconfig, $form->{"sellprice_$i"});
+ my ($dec) = ($sellprice =~ /\.(\d+)/);
+ $dec = length $dec;
+ my $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ my $discount = $form->round_amount($sellprice * $form->parse_amount($myconfig, $form->{"discount_$i"}) / 100, $decimalplaces);
+
+ # keep a netprice as well, (sellprice - discount)
+ $form->{"netprice_$i"} = $sellprice - $discount;
+
+ my $linetotal = $form->round_amount($form->{"qty_$i"} * $form->{"netprice_$i"}, 2);
+
+ push(@{ $form->{netprice} }, ($form->{"netprice_$i"} != 0) ? $form->format_amount($myconfig, $form->{"netprice_$i"}, $decimalplaces) : " ");
+
+ $discount = ($discount != 0) ? $form->format_amount($myconfig, $discount * -1, $decimalplaces) : " ";
+ $linetotal = ($linetotal != 0) ? $linetotal : " ";
+
+ push(@{ $form->{discount} }, $discount);
+
+ $form->{ordtotal} += $linetotal;
+
+ push(@{ $form->{linetotal} }, $form->format_amount($myconfig, $linetotal, 2));
+
+ my ($taxamount, $taxbase);
+ my $taxrate = 0;
+
+ map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{"taxaccounts_$i"};
+
+ if ($form->{taxincluded}) {
+ # calculate tax
+ $taxamount = $linetotal * $taxrate / (1 + $taxrate);
+ $taxbase = $linetotal / (1 + $taxrate);
+ } else {
+ $taxamount = $linetotal * $taxrate;
+ $taxbase = $linetotal;
+ }
+
+
+ if ($taxamount != 0) {
+ foreach my $item (split / /, $form->{"taxaccounts_$i"}) {
+ $taxaccounts{$item} += $taxamount * $form->{"${item}_rate"} / $taxrate;
+ $taxbase{$item} += $taxbase;
+ }
+ }
+
+ if ($form->{"assembly_$i"}) {
+ $sameitem = "";
+
+ # get parts and push them onto the stack
+ my $sortorder = "";
+ if ($form->{groupitems}) {
+ $sortorder = qq|ORDER BY pg.partsgroup, a.$oid{$myconfig->{dbdriver}}|;
+ } else {
+ $sortorder = qq|ORDER BY a.$oid{$myconfig->{dbdriver}}|;
+ }
+
+ $query = qq|SELECT p.partnumber, p.description, p.unit, a.qty,
+ pg.partsgroup
+ FROM assembly a
+ JOIN parts p ON (a.parts_id = p.id)
+ LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+ WHERE a.bom = '1'
+ AND a.id = '$form->{"id_$i"}'
+ $sortorder|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ if ($form->{groupitems} && $ref->{partsgroup} ne $sameitem) {
+ map { push(@{ $form->{$_} }, "") } qw(runningnumber number unit bin qty sellprice listprice netprice discount linetotal);
+ $sameitem = ($ref->{partsgroup}) ? $ref->{partsgroup} : "--";
+ push(@{ $form->{description} }, $sameitem);
+ }
+
+ push(@{ $form->{number} }, qq|$ref->{partnumber}|);
+ push(@{ $form->{description} }, qq|$ref->{description}|);
+ push(@{ $form->{unit} }, qq|$ref->{unit}|);
+ push(@{ $form->{qty} }, $form->format_amount($myconfig, $ref->{qty} * $form->{"qty_$i"}));
+
+ map { push(@{ $form->{$_} }, "") } qw(runningnumber bin sellprice listprice netprice discount linetotal);
+
+ }
+ $sth->finish;
+ }
+
+ }
+ }
+
+
+ foreach $item (sort keys %taxaccounts) {
+ if ($form->round_amount($taxaccounts{$item}, 2) != 0) {
+ push(@{ $form->{taxbase} }, $form->format_amount($myconfig, $taxbase{$item}, 2));
+
+ $taxamount = $form->round_amount($taxaccounts{$item}, 2);
+ $tax += $taxamount;
+
+ push(@{ $form->{tax} }, $form->format_amount($myconfig, $taxamount, 2));
+ push(@{ $form->{taxdescription} }, $form->{"${item}_description"});
+ push(@{ $form->{taxrate} }, $form->format_amount($myconfig, $form->{"${item}_rate"} * 100));
+ push(@{ $form->{taxnumber} }, $form->{"${item}_taxnumber"});
+ }
+ }
+
+
+ $form->{subtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
+ $form->{ordtotal} = ($form->{taxincluded}) ? $form->{ordtotal} : $form->{ordtotal} + $tax;
+
+ # format amounts
+ $form->{ordtotal} = $form->format_amount($myconfig, $form->{ordtotal}, 2);
+
+ # myconfig variables
+ map { $form->{$_} = $myconfig->{$_} } (qw(company address tel fax signature businessnumber));
+ $form->{username} = $myconfig->{name};
+
+ $dbh->disconnect;
+
+}
+
+
+sub project_description {
+ my ($self, $dbh, $id) = @_;
+
+ my $query = qq|SELECT description
+ FROM project
+ WHERE id = $id|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($_) = $sth->fetchrow_array;
+
+ $sth->finish;
+
+ $_;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/SL/PE.pm b/sql-ledger/SL/PE.pm
new file mode 100644
index 0000000..dec04bb
--- /dev/null
+++ b/sql-ledger/SL/PE.pm
@@ -0,0 +1,276 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Project module
+# also used for partsgroups
+#
+#======================================================================
+
+package PE;
+
+
+sub projects {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $sortorder = ($form->{sort}) ? $form->{sort} : "projectnumber";
+
+ my $query = qq|SELECT id, projectnumber, description
+ FROM project
+ WHERE 1 = 1|;
+
+ if ($form->{projectnumber}) {
+ my $projectnumber = $form->like(lc $form->{projectnumber});
+ $query .= " AND lower(projectnumber) LIKE '$projectnumber'";
+ }
+ if ($form->{projectdescription}) {
+ my $description = $form->like(lc $form->{projectdescription});
+ $query .= " AND lower(description) LIKE '$description'";
+ }
+ if ($form->{status} eq 'orphaned') {
+ $query .= " AND id NOT IN (SELECT p.id
+ FROM project p, acc_trans a
+ WHERE p.id = a.project_id)
+ AND id NOT IN (SELECT p.id
+ FROM project p, invoice i
+ WHERE p.id = i.project_id)
+ AND id NOT IN (SELECT p.id
+ FROM project p, orderitems o
+ WHERE p.id = o.project_id)";
+ }
+
+ $query .= qq|
+ ORDER BY $sortorder|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $i = 0;
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{project_list} }, $ref;
+ $i++;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+ $i;
+
+}
+
+
+sub get_project {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT *
+ FROM project
+ WHERE id = $form->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+
+ $sth->finish;
+
+ # check if it is orphaned
+ $query = qq|SELECT count(*)
+ FROM acc_trans
+ WHERE project_id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{orphaned}) = $sth->fetchrow_array;
+ $form->{orphaned} = !$form->{orphaned};
+
+ $sth->finish;
+
+ $dbh->disconnect;
+
+}
+
+
+sub save_project {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ map { $form->{$_} =~ s/'/''/g } (projectnumber, description);
+
+ if ($form->{id}) {
+ $query = qq|UPDATE project SET
+ projectnumber = '$form->{projectnumber}',
+ description = '$form->{description}'
+ WHERE id = $form->{id}|;
+ } else {
+ $query = qq|INSERT INTO project
+ (projectnumber, description)
+ VALUES ('$form->{projectnumber}', '$form->{description}')|;
+ }
+ $dbh->do($query) || $form->dberror($query);
+
+ $dbh->disconnect;
+
+}
+
+
+sub partsgroups {
+ my ($self, $myconfig, $form) = @_;
+
+ my $var;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $sortorder = ($form->{sort}) ? $form->{sort} : "partsgroup";
+
+ my $query = qq|SELECT g.*
+ FROM partsgroup g|;
+
+ my $where = "1 = 1";
+
+ if ($form->{partsgroup}) {
+ $var = $form->like(lc $form->{partsgroup});
+ $where .= " AND lower(partsgroup) LIKE '$var'";
+ }
+ $query .= qq|
+ WHERE $where
+ ORDER BY $sortorder|;
+
+ if ($form->{status} eq 'orphaned') {
+ $query = qq|SELECT g.*
+ FROM partsgroup g
+ LEFT JOIN parts p ON (p.partsgroup_id = g.id)
+ WHERE $where
+ EXCEPT
+ SELECT g.*
+ FROM partsgroup g
+ JOIN parts p ON (p.partsgroup_id = g.id)
+ WHERE $where
+ ORDER BY $sortorder|;
+ }
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $i = 0;
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{item_list} }, $ref;
+ $i++;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+ $i;
+
+}
+
+
+sub save_partsgroup {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ map { $form->{$_} =~ s/'/''/g } (partsgroup);
+
+
+ if ($form->{id}) {
+ $query = qq|UPDATE partsgroup SET
+ partsgroup = '$form->{partsgroup}'
+ WHERE id = $form->{id}|;
+ } else {
+ $query = qq|INSERT INTO partsgroup
+ (partsgroup)
+ VALUES ('$form->{partsgroup}')|;
+ }
+ $dbh->do($query) || $form->dberror($query);
+
+ $dbh->disconnect;
+
+}
+
+
+sub get_partsgroup {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT *
+ FROM partsgroup
+ WHERE id = $form->{id}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+
+ map { $form->{$_} = $ref->{$_} } keys %$ref;
+
+ $sth->finish;
+
+ # check if it is orphaned
+ $query = qq|SELECT count(*)
+ FROM parts
+ WHERE partsgroup_id = $form->{id}|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{orphaned}) = $sth->fetchrow_array;
+ $form->{orphaned} = !$form->{orphaned};
+
+ $sth->finish;
+
+ $dbh->disconnect;
+
+}
+
+
+
+sub delete_tuple {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ $query = qq|DELETE FROM $form->{type}
+ WHERE id = $form->{id}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $dbh->disconnect;
+
+}
+
+
+
+1;
+
diff --git a/sql-ledger/SL/RC.pm b/sql-ledger/SL/RC.pm
new file mode 100644
index 0000000..9957d73
--- /dev/null
+++ b/sql-ledger/SL/RC.pm
@@ -0,0 +1,186 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Account reconciliation routines
+#
+#======================================================================
+
+package RC;
+
+
+sub paymentaccounts {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT accno, description
+ FROM chart
+ WHERE link LIKE '%_paid%'
+ AND category = 'A'
+ ORDER BY accno|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{PR} }, $ref;
+ }
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub payment_transactions {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn AutoCommit off
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my ($query, $sth);
+
+ # get cleared balance
+ if ($form->{fromdate}) {
+ $query = qq|SELECT sum(a.amount)
+ FROM acc_trans a, chart c
+ WHERE a.transdate < date '$form->{fromdate}'
+ AND a.cleared = '1'
+ AND c.id = a.chart_id
+ AND c.accno = '$form->{accno}'
+ |;
+ } else {
+ $query = qq|SELECT sum(a.amount)
+ FROM acc_trans a, chart c
+ WHERE a.cleared = '1'
+ AND c.id = a.chart_id
+ AND c.accno = '$form->{accno}'
+ |;
+ }
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{beginningbalance}) = $sth->fetchrow_array;
+
+ $sth->finish;
+
+ my %oid = ( 'Pg' => 'ac.oid',
+ 'Oracle' => 'ac.rowid');
+
+ $query = qq|SELECT c.name, ac.source, ac.transdate, ac.cleared,
+ ac.fx_transaction, ac.amount, a.id,
+ $oid{$myconfig->{dbdriver}} AS oid
+ FROM customer c, acc_trans ac, ar a, chart ch
+ WHERE c.id = a.customer_id
+ AND ac.cleared = '0'
+ AND ac.trans_id = a.id
+ AND ac.chart_id = ch.id
+ AND ch.accno = '$form->{accno}'
+ |;
+
+ $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
+ $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
+
+
+ $query .= qq|
+
+ UNION
+ SELECT v.name, ac.source, ac.transdate, ac.cleared,
+ ac.fx_transaction, ac.amount, a.id,
+ $oid{$myconfig->{dbdriver}} AS oid
+ FROM vendor v, acc_trans ac, ap a, chart ch
+ WHERE v.id = a.vendor_id
+ AND ac.cleared = '0'
+ AND ac.trans_id = a.id
+ AND ac.chart_id = ch.id
+ AND ch.accno = '$form->{accno}'
+ |;
+
+ $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
+ $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
+
+ $query .= qq|
+
+ UNION
+ SELECT g.description, ac.source, ac.transdate, ac.cleared,
+ ac.fx_transaction, ac.amount, g.id,
+ $oid{$myconfig->{dbdriver}} AS oid
+ FROM gl g, acc_trans ac, chart ch
+ WHERE g.id = ac.trans_id
+ AND ac.cleared = '0'
+ AND ac.trans_id = g.id
+ AND ac.chart_id = ch.id
+ AND ch.accno = '$form->{accno}'
+ |;
+
+ $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
+ $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
+
+ $query .= " ORDER BY 3,7,8";
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $pr = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{PR} }, $pr;
+ }
+ $sth->finish;
+
+ $dbh->disconnect;
+
+}
+
+
+sub reconcile {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my ($query, $i);
+ my %oid = ( 'Pg' => 'oid',
+ 'Oracle' => 'rowid');
+
+ # clear flags
+ for $i (1 .. $form->{rowcount}) {
+ if ($form->{"cleared_$i"}) {
+ $query = qq|UPDATE acc_trans SET cleared = '1'
+ WHERE $oid{$myconfig->{dbdriver}} = $form->{"oid_$i"}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ # clear fx_transaction
+ if ($form->{"fxoid_$i"}) {
+ $query = qq|UPDATE acc_trans SET cleared = '1'
+ WHERE $oid{$myconfig->{dbdriver}} = $form->{"fxoid_$i"}|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ }
+ }
+
+ $dbh->disconnect;
+
+}
+
+1;
+
diff --git a/sql-ledger/SL/RP.pm b/sql-ledger/SL/RP.pm
new file mode 100644
index 0000000..3f07bb5
--- /dev/null
+++ b/sql-ledger/SL/RP.pm
@@ -0,0 +1,1310 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors: Benjamin Lee <benjaminlee@consultant.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# backend code for reports
+#
+#======================================================================
+
+package RP;
+
+
+sub income_statement {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $last_period = 0;
+ my @categories = qw(I E);
+ my $category;
+
+ $form->{decimalplaces} *= 1;
+
+ &get_accounts($dbh, $last_period, $form->{fromdate}, $form->{todate}, $form, \@categories);
+
+ # if there are any compare dates
+ if ($form->{comparefromdate} || $form->{comparetodate}) {
+ $last_period = 1;
+
+ &get_accounts($dbh, $last_period, $form->{comparefromdate}, $form->{comparetodate}, $form, \@categories);
+ }
+
+
+ # disconnect
+ $dbh->disconnect;
+
+
+ # now we got $form->{I}{accno}{ }
+ # and $form->{E}{accno}{ }
+
+ my %account = ( 'I' => { 'label' => 'income',
+ 'labels' => 'income',
+ 'ml' => 1 },
+ 'E' => { 'label' => 'expense',
+ 'labels' => 'expenses',
+ 'ml' => -1 }
+ );
+
+ my $str;
+
+ foreach $category (@categories) {
+
+ foreach $key (sort keys %{ $form->{$category} }) {
+ # push description onto array
+
+ $str = ($form->{l_heading}) ? $form->{padding} : "";
+
+ if ($form->{$category}{$key}{charttype} eq "A") {
+ $str .= ($form->{l_accno}) ? "$form->{$category}{$key}{accno} - $form->{$category}{$key}{description}" : "$form->{$category}{$key}{description}";
+ }
+ if ($form->{$category}{$key}{charttype} eq "H") {
+ if ($account{$category}{subtotal} && $form->{l_subtotal}) {
+ $dash = "- ";
+ push(@{$form->{"$account{$category}{label}_account"}}, "$str$form->{bold}$account{$category}{subdescription}$form->{endbold}");
+ push(@{$form->{"$account{$category}{labels}_this_period"}}, $form->format_amount($myconfig, $account{$category}{subthis} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+
+ if ($last_period) {
+ push(@{$form->{"$account{$category}{labels}_last_period"}}, $form->format_amount($myconfig, $account{$category}{sublast} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+ }
+
+ }
+
+ $str = "$form->{br}$form->{bold}$form->{$category}{$key}{description}$form->{endbold}";
+
+ $account{$category}{subthis} = $form->{$category}{$key}{this};
+ $account{$category}{sublast} = $form->{$category}{$key}{last};
+ $account{$category}{subdescription} = $form->{$category}{$key}{description};
+ $account{$category}{subtotal} = 1;
+
+ $form->{$category}{$key}{this} = 0;
+ $form->{$category}{$key}{last} = 0;
+
+ next unless $form->{l_heading};
+
+ $dash = " ";
+ }
+
+ push(@{$form->{"$account{$category}{label}_account"}}, $str);
+
+ if ($form->{$category}{$key}{charttype} eq 'A') {
+ $form->{"total_$account{$category}{labels}_this_period"} += $form->{$category}{$key}{this} * $account{$category}{ml};
+ $dash = "- ";
+ }
+
+ push(@{$form->{"$account{$category}{labels}_this_period"}}, $form->format_amount($myconfig, $form->{$category}{$key}{this} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+
+ # add amount or - for last period
+ if ($last_period) {
+ $form->{"total_$account{$category}{labels}_last_period"} += $form->{$category}{$key}{last} * $account{$category}{ml};
+
+ push(@{$form->{"$account{$category}{labels}_last_period"}}, $form->format_amount($myconfig,$form->{$category}{$key}{last} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+ }
+ }
+
+ $str = ($form->{l_heading}) ? $form->{padding} : "";
+ if ($account{$category}{subtotal} && $form->{l_subtotal}) {
+ push(@{$form->{"$account{$category}{label}_account"}}, "$str$form->{bold}$account{$category}{subdescription}$form->{endbold}");
+ push(@{$form->{"$account{$category}{labels}_this_period"}}, $form->format_amount($myconfig, $account{$category}{subthis} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+
+ if ($last_period) {
+ push(@{$form->{"$account{$category}{labels}_last_period"}}, $form->format_amount($myconfig, $account{$category}{sublast} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+ }
+ }
+
+ }
+
+
+ # totals for income and expenses
+ $form->{total_income_this_period} = $form->round_amount($form->{total_income_this_period}, $form->{decimalplaces});
+ $form->{total_expenses_this_period} = $form->round_amount($form->{total_expenses_this_period}, $form->{decimalplaces});
+
+ # total for income/loss
+ $form->{total_this_period} = $form->{total_income_this_period} - $form->{total_expenses_this_period};
+
+ if ($last_period) {
+ # total for income/loss
+ $form->{total_last_period} = $form->format_amount($myconfig, $form->{total_income_last_period} - $form->{total_expenses_last_period}, $form->{decimalplaces}, "- ");
+
+ # totals for income and expenses for last_period
+ $form->{total_income_last_period} = $form->format_amount($myconfig, $form->{total_income_last_period}, $form->{decimalplaces}, "- ");
+ $form->{total_expenses_last_period} = $form->format_amount($myconfig, $form->{total_expenses_last_period}, $form->{decimalplaces}, "- ");
+
+ }
+
+
+ $form->{total_income_this_period} = $form->format_amount($myconfig,$form->{total_income_this_period}, $form->{decimalplaces}, "- ");
+ $form->{total_expenses_this_period} = $form->format_amount($myconfig,$form->{total_expenses_this_period}, $form->{decimalplaces}, "- ");
+ $form->{total_this_period} = $form->format_amount($myconfig,$form->{total_this_period}, $form->{decimalplaces}, "- ");
+
+}
+
+
+
+sub balance_sheet {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $last_period = 0;
+ my @categories = qw(A L Q);
+
+ # if there are any dates construct a where
+ if ($form->{asofdate}) {
+
+ $form->{this_period} = "$form->{asofdate}";
+ $form->{period} = "$form->{asofdate}";
+
+ }
+
+ $form->{decimalplaces} *= 1;
+
+ &get_accounts($dbh, $last_period, "", $form->{asofdate}, $form, \@categories);
+
+ # if there are any compare dates
+ if ($form->{compareasofdate}) {
+
+ $last_period = 1;
+ &get_accounts($dbh, $last_period, "", $form->{compareasofdate}, $form, \@categories);
+
+ $form->{last_period} = "$form->{compareasofdate}";
+
+ }
+
+
+ # disconnect
+ $dbh->disconnect;
+
+
+ # now we got $form->{A}{accno}{ } assets
+ # and $form->{L}{accno}{ } liabilities
+ # and $form->{Q}{accno}{ } equity
+ # build asset accounts
+
+ my $str;
+ my $key;
+
+ my %account = ( 'A' => { 'label' => 'asset',
+ 'labels' => 'assets',
+ 'ml' => -1 },
+ 'L' => { 'label' => 'liability',
+ 'labels' => 'liabilities',
+ 'ml' => 1 },
+ 'Q' => { 'label' => 'equity',
+ 'labels' => 'equities',
+ 'ml' => 1 }
+ );
+
+ foreach $category (@categories) {
+
+ foreach $key (sort keys %{ $form->{$category} }) {
+
+ $str = ($form->{l_heading}) ? $form->{padding} : "";
+
+ if ($form->{$category}{$key}{charttype} eq "A") {
+ $str .= ($form->{l_accno}) ? "$form->{$category}{$key}{accno} - $form->{$category}{$key}{description}" : "$form->{$category}{$key}{description}";
+ }
+ if ($form->{$category}{$key}{charttype} eq "H") {
+ if ($account{$category}{subtotal} && $form->{l_subtotal}) {
+ $dash = "- ";
+ push(@{$form->{"$account{$category}{label}_account"}}, "$str$form->{bold}$account{$category}{subdescription}$form->{endbold}");
+ push(@{$form->{"$account{$category}{label}_this_period"}}, $form->format_amount($myconfig, $account{$category}{subthis} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+
+ if ($last_period) {
+ push(@{$form->{"$account{$category}{label}_last_period"}}, $form->format_amount($myconfig, $account{$category}{sublast} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+ }
+ }
+
+ $str = "$form->{bold}$form->{$category}{$key}{description}$form->{endbold}";
+
+ $account{$category}{subthis} = $form->{$category}{$key}{this};
+ $account{$category}{sublast} = $form->{$category}{$key}{last};
+ $account{$category}{subdescription} = $form->{$category}{$key}{description};
+ $account{$category}{subtotal} = 1;
+
+ $form->{$category}{$key}{this} = 0;
+ $form->{$category}{$key}{last} = 0;
+
+ next unless $form->{l_heading};
+
+ $dash = " ";
+ }
+
+ # push description onto array
+ push(@{$form->{"$account{$category}{label}_account"}}, $str);
+
+ if ($form->{$category}{$key}{charttype} eq 'A') {
+ $form->{"total_$account{$category}{labels}_this_period"} += $form->{$category}{$key}{this} * $account{$category}{ml};
+ $dash = "- ";
+ }
+
+ push(@{$form->{"$account{$category}{label}_this_period"}}, $form->format_amount($myconfig, $form->{$category}{$key}{this} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+
+ if ($last_period) {
+ $form->{"total_$account{$category}{labels}_last_period"} += $form->{$category}{$key}{last} * $account{$category}{ml};
+
+ push(@{$form->{"$account{$category}{label}_last_period"}}, $form->format_amount($myconfig, $form->{$category}{$key}{last} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+ }
+ }
+
+ $str = ($form->{l_heading}) ? $form->{padding} : "";
+ if ($account{$category}{subtotal} && $form->{l_subtotal}) {
+ push(@{$form->{"$account{$category}{label}_account"}}, "$str$form->{bold}$account{$category}{subdescription}$form->{endbold}");
+ push(@{$form->{"$account{$category}{label}_this_period"}}, $form->format_amount($myconfig, $account{$category}{subthis} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+
+ if ($last_period) {
+ push(@{$form->{"$account{$category}{label}_last_period"}}, $form->format_amount($myconfig, $account{$category}{sublast} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
+ }
+ }
+
+ }
+
+
+ # totals for assets, liabilities
+ $form->{total_assets_this_period} = $form->round_amount($form->{total_assets_this_period}, $form->{decimalplaces});
+ $form->{total_liabilities_this_period} = $form->round_amount($form->{total_liabilities_this_period}, $form->{decimalplaces});
+
+
+ # calculate retained earnings
+ $form->{earnings_this_period} = $form->{total_assets_this_period} - $form->{total_liabilities_this_period} - $form->{total_equity_this_period};
+
+ push(@{$form->{equity_this_period}}, $form->format_amount($myconfig, $form->{earnings_this_period}, $form->{decimalplaces}, "- "));
+
+ $form->{total_equity_this_period} = $form->round_amount($form->{total_equity_this_period} + $form->{earnings_this_period}, $form->{decimalplaces});
+
+ # add liability + equity
+ $form->{total_this_period} = $form->format_amount($myconfig, $form->{total_liabilities_this_period} + $form->{total_equity_this_period}, $form->{decimalplaces}, "- ");
+
+
+ if ($last_period) {
+ # totals for assets, liabilities
+ $form->{total_assets_last_period} = $form->round_amount($form->{total_assets_last_period}, $form->{decimalplaces});
+ $form->{total_liabilities_last_period} = $form->round_amount($form->{total_liabilities_last_period}, $form->{decimalplaces});
+
+
+ # calculate retained earnings
+ $form->{earnings_last_period} = $form->{total_assets_last_period} - $form->{total_liabilities_last_period} - $form->{total_equity_last_period};
+
+ push(@{$form->{equity_last_period}}, $form->format_amount($myconfig,$form->{earnings_last_period}, $form->{decimalplaces}, "- "));
+
+ $form->{total_equity_last_period} = $form->round_amount($form->{total_equity_last_period} + $form->{earnings_last_period}, $form->{decimalplaces});
+
+ # add liability + equity
+ $form->{total_last_period} = $form->format_amount($myconfig, $form->{total_liabilities_last_period} + $form->{total_equity_last_period}, $form->{decimalplaces}, "- ");
+
+ }
+
+
+ $form->{total_liabilities_last_period} = $form->format_amount($myconfig, $form->{total_liabilities_last_period}, $form->{decimalplaces}, "- ") if ($form->{total_liabilities_last_period} != 0);
+
+ $form->{total_equity_last_period} = $form->format_amount($myconfig, $form->{total_equity_last_period}, $form->{decimalplaces}, "- ") if ($form->{total_equity_last_period} != 0);
+
+ $form->{total_assets_last_period} = $form->format_amount($myconfig, $form->{total_assets_last_period}, $form->{decimalplaces}, "- ") if ($form->{total_assets_last_period} != 0);
+
+ $form->{total_assets_this_period} = $form->format_amount($myconfig, $form->{total_assets_this_period}, $form->{decimalplaces}, "- ");
+
+ $form->{total_liabilities_this_period} = $form->format_amount($myconfig, $form->{total_liabilities_this_period}, $form->{decimalplaces}, "- ");
+
+ $form->{total_equity_this_period} = $form->format_amount($myconfig, $form->{total_equity_this_period}, $form->{decimalplaces}, "- ");
+
+}
+
+
+
+sub get_accounts {
+ my ($dbh, $last_period, $fromdate, $todate, $form, $categories) = @_;
+
+ my $query;
+ my $where = "WHERE 1 = 1";
+ my $subwhere;
+ my $item;
+
+ my $category = "AND (";
+ foreach $item (@{ $categories }) {
+ $category .= qq|c.category = '$item' OR |;
+ }
+ $category =~ s/OR $/\)/;
+
+
+ # get headings
+ $query = qq|SELECT accno, description, category
+ FROM chart c
+ WHERE c.charttype = 'H'
+ $category
+ ORDER by c.accno|;
+
+ if ($form->{accounttype} eq 'gifi')
+ {
+ $query = qq|SELECT g.accno, g.description, c.category
+ FROM gifi g
+ JOIN chart c ON (c.gifi_accno = g.accno)
+ WHERE c.charttype = 'H'
+ $category
+ ORDER BY g.accno|;
+ }
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my @headingaccounts = ();
+ while ($ref = $sth->fetchrow_hashref(NAME_lc))
+ {
+ $form->{$ref->{category}}{$ref->{accno}}{description} = "$ref->{description}";
+ $form->{$ref->{category}}{$ref->{accno}}{charttype} = "H";
+ $form->{$ref->{category}}{$ref->{accno}}{accno} = $ref->{accno};
+
+ push @headingaccounts, $ref->{accno};
+ }
+
+ $sth->finish;
+
+
+ $where .= " AND ac.transdate >= '$fromdate'" if $fromdate;
+
+ if ($todate) {
+ $where .= " AND ac.transdate <= '$todate'";
+ $subwhere = " AND transdate <= '$todate'";
+ }
+
+
+ if ($form->{project_id})
+ {
+ $project = qq|
+ AND ac.project_id = $form->{project_id}
+ |;
+ }
+
+
+ if ($form->{accounttype} eq 'gifi')
+ {
+
+ if ($form->{method} eq 'cash')
+ {
+
+ $query = qq|
+
+ SELECT g.accno, sum(ac.amount) AS amount,
+ g.description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN ar a ON (a.id = ac.trans_id)
+ JOIN gifi g ON (g.accno = c.gifi_accno)
+ $where
+ $category
+ AND ac.trans_id IN
+ (
+ SELECT trans_id
+ FROM acc_trans
+ JOIN chart ON (chart_id = id)
+ WHERE link LIKE '%AR_paid%'
+ $subwhere
+ )
+ $project
+ GROUP BY g.accno, g.description, c.category
+
+ UNION
+
+ SELECT '' AS accno, SUM(ac.amount) AS amount,
+ '' AS description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN ar a ON (a.id = ac.trans_id)
+ $where
+ $category
+ AND c.gifi_accno = ''
+ AND ac.trans_id IN
+ (
+ SELECT trans_id
+ FROM acc_trans
+ JOIN chart ON (chart_id = id)
+ WHERE link LIKE '%AR_paid%'
+ $subwhere
+ )
+ $project
+ GROUP BY c.category
+
+ UNION
+
+ SELECT g.accno, sum(ac.amount) AS amount,
+ g.description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN ap a ON (a.id = ac.trans_id)
+ JOIN gifi g ON (g.accno = c.gifi_accno)
+ $where
+ $category
+ AND ac.trans_id IN
+ (
+ SELECT trans_id
+ FROM acc_trans
+ JOIN chart ON (chart_id = id)
+ WHERE link LIKE '%AP_paid%'
+ $subwhere
+ )
+ $project
+ GROUP BY g.accno, g.description, c.category
+
+ UNION
+
+ SELECT '' AS accno, SUM(ac.amount) AS amount,
+ '' AS description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN ap a ON (a.id = ac.trans_id)
+ $where
+ $category
+ AND c.gifi_accno = ''
+ AND ac.trans_id IN
+ (
+ SELECT trans_id
+ FROM acc_trans
+ JOIN chart ON (chart_id = id)
+ WHERE link LIKE '%AP_paid%'
+ $subwhere
+ )
+ $project
+ GROUP BY c.category
+
+ UNION
+
+-- add gl
+
+ SELECT g.accno, sum(ac.amount) AS amount,
+ g.description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN gifi g ON (g.accno = c.gifi_accno)
+ JOIN gl a ON (a.id = ac.trans_id)
+ $where
+ $category
+ AND NOT (c.link = 'AR' OR c.link = 'AP')
+ $project
+ GROUP BY g.accno, g.description, c.category
+
+ UNION
+
+ SELECT '' AS accno, SUM(ac.amount) AS amount,
+ '' AS description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN gl a ON (a.id = ac.trans_id)
+ $where
+ $category
+ AND c.gifi_accno = ''
+ AND NOT (c.link = 'AR' OR c.link = 'AP')
+ $project
+ GROUP BY c.category
+ |;
+
+ } else {
+
+ $query = qq|
+
+ SELECT g.accno, SUM(ac.amount) AS amount,
+ g.description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN gifi g ON (c.gifi_accno = g.accno)
+ $where
+ $category
+ $project
+ GROUP BY g.accno, g.description, c.category
+
+ UNION
+
+ SELECT '' AS accno, SUM(ac.amount) AS amount,
+ '' AS description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ $where
+ $category
+ AND c.gifi_accno = ''
+ $project
+ GROUP by c.category
+ |;
+
+ }
+
+ } else {
+
+ if ($form->{method} eq 'cash')
+ {
+
+
+ $query = qq|
+
+ SELECT c.accno, sum(ac.amount) AS amount,
+ c.description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN ar a ON (a.id = ac.trans_id)
+ $where
+ $category
+ AND ac.trans_id IN
+ (
+ SELECT trans_id
+ FROM acc_trans
+ JOIN chart ON (chart_id = id)
+ WHERE link LIKE '%AR_paid%'
+ $subwhere
+ )
+
+ $project
+ GROUP BY c.accno, c.description, c.category
+
+ UNION
+
+ SELECT c.accno, sum(ac.amount) AS amount,
+ c.description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN ap a ON (a.id = ac.trans_id)
+ $where
+ $category
+ AND ac.trans_id IN
+ (
+ SELECT trans_id
+ FROM acc_trans
+ JOIN chart ON (chart_id = id)
+ WHERE link LIKE '%AP_paid%'
+ $subwhere
+ )
+
+ $project
+ GROUP BY c.accno, c.description, c.category
+
+ UNION
+
+ SELECT c.accno, sum(ac.amount) AS amount,
+ c.description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ JOIN gl a ON (a.id = ac.trans_id)
+ $where
+ $category
+ AND NOT (c.link = 'AR' OR c.link = 'AP')
+ $project
+ GROUP BY c.accno, c.description, c.category
+ |;
+
+ } else {
+
+ $query = qq|
+
+ SELECT c.accno, sum(ac.amount) AS amount,
+ c.description, c.category
+ FROM acc_trans ac
+ JOIN chart c ON (c.id = ac.chart_id)
+ $where
+ $category
+ $project
+ GROUP BY c.accno, c.description, c.category
+ |;
+
+ }
+
+ }
+
+
+ my @accno;
+ my $accno;
+ my $ref;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while ($ref = $sth->fetchrow_hashref(NAME_lc))
+ {
+
+ if ($ref->{category} eq 'C') {
+ $ref->{category} = 'A';
+ }
+
+ # get last heading account
+ @accno = grep { $_ le "$ref->{accno}" } @headingaccounts;
+ $accno = pop @accno;
+ if ($accno) {
+ if ($last_period)
+ {
+ $form->{$ref->{category}}{$accno}{last} += $ref->{amount};
+ } else {
+ $form->{$ref->{category}}{$accno}{this} += $ref->{amount};
+ }
+ }
+
+ $form->{$ref->{category}}{$ref->{accno}}{accno} = $ref->{accno};
+ $form->{$ref->{category}}{$ref->{accno}}{description} = $ref->{description};
+ $form->{$ref->{category}}{$ref->{accno}}{charttype} = "A";
+
+ if ($last_period)
+ {
+ $form->{$ref->{category}}{$ref->{accno}}{last} += $ref->{amount};
+ } else {
+ $form->{$ref->{category}}{$ref->{accno}}{this} += $ref->{amount};
+ }
+ }
+ $sth->finish;
+
+
+ # remove accounts with zero balance
+ foreach $category (@{ $categories }) {
+ foreach $accno (keys %{ $form->{$category} }) {
+ $form->{$category}{$accno}{last} = $form->round_amount($form->{$category}{$accno}{last}, $form->{decimalplaces});
+ $form->{$category}{$accno}{this} = $form->round_amount($form->{$category}{$accno}{this}, $form->{decimalplaces});
+
+ delete $form->{$category}{$accno} if ($form->{$category}{$accno}{this} == 0 && $form->{$category}{$accno}{last} == 0);
+ }
+ }
+
+}
+
+
+
+sub trial_balance_details {
+ my ($self, $myconfig, $form) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+
+ my ($query, $sth, $ref);
+ my %balance = ();
+ my %trb = ();
+
+ my $where = "WHERE 1 = 1";
+
+ if ($form->{project_id}) {
+ $where .= qq|
+ AND a.project_id = $form->{project_id}
+ |;
+ }
+
+ # get beginning balances
+ if ($form->{fromdate}) {
+
+ if ($form->{accounttype} eq 'gifi') {
+
+ $query = qq|SELECT g.accno, c.category, SUM(a.amount) AS amount,
+ g.description
+ FROM acc_trans a
+ JOIN chart c ON (a.chart_id = c.id)
+ JOIN gifi g ON (c.gifi_accno = g.accno)
+ $where
+ AND a.transdate < '$form->{fromdate}'
+ GROUP BY g.accno, c.category, g.description
+ |;
+
+ } else {
+
+ $query = qq|SELECT c.accno, c.category, SUM(a.amount) AS amount,
+ c.description
+ FROM acc_trans a
+ JOIN chart c ON (a.chart_id = c.id)
+ $where
+ AND a.transdate < '$form->{fromdate}'
+ GROUP BY c.accno, c.category, c.description
+ |;
+ }
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $balance{$ref->{accno}} = $ref->{amount};
+
+ if ($ref->{amount} != 0 && $form->{all_accounts}) {
+ $trb{$ref->{accno}}{description} = $ref->{description};
+ $trb{$ref->{accno}}{charttype} = 'A';
+ $trb{$ref->{accno}}{category} = $ref->{category};
+ }
+
+ }
+ $sth->finish;
+
+ }
+
+
+ # get headings
+ $query = qq|SELECT c.accno, c.description, c.category
+ FROM chart c
+ WHERE c.charttype = 'H'
+ ORDER by c.accno|;
+
+ if ($form->{accounttype} eq 'gifi')
+ {
+ $query = qq|SELECT g.accno, g.description, c.category
+ FROM gifi g
+ JOIN chart c ON (c.gifi_accno = g.accno)
+ WHERE c.charttype = 'H'
+ ORDER BY g.accno|;
+ }
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my @headingaccounts = ();
+ while ($ref = $sth->fetchrow_hashref(NAME_lc))
+ {
+ $trb{$ref->{accno}}{description} = $ref->{description};
+ $trb{$ref->{accno}}{charttype} = 'H';
+ $trb{$ref->{accno}}{category} = $ref->{category};
+
+ push @headingaccounts, $ref->{accno};
+ }
+
+ $sth->finish;
+
+
+ if ($form->{fromdate} || $form->{todate}) {
+ if ($form->{fromdate}) {
+ $where .= " AND a.transdate >= '$form->{fromdate}'";
+ }
+ if ($form->{todate}) {
+ $where .= " AND a.transdate <= '$form->{todate}'";
+ }
+ }
+
+
+ if ($form->{accounttype} eq 'gifi') {
+
+ $query = qq|SELECT g.accno, g.description, c.category,
+ SUM(a.amount) AS amount
+ FROM acc_trans a
+ JOIN chart c ON (c.id = a.chart_id)
+ JOIN gifi g ON (c.gifi_accno = g.accno)
+ $where
+ GROUP BY g.accno, g.description, c.category
+
+ UNION
+
+ SELECT '' AS accno, '' AS description, c.category,
+ SUM(a.amount) AS amount
+ FROM acc_trans a
+ JOIN chart c ON (c.id = a.chart_id)
+ $where
+ AND c.gifi_accno = ''
+ GROUP BY c.category
+ ORDER BY accno|;
+
+ } else {
+
+ $query = qq|SELECT c.accno, c.description, c.category,
+ SUM(a.amount) AS amount
+ FROM acc_trans a
+ JOIN chart c ON (c.id = a.chart_id)
+ $where
+ GROUP BY c.accno, c.description, c.category
+ ORDER BY accno|;
+
+ }
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+
+ # prepare query for each account
+
+ $query = qq|SELECT (SELECT SUM(a.amount) * -1
+ FROM acc_trans a
+ JOIN chart c ON (c.id = a.chart_id)
+ $where
+ AND a.amount < 0
+ AND c.accno = ?) AS debit,
+ (SELECT SUM(a.amount)
+ FROM acc_trans a
+ JOIN chart c ON (c.id = a.chart_id)
+ $where
+ AND a.amount > 0
+ AND c.accno = ?) AS credit
+ |;
+
+ if ($form->{accounttype} eq 'gifi') {
+
+ $query = qq|SELECT (SELECT SUM(a.amount) * -1
+ FROM acc_trans a
+ JOIN chart c ON (c.id = a.chart_id)
+ $where
+ AND a.amount < 0
+ AND c.gifi_accno = ?) AS debit,
+ (SELECT SUM(a.amount)
+ FROM acc_trans a
+ JOIN chart c ON (c.id = a.chart_id)
+ $where
+ AND a.amount > 0
+ AND c.gifi_accno = ?) AS credit|;
+
+ }
+
+ $drcr = $dbh->prepare($query);
+
+ # calculate the debit and credit in the period
+ while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $trb{$ref->{accno}}{description} = $ref->{description};
+ $trb{$ref->{accno}}{charttype} = 'A';
+ $trb{$ref->{accno}}{category} = $ref->{category};
+ $trb{$ref->{accno}}{amount} += $ref->{amount};
+
+ }
+ $sth->finish;
+
+ my ($debit, $credit);
+
+ foreach my $accno (sort keys %trb) {
+ $ref = ();
+
+ $ref->{accno} = $accno;
+ map { $ref->{$_} = $trb{$accno}{$_} } qw(description category charttype amount);
+
+ $ref->{balance} = $form->round_amount($balance{$ref->{accno}}, 2);
+
+ if ($trb{$accno}{charttype} eq 'A') {
+ # get DR/CR
+ $drcr->execute($ref->{accno}, $ref->{accno}) || $form->dberror($query);
+
+ ($debit, $credit) = (0,0);
+ while (($debit, $credit) = $drcr->fetchrow_array) {
+ $ref->{debit} += $debit;
+ $ref->{credit} += $credit;
+ }
+ $drcr->finish;
+
+ $ref->{debit} = $form->round_amount($ref->{debit}, 2);
+ $ref->{credit} = $form->round_amount($ref->{credit}, 2);
+
+ }
+
+
+ # add subtotal
+ @accno = grep { $_ le "$ref->{accno}" } @headingaccounts;
+ $accno = pop @accno;
+ if ($accno) {
+ $trb{$accno}{debit} += $ref->{debit};
+ $trb{$accno}{credit} += $ref->{credit};
+ }
+
+ push @{ $form->{TB} }, $ref;
+
+ }
+
+ $dbh->disconnect;
+
+ # debits and credits for headings
+ foreach $accno (@headingaccounts) {
+ foreach $ref (@{ $form->{TB} }) {
+ if ($accno eq $ref->{accno}) {
+ $ref->{debit} = $trb{$accno}{debit};
+ $ref->{credit} = $trb{$accno}{credit};
+ }
+ }
+ }
+
+}
+
+
+
+sub aging {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+ my $invoice = ($form->{arap} eq 'ar') ? 'is' : 'ir';
+
+ $form->{todate} = $form->current_date($myconfig) unless ($form->{todate});
+
+ my $where = "1 = 1";
+ my $name;
+
+ if ($form->{"$form->{ct}_id"}) {
+ $where .= qq| AND ct.id = $form->{"$form->{ct}_id"}|;
+ } else {
+ if ($form->{$form->{ct}}) {
+ $name = $form->like(lc $form->{$form->{ct}});
+ $where .= qq| AND lower(ct.name) LIKE '$name'| if $form->{$form->{ct}};
+ }
+ }
+
+ # select outstanding vendors or customers, depends on $ct
+ my $query = qq|SELECT DISTINCT ct.id, ct.name
+ FROM $form->{ct} ct, $form->{arap} a
+ WHERE $where
+ AND a.$form->{ct}_id = ct.id
+ AND a.paid != a.amount
+ AND (a.transdate <= '$form->{todate}')
+ ORDER BY ct.name|;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror;
+
+ my $buysell = ($form->{arap} eq 'ar') ? 'buy' : 'sell';
+
+ # for each company that has some stuff outstanding
+ while ( my ($id) = $sth->fetchrow_array ) {
+
+ $query = qq|
+
+-- between 0-30 days
+
+ SELECT $form->{ct}.id AS ctid, $form->{ct}.name,
+ addr1, addr2, addr3, addr4, contact,
+ phone as customerphone, fax as customerfax, $form->{ct}number,
+ "invnumber", "transdate",
+ (amount - paid) as "c0", 0.00 as "c30", 0.00 as "c60", 0.00 as "c90",
+ "duedate", invoice, $form->{arap}.id,
+ (SELECT $buysell FROM exchangerate
+ WHERE $form->{arap}.curr = exchangerate.curr
+ AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate
+ FROM $form->{arap}, $form->{ct}
+ WHERE paid != amount
+ AND $form->{arap}.$form->{ct}_id = $form->{ct}.id
+ AND $form->{ct}.id = $id
+ AND (
+ transdate <= (date '$form->{todate}' - interval '0 days')
+ AND transdate >= (date '$form->{todate}' - interval '30 days')
+ )
+
+ UNION
+
+-- between 31-60 days
+
+ SELECT $form->{ct}.id AS ctid, $form->{ct}.name,
+ addr1, addr2, addr3, addr4, contact,
+ phone as customerphone, fax as customerfax, $form->{ct}number,
+ "invnumber", "transdate",
+ 0.00 as "c0", (amount - paid) as "c30", 0.00 as "c60", 0.00 as "c90",
+ "duedate", invoice, $form->{arap}.id,
+ (SELECT $buysell FROM exchangerate
+ WHERE $form->{arap}.curr = exchangerate.curr
+ AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate
+ FROM $form->{arap}, $form->{ct}
+ WHERE paid != amount
+ AND $form->{arap}.$form->{ct}_id = $form->{ct}.id
+ AND $form->{ct}.id = $id
+ AND (
+ transdate < (date '$form->{todate}' - interval '30 days')
+ AND transdate >= (date '$form->{todate}' - interval '60 days')
+ )
+
+ UNION
+
+-- between 61-90 days
+
+ SELECT $form->{ct}.id AS ctid, $form->{ct}.name,
+ addr1, addr2, addr3, addr4, contact,
+ phone as customerphone, fax as customerfax, $form->{ct}number,
+ "invnumber", "transdate",
+ 0.00 as "c0", 0.00 as "c30", (amount - paid) as "c60", 0.00 as "c90",
+ "duedate", invoice, $form->{arap}.id,
+ (SELECT $buysell FROM exchangerate
+ WHERE $form->{arap}.curr = exchangerate.curr
+ AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate
+ FROM $form->{arap}, $form->{ct}
+ WHERE paid != amount
+ AND $form->{arap}.$form->{ct}_id = $form->{ct}.id
+ AND $form->{ct}.id = $id
+ AND (
+ transdate < (date '$form->{todate}' - interval '60 days')
+ AND transdate >= (date '$form->{todate}' - interval '90 days')
+ )
+
+ UNION
+
+-- over 90 days
+
+ SELECT $form->{ct}.id AS ctid, $form->{ct}.name,
+ addr1, addr2, addr3, addr4, contact,
+ phone as customerphone, fax as customerfax, $form->{ct}number,
+ "invnumber", "transdate",
+ 0.00 as "c0", 0.00 as "c30", 0.00 as "c60", (amount - paid) as "c90",
+ "duedate", invoice, $form->{arap}.id,
+ (SELECT $buysell FROM exchangerate
+ WHERE $form->{arap}.curr = exchangerate.curr
+ AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate
+ FROM $form->{arap}, $form->{ct}
+ WHERE paid != amount
+ AND $form->{arap}.$form->{ct}_id = $form->{ct}.id
+ AND $form->{ct}.id = $id
+ AND transdate < (date '$form->{todate}' - interval '90 days')
+
+ ORDER BY
+
+ ctid, invnumber, transdate
+
+ |;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror;
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $ref->{module} = ($ref->{invoice}) ? $invoice : $form->{arap};
+ $ref->{exchangerate} = 1 unless $ref->{exchangerate};
+ push @{ $form->{AG} }, $ref;
+ }
+
+ $sth->finish;
+
+ }
+
+ $sth->finish;
+ # disconnect
+ $dbh->disconnect;
+
+}
+
+
+sub get_customer {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT name, email, cc, bcc
+ FROM $form->{ct} ct
+ WHERE ct.id = $form->{"$form->{ct}_id"}|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror;
+
+ ($form->{$form->{ct}}, $form->{email}, $form->{cc}, $form->{bcc}) = $sth->fetchrow_array;
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub get_taxaccounts {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # get tax accounts
+ my $query = qq|SELECT accno, description
+ FROM chart
+ WHERE link LIKE '%CT_tax%'
+ ORDER BY accno|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror;
+
+ while ( my ($accno, $description) = $sth->fetchrow_array ) {
+ push @{ $form->{taxaccounts} }, "$accno--$description";
+ }
+ $sth->finish;
+
+ # get gifi tax accounts
+ my $query = qq|SELECT DISTINCT ON (g.accno) g.accno, g.description
+ FROM gifi g, chart c
+ WHERE g.accno = c.gifi_accno
+ AND c.link LIKE '%CT_tax%'
+ ORDER BY accno|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror;
+
+ while ( my ($accno, $description) = $sth->fetchrow_array ) {
+ push @{ $form->{gifi_taxaccounts} }, "$accno--$description";
+ }
+ $sth->finish;
+
+ $dbh->disconnect;
+
+}
+
+
+
+sub tax_report {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # build WHERE
+ my $where = qq|WHERE ac.trans_id = a.id
+ AND ac.chart_id = ch.id|;
+
+
+ if ($form->{accno} =~ /^gifi_/) {
+ my ($null, $accno) = split /_/, $form->{accno};
+ $where .= qq| AND ch.gifi_accno = '$accno'|;
+ } else {
+ $where .= qq| AND ch.accno = '$form->{accno}'|;
+ }
+
+ my $table;
+
+ if ($form->{db} eq 'ar') {
+ $where .= " AND n.id = a.customer_id";
+ $table = "customer";
+ }
+ if ($form->{db} eq 'ap') {
+ $where .= " AND n.id = a.vendor_id";
+ $table = "vendor";
+ }
+
+ my $transdate = ($form->{cashbased}) ? "a.datepaid" : "ac.transdate";
+ if ($form->{cashbased}) {
+ $where .= " AND a.amount = a.paid";
+ }
+
+ # if there are any dates construct a where
+ if ($form->{fromdate} || $form->{todate}) {
+ if ($form->{fromdate}) {
+ $where .= " AND $transdate >= '$form->{fromdate}'";
+ }
+ if ($form->{todate}) {
+ $where .= " AND $transdate <= '$form->{todate}'";
+ }
+ }
+
+ my $query = qq|SELECT a.id, a.invoice, $transdate AS transdate, a.invnumber,
+ n.name, a.netamount,|;
+ my $sortorder = join ', ', $form->sort_columns(qw(transdate invnumber name));
+ $sortorder = $form->{sort} unless $sortorder;
+
+ if ($form->{db} eq 'ar') {
+ $query .= " ac.amount AS tax";
+ }
+ if ($form->{db} eq 'ap') {
+ $query .= " ac.amount * -1 AS tax";
+ }
+
+ $query .= qq|
+ FROM acc_trans ac, "$form->{db}" a, "$table" n, chart ch
+ $where
+ ORDER by $sortorder|;
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while ( my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{TR} }, $ref;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub paymentaccounts {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn AutoCommit off
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my $arap = uc $form->{db};
+ $arap .= "_paid";
+
+ # get A(R|P)_paid accounts
+ my $query = qq|SELECT accno, description
+ FROM chart
+ WHERE link LIKE '%$arap%'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{PR} }, $ref;
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+}
+
+
+sub payments {
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database, turn AutoCommit off
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my $ml = 1;
+ if ($form->{db} eq 'ar') {
+ $table = 'customer';
+ $ml = -1;
+ }
+ if ($form->{db} eq 'ap') {
+ $table = 'vendor';
+ }
+
+ my ($query, $sth);
+
+ # cycle through each id
+ foreach my $accno (split(/ /, $form->{paymentaccounts})) {
+
+ $query = qq|SELECT id, accno, description
+ FROM chart
+ WHERE accno = '$accno'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my $ref = $sth->fetchrow_hashref(NAME_lc);
+ push @{ $form->{PR} }, $ref;
+ $sth->finish;
+
+ $query = qq|SELECT c.name, a.invnumber, a.ordnumber,
+ ac.transdate,
+ ac.amount * $ml AS paid, ac.source, a.invoice, a.id,
+ '$form->{db}' AS module
+ FROM $table c, acc_trans ac, $form->{db} a
+ WHERE c.id = a.${table}_id
+ AND ac.trans_id = a.id
+ AND ac.chart_id = $ref->{id}|;
+
+ $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
+ $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
+
+ $query .= qq|
+ UNION
+ SELECT g.description, g.reference, NULL AS ordnumber,
+ ac.transdate,
+ ac.amount * $ml AS paid, ac.source, '0' as invoice, g.id,
+ 'gl' AS module
+ FROM gl g, acc_trans ac
+ WHERE g.id = ac.trans_id
+ AND ac.chart_id = $ref->{id}
+ AND (ac.amount * $ml) > 0
+ |;
+
+ $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
+ $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
+
+
+ my $sortorder = join ', ', $form->sort_columns(qw(name invnumber ordnumber transdate source));
+
+ $query .= " ORDER BY $sortorder";
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $pr = $sth->fetchrow_hashref(NAME_lc)) {
+ push @{ $form->{$ref->{id}} }, $pr;
+ }
+ $sth->finish;
+
+ }
+
+ $dbh->disconnect;
+
+}
+
+
+1;
+
+
diff --git a/sql-ledger/SL/User.pm b/sql-ledger/SL/User.pm
new file mode 100644
index 0000000..d9b463d
--- /dev/null
+++ b/sql-ledger/SL/User.pm
@@ -0,0 +1,692 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#=====================================================================
+#
+# user related functions
+#
+#=====================================================================
+
+package User;
+
+
+sub new {
+ my ($type, $memfile, $login) = @_;
+ my $self = {};
+
+ if ($login ne "") {
+ # check if the file is locked
+ &error("", "$memfile locked!") if (-f "${memfile}.LCK");
+
+ open(MEMBER, "$memfile") or &error("", "$memfile : $!");
+
+ while (<MEMBER>) {
+ if (/^\[$login\]/) {
+ while (<MEMBER>) {
+ last if /^\[/;
+ next if /^(#|\s)/;
+
+ # remove comments
+ s/\s#.*//g;
+
+ # remove any trailing whitespace
+ s/^\s*(.*?)\s*$/$1/;
+
+ ($key, $value) = split /=/, $_, 2;
+
+ $self->{$key} = $value;
+ }
+
+ $self->{login} = $login;
+
+ last;
+ }
+ }
+ close MEMBER;
+ }
+
+ bless $self, $type;
+}
+
+
+sub country_codes {
+
+ my %cc = ();
+ my @language = ();
+
+ # scan the locale directory and read in the LANGUAGE files
+ opendir DIR, "locale";
+
+ my @dir = grep !/(^\.\.?$|\..*)/, readdir DIR;
+
+ foreach my $dir (@dir) {
+ next unless open(FH, "locale/$dir/LANGUAGE");
+ @language = <FH>;
+ close FH;
+
+ $cc{$dir} = "@language";
+ }
+
+ closedir(DIR);
+
+ %cc;
+
+}
+
+
+sub login {
+ my ($self, $form, $userspath) = @_;
+
+
+ if ($self->{login}) {
+
+ if ($self->{password}) {
+ $form->{password} = crypt $form->{password}, substr($self->{login}, 0, 2);
+ if ($self->{password} ne $form->{password}) {
+ return -1;
+ }
+ }
+
+ unless (-e "$userspath/$self->{login}.conf") {
+ $self->create_config("$userspath/$self->{login}.conf");
+ }
+
+ do "$userspath/$self->{login}.conf";
+ $myconfig{dbpasswd} = unpack 'u', $myconfig{dbpasswd};
+
+ # check if database is down
+ my $dbh = DBI->connect($myconfig{dbconnect}, $myconfig{dbuser}, $myconfig{dbpasswd}) or $self->error(DBI::errstr);
+
+ # we got a connection, check the version
+ my $query = qq|SELECT version FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ my ($dbversion) = $sth->fetchrow_array;
+ $sth->finish;
+
+ # add login to employee table if it does not exist
+ # no error check for employee table, ignore if it does not exist
+ $query = qq|SELECT id FROM employee WHERE login = '$self->{login}'|;
+ $sth = $dbh->prepare($query);
+ $sth->execute;
+
+ my ($login) = $sth->fetchrow_array;
+ $sth->finish;
+
+ if (!$login) {
+ $query = qq|INSERT INTO employee (login, name, workphone)
+ VALUES ('$self->{login}', '$myconfig{name}', '$myconfig{tel}')|;
+ $dbh->do($query);
+ }
+ $dbh->disconnect;
+
+ if ($form->{dbversion} ne $dbversion) {
+ return -2;
+ }
+
+ } else {
+ return -3;
+ }
+
+}
+
+
+
+sub dbconnect_vars {
+ my ($form, $db) = @_;
+
+ my %dboptions = (
+ 'Pg' => {
+ 'yy-mm-dd' => 'set DateStyle to \'ISO\'',
+ 'mm/dd/yy' => 'set DateStyle to \'SQL, US\'',
+ 'mm-dd-yy' => 'set DateStyle to \'POSTGRES, US\'',
+ 'dd/mm/yy' => 'set DateStyle to \'SQL, EUROPEAN\'',
+ 'dd-mm-yy' => 'set DateStyle to \'POSTGRES, EUROPEAN\'',
+ 'dd.mm.yy' => 'set DateStyle to \'GERMAN\''
+ },
+ 'Oracle' => {
+ 'yy-mm-dd' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'YY-MM-DD\'',
+ 'mm/dd/yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'MM/DD/YY\'',
+ 'mm-dd-yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'MM-DD-YY\'',
+ 'dd/mm/yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD/MM/YY\'',
+ 'dd-mm-yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD-MM-YY\'',
+ 'dd.mm.yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD.MM.YY\'',
+ }
+ );
+
+ $form->{dboptions} = $dboptions{$form->{dbdriver}}{$form->{dateformat}};
+
+ if ($form->{dbdriver} eq 'Pg') {
+ $form->{dbconnect} = "dbi:Pg:dbname=$db";
+ }
+
+ if ($form->{dbdriver} eq 'Oracle') {
+ $form->{dbconnect} = "dbi:Oracle:sid=$form->{sid}";
+ }
+
+ if ($form->{dbhost}) {
+ $form->{dbconnect} .= ";host=$form->{dbhost}";
+ }
+ if ($form->{dbport}) {
+ $form->{dbconnect} .= ";port=$form->{dbport}";
+ }
+
+}
+
+
+sub dbdrivers {
+
+ my @drivers = DBI->available_drivers();
+
+ return (grep { /(Pg|Oracle)$/ } @drivers);
+
+}
+
+
+sub dbsources {
+ my ($self, $form) = @_;
+
+ my @dbsources = ();
+ my ($sth, $query);
+
+ $form->{dbdefault} = $form->{dbuser} unless $form->{dbdefault};
+ $form->{sid} = $form->{dbdefault};
+ &dbconnect_vars($form, $form->{dbdefault});
+
+ my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+
+
+ if ($form->{dbdriver} eq 'Pg') {
+
+ $query = qq|SELECT datname FROM pg_database|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my ($db) = $sth->fetchrow_array) {
+
+ if ($form->{only_acc_db}) {
+
+ next if ($db =~ /^template/);
+
+ &dbconnect_vars($form, $db);
+ my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+
+ $query = qq|SELECT tablename FROM pg_tables
+ WHERE tablename = 'defaults'
+ AND tableowner = '$form->{dbuser}'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ if ($sth->fetchrow_array) {
+ push @dbsources, $db;
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ next;
+ }
+ push @dbsources, $db;
+ }
+ }
+
+ if ($form->{dbdriver} eq 'Oracle') {
+ if ($form->{only_acc_db}) {
+ $query = qq|SELECT owner FROM dba_objects
+ WHERE object_name = 'DEFAULTS'
+ AND object_type = 'TABLE'|;
+ } else {
+ $query = qq|SELECT username FROM dba_users|;
+ }
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my ($db) = $sth->fetchrow_array) {
+ push @dbsources, $db;
+ }
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+ return @dbsources;
+
+}
+
+
+sub dbcreate {
+ my ($self, $form) = @_;
+
+ my %dbcreate = ( 'Pg' => qq|CREATE DATABASE "$form->{db}"|,
+ 'Oracle' => qq|CREATE USER "$form->{db}" DEFAULT TABLESPACE USERS TEMPORARY TABLESPACE TEMP IDENTIFIED BY "$form->{db}"|);
+
+ $dbcreate{Pg} .= " WITH ENCODING = '$form->{encoding}'" if $form->{encoding};
+
+ $form->{sid} = $form->{dbdefault};
+ &dbconnect_vars($form, $form->{dbdefault});
+ my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+ my $query = qq|$dbcreate{$form->{dbdriver}}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ if ($form->{dbdriver} eq 'Oracle') {
+ $query = qq|GRANT CONNECT,RESOURCE TO "$form->{db}"|;
+ $dbh->do($query) || $form->dberror($query);
+ }
+ $dbh->disconnect;
+
+
+ # setup variables for the new database
+ if ($form->{dbdriver} eq 'Oracle') {
+ $form->{dbuser} = $form->{db};
+ $form->{dbpasswd} = $form->{db};
+ }
+
+
+ &dbconnect_vars($form, $form->{db});
+
+ $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+
+ # create the tables
+ my $filename = qq|sql/$form->{dbdriver}-tables.sql|;
+ $self->processquery($form, $dbh, $filename);
+
+ # load gifi
+ ($filename) = split /_/, $form->{chart};
+ $filename =~ s/_//;
+ $self->processquery($form, $dbh, "sql/${filename}-gifi.sql");
+
+ # load chart of accounts
+ $filename = qq|sql/$form->{chart}-chart.sql|;
+ $self->processquery($form, $dbh, $filename);
+
+ # create indices
+ $filename = qq|sql/$form->{dbdriver}-indices.sql|;
+ $self->processquery($form, $dbh, $filename);
+
+ $dbh->disconnect;
+
+}
+
+
+
+sub processquery {
+ my ($self, $form, $dbh, $filename) = @_;
+
+ return unless (-f $filename);
+
+ open(FH, "$filename") or $form->error("$filename : $!\n");
+ my $query = "";
+
+ while (<FH>) {
+ $query .= $_;
+
+ if (/;\s*$/) {
+ # strip ;... Oracle doesn't like it
+ $query =~ s/;\s*$//;
+ $dbh->do($query) || $form->dberror($query);
+ $query = "";
+ }
+ }
+ close FH;
+
+}
+
+
+
+sub dbdelete {
+ my ($self, $form) = @_;
+
+ my %dbdelete = ( 'Pg' => qq|DROP DATABASE "$form->{db}"|,
+ 'Oracle' => qq|DROP USER $form->{db} CASCADE|
+ );
+
+ $form->{sid} = $form->{dbdefault};
+ &dbconnect_vars($form, $form->{dbdefault});
+ my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+ my $query = qq|$dbdelete{$form->{dbdriver}}|;
+ $dbh->do($query) || $form->dberror($query);
+
+ $dbh->disconnect;
+
+}
+
+
+
+sub dbsources_unused {
+ my ($self, $form, $memfile) = @_;
+
+ my @dbexcl = ();
+ my @dbsources = ();
+
+ $form->error('File locked!') if (-f "${memfile}.LCK");
+
+ # open members file
+ open(FH, "$memfile") or $form->error("$memfile : $!");
+
+ while (<FH>) {
+ if (/^dbname=/) {
+ my ($null,$item) = split /=/;
+ push @dbexcl, $item;
+ }
+ }
+
+ close FH;
+
+ $form->{only_acc_db} = 1;
+ my @db = &dbsources("", $form);
+
+ push @dbexcl, $form->{dbdefault};
+
+ foreach $item (@db) {
+ unless (grep /$item$/, @dbexcl) {
+ push @dbsources, $item;
+ }
+ }
+
+ return @dbsources;
+
+}
+
+
+sub dbneedsupdate {
+ my ($self, $form) = @_;
+
+ my %dbsources = ();
+ my $query;
+
+ $form->{sid} = $form->{dbdefault};
+ &dbconnect_vars($form, $form->{dbdefault});
+
+ my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+
+ if ($form->{dbdriver} eq 'Pg') {
+
+ $query = qq|SELECT d.datname FROM pg_database d, pg_user u
+ WHERE d.datdba = u.usesysid
+ AND u.usename = '$form->{dbuser}'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my ($db) = $sth->fetchrow_array) {
+
+ next if ($db =~ /^template/);
+
+ &dbconnect_vars($form, $db);
+
+ my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+
+ $query = qq|SELECT tablename FROM pg_tables
+ WHERE tablename = 'defaults'|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ if ($sth->fetchrow_array) {
+ $query = qq|SELECT version FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+
+ if (my ($version) = $sth->fetchrow_array) {
+ $dbsources{$db} = $version;
+ }
+ $sth->finish;
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ }
+ $sth->finish;
+ }
+
+
+ if ($form->{dbdriver} eq 'Oracle') {
+ $query = qq|SELECT owner FROM dba_objects
+ WHERE object_name = 'DEFAULTS'
+ AND object_type = 'TABLE'|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my ($db) = $sth->fetchrow_array) {
+
+ $form->{dbuser} = $db;
+ &dbconnect_vars($form, $db);
+
+ my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+
+ $query = qq|SELECT version FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute;
+
+ if (my ($version) = $sth->fetchrow_array) {
+ $dbsources{$db} = $version;
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ }
+ $sth->finish;
+ }
+
+ $dbh->disconnect;
+
+ %dbsources;
+
+}
+
+
+sub dbupdate {
+ my ($self, $form) = @_;
+
+ $form->{sid} = $form->{dbdefault};
+
+ my @upgradescripts = ();
+ my $query;
+
+ if ($form->{dbupdate}) {
+ # read update scripts into memory
+ opendir SQLDIR, "sql/." or $form-error($!);
+ @upgradescripts = sort grep /$form->{dbdriver}-upgrade-.*?\.sql/, readdir SQLDIR;
+ closedir SQLDIR;
+ }
+
+
+ foreach my $db (split / /, $form->{dbupdate}) {
+
+ next unless $form->{$db};
+
+ # strip db from dataset
+ $db =~ s/^db//;
+ &dbconnect_vars($form, $db);
+
+ my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+
+ # check version
+ $query = qq|SELECT version FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ # no error check, let it fall through
+ $sth->execute;
+
+ my $version = $sth->fetchrow_array;
+ $sth->finish;
+
+ next unless $version;
+
+ foreach my $upgradescript (@upgradescripts) {
+ my $a = $upgradescript;
+ $a =~ s/(^$form->{dbdriver}-upgrade-|\.sql$)//g;
+
+ my ($mindb, $maxdb) = split /-/, $a;
+
+ next if ($version ge $maxdb);
+
+ # if there is no upgrade script exit
+ last if ($version lt $mindb);
+
+ # apply upgrade
+ $self->processquery($form, $dbh, "sql/$upgradescript");
+
+ $version = $maxdb;
+
+ }
+
+ $dbh->disconnect;
+
+ }
+}
+
+
+
+sub create_config {
+ my ($self, $filename) = @_;
+
+
+ @config = &config_vars;
+
+ open(CONF, ">$filename") or $self->error("$filename : $!");
+
+ # create the config file
+ print CONF qq|# configuration file for $self->{login}
+
+\%myconfig = (
+|;
+
+ foreach $key (sort @config) {
+ $self->{$key} =~ s/'/\\'/g;
+ print CONF qq| $key => '$self->{$key}',\n|;
+ }
+
+
+ print CONF qq|);\n\n|;
+
+ close CONF;
+
+}
+
+
+sub save_member {
+ my ($self, $memberfile, $userspath) = @_;
+
+ my $newmember = 1;
+
+ # format dbconnect and dboptions string
+ map { $self->{$_} = lc $self->{$_} } qw(dbname host);
+ &dbconnect_vars($self, $self->{dbname});
+
+ $self->error('File locked!') if (-f "${memberfile}.LCK");
+ open(FH, ">${memberfile}.LCK") or $self->error("${memberfile}.LCK : $!");
+ close(FH);
+
+ open(CONF, "+<$memberfile") or $self->error("$memberfile : $!");
+
+ @config = <CONF>;
+
+ seek(CONF, 0, 0);
+ truncate(CONF, 0);
+
+ while ($line = shift @config) {
+ if ($line =~ /^\[$self->{login}\]/) {
+ $newmember = 0;
+ last;
+ }
+ print CONF $line;
+ }
+
+ # remove everything up to next login or EOF
+ while ($line = shift @config) {
+ last if ($line =~ /^\[/);
+ }
+
+ # this one is either the next login or EOF
+ print CONF $line;
+
+ while ($line = shift @config) {
+ print CONF $line;
+ }
+
+ print CONF qq|[$self->{login}]\n|;
+
+ if ((($self->{dbpasswd} ne $self->{old_dbpasswd}) || $newmember) && $self->{root}) {
+ $self->{dbpasswd} = pack 'u', $self->{dbpasswd};
+ chop $self->{dbpasswd};
+ }
+
+ if ($self->{password} ne $self->{old_password}) {
+ $self->{password} = crypt $self->{password}, substr($self->{login}, 0, 2) if $self->{password};
+ }
+
+ if ($self->{'root login'}) {
+ @config = ("password");
+ } else {
+ @config = &config_vars;
+ }
+
+ # replace \r\n with \n
+ $self->{address} =~ s/\r\n/\\n/g if $self->{address};
+ $self->{signature} =~ s/\r\n/\\n/g if $self->{signature};
+
+ foreach $key (sort @config) {
+ print CONF qq|$key=$self->{$key}\n|;
+ }
+
+ print CONF "\n";
+ close CONF;
+ unlink "${memberfile}.LCK";
+
+ # create conf file
+ $self->create_config("$userspath/$self->{login}.conf") unless $self->{'root login'};
+
+}
+
+
+sub config_vars {
+
+ my @conf = qw(acs address admin businessnumber charset company countrycode
+ currency dateformat dbconnect dbdriver dbhost dbport dboptions
+ dbname dbuser dbpasswd email fax name numberformat password
+ printer sid shippingpoint signature stylesheet tel templates
+ vclimit);
+
+ @conf;
+
+}
+
+
+sub error {
+ my ($self, $msg) = @_;
+
+ if ($ENV{HTTP_USER_AGENT}) {
+ print qq|Content-Type: text/html
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+
+<body bgcolor=ffffff>
+
+<h2><font color=red>Error!</font></h2>
+<p><b>$msg</b>|;
+
+ }
+
+ die "Error: $msg\n";
+
+}
+
+
+1;
+
diff --git a/sql-ledger/VERSION b/sql-ledger/VERSION
new file mode 100644
index 0000000..815e68d
--- /dev/null
+++ b/sql-ledger/VERSION
@@ -0,0 +1 @@
+2.0.8
diff --git a/sql-ledger/am.pl b/sql-ledger/am.pl
new file mode 100755
index 0000000..f69a15a
--- /dev/null
+++ b/sql-ledger/am.pl
@@ -0,0 +1,126 @@
+#!/usr/bin/perl
+#
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#######################################################################
+#
+# this script is the frontend called from bin/$terminal/$script
+# all the accounting modules are linked to this script which in
+# turn execute the same script in bin/$terminal/
+#
+#######################################################################
+
+# setup defaults, these are overidden by sql-ledger.conf
+# DO NOT CHANGE
+$userspath = "users";
+$templates = "templates";
+$memberfile = "users/members";
+$sendmail = "| /usr/sbin/sendmail -t";
+########## end ###########################################
+
+
+$| = 1;
+
+use SL::Form;
+
+eval { require "sql-ledger.conf"; };
+
+
+$form = new Form;
+
+
+# name of this script
+$0 =~ tr/\\/\//;
+$pos = rindex $0, '/';
+$script = substr($0, $pos + 1);
+
+# we use $script for the language module
+$form->{script} = $script;
+# strip .pl for translation files
+$script =~ s/\.pl//;
+
+# pull in DBI
+use DBI;
+
+# check for user config file, could be missing or ???
+eval { require("$userspath/$form->{login}.conf"); };
+if ($@) {
+ $locale = new Locale "$language", "$script";
+
+ $form->{callback} = "";
+ $msg1 = $locale->text('You are logged out!');
+ $msg2 = $locale->text('Login');
+ $form->redirect("$msg1 <p><a href=login.pl target=_top>$msg2</a>");
+}
+
+
+$myconfig{dbpasswd} = unpack 'u', $myconfig{dbpasswd};
+map { $form->{$_} = $myconfig{$_} } qw(stylesheet charset) unless (($form->{action} eq "save") && ($form->{type} eq 'preferences'));
+
+
+# locale messages
+$locale = new Locale "$myconfig{countrycode}", "$script";
+
+
+# check password
+$form->error($locale->text('Incorrect Password!')) if ($form->{password} ne $myconfig{password});
+
+
+$form->{path} =~ s/\.\.\///g;
+if ($form->{path} !~ /^bin\//) {
+ $form->error($locale->text('Invalid path!')."\n");
+}
+
+# did sysadmin lock us out
+if (-e "$userspath/nologin") {
+ $form->error($locale->text('System currently down for maintenance!'));
+}
+
+
+# pull in the main code
+require "$form->{path}/$form->{script}";
+
+# customized scripts
+if (-f "$form->{path}/custom_$form->{script}") {
+ eval { require "$form->{path}/custom_$form->{script}"; };
+ $form->error($@) if ($@);
+}
+
+# customized scripts for login
+if (-f "$form->{path}/$form->{login}_$form->{script}") {
+ eval { require "$form->{path}/$form->{login}_$form->{script}"; };
+ $form->error($@) if ($@);
+}
+
+if ($form->{action}) {
+ # window title bar, user info
+ $form->{titlebar} = "SQL-Ledger ".$locale->text('Version'). " $form->{version} - $myconfig{name} - $myconfig{dbname}";
+
+ &{ $locale->findsub($form->{action}) };
+} else {
+ $form->error($locale->text('action= not defined!'));
+}
+
+
+# end
+
diff --git a/sql-ledger/bin/lynx/menu.pl b/sql-ledger/bin/lynx/menu.pl
new file mode 100644
index 0000000..5599716
--- /dev/null
+++ b/sql-ledger/bin/lynx/menu.pl
@@ -0,0 +1,128 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors: Christopher Browne
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#######################################################################
+#
+# menu for text based browsers (lynx)
+#
+# CHANGE LOG:
+# DS. 2000-07-04 Created
+# DS. 2001-08-07 access control
+# CBB 2002-02-09 Refactored HTML out to subroutines
+#######################################################################
+
+$menufile = "menu.ini";
+use SL::Menu;
+
+
+1;
+# end of main
+
+
+
+sub display {
+
+ $menu = new Menu "$menufile";
+
+ @menuorder = $menu->access_control(\%myconfig);
+
+ $form->{title} = "SQL-Ledger $form->{version}";
+
+ $form->header;
+
+ $offset = int (21 - $#menuorder)/2;
+
+ print "<pre>";
+ print "\n" x $offset;
+ print "</pre>";
+
+ print qq|<center><table>|;
+
+ map { print "<tr><td>".$menu->menuitem(\%myconfig, \%$form, $_).$locale->text($_).qq|</a></td></tr>|; } @menuorder;
+
+ print qq'
+</table>
+
+</body>
+</html>
+';
+
+ # display the company logo
+# $argv = "login=$form->{login}&password=$form->{password}&path=$form->{path}&action=company_logo&noheader=1";
+# exec "./login.pl", $argv;
+
+}
+
+
+sub section_menu {
+
+ $menu = new Menu "$menufile", $form->{level};
+
+ # build tiered menus
+ @menuorder = $menu->access_control(\%myconfig, $form->{level});
+
+ foreach $item (@menuorder) {
+ $a = $item;
+ $item =~ s/^$form->{level}--//;
+ push @neworder, $a unless ($item =~ /--/);
+ }
+ @menuorder = @neworder;
+
+ $level = $form->{level};
+ $level =~ s/--/ /g;
+
+ $form->{title} = $locale->text($level);
+
+ $form->header;
+
+ $offset = int (21 - $#menuorder)/2;
+ print "<pre>";
+ print "\n" x $offset;
+ print "</pre>";
+
+ print qq|<center><table>|;
+
+ foreach $item (@menuorder) {
+ $label = $item;
+ $label =~ s/$form->{level}--//g;
+
+ # remove target
+ $menu->{$item}{target} = "";
+
+ print "<tr><td>".$menu->menuitem(\%myconfig, \%$form, $item, $form->{level}).$locale->text($label)."</a></td></tr>";
+ }
+
+ print qq'</table>
+
+</body>
+</html>
+';
+
+}
+
+
+sub acc_menu {
+
+ &section_menu;
+
+}
+
diff --git a/sql-ledger/bin/mozilla/admin.pl b/sql-ledger/bin/mozilla/admin.pl
new file mode 100644
index 0000000..39247b5
--- /dev/null
+++ b/sql-ledger/bin/mozilla/admin.pl
@@ -0,0 +1,1504 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# setup module
+# add/edit/delete users
+#
+#======================================================================
+
+$menufile = "menu.ini";
+
+use SL::Form;
+use SL::User;
+
+
+$form = new Form;
+
+$locale = new Locale $language, "admin";
+
+eval { require DBI; };
+$form->error($locale->text('DBI not installed!')) if ($@);
+
+
+# customization
+if (-f "$form->{path}/custom_$form->{script}") {
+ eval { require "$form->{path}/custom_$form->{script}"; };
+ $form->error($@) if ($@);
+}
+
+
+if (-f "css/sql-ledger.css") {
+ $form->{stylesheet} = "sql-ledger.css";
+}
+
+
+if ($form->{action}) {
+
+ $subroutine = $locale->findsub($form->{action});
+
+ if ($subroutine eq 'login') {
+ if ($form->{rpw}) {
+ $form->{rpw} = crypt $form->{rpw}, "ro";
+ }
+ }
+
+ &check_password;
+
+ &$subroutine;
+
+} else {
+
+ # if there are no drivers bail out
+ $form->error($locale->text('No Database Drivers available!')) unless (User->dbdrivers);
+
+ # create memberfile
+ if (! -f $memberfile) {
+ open(FH, ">$memberfile") or $form->error("$memberfile : $!");
+ print FH qq|# SQL-Ledger Accounting members
+
+[root login]
+password=
+
+|;
+ close(FH);
+ }
+
+ &adminlogin;
+
+}
+
+1;
+# end
+
+
+sub adminlogin {
+
+ $form->{title} = qq|SQL-Ledger $form->{version} |.$locale->text('Administration');
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+
+<div align=center>
+
+<a href="http://www.sql-ledger.org"><img src=sql-ledger.png border=0></a>
+<h1 class=login>|.$locale->text('Version').qq| $form->{version}<p>|.$locale->text('Administration').qq|</h1>
+
+<form method=post action="$form->{script}">
+
+<table>
+ <tr>
+ <th>|.$locale->text('Password').qq|</th>
+ <td><input type=password name=rpw></td>
+ <td><input type=submit class=submit name=action value="|.$locale->text('Login').qq|"></td>
+ </tr>
+<input type=hidden name=action value=login>
+<input type=hidden name=root value="root login">
+<input type=hidden name=path value=$form->{path}>
+</table>
+
+
+</form>
+
+<a href=http://www.sql-ledger.org>SQL-Ledger |.$locale->text('website').qq|</a>
+
+</div>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+
+sub login {
+
+ &list_users;
+
+}
+
+
+
+sub add_user {
+
+ $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Administration')." / ".$locale->text('Add User');
+
+ $form->{Oracle_sid} = $sid;
+ $form->{Oracle_dbport} = '1521';
+ $form->{Oracle_dbhost} = `hostname`;
+
+ if (-f "css/sql-ledger.css") {
+ $myconfig->{stylesheet} = "sql-ledger.css";
+ }
+ $myconfig->{vclimit} = 200;
+
+ &form_header;
+ &form_footer;
+
+}
+
+
+
+sub edit {
+
+ $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Administration')." / ".$locale->text('Edit User');
+ $form->{edit} = 1;
+
+ &form_header;
+ &form_footer;
+
+}
+
+
+sub form_footer {
+
+ if ($form->{edit}) {
+ $delete = qq|<input type=submit class=submit name=action value="|.$locale->text('Delete').qq|">
+<input type=hidden name=edit value=1>|;
+ }
+
+ print qq|
+
+<input name=callback type=hidden value="$form->{script}?action=list_users&path=$form->{path}&root=$form->{root}&rpw=$form->{rpw}">
+<input type=hidden name=root value="$form->{root}">
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=rpw value=$form->{rpw}>
+
+<input type=submit class=submit name=action value="|.$locale->text('Save').qq|">
+$delete
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub list_users {
+
+ $form->error("$memberfile : ".$locale->text('locked!')) if (-f "${memberfile}.LCK");
+
+ open(FH, "$memberfile") or $form->error("$memberfile : $!");
+
+ while (<FH>) {
+ chop;
+
+ if (/^\[.*\]/) {
+ $login = $_;
+ $login =~ s/(\[|\])//g;
+ }
+
+ if (/^(name=|company=|templates=|dbuser=|dbdriver=|dbname=|dbhost=)/) {
+ chop ($var = $&);
+ ($null, $member{$login}{$var}) = split /=/, $_, 2;
+ }
+ }
+
+ close(FH);
+
+# type=submit $locale->text('Pg Database Administration')
+# type=submit $locale->text('Oracle Database Administration')
+
+ foreach $item (User->dbdrivers) {
+ $dbdrivers .= qq|<input name=action type=submit class=submit value="|.$locale->text("$item Database Administration").qq|">|;
+ }
+
+
+ $column_header{login} = qq|<th>|.$locale->text('Login').qq|</th>|;
+ $column_header{name} = qq|<th>|.$locale->text('Name').qq|</th>|;
+ $column_header{company} = qq|<th>|.$locale->text('Company').qq|</th>|;
+ $column_header{dbdriver} = qq|<th>|.$locale->text('Driver').qq|</th>|;
+ $column_header{dbhost} = qq|<th>|.$locale->text('Host').qq|</th>|;
+ $column_header{dataset} = qq|<th>|.$locale->text('Dataset').qq|</th>|;
+ $column_header{templates} = qq|<th>|.$locale->text('Templates').qq|</th>|;
+
+ @column_index = qw(login name company dbdriver dbhost dataset templates);
+
+ $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Administration');
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <tr class=listheading>
+ <th>$form->{title}</th>
+ </tr>
+ <tr size=5></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>|;
+
+ map { print "$column_header{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+foreach $key (sort keys %member) {
+ $href = "$script?action=edit&login=$key&path=$form->{path}&root=$form->{root}&rpw=$form->{rpw}";
+ $href =~ s/ /%20/g;
+
+ $member{$key}{templates} =~ s/^$templates\///;
+ $member{$key}{dbhost} = $locale->text('localhost') unless $member{$key}{dbhost};
+ $member{$key}{dbname} = $member{$key}{dbuser} if ($member{$key}{dbdriver} eq 'Oracle');
+
+ $column_data{login} = qq|<td><a href=$href>$key</a></td>|;
+ $column_data{name} = qq|<td>$member{$key}{name}</td>|;
+ $column_data{company} = qq|<td>$member{$key}{company}</td>|;
+ $column_data{dbdriver} = qq|<td>$member{$key}{dbdriver}</td>|;
+ $column_data{dbhost} = qq|<td>$member{$key}{dbhost}</td>|;
+ $column_data{dataset} = qq|<td>$member{$key}{dbname}</td>|;
+ $column_data{templates} = qq|<td>$member{$key}{templates}</td>|;
+
+ $i++; $i %= 2;
+ print qq|
+ <tr class=listrow$i>|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>|;
+}
+
+
+print qq|
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=rpw value=$form->{rpw}>
+<input type=hidden name=root value="$form->{root}">
+
+<br><input type=submit class=submit name=action value="|.$locale->text('Add User').qq|">
+<input type=submit class=submit name=action value="|.$locale->text('Change Admin Password').qq|">
+
+$dbdrivers
+
+</form>
+
+|.$locale->text('Click on login name to edit!').qq|
+<br>
+|.$locale->text('To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.').qq|
+
+<p>
+
+<form method=post action=login.pl>
+
+<table border=0 width=100%>
+ <tr class=listheading>
+ <th>SQL-Ledger |.$locale->text('Accounting')." ".$locale->text('Login').qq|</th>
+ </tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Name').qq|</th>
+ <td><input class=login name=login></td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Password').qq|</th>
+ <td><input class=login type=password name=password></td>
+ <td><input type=submit name=action value="|.$locale->text('Login').qq|"></td>
+ </tr>
+<input type=hidden name=path value=$form->{path}>
+ </table>
+ </td>
+ </tr>
+</table>
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+
+sub form_header {
+
+ # if there is a login, get user
+ if ($form->{login}) {
+ # get user
+ $myconfig = new User "$memberfile", "$form->{login}";
+
+ $myconfig->{signature} =~ s/\\n/\r\n/g;
+ $myconfig->{address} =~ s/\\n/\r\n/g;
+
+ # strip basedir from templates directory
+ $myconfig->{templates} =~ s/^$templates\///;
+
+ $myconfig->{dbpasswd} = unpack 'u', $myconfig->{dbpasswd};
+ }
+
+
+ foreach $item (qw(mm-dd-yy mm/dd/yy dd-mm-yy dd/mm/yy dd.mm.yy yyyy-mm-dd)) {
+ $dateformat .= ($item eq $myconfig->{dateformat}) ? "<option selected>$item\n" : "<option>$item\n";
+ }
+
+ foreach $item (qw(1,000.00 1000.00 1.000,00 1000,00)) {
+ $numberformat .= ($item eq $myconfig->{numberformat}) ? "<option selected>$item\n" : "<option>$item\n";
+ }
+
+
+ %countrycodes = User->country_codes;
+ $countrycodes = "";
+ foreach $key (sort { $countrycodes{$a} cmp $countrycodes{$b} } keys %countrycodes) {
+ $countrycodes .= ($myconfig->{countrycode} eq $key) ? "<option selected value=$key>$countrycodes{$key}" : "<option value=$key>$countrycodes{$key}";
+ }
+ $countrycodes = qq|<option value="">American English\n$countrycodes|;
+
+ # is there a templates basedir
+ if (! -d "$templates") {
+ $form->error($locale->text('Directory').": $templates ".$locale->text('does not exist'));
+ }
+
+ opendir TEMPLATEDIR, "$templates/." or $form->error("$templates : $!");
+ @all = grep !/^\.\.?$/, readdir TEMPLATEDIR;
+ closedir TEMPLATEDIR;
+
+ @allhtml = sort grep /\.html/, @all;
+ @alldir = grep !/\.(html|tex)$/, @all;
+
+ @allhtml = reverse grep !/Default/, @allhtml;
+ push @allhtml, 'Default';
+ @allhtml = reverse @allhtml;
+
+ foreach $item (@alldir) {
+ if ($item eq $myconfig->{templates}) {
+ $usetemplates .= qq|<option selected>$item\n|;
+ } else {
+ $usetemplates .= qq|<option>$item\n|;
+ }
+ }
+
+ $lastitem = $allhtml[0];
+ $lastitem =~ s/-.*//g;
+ $mastertemplates = qq|<option>$lastitem\n|;
+ foreach $item (@allhtml) {
+ $item =~ s/-.*//g;
+
+ if ($item ne $lastitem) {
+ $mastertemplates .= qq|<option>$item\n|;
+ $lastitem = $item;
+ }
+ }
+
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr class=listheading><th colspan=2>$form->{title}</th></tr>
+ <tr size=5></tr>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Login').qq|</th>
+ <td><input name=login value="$myconfig->{login}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Password').qq|</th>
+ <td><input type=password name=password size=8 value=$myconfig->{password}></td>
+ <input type=hidden name=old_password value=$myconfig->{password}>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Name').qq|</th>
+ <td><input name=name size=15 value="$myconfig->{name}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('E-mail').qq|</th>
+ <td><input name=email size=30 value="$myconfig->{email}"></td>
+ </tr>
+ <tr valign=top>
+ <th align=right>|.$locale->text('Signature').qq|</th>
+ <td><textarea name=signature rows=3 cols=35>$myconfig->{signature}</textarea></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Phone').qq|</th>
+ <td><input name=tel size=14 value="$myconfig->{tel}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Fax').qq|</th>
+ <td><input name=fax size=14 value="$myconfig->{fax}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Company').qq|</th>
+ <td><input name=company size=35 value="$myconfig->{company}"></td>
+ </tr>
+ <tr valign=top>
+ <th align=right>|.$locale->text('Address').qq|</th>
+ <td><textarea name=address rows=4 cols=35>$myconfig->{address}</textarea></td>
+ </tr>
+ </table>
+ </td>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Date Format').qq|</th>
+ <td><select name=dateformat>$dateformat</select></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Number Format').qq|</th>
+ <td><select name=numberformat>$numberformat</select></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Dropdown Limit').qq|</th>
+ <td><input name=vclimit value="$myconfig->{vclimit}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Language').qq|</th>
+ <td><select name=countrycode>$countrycodes</select></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Character Set').qq|</th>
+ <td><input name=charset value="$myconfig->{charset}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Stylesheet').qq|</th>
+ <td><input name=userstylesheet value="$myconfig->{stylesheet}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Printer').qq|</th>
+ <td><input name=printer size=20 value="$myconfig->{printer}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Ship via').qq|</th>
+ <td><input name=shippingpoint size=15 value="$myconfig->{shippingpoint}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Use Templates').qq|</th>
+ <td><select name=usetemplates>$usetemplates</select></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('New Templates').qq|</th>
+ <td><input name=newtemplates></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Setup Templates').qq|</th>
+ <td><select name=mastertemplates>$mastertemplates</select></td>
+ </tr>
+ <input type=hidden name=templates value=$myconfig->{templates}>
+ </table>
+ </td>
+ </tr>
+ <tr class=listheading>
+ <th colspan=2>|.$locale->text('Database').qq|</th>
+ </tr>|;
+
+ # list section for database drivers
+ foreach $item (User->dbdrivers) {
+
+ print qq|
+ <tr>
+ <td colspan=2>
+ <table>
+ <tr>|;
+
+ $checked = "";
+ if ($myconfig->{dbdriver} eq $item) {
+ map { $form->{"${item}_$_"} = $myconfig->{$_} } qw(dbhost dbport dbuser dbpasswd dbname sid);
+ $checked = "checked";
+ }
+
+ print qq|
+ <th align=right>|.$locale->text('Driver').qq|</th>
+ <td><input name=dbdriver type=radio class=radio value=$item $checked>&nbsp;$item</td>
+ <th align=right>|.$locale->text('Host').qq|</th>
+ <td><input name="${item}_dbhost" value=$form->{"${item}_dbhost"}></td>
+ </tr>
+ <tr>|;
+
+ if ($item eq 'Pg') {
+ print qq|
+ <th align=right>|.$locale->text('Dataset').qq|</th>
+ <td><input name=Pg_dbname size=10 value=$form->{Pg_dbname}></td>
+ <th align=right>|.$locale->text('Port').qq|</th>
+ <td><input name=Pg_dbport size=4 value=$form->{Pg_dbport}></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('User').qq|</th>
+ <td><input name="${item}_dbuser" size=10 value=$form->{"${item}_dbuser"}></td>
+ <th align=right>|.$locale->text('Password').qq|</th>
+ <td><input name="${item}_dbpasswd" type=password size=10 value=$form->{"${item}_dbpasswd"}></td>
+ </tr>|;
+
+ }
+
+ if ($item eq 'Oracle') {
+ print qq|
+ <th align=right>SID</th>
+ <td><input name=Oracle_sid value=$form->{Oracle_sid}></td>
+ <th align=right>|.$locale->text('Port').qq|</th>
+ <td><input name=Oracle_dbport size=4 value=$form->{Oracle_dbport}></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Dataset').qq|</th>
+ <td><input name="${item}_dbuser" size=10 value=$form->{"${item}_dbuser"}></td>
+ <th align=right>|.$locale->text('Password').qq|</th>
+ <td><input name="${item}_dbpasswd" type=password size=10 value=$form->{"${item}_dbpasswd"}></td>
+
+ </tr>|;
+ }
+
+
+ print qq|
+ <input type=hidden name=old_dbpasswd value=$myconfig->{dbpasswd}>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=2><hr size=2 noshade></td>
+ </tr>
+|;
+
+ }
+
+
+ # access control
+ open(FH, $menufile) or $form->error("$menufile : $!");
+ # scan for first menu level
+ @a = <FH>;
+ close(FH);
+
+ if (open(FH, "custom_$menufile")) {
+ push @a, <FH>;
+ }
+ close(FH);
+
+ foreach $item (@a) {
+ next unless $item =~ /\[/;
+ next if $item =~ /\#/;
+
+ $item =~ s/(\[|\])//g;
+ chop $item;
+
+ if ($item =~ /--/) {
+ ($level, $menuitem) = split /--/, $item, 2;
+ } else {
+ $level = $item;
+ $menuitem = $item;
+ push @acsorder, $item;
+ }
+
+ push @{ $acs{$level} }, $menuitem;
+
+ }
+
+ $admincheck = "checked" if $myconfig->{admin};
+
+ print qq|
+ <tr class=listheading>
+ <th colspan=2>|.$locale->text('Access Control').qq|</th>
+ </tr>
+ <tr>
+ <td><input name=admin type=checkbox class=checkbox value=1 $admincheck>&nbsp;<b>|.$locale->text('Administrator').qq|</b></td>
+ </tr>
+|;
+
+ foreach $item (split /;/, $myconfig->{acs}) {
+ ($key, $value) = split /--/, $item, 2;
+ $excl{$key}{$value} = 1;
+ }
+
+ foreach $key (@acsorder) {
+
+ $checked = "checked";
+ if ($form->{login}) {
+ $checked = ($excl{$key}{$key}) ? "" : "checked";
+ }
+
+ # can't have variable names with spaces
+ # the 1 is for apache 2
+ $item = $form->escape("${key}--$key", 1);
+
+ $acsheading = $key;
+ $acsheading =~ s/ /&nbsp;/g;
+
+ $acsheading = qq|
+ <th align=left><input name="$item" class=checkbox type=checkbox value=1 $checked>&nbsp;$acsheading</th>\n|;
+ $menuitems .= "$item;";
+ $acsdata = "
+ <td>";
+
+ foreach $item (@{ $acs{$key} }) {
+ next if ($key eq $item);
+
+ $checked = "checked";
+ if ($form->{login}) {
+ $checked = ($excl{$key}{$item}) ? "" : "checked";
+ }
+
+ $acsitem = $form->escape("${key}--$item", 1);
+
+ $acsdata .= qq|
+ <br><input name="$acsitem" class=checkbox type=checkbox value=1 $checked>&nbsp;$item|;
+ $menuitems .= "$acsitem;";
+ }
+
+ $acsdata .= "
+ </td>";
+
+ print qq|
+ <tr valign=top>$acsheading $acsdata
+ </tr>
+|;
+ }
+
+ print qq|<input type=hidden name=acs value="$menuitems">
+
+ <tr>
+ <td colspan=2><hr size=3 noshade></td>
+ </tr>
+ <tr>
+ <td>
+ </td>
+ </tr>
+</table>
+|;
+
+}
+
+
+sub save {
+
+ # no driver checked
+ $form->error($locale->text('Database Driver not checked!')) unless $form->{dbdriver};
+
+ # no spaces allowed in login name
+ ($form->{login}) = split / /, $form->{login};
+
+ # check for duplicates
+ if (!$form->{edit}) {
+ $temp = new User "$memberfile", "$form->{login}";
+
+ if ($temp->{login}) {
+ $form->error("$form->{login} ".$locale->text('is already a member!'));
+ }
+ }
+
+ # does stylesheet exist
+ if ($form->{userstylesheet}) {
+ $form->error($locale->text('Stylesheet').": css/$form->{userstylesheet} ".$locale->text('does not exist')) unless (-f "css/$form->{userstylesheet}");
+ }
+
+ # no spaces allowed in directories
+ ($form->{newtemplates}) = split / /, $form->{newtemplates};
+
+ if ($form->{newtemplates}) {
+ $form->{templates} = $form->{newtemplates};
+ } else {
+ $form->{templates} = ($form->{usetemplates}) ? $form->{usetemplates} : $form->{login};
+ }
+
+
+ # is there a basedir
+ if (! -d "$templates") {
+ $form->error($locale->text('Directory').": $templates ".$locale->text('does not exist'));
+ }
+
+ # add base directory to $form->{templates}
+ $form->{templates} = "$templates/$form->{templates}";
+
+
+ $myconfig = new User "$memberfile", "$form->{login}";
+
+ # redo acs variable and delete all the acs codes
+ @acs = split /;/, $form->{acs};
+
+ $form->{acs} = "";
+ foreach $item (@acs) {
+ $item = $form->escape($item, 1);
+
+ if (!$form->{$item}) {
+ $form->{acs} .= $form->unescape($form->unescape($item)).";";
+ }
+ delete $form->{$item};
+ }
+
+ # check which database was filled in
+ if ($form->{dbdriver} eq 'Oracle') {
+ $form->{sid} = $form->{Oracle_sid}, ;
+ $form->{dbhost} = $form->{Oracle_dbhost}, ;
+ $form->{dbport} = $form->{Oracle_dbport};
+ $form->{dbpasswd} = $form->{Oracle_dbpasswd};
+ $form->{dbuser} = $form->{Oracle_dbuser};
+ $form->{dbname} = $form->{Oracle_dbuser};
+
+ $form->isblank("dbhost", $locale->text('Hostname missing!'));
+ $form->isblank("dbport", $locale->text('Port missing!'));
+ $form->isblank("dbuser", $locale->text('Dataset missing!'));
+ }
+ if ($form->{dbdriver} eq 'Pg') {
+ $form->{dbhost} = $form->{Pg_dbhost};
+ $form->{dbport} = $form->{Pg_dbport};
+ $form->{dbpasswd} = $form->{Pg_dbpasswd};
+ $form->{dbuser} = $form->{Pg_dbuser};
+ $form->{dbname} = $form->{Pg_dbname};
+
+ $form->isblank("dbname", $locale->text('Dataset missing!'));
+ $form->isblank("dbuser", $locale->text('Database User missing!'));
+ }
+
+ # set admin
+ $form->{admin} = "" unless $form->{admin};
+
+ foreach $item (keys %{$form}) {
+ $myconfig->{$item} = $form->{$item};
+ }
+
+ delete $myconfig->{stylesheet};
+ if ($form->{userstylesheet}) {
+ $myconfig->{stylesheet} = $form->{userstylesheet};
+ }
+
+ $myconfig->save_member($memberfile, $userspath);
+
+ # create user template directory and copy master files
+ if (! -d "$form->{templates}") {
+ umask(002);
+
+ if (mkdir "$form->{templates}", oct("771")) {
+
+ umask(007);
+
+ # copy templates to the directory
+ opendir TEMPLATEDIR, "$templates/." or $form-error("$templates : $!");
+ @templates = grep /$form->{mastertemplates}.*?\.(html|tex)$/, readdir TEMPLATEDIR;
+ closedir TEMPLATEDIR;
+
+ foreach $file (@templates) {
+ open(TEMP, "$templates/$file") or $form->error("$templates/$file : $!");
+
+ $file =~ s/$form->{mastertemplates}-//;
+ open(NEW, ">$form->{templates}/$file") or $form->error("$form->{templates}/$file : $!");
+
+ while ($line = <TEMP>) {
+ print NEW $line;
+ }
+ close(TEMP);
+ close(NEW);
+ }
+ } else {
+ $form->error("$!: $form->{templates}");
+ }
+ }
+
+ $form->redirect($locale->text('User saved!'));
+
+}
+
+
+sub delete {
+
+ $form->{templates} = ($form->{templates}) ? "$templates/$form->{templates}" : "$templates/$form->{login}";
+
+ $form->error("$memberfile : ".$locale->text('locked!')) if (-f ${memberfile}.LCK);
+ open(FH, ">${memberfile}.LCK") or $form->error("${memberfile}.LCK : $!");
+ close(FH);
+
+ open(CONF, "+<$memberfile") or $form->error("$memberfile : $!");
+
+ @config = <CONF>;
+
+ seek(CONF, 0, 0);
+ truncate(CONF, 0);
+
+ while ($line = shift @config) {
+
+ if ($line =~ /^\[/) {
+ last if ($line =~ /\[$form->{login}\]/);
+ $login = &login_name($line);
+ }
+
+ if ($line =~ /^templates=/) {
+ $user{$login} = &get_value($line);
+ }
+
+ print CONF $line;
+ }
+
+ # remove everything up to next login or EOF
+ # and save template variable
+ while ($line = shift @config) {
+ if ($line =~ /^templates=/) {
+ $templatedir = &get_value($line);
+ }
+ last if ($line =~ /^\[/);
+ }
+
+ # this one is either the next login or EOF
+ print CONF $line;
+
+ $login = &login_name($line);
+
+
+ while ($line = shift @config) {
+ if ($line =~ /^\[/) {
+ $login = &login_name($line);
+ }
+
+ if ($line =~ /^templates=/) {
+ $user{$login} = &get_value($line);
+ }
+
+ print CONF $line;
+ }
+
+ close(CONF);
+ unlink "${memberfile}.LCK";
+
+ # scan %user for $templatedir
+ foreach $login (keys %user) {
+ last if ($found = ($templatedir eq $user{$login}));
+ }
+
+ # if found keep directory otherwise delete
+ if (!$found) {
+ # delete it if there is a template directory
+ $dir = "$form->{templates}";
+ if (-d "$dir") {
+ unlink <$dir/*.html>;
+ unlink <$dir/*.tex>;
+ rmdir "$dir";
+ }
+ }
+
+ # delete config file for user
+ unlink "$userspath/$form->{login}.conf";
+
+ $form->redirect($locale->text('User deleted!'));
+
+}
+
+
+sub login_name {
+ my $login = shift;
+
+ $login =~ s/\[\]//g;
+ return ($login) ? $login : undef;
+
+}
+
+
+
+sub get_value {
+ my $line = shift;
+
+ my ($null, $value) = split(/=/, $line, 2);
+
+ # remove comments
+ $value =~ s/\s#.*//g;
+
+ # remove any trailing whitespace
+ $value =~ s/^\s*(.*?)\s*$/$1/;
+
+ $value;
+}
+
+
+
+sub change_admin_password {
+
+ $form->{title} = qq|SQL-Ledger |.$locale->text('Accounting')." ".$locale->text('Administration')." / ".$locale->text('Change Admin Password');
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+
+<h2>|.$locale->text('Change Admin Password').qq|</h2>
+
+<form method=post action=$form->{script}>
+
+<b>|.$locale->text('Password').qq|</b> <input type=password name=password size=8>
+
+<input type=hidden name=root value="$form->{root}">
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=rpw value=$form->{rpw}>
+
+<p>
+<input type=submit class=submit name=action value="|.$locale->text('Change Password').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub change_password {
+
+ $root->{password} = $form->{password};
+
+ $root->{'root login'} = 1;
+ $root->save_member($memberfile);
+
+ $form->{callback} = "$form->{script}?action=list_users&path=$form->{path}&root=$form->{root}&rpw=$root->{password}";
+
+ $form->redirect($locale->text('Password changed!'));
+
+}
+
+
+sub check_password {
+
+ $root = new User "$memberfile", $form->{root};
+
+ if ($root->{password}) {
+ if ($root->{password} ne $form->{rpw}) {
+ $form->error($locale->text('Incorrect Password!'));
+ }
+ }
+
+}
+
+
+sub pg_database_administration {
+
+ $form->{dbdriver} = 'Pg';
+ &dbselect_source;
+
+}
+
+
+sub oracle_database_administration {
+
+ $form->{dbdriver} = 'Oracle';
+ &dbselect_source;
+
+}
+
+
+sub dbdriver_defaults {
+
+ # load some defaults for the selected driver
+ %driverdefaults = ( 'Pg' => { dbport => '',
+ dbuser => 'sql-ledger',
+ dbdefault => 'template1',
+ dbhost => '',
+ connectstring => $locale->text('Connect to')
+ },
+ 'Oracle' => { dbport => '1521',
+ dbuser => 'oralin',
+ dbdefault => $sid,
+ dbhost => `hostname`,
+ connectstring => 'SID'
+ }
+ );
+
+ map { $form->{$_} = $driverdefaults{$form->{dbdriver}}{$_} } keys %{ $driverdefaults{Pg} };
+
+}
+
+
+sub dbselect_source {
+
+ &dbdriver_defaults;
+
+ $msg{Pg} = $locale->text('Leave host and port field empty unless you want to make a remote connection.');
+ $msg{Oracle} = $locale->text('You must enter a host and port for local and remote connections!');
+
+
+ $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." / ".$locale->text('Database Administration');
+
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+
+<center>
+<h2>$form->{title}</h2>
+
+<form method=post action=$form->{script}>
+
+<table>
+<tr><td>
+
+<table>
+
+ <tr class=listheading>
+ <th colspan=4>|.$locale->text('Database').qq|</th>
+ </tr>
+
+<input type=hidden name=dbdriver value=$form->{dbdriver}>
+
+ <tr><td>
+ <table>
+
+ <tr>
+
+ <th align=right>|.$locale->text('Host').qq|</th>
+ <td><input name=dbhost size=25 value=$form->{dbhost}></td>
+ <th align=right>|.$locale->text('Port').qq|</th>
+ <td><input name=dbport size=5 value=$form->{dbport}></td>
+
+ </tr>
+
+ <tr>
+
+ <th align=right>|.$locale->text('User').qq|</th>
+ <td><input name=dbuser size=10 value=$form->{dbuser}></td>
+ <th align=right>|.$locale->text('Password').qq|</th>
+ <td><input type=password name=dbpasswd size=10></td>
+
+ </tr>
+
+ <tr>
+
+ <th align=right>$form->{connectstring}</th>
+ <td colspan=3><input name=dbdefault size=10 value=$form->{dbdefault}></td>
+
+ </tr>
+
+</table>
+
+</td></tr>
+</table>
+
+<input name=callback type=hidden value="$form->{script}?action=list_users&path=$form->{path}&root=$form->{root}&rpw=$form->{rpw}">
+<input type=hidden name=root value="$form->{root}">
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=rpw value=$form->{rpw}>
+
+<hr size=3 noshade>
+<br>
+
+<input type=submit class=submit name=action value="|.$locale->text('Create Dataset').qq|">
+<input type=submit class=submit name=action value="|.$locale->text('Update Dataset').qq|">
+<input type=submit class=submit name=action value="|.$locale->text('Delete Dataset').qq|">
+
+</form>
+
+</td></tr>
+</table>
+
+<p>|.$locale->text('This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!')
+
+.qq|
+<br>$msg{$form->{dbdriver}}
+
+
+</body>
+</html>
+|;
+
+}
+
+
+sub continue {
+
+ &{ $form->{nextsub} };
+
+}
+
+
+sub update_dataset {
+
+ %needsupdate = User->dbneedsupdate(\%$form);
+
+ $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Database Administration')." / ".$locale->text('Update Dataset');
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+
+<center>
+<h2>$form->{title}</h2>
+|;
+
+
+ foreach $key (sort keys %needsupdate) {
+ if ($needsupdate{$key} lt $form->{dbversion}) {
+ $upd .= qq|<br><input name="db$key" type=checkbox value=1 checked> $key\n|;
+ $form->{dbupdate} .= "db$key ";
+ }
+ }
+
+ chop $form->{dbupdate};
+
+
+ if ($form->{dbupdate}) {
+
+ print qq|
+<table>
+<form method=post action=$form->{script}>
+
+<input type=hidden name=dbdriver value=$form->{dbdriver}>
+<input type=hidden name=dbhost value=$form->{dbhost}>
+<input type=hidden name=dbport value=$form->{dbport}>
+<input type=hidden name=dbuser value=$form->{dbuser}>
+<input type=hidden name=dbpasswd value=$form->{dbpasswd}>
+<input type=hidden name=dbdefault value=$form->{dbdefault}>
+
+<tr class=listheading>
+ <th>|.$locale->text('The following Datasets need to be updated').qq|</th>
+</tr>
+<tr>
+<td>
+
+$upd
+
+</td></tr>
+<tr><td>
+
+<input name=dbupdate type=hidden value="$form->{dbupdate}">
+
+<input name=callback type=hidden value="$form->{script}?action=list_users&path=$form->{path}&root=$form->{root}&rpw=$form->{rpw}">
+
+<input type=hidden name=root value="$form->{root}">
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=rpw value=$form->{rpw}>
+
+<input type=hidden name=nextsub value=dbupdate>
+
+<input type=submit class=submit name=action value="|.$locale->text('Continue').qq|">
+
+</td></tr>
+</table>
+</form>
+|;
+
+ } else {
+
+ print $locale->text('All Datasets up to date!');
+
+ }
+
+ print qq|
+
+</body>
+</html>
+|;
+
+}
+
+
+sub dbupdate {
+
+ User->dbupdate(\%$form);
+
+ $form->redirect($locale->text('Dataset updated!'));
+
+}
+
+
+sub create_dataset {
+
+ foreach $item (sort User->dbsources(\%$form)) {
+ $dbsources .= "[$item] ";
+ }
+
+ opendir SQLDIR, "sql/." or $form-error($!);
+ foreach $item (sort grep /-chart\.sql/, readdir SQLDIR) {
+ next if ($item eq 'Default-chart.sql');
+ $item =~ s/-chart\.sql//;
+ push @charts, qq| <input name=chart class=radio type=radio value="$item">&nbsp;$item|;
+ }
+ closedir SQLDIR;
+
+ # add Default at beginning
+ @charts = (qq|<input name=chart class=radio type=radio value="Default" checked>&nbsp;Default|, @charts);
+
+ $selectencoding = qq|<option>
+ <option value=SQL_ASCII>ASCII
+ <option value=EUC_JP>Japanese Extended UNIX Code
+ <option value=EUC_CN>Chinese Extended UNIX Code
+ <option value=EUC_KR>Korean Extended UNIX Code
+ <option value=EUC_TW>Taiwan Extended UNIX Code
+ <option value=UNICODE>UTF-8 Unicode
+ <option value=MULE_INTERNAL>Mule internal type
+ <option value=LATIN1>ISO 8859-1
+ <option value=LATIN2>ISO 8859-2
+ <option value=LATIN3>ISO 8859-3
+ <option value=LATIN4>ISO 8859-4
+ <option value=LATIN5>ISO 8859-5
+ <option value=KOI8>KOI8-R
+ <option value=WIN>Windows CP1251
+ <option value=ALT>Windows CP866
+ |;
+
+ $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Database Administration')." / ".$locale->text('Create Dataset');
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+
+<center>
+<h2>$form->{title}</h2>
+
+<form method=post action=$form->{script}>
+
+<table>
+ <tr class=listheading>
+ <th colspan=2>&nbsp;</th>
+ </tr>
+
+ <tr>
+
+ <th align=right nowrap>|.$locale->text('Existing Datasets').qq|</th>
+ <td>$dbsources</td>
+
+ </tr>
+
+ <tr>
+
+ <th align=right nowrap>|.$locale->text('Create Dataset').qq|</th>
+ <td><input name=db></td>
+
+ </tr>
+
+ <tr>
+
+ <th align=right nowrap>|.$locale->text('Multibyte Encoding').qq|</th>
+ <td><select name=encoding>$selectencoding</select></td>
+
+ </tr>
+
+ <tr>
+
+ <th align=right>|.$locale->text('Create Chart of Accounts').qq|</th>
+ <td>@charts</td>
+
+ </tr>
+
+ <tr><td colspan=2>
+<hr size=3 noshade>
+<br>
+<input type=hidden name=dbdriver value=$form->{dbdriver}>
+<input type=hidden name=dbuser value=$form->{dbuser}>
+<input type=hidden name=dbhost value=$form->{dbhost}>
+<input type=hidden name=dbport value=$form->{dbport}>
+<input type=hidden name=dbpasswd value=$form->{dbpasswd}>
+<input type=hidden name=dbdefault value=$form->{dbdefault}>
+
+<input name=callback type=hidden value="$form->{script}?action=list_users&path=$form->{path}&root=$form->{root}&rpw=$form->{rpw}">
+
+<input type=hidden name=root value="$form->{root}">
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=rpw value=$form->{rpw}>
+
+<input type=hidden name=nextsub value=dbcreate>
+
+<input type=submit class=submit name=action value="|.$locale->text('Continue').qq|">
+
+ </td></tr>
+</table>
+
+</form>
+
+
+</body>
+</html>
+|;
+
+}
+
+
+sub dbcreate {
+
+ $form->isblank("db", $locale->text('Dataset missing!'));
+
+ User->dbcreate(\%$form);
+
+ $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Database Administration')." / ".$locale->text('Create Dataset');
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+
+<center>
+<h2>$form->{title}</h2>
+
+<form method=post action=$form->{script}>|
+
+.$locale->text('Dataset')." $form->{db} ".$locale->text('successfully created!')
+
+.qq|
+
+<input type=hidden name=root value="$form->{root}">
+<input type=hidden name=path value="$form->{path}">
+<input type=hidden name=rpw value="$form->{rpw}">
+
+<input type=hidden name=nextsub value=list_users>
+
+<p><input type=submit class=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+
+</body>
+</html>
+|;
+
+}
+
+
+sub delete_dataset {
+
+ if (@dbsources = User->dbsources_unused(\%$form, $memberfile)) {
+ foreach $item (sort @dbsources) {
+ $dbsources .= qq|<input name=db class=radio type=radio value=$item>&nbsp;$item\n<br>|;
+ }
+ } else {
+ $form->error($locale->text('Nothing to delete!'));
+ }
+
+ $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Database Administration')." / ".$locale->text('Delete Dataset');
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+
+<center>
+<h2>$form->{title}</h2>
+
+<form method=post action=$form->{script}>
+
+<table>
+ <tr class=listheading>
+ <th>|.$locale->text('The following Datasets are not in use and can be deleted').qq|</th>
+ </tr>
+
+ <tr>
+ <td>
+ $dbsources
+ </td>
+ </tr>
+
+ <tr><td>
+
+<hr size=3 noshade>
+<br>
+<input type=hidden name=dbdriver value=$form->{dbdriver}>
+<input type=hidden name=dbuser value=$form->{dbuser}>
+<input type=hidden name=dbhost value=$form->{dbhost}>
+<input type=hidden name=dbport value=$form->{dbport}>
+<input type=hidden name=dbpasswd value=$form->{dbpasswd}>
+<input type=hidden name=dbdefault value=$form->{dbdefault}>
+
+<input name=callback type=hidden value="$form->{script}?action=list_users&path=$form->{path}&root=$form->{root}&rpw=$form->{rpw}">
+
+<input type=hidden name=root value="$form->{root}">
+<input type=hidden name=path value="$form->{path}">
+<input type=hidden name=rpw value="$form->{rpw}">
+
+<input type=hidden name=nextsub value=dbdelete>
+
+<input type=submit class=submit name=action value="|.$locale->text('Continue').qq|">
+
+ </td></tr>
+</table>
+
+</form>
+
+<p>|.$locale->text('Select a Dataset to delete and press "Continue"')
+
+.qq|
+
+
+</body>
+</html>
+|;
+
+}
+
+
+sub dbdelete {
+
+ if (!$form->{db}) {
+ $form->error($locale->text('No Dataset selected!'));
+ }
+
+ User->dbdelete(\%$form);
+
+ $form->{title} = "SQL-Ledger ".$locale->text('Accounting')." ".$locale->text('Database Administration')." / ".$locale->text('Delete Dataset');
+
+ $form->header;
+
+ print qq|
+<body class=admin>
+
+
+<center>
+<h2>$form->{title}</h2>
+
+<form method=post action=$form->{script}>
+
+$form->{db} |.$locale->text('successfully deleted!')
+
+.qq|
+
+<input type=hidden name=root value="$form->{root}">
+<input type=hidden name=path value="$form->{path}">
+<input type=hidden name=rpw value="$form->{rpw}">
+
+<input type=hidden name=nextsub value=list_users>
+
+<p><input type=submit class=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+
+</body>
+</html>
+|;
+
+}
+
diff --git a/sql-ledger/bin/mozilla/am.pl b/sql-ledger/bin/mozilla/am.pl
new file mode 100644
index 0000000..7e36cfd
--- /dev/null
+++ b/sql-ledger/bin/mozilla/am.pl
@@ -0,0 +1,1051 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# administration
+#
+#======================================================================
+
+
+use SL::AM;
+use SL::CA;
+use SL::Form;
+use SL::User;
+
+
+1;
+# end of main
+
+
+
+sub add {
+
+ $form->{title} = "Add";
+ $form->{charttype} = "A";
+
+ $form->{callback} = "$form->{script}?action=list&path=$form->{path}&login=$form->{login}&password=$form->{password}" unless $form->{callback};
+
+ &form_header;
+ &form_footer;
+
+}
+
+
+sub edit {
+ $form->{title} = "Edit";
+
+ # if it is a template
+ if ($form->{file}) {
+ $form->{type} = "template";
+ &edit_template;
+ exit;
+ }
+
+ AM->get_account(\%myconfig, \%$form);
+
+ foreach my $item (split(/:/, $form->{link})) {
+ $form->{$item} = "checked";
+ }
+
+ &form_header;
+ &form_footer;
+
+}
+
+
+sub form_header {
+
+ $form->{title} = $locale->text("$form->{title} Account");
+
+ $checked{$form->{charttype}} = "checked";
+ $checked{"$form->{category}_"} = "checked";
+ $checked{CT_tax} = ($form->{CT_tax}) ? "" : "checked";
+
+ $form->{description} =~ s/"/&quot;/g;
+
+# this is for our parser only!
+# type=submit $locale->text('Add Account')
+# type=submit $locale->text('Edit Account')
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=id value=$form->{id}>
+<input type=hidden name=type value=account>
+
+<input type=hidden name=inventory_accno_id value=$form->{inventory_accno_id}>
+<input type=hidden name=income_accno_id value=$form->{income_accno_id}>
+<input type=hidden name=expense_accno_id value=$form->{expense_accno_id}>
+<input type=hidden name=fxgain_accno_id values=$form->{fxgain_accno_id}>
+<input type=hidden name=fxloss_accno_id values=$form->{fxloss_accno_id}>
+
+<input type=hidden name=amount value=$form->{amount}>
+
+<table border=0 width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Account Number').qq|</th>
+ <td><input name=accno size=20 value=$form->{accno}></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Description').qq|</th>
+ <td><input name=description size=40 value="$form->{description}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Account Type').qq|</th>
+ <td>
+ <table>
+ <tr valign=top>
+ <td><input name=category type=radio class=radio value=A $checked{A_}>&nbsp;|.$locale->text('Asset').qq|\n<br>
+ <input name=category type=radio class=radio value=L $checked{L_}>&nbsp;|.$locale->text('Liability').qq|\n<br>
+ <input name=category type=radio class=radio value=Q $checked{Q_}>&nbsp;|.$locale->text('Equity').qq|\n<br>
+ <input name=category type=radio class=radio value=I $checked{I_}>&nbsp;|.$locale->text('Income').qq|\n<br>
+ <input name=category type=radio class=radio value=E $checked{E_}>&nbsp;|.$locale->text('Expense')
+ .qq|</td>
+ <td>
+ <input name=charttype type=radio class=radio value="H" $checked{H}>&nbsp;|.$locale->text('Heading').qq|<br>
+ <input name=charttype type=radio class=radio value="A" $checked{A}>&nbsp;|.$locale->text('Account')
+ .qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+
+
+if ($form->{charttype} eq "A") {
+ print qq|
+ <tr>
+ <td colspan=2>
+ <table>
+ <tr>
+ <th align=left>|.$locale->text('Is this a summary account to record').qq|</th>
+ <td>
+ <input name=AR type=checkbox class=checkbox value=AR $form->{AR}>&nbsp;|.$locale->text('AR')
+ .qq|&nbsp;<input name=AP type=checkbox class=checkbox value=AP $form->{AP}>&nbsp;|.$locale->text('AP')
+ .qq|&nbsp;<input name=IC type=checkbox class=checkbox value=IC $form->{IC}>&nbsp;|.$locale->text('Inventory')
+ .qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=2>|.$locale->text('Include in drop-down menus').qq|</th>
+ </tr>
+ <tr valign=top>
+ <td colspan=2>
+ <table width=100%>
+ <tr>
+ <th align=left>|.$locale->text('Receivables').qq|</th>
+ <th align=left>|.$locale->text('Payables').qq|</th>
+ <th align=left>|.$locale->text('Parts Inventory').qq|</th>
+ <th align=left>|.$locale->text('Service Items').qq|</th>
+ </tr>
+ <tr>
+ <td>
+ <input name=AR_amount type=checkbox class=checkbox value=AR_amount $form->{AR_amount}>&nbsp;|.$locale->text('Income').qq|\n<br>
+ <input name=AR_paid type=checkbox class=checkbox value=AR_paid $form->{AR_paid}>&nbsp;|.$locale->text('Payment').qq|\n<br>
+ <input name=AR_tax type=checkbox class=checkbox value=AR_tax $form->{AR_tax}>&nbsp;|.$locale->text('Tax')
+ .qq|
+ </td>
+ <td>
+ <input name=AP_amount type=checkbox class=checkbox value=AP_amount $form->{AP_amount}>&nbsp;|.$locale->text('Expense/Asset').qq|\n<br>
+ <input name=AP_paid type=checkbox class=checkbox value=AP_paid $form->{AP_paid}>&nbsp;|.$locale->text('Payment').qq|\n<br>
+ <input name=AP_tax type=checkbox class=checkbox value=AP_tax $form->{AP_tax}>&nbsp;|.$locale->text('Tax')
+ .qq|
+ </td>
+ <td>
+ <input name=IC_sale type=checkbox class=checkbox value=IC_sale $form->{IC_sale}>&nbsp;|.$locale->text('Sales').qq|\n<br>
+ <input name=IC_cogs type=checkbox class=checkbox value=IC_cogs $form->{IC_cogs}>&nbsp;|.$locale->text('COGS').qq|\n<br>
+ <input name=IC_taxpart type=checkbox class=checkbox value=IC_taxpart $form->{IC_taxpart}>&nbsp;|.$locale->text('Tax')
+ .qq|
+ </td>
+ <td>
+ <input name=IC_income type=checkbox class=checkbox value=IC_income $form->{IC_income}>&nbsp;|.$locale->text('Income').qq|\n<br>
+ <input name=IC_expense type=checkbox class=checkbox value=IC_expense $form->{IC_expense}>&nbsp;|.$locale->text('Expense').qq|\n<br>
+ <input name=IC_taxservice type=checkbox class=checkbox value=IC_taxservice $form->{IC_taxservice}>&nbsp;|.$locale->text('Tax')
+ .qq|
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=2>
+ <table>
+ <tr>
+ <th align=left>|.$locale->text('Include this account on the customer/vendor forms to flag customer/vendor as taxable?').qq|</th>
+ <td>
+ <input name=CT_tax type=radio class=radio value=CT_tax $form->{CT_tax}>&nbsp;|.$locale->text('Yes').qq|&nbsp;
+ <input name=CT_tax type=radio class=radio value="" $checked{CT_tax}>&nbsp;|.$locale->text('No')
+ .qq|
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+}
+
+print qq|
+ <tr>
+ <th align=right>|.$locale->text('GIFI').qq|</th>
+ <td><input name=gifi_accno size=9 value=$form->{gifi_accno}></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+|;
+
+}
+
+
+sub form_footer {
+
+ print qq|
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input type=submit class=submit name=action value="|.$locale->text('Save').qq|">
+|;
+
+ if ($form->{id}) {
+ print qq|<input type=submit class=submit name=action value="|.$locale->text('Delete').qq|">|;
+ }
+
+ print qq|
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub save { &{ "save_$form->{type}" } };
+
+sub save_account {
+
+ $form->isblank("accno", $locale->text('Account Number missing!'));
+ $form->isblank("category", $locale->text('Account Type missing!'));
+
+ $form->redirect($locale->text('Account saved!')) if (AM->save_account(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot save account!'));
+
+}
+
+
+sub list {
+
+ CA->all_accounts(\%myconfig, \%$form);
+
+ $form->{title} = $locale->text('Chart of Accounts');
+
+ # construct callback
+ $callback = "$form->{script}?action=list&path=$form->{path}&login=$form->{login}&password=$form->{password}";
+
+ @column_index = qw(accno gifi_accno description debit credit link);
+
+ $column_header{accno} = qq|<th class=listheading>|.$locale->text('Account').qq|</a></th>|;
+ $column_header{gifi_accno} = qq|<th class=listheading>|.$locale->text('GIFI').qq|</a></th>|;
+ $column_header{description} = qq|<th class=listheading>|.$locale->text('Description').qq|</a></th>|;
+ $column_header{debit} = qq|<th class=listheading>|.$locale->text('Debit').qq|</a></th>|;
+ $column_header{credit} = qq|<th class=listheading>|.$locale->text('Credit').qq|</a></th>|;
+ $column_header{link} = qq|<th class=listheading>|.$locale->text('Link').qq|</a></th>|;
+
+
+ $form->header;
+ $colspan = $#column_index + 1;
+
+ print qq|
+<body>
+
+<table border=0 width=100%>
+ <tr><th class=listtop colspan=$colspan>$form->{title}</th></tr>
+ <tr height=5></tr>
+ <tr class=listheading>
+|;
+
+ map { print "$column_header{$_}\n" } @column_index;
+
+ print qq|
+</tr>
+|;
+
+ # escape callback
+ $callback = $form->escape($callback);
+
+ foreach $ca (@{ $form->{CA} }) {
+
+ $ca->{debit} = "&nbsp;";
+ $ca->{credit} = "&nbsp;";
+
+ # needed if we can delete an account
+ $amount = 0;
+
+ if ($ca->{amount} > 0) {
+ $amount = $ca->{amount};
+ $ca->{credit} = $form->format_amount(\%myconfig, $ca->{amount}, 2, "&nbsp;");
+ }
+ if ($ca->{amount} < 0) {
+ $amount = -$ca->{amount};
+ $ca->{debit} = $form->format_amount(\%myconfig, -$ca->{amount}, 2, "&nbsp;");
+ }
+
+ $ca->{link} =~ s/:/<br>/og;
+
+ if ($ca->{charttype} eq "H") {
+ print qq|<tr class=listheading>|;
+
+ $column_data{accno} = qq|<th><a class=listheading href=$form->{script}?action=edit&id=$ca->{id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ca->{accno}</a></th>|;
+ $column_data{gifi_accno} = qq|<th><a class=listheading href=$form->{script}?action=edit_gifi&accno=$ca->{gifi_accno}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ca->{gifi_accno}</a>&nbsp;</th>|;
+ $column_data{description} = qq|<th class=listheading>$ca->{description}&nbsp;</th>|;
+ $column_data{debit} = qq|<th>&nbsp;</th>|;
+ $column_data{credit} = qq| <th>&nbsp;</th>|;
+ $column_data{link} = qq|<th>&nbsp;</th>|;
+
+ } else {
+ $i++; $i %= 2;
+ print qq|
+<tr valign=top class=listrow$i>|;
+ $column_data{accno} = qq|<td><a href=$form->{script}?action=edit&id=$ca->{id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback&amount=$amount>$ca->{accno}</a></td>|;
+ $column_data{gifi_accno} = qq|<td><a href=$form->{script}?action=edit_gifi&accno=$ca->{gifi_accno}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback&amount=$amount>$ca->{gifi_accno}</a>&nbsp;</td>|;
+ $column_data{description} = qq|<td>$ca->{description}&nbsp;</td>|;
+ $column_data{debit} = qq|<td align=right>$ca->{debit}</td>|;
+ $column_data{credit} = qq|<td align=right>$ca->{credit}</td>|;
+ $column_data{link} = qq|<td>$ca->{link}&nbsp;</td>|;
+
+ }
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print "</tr>\n";
+ }
+
+ print qq|
+ <tr><td colspan=$colspan><hr size=3 noshade></td></tr>
+</table>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub delete { &{ "delete_$form->{type}" } };
+
+sub delete_account {
+
+ $form->{title} = $locale->text('Delete Account');
+
+ if ($form->{amount} != 0) {
+ $form->error($locale->text('Transactions exist; cannot delete account!'));
+ }
+
+ foreach $id (qw(inventory_accno_id income_accno_id expense_accno_id fxgain_accno_id fxloss_accno_id)) {
+ if ($form->{id} == $form->{$id}) {
+ $form->error($locale->text('Cannot delete default account!'));
+ }
+ }
+
+ $form->redirect($locale->text('Account deleted!')) if (AM->delete_account(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot delete account!'));
+
+}
+
+
+sub list_gifi {
+
+ @{ $form->{fields} } = (accno, description);
+ $form->{table} = "gifi";
+ $form->{sortorder} = "accno";
+
+ AM->gifi_accounts(\%myconfig, \%$form);
+
+ $form->{title} = $locale->text('GIFI');
+
+ # construct callback
+ $callback = "$form->{script}?action=list_gifi&path=$form->{path}&login=$form->{login}&password=$form->{password}";
+
+ @column_index = qw(accno description);
+
+ $column_header{accno} = qq|<th class=listheading>|.$locale->text('GIFI').qq|</a></th>|;
+ $column_header{description} = qq|<th class=listheading>|.$locale->text('Description').qq|</a></th>|;
+
+
+ $form->header;
+ $colspan = $#column_index + 1;
+
+ print qq|
+<body>
+
+<table border=0 width=100%>
+ <tr><th class=listtop colspan=$colspan>$form->{title}</th></tr>
+ <tr height="5"></tr>
+ <tr class=listheading>
+|;
+
+ map { print "$column_header{$_}\n" } @column_index;
+
+ print qq|
+</tr>
+|;
+
+ # escape callback
+ $callback = $form->escape($callback);
+
+ foreach $ca (@{ $form->{ALL} }) {
+
+ $i++; $i %= 2;
+
+ print qq|
+<tr valign=top class=listrow$i>|;
+
+ $column_data{accno} = qq|<td><a href=$form->{script}?action=edit_gifi&coa=1&accno=$ca->{accno}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ca->{accno}</td>|;
+ $column_data{description} = qq|<td>$ca->{description}&nbsp;</td>|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print "</tr>\n";
+ }
+
+ print qq|
+ <tr>
+ <td colspan=$colspan><hr size=3 noshade></td>
+ </tr>
+</table>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub add_gifi {
+ $form->{title} = "Add";
+
+ # construct callback
+ $form->{callback} = "$form->{script}?action=list_gifi&path=$form->{path}&login=$form->{login}&password=$form->{password}";
+
+ $form->{coa} = 1;
+
+ &gifi_header;
+ &gifi_footer;
+
+}
+
+
+sub edit_gifi {
+
+ $form->{title} = "Edit";
+
+ AM->get_gifi(\%myconfig, \%$form);
+
+ &gifi_header;
+ &gifi_footer;
+
+}
+
+
+sub gifi_header {
+
+ $form->{title} = $locale->text("$form->{title} GIFI");
+
+# $locale->text('Add GIFI')
+# $locale->text('Edit GIFI')
+
+ $form->{description} =~ s/"/&quot;/g;
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=id value=$form->{accno}>
+<input type=hidden name=type value=gifi>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('GIFI').qq|</th>
+ <td><input name=accno size=20 value=$form->{accno}></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Description').qq|</th>
+ <td><input name=description size=60 value="$form->{description}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=2><hr size=3 noshade></td>
+ </tr>
+</table>
+|;
+
+}
+
+
+sub gifi_footer {
+
+ print qq|
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br><input type=submit class=submit name=action value="|.$locale->text('Save').qq|">
+|;
+
+ if ($form->{coa}) {
+ print qq|
+<input type=submit class=submit name=action value="|.$locale->text('Copy to COA').qq|">
+|;
+
+ if ($form->{accno}) {
+ print qq|<input type=submit class=submit name=action value="|.$locale->text('Delete').qq|">|;
+ }
+ }
+
+ print qq|
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub save_gifi {
+
+ $form->isblank("accno", $locale->text('GIFI missing!'));
+ AM->save_gifi(\%myconfig, \%$form);
+ $form->redirect($locale->text('GIFI saved!'));
+
+}
+
+
+sub copy_to_coa {
+
+ $form->isblank("accno", $locale->text('GIFI missing!'));
+
+ AM->save_gifi(\%myconfig, \%$form);
+
+ delete $form->{id};
+ $form->{gifi_accno} = $form->{accno};
+ $form->{title} = "Add";
+ $form->{charttype} = "A";
+
+ &form_header;
+ &form_footer;
+
+}
+
+
+sub delete_gifi {
+
+ AM->delete_gifi(\%myconfig, \%$form);
+ $form->redirect($locale->text('GIFI deleted!'));
+
+}
+
+
+sub display_stylesheet {
+
+ $form->{file} = "css/$myconfig{stylesheet}";
+ &display_form;
+
+}
+
+
+sub display_form {
+
+ $form->{file} =~ s/^(.:)*?\/|\.\.\///g;
+ $form->{file} =~ s/^\/*//g;
+ $form->{file} =~ s/$userspath//;
+
+ $form->error("$!: $form->{file}") unless -f $form->{file};
+
+ AM->load_template(\%$form);
+
+ $form->{title} = $form->{file};
+
+ # if it is anything but html
+ if ($form->{file} !~ /\.html$/) {
+ $form->{body} = "<pre>\n$form->{body}\n</pre>";
+ }
+
+ $form->header;
+
+ print qq|
+<body>
+
+$form->{body}
+
+<form method=post action=$form->{script}>
+
+<input name=file type=hidden value=$form->{file}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input name=action type=submit class=submit value="|.$locale->text('Edit').qq|">
+</form>
+
+
+</body>
+</html>
+|;
+
+}
+
+
+sub edit_template {
+
+ AM->load_template(\%$form);
+
+ $form->{title} = $locale->text('Edit Template');
+ # convert &nbsp to &amp;nbsp;
+ $form->{body} =~ s/&nbsp;/&amp;nbsp;/gi;
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input name=file type=hidden value=$form->{file}>
+<input name=type type=hidden value=template>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input name=callback type=hidden value="$form->{script}?action=display_form&file=$form->{file}&path=$form->{path}&login=$form->{login}&password=$form->{password}">
+
+<textarea name=body rows=25 cols=70>
+$form->{body}
+</textarea>
+
+<br>
+<input type=submit class=submit name=action value="|.$locale->text('Save').qq|">
+
+</form>
+
+
+</body>
+</html>
+|;
+
+}
+
+
+sub save_template {
+
+ AM->save_template(\%$form);
+ $form->redirect($locale->text('Template saved!'));
+
+}
+
+
+sub config {
+
+ # get defaults for account numbers and last numbers
+ AM->defaultaccounts(\%myconfig, \%$form);
+
+ foreach $item (qw(mm-dd-yy mm/dd/yy dd-mm-yy dd/mm/yy dd.mm.yy yyyy-mm-dd)) {
+ $dateformat .= ($item eq $myconfig{dateformat}) ? "<option selected>$item\n" : "<option>$item\n";
+ }
+
+ foreach $item (qw(1,000.00 1000.00 1.000,00 1000,00)) {
+ $numberformat .= ($item eq $myconfig{numberformat}) ? "<option selected>$item\n" : "<option>$item\n";
+ }
+
+ foreach $item (qw(name company address signature shippingpoint)) {
+ $myconfig{$item} =~ s/"/&quot;/g;
+ }
+
+ foreach $item (qw(address signature)) {
+ $myconfig{$item} =~ s/\\n/\r\n/g;
+ }
+
+ %countrycodes = User->country_codes;
+ $countrycodes = '';
+ foreach $key (sort { $countrycodes{$a} cmp $countrycodes{$b} } keys %countrycodes) {
+ $countrycodes .= ($myconfig{countrycode} eq $key) ? "<option selected value=$key>$countrycodes{$key}\n" : "<option value=$key>$countrycodes{$key}\n";
+ }
+ $countrycodes = "<option>American English\n$countrycodes";
+
+ foreach $key (keys %{ $form->{IC} }) {
+ foreach $accno (sort keys %{ $form->{IC}{$key} }) {
+ $myconfig{$key} .= ($form->{IC}{$key}{$accno}{id} == $form->{defaults}{$key}) ? "<option selected>$accno--$form->{IC}{$key}{$accno}{description}\n" : "<option>$accno--$form->{IC}{$key}{$accno}{description}\n";
+ }
+ }
+
+ $form->{title} = $locale->text('Edit Preferences for').qq| $form->{login}|;
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=old_password value=$myconfig{password}>
+<input type=hidden name=type value=preferences>
+
+<table width=100%>
+ <tr><th class=listtop>$form->{title}</th></tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Name').qq|</th>
+ <td><input name=name size=15 value="$myconfig{name}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Password').qq|</th>
+ <td><input type=password name=password size=10 value=$myconfig{password}></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('E-mail').qq|</th>
+ <td><input name=email size=30 value="$myconfig{email}"></td>
+ </tr>
+ <tr valign=top>
+ <th align=right>|.$locale->text('Signature').qq|</th>
+ <td><textarea name=signature rows=3 cols=50>$myconfig{signature}</textarea></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Phone').qq|</th>
+ <td><input name=tel size=14 value="$myconfig{tel}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Fax').qq|</th>
+ <td><input name=fax size=14 value="$myconfig{fax}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Company').qq|</th>
+ <td><input name=company size=30 value="$myconfig{company}"></td>
+ </tr>
+ <tr valign=top>
+ <th align=right>|.$locale->text('Address').qq|</th>
+ <td><textarea name=address rows=4 cols=50>$myconfig{address}</textarea></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Date Format').qq|</th>
+ <td><select name=dateformat>$dateformat</select></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Number Format').qq|</th>
+ <td><select name=numberformat>$numberformat</select></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Dropdown Limit').qq|</th>
+ <td><input name=vclimit size=10 value="$myconfig{vclimit}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Language').qq|</th>
+ <td><select name=countrycode>$countrycodes</select></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Character Set').qq|</th>
+ <td><input name=charset size=20 value="$myconfig{charset}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Stylesheet').qq|</th>
+ <td><input name=stylesheet size=20 value="$myconfig{stylesheet}"></td>
+ </tr>
+ <input name=printer type=hidden value="$myconfig{printer}">
+ <tr>
+ <th align=right>|.$locale->text('Ship via').qq|</th>
+ <td><input name=shippingpoint size=25 value="$myconfig{shippingpoint}"></td>
+ </tr>
+ <tr class=listheading>
+ <th colspan=2>&nbsp;</th>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Business Number').qq|</th>
+ <td><input name=businessnumber size=25 value="$myconfig{businessnumber}"></td>
+ </tr>
+ <tr>
+ <td colspan=2>
+ <table width=100%>
+ <tr>
+ <th align=right>|.$locale->text('Year End').qq| (mm/dd)</th>
+ <td><input name=yearend size=5 maxsize=5 value=$form->{defaults}{yearend}></td>
+ <th align=right>|.$locale->text('Weight Unit').qq|</th>
+ <td><input name=weightunit size=5 value="$form->{defaults}{weightunit}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr class=listheading>
+ <th class=listheading colspan=2>|.$locale->text('Last Numbers & Default Accounts').qq|</th>
+ </tr>
+ <tr>
+ <td colspan=2>
+ <table width=100%>
+ <tr>
+ <th width=1% align=right nowrap>|.$locale->text('Inventory Account').qq|</th>
+ <td><select name=inventory_accno>$myconfig{IC}</select></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Income Account').qq|</th>
+ <td><select name=income_accno>$myconfig{IC_income}</select></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Expense Account').qq|</th>
+ <td><select name=expense_accno>$myconfig{IC_expense}</select></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Foreign Exchange Gain').qq|</th>
+ <td><select name=fxgain_accno>$myconfig{FX_gain}</select></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Foreign Exchange Loss').qq|</th>
+ <td><select name=fxloss_accno>$myconfig{FX_loss}</select></td>
+ </tr>
+ <tr>
+ <td colspan=2>|.$locale->text('Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies').qq|<br><input name=curr size=40 value="$form->{defaults}{curr}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Last Invoice Number').qq|</th>
+ <td><input name=invnumber size=10 value=$form->{defaults}{invnumber}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Last Sales Order Number').qq|</th>
+ <td><input name=sonumber size=10 value=$form->{defaults}{sonumber}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Last Purchase Order Number').qq|</th>
+ <td><input name=ponumber size=10 value=$form->{defaults}{ponumber}></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr class=listheading>
+ <th class=listheading colspan=2>|.$locale->text('Tax Accounts').qq|</th>
+ </tr>
+ <tr>
+ <td colspan=2>
+ <table>
+ <tr>
+ <th>&nbsp;</th>
+ <th>|.$locale->text('Rate').qq| (%)</th>
+ <th>|.$locale->text('Number').qq|</th>
+ </tr>
+|;
+
+ foreach $accno (sort keys %{ $form->{taxrates} }) {
+ print qq|
+ <tr>
+ <th align=right>$form->{taxrates}{$accno}{description}</th>
+ <td><input name=$form->{taxrates}{$accno}{id} size=6 value=$form->{taxrates}{$accno}{rate}></td>
+ <td><input name="taxnumber_$form->{taxrates}{$accno}{id}" value="$form->{taxrates}{$accno}{taxnumber}"></td>
+ </tr>
+|;
+ $form->{taxaccounts} .= "$form->{taxrates}{$accno}{id} ";
+ }
+
+ chop $form->{taxaccounts};
+
+ print qq|
+<input name=taxaccounts type=hidden value="$form->{taxaccounts}">
+
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input type=submit class=submit name=action value="|.$locale->text('Save').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub save_preferences {
+
+ # does stylesheet exist
+ if ($form->{stylesheet}) {
+ $form->error($locale->text('Stylesheet').": css/$form->{stylesheet} ".$locale->text('does not exist')) unless (-f "css/$form->{stylesheet}");
+ }
+
+ $form->redirect($locale->text('Preferences saved!')) if (AM->save_preferences(\%myconfig, \%$form, $memberfile, $userspath));
+ $form->error($locale->text('Cannot save preferences!'));
+
+}
+
+
+sub backup {
+
+ if ($form->{media} eq 'email') {
+ $form->error($locale->text('No email address for')." $myconfig{name}") unless ($myconfig{email});
+
+ $form->{OUT} = "$sendmail";
+
+ }
+
+ AM->backup(\%myconfig, \%$form, $userspath);
+
+ if ($form->{media} eq 'email') {
+ $form->redirect($locale->text('Backup sent to').qq| $myconfig{email}|);
+ }
+
+}
+
+
+
+sub audit_control {
+
+ $form->{title} = $locale->text('Audit Control');
+
+ AM->closedto(\%myconfig, \%$form);
+
+ if ($form->{revtrans}) {
+ $checked{Y} = "checked";
+ } else {
+ $checked{N} = "checked";
+ }
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<table width=100%>
+ <tr><th class=listtop>$form->{title}</th></tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <td>|.$locale->text('Enforce transaction reversal for all dates').qq|</th>
+ <td><input name=revtrans class=radio type=radio value="1" $checked{Y}> |.$locale->text('Yes').qq| <input name=revtrans class=radio type=radio value="0" $checked{N}> |.$locale->text('No').qq|</td>
+ </tr>
+ <tr>
+ <td>|.$locale->text('Close Books up to').qq|</th>
+ <td><input name=closedto size=11 title="$myconfig{dateformat}" value=$form->{closedto}></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+
+<hr size=3 noshade>
+
+<br>
+<input type=hidden name=nextsub value=doclose>
+
+<input type=submit class=submit name=action value="|.$locale->text('Continue').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub doclose {
+
+ AM->closebooks(\%myconfig, \%$form);
+
+ if ($form->{revtrans}) {
+ $form->redirect($locale->text('Transaction reversal enforced for all dates'));
+ } else {
+ if ($form->{closedto}) {
+ $form->redirect($locale->text('Transaction reversal enforced up to')
+ ." ".$locale->date(\%myconfig, $form->{closedto}, 1));
+ } else {
+ $form->redirect($locale->text('Books are open'));
+ }
+ }
+
+}
+
+
+
+sub continue {
+
+ &{ $form->{nextsub} };
+
+}
+
+
diff --git a/sql-ledger/bin/mozilla/ap.pl b/sql-ledger/bin/mozilla/ap.pl
new file mode 100644
index 0000000..269f7cf
--- /dev/null
+++ b/sql-ledger/bin/mozilla/ap.pl
@@ -0,0 +1,1103 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Accounts Payables
+#
+#======================================================================
+
+
+use SL::AP;
+use SL::IR;
+use SL::PE;
+
+require "$form->{path}/arap.pl";
+
+1;
+# end of main
+
+
+# this is for our long dates
+# $locale->text('January')
+# $locale->text('February')
+# $locale->text('March')
+# $locale->text('April')
+# $locale->text('May ')
+# $locale->text('June')
+# $locale->text('July')
+# $locale->text('August')
+# $locale->text('September')
+# $locale->text('October')
+# $locale->text('November')
+# $locale->text('December')
+
+# this is for our short month
+# $locale->text('Jan')
+# $locale->text('Feb')
+# $locale->text('Mar')
+# $locale->text('Apr')
+# $locale->text('May')
+# $locale->text('Jun')
+# $locale->text('Jul')
+# $locale->text('Aug')
+# $locale->text('Sep')
+# $locale->text('Oct')
+# $locale->text('Nov')
+# $locale->text('Dec')
+
+
+sub add {
+
+ $form->{title} = "Add";
+
+ $form->{callback} = "$form->{script}?action=add&path=$form->{path}&login=$form->{login}&password=$form->{password}" unless $form->{callback};
+
+ &create_links;
+ &display_form;
+
+}
+
+
+sub edit {
+
+ $form->{title} = "Edit";
+
+ &create_links;
+ &display_form;
+
+}
+
+
+sub display_form {
+
+ &form_header;
+ &form_footer;
+
+}
+
+
+sub create_links {
+
+ $form->create_links("AP", \%myconfig, "vendor");
+
+ $taxincluded = $form->{taxincluded};
+ $duedate = $form->{duedate};
+
+ IR->get_vendor(\%myconfig, \%$form);
+
+ $form->{duedate} = $duedate;
+ $form->{oldvendor} = "$form->{vendor}--$form->{vendor_id}";
+
+ # build the popup menus
+
+ # currencies
+ @curr = split /:/, $form->{currencies};
+ chomp $curr[0];
+ $form->{defaultcurrency} = $curr[0];
+
+ map { $form->{selectcurrency} .= "<option>$_\n" } @curr;
+
+ # vendors
+ if (@{ $form->{all_vendor} }) {
+ $form->{vendor} = qq|$form->{vendor}--$form->{vendor_id}|;
+ map { $form->{selectvendor} .= "<option>$_->{name}--$_->{id}\n" } (@{ $form->{all_vendor} });
+ }
+
+
+ # forex
+ $form->{forex} = $form->{exchangerate};
+ $exchangerate = ($form->{exchangerate}) ? $form->{exchangerate} : 1;
+
+ foreach $key (keys %{ $form->{AP_links} }) {
+
+ foreach $ref (@{ $form->{AP_links}{$key} }) {
+ if ($key eq "AP_tax") {
+ $form->{"selectAP_tax_$ref->{accno}"} = "<option>$ref->{accno}--$ref->{description}\n";
+ next;
+ }
+ $form->{"select$key"} .= "<option>$ref->{accno}--$ref->{description}\n";
+ }
+
+ # if there is a value we have an old entry
+ for $i (1 .. scalar @{ $form->{acc_trans}{$key} }) {
+
+ if ($key eq "AP_paid") {
+ $form->{"AP_paid_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{accno}--$form->{acc_trans}{$key}->[$i-1]->{description}";
+ $form->{"paid_$i"} = $form->{acc_trans}{$key}->[$i-1]->{amount};
+ $form->{"datepaid_$i"} = $form->{acc_trans}{$key}->[$i-1]->{transdate};
+ $form->{"source_$i"} = $form->{acc_trans}{$key}->[$i-1]->{source};
+
+ $form->{"forex_$i"} = $form->{"exchangerate_$i"} = $form->{acc_trans}{$key}->[$i-1]->{exchangerate};
+
+ $form->{paidaccounts}++;
+ } else {
+
+ $akey = $key;
+ $akey =~ s/AP_//;
+
+ if ($key eq "AP_tax") {
+ $form->{"${key}_$form->{acc_trans}{$key}->[$i-1]->{accno}"} = "$form->{acc_trans}{$key}->[$i-1]->{accno}--$form->{acc_trans}{$key}->[$i-1]->{description}";
+ $form->{"${akey}_$form->{acc_trans}{$key}->[$i-1]->{accno}"} = $form->round_amount($form->{acc_trans}{$key}->[$i-1]->{amount} / $exchangerate * -1, 2);
+ $totaltax += $form->{"${akey}_$form->{acc_trans}{$key}->[$i-1]->{accno}"};
+ } else {
+ $form->{"${akey}_$i"} = $form->round_amount($form->{acc_trans}{$key}->[$i-1]->{amount} / $exchangerate, 2);
+ if ($akey eq 'amount') {
+ $form->{"${akey}_$i"} *= -1;
+ $totalamount += $form->{"${akey}_$i"};
+ $form->{rowcount}++;
+
+ $form->{"oldprojectnumber_$i"} = $form->{"projectnumber_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{projectnumber}";
+ $form->{"project_id_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{project_id}";
+ }
+ $form->{"${key}_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{accno}--$form->{acc_trans}{$key}->[$i-1]->{description}";
+ }
+ }
+ }
+ }
+
+ $form->{taxincluded} = $taxincluded if ($form->{id});
+ $form->{paidaccounts} = 1 if not defined $form->{paidaccounts};
+
+ if ($form->{taxincluded} && $totalamount) {
+ # add tax to amounts and invtotal
+ for $i (1 .. $form->{rowcount}) {
+ $taxamount = $totaltax * $form->{"amount_$i"} / $totalamount;
+ $tax = $form->round_amount($taxamount, 2);
+ $diff += ($taxamount - $tax);
+ $form->{"amount_$i"} += $tax;
+ }
+ $form->{amount_1} += $form->round_amount($diff, 2);
+ }
+
+ $form->{invtotal} = $totalamount + $totaltax;
+ $form->{rowcount}++ if $form->{id};
+
+ $form->{AP} = $form->{AP_1};
+
+ $form->{locked} = ($form->datetonum($form->{transdate}, \%myconfig) <= $form->datetonum($form->{closedto}, \%myconfig));
+
+}
+
+
+sub form_header {
+
+ $title = $form->{title};
+ $form->{title} = $locale->text("$title Accounts Payables Transaction");
+
+ $form->{taxincluded} = ($form->{taxincluded}) ? "checked" : "";
+
+# type=submit $locale->text('Add Accounts Payables Transaction')
+# type=submit $locale->text('Edit Accounts Payables Transaction')
+
+ # set option selected
+ foreach $item (qw(AP vendor currency)) {
+ $form->{"select$item"} =~ s/ selected//;
+ $form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
+ }
+
+
+ # format amounts
+ $form->{exchangerate} = $form->format_amount(\%myconfig, $form->{exchangerate});
+
+ $exchangerate = qq|
+<input type=hidden name=forex value=$form->{forex}>
+|;
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ if ($form->{forex}) {
+ $exchangerate .= qq|
+ <th align=right>|.$locale->text('Exchangerate').qq|</th>
+ <td><input type=hidden name=exchangerate value=$form->{exchangerate}>$form->{exchangerate}</td>
+|;
+ } else {
+ $exchangerate .= qq|
+ <th align=right>|.$locale->text('Exchangerate').qq|</th>
+ <td><input name=exchangerate size=10 value=$form->{exchangerate}></td>
+|;
+ }
+ }
+
+ $taxincluded = "";
+ if ($form->{taxaccounts}) {
+ $taxincluded = qq|
+ <tr>
+ <td align=right><input name=taxincluded class=checkbox type=checkbox value=1 $form->{taxincluded}></td>
+ <th align=left nowrap>|.$locale->text('Tax Included').qq|</th>
+ </tr>
+|;
+ }
+
+
+ if (($rows = $form->numtextrows($form->{notes}, 50)) < 2) {
+ $rows = 2;
+ }
+ $notes = qq|<textarea name=notes rows=$rows cols=50 wrap=soft>$form->{notes}</textarea>|;
+
+
+ $form->header;
+
+ $vendor = ($form->{selectvendor}) ? qq|<select name=vendor>$form->{selectvendor}</select>| : qq|<input name=vendor value="$form->{vendor}" size=35>|;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=id value=$form->{id}>
+<input type=hidden name=sort value=$form->{sort}>
+<input type=hidden name=closedto value=$form->{closedto}>
+<input type=hidden name=locked value=$form->{locked}>
+<input type=hidden name=title value="$title">
+
+<table width=100%>
+ <tr class=listtop>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr valign=top>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Vendor').qq|</th>
+ <td colspan=3>$vendor</td>
+ <input type=hidden name=selectvendor value="$form->{selectvendor}">
+ <input type=hidden name=oldvendor value="$form->{oldvendor}">
+ <input type=hidden name=vendor_id value="$form->{vendor_id}">
+ <input type=hidden name=terms value=$form->{terms}>
+ </tr>
+ $taxincluded
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Currency').qq|</th>
+ <td><select name=currency>$form->{selectcurrency}</select></td>
+ <input type=hidden name=selectcurrency value="$form->{selectcurrency}">
+ <input type=hidden name=defaultcurrency value=$form->{defaultcurrency}>
+ <input type=hidden name=fxgain_accno value=$form->{fxgain_accno}>
+ <input type=hidden name=fxloss_accno value=$form->{fxloss_accno}>
+ $exchangerate
+ </tr>
+ </table>
+ </td>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Invoice Number').qq|</th>
+ <td><input name=invnumber size=11 value="$form->{invnumber}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Order Number').qq|</th>
+ <td><input name=ordnumber size=11 value="$form->{ordnumber}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Invoice Date').qq|</th>
+ <td><input name=transdate size=11 title="$myconfig{'dateformat'}" value=$form->{transdate}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Due Date').qq|</th>
+ <td><input name=duedate size=11 title="$myconfig{'dateformat'}" value=$form->{duedate}></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <input type=hidden name=selectAP_amount value="$form->{selectAP_amount}">
+ <input type=hidden name=rowcount value=$form->{rowcount}>
+ <tr>
+ <td>
+ <table width=100%>
+|;
+
+ $amount = $locale->text('Amount');
+ $project = $locale->text('Project');
+
+ for $i (1 .. $form->{rowcount}) {
+
+ $form->{"selectAP_amount"} =~ s/ selected//;
+ $form->{"selectAP_amount"} =~ s/option>\Q$form->{"AP_amount_$i"}\E/option selected>$form->{"AP_amount_$i"}/;
+
+ # format amounts
+ $form->{"amount_$i"} = $form->format_amount(\%myconfig, $form->{"amount_$i"}, 2);
+
+ print qq|
+ <tr>
+ <th align=right nowrap>$amount</th>
+ <td><input name="amount_$i" size=10 value=$form->{"amount_$i"}></td>
+ <th>$project</th>
+ <td><input name="projectnumber_$i" size=20 value="$form->{"projectnumber_$i"}">
+ <input type=hidden name="project_id_$i" value=$form->{"project_id_$i"}>
+ <input type=hidden name="oldprojectnumber_$i" value="$form->{"oldprojectnumber_$i"}"></td>
+ <td width=50%><select name="AP_amount_$i">$form->{selectAP_amount}</select></td>
+ </tr>
+|;
+ $amount = "";
+ $project = "";
+ }
+
+ $taxlabel = ($form->{taxincluded}) ? $locale->text('Tax Included') : $locale->text('Tax');
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+
+ # format and reverse tax
+ $form->{"tax_$item"} = $form->format_amount(\%myconfig, $form->{"tax_$item"}, 2);
+
+ print qq|
+ <tr>
+ <th align=right nowrap>${taxlabel}</th>
+ <td><input name="tax_$item" size=10 value=$form->{"tax_$item"}></td>
+ <td colspan=2></td>
+ <td><select name=AP_tax_$item>$form->{"selectAP_tax_$item"}</select></td>
+ </tr>
+ <input type=hidden name="${item}_rate" value="$form->{"${item}_rate"}">
+ <input type=hidden name="${item}_description" value="$form->{"${item}_description"}">
+ <input type=hidden name="selectAP_tax_$item" value="$form->{"selectAP_tax_$item"}">
+|;
+ }
+
+ $form->{invtotal} = $form->format_amount(\%myconfig, $form->{invtotal}, 2);
+
+ print qq|
+ <tr>
+ <th align=right nowrap>|.$locale->text('Total').qq|</th>
+ <td>$form->{invtotal}</td>
+ <td colspan=2></td>
+ <td><select name=AP>$form->{selectAP}</select></td>
+ <input type=hidden name=selectAP value="$form->{selectAP}">
+ <input type=hidden name=taxaccounts value="$form->{taxaccounts}">
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Notes').qq|</th>
+ <td colspan=5>$notes</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+ <th class=listheading colspan=5>|.$locale->text('Payments').qq|</th>
+ </tr>
+|;
+
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ @column_index = qw(datepaid source paid AP_paid);
+ } else {
+ @column_index = qw(datepaid source paid exchangerate AP_paid);
+ }
+
+ $column_data{datepaid} = "<th>".$locale->text('Date')."</th>";
+ $column_data{paid} = "<th>".$locale->text('Amount')."</th>";
+ $column_data{exchangerate} = "<th>".$locale->text('Exch')."</th>";
+ $column_data{AP_paid} = "<th>".$locale->text('Account')."</th>";
+ $column_data{source} = "<th>".$locale->text('Source')."</th>";
+
+ print "
+ <tr>
+";
+ map { print "$column_data{$_}\n" } @column_index;
+ print "
+ </tr>
+";
+
+ $form->{paidaccounts}++ if ($form->{"paid_$form->{paidaccounts}"});
+ for $i (1 .. $form->{paidaccounts}) {
+ print "
+ <tr>
+";
+
+ $form->{"selectAP_paid_$i"} = $form->{selectAP_paid};
+ $form->{"selectAP_paid_$i"} =~ s/option>\Q$form->{"AP_paid_$i"}\E/option selected>$form->{"AP_paid_$i"}/;
+
+ # format amounts
+ $form->{"paid_$i"} = $form->format_amount(\%myconfig, $form->{"paid_$i"}, 2);
+ $form->{"exchangerate_$i"} = $form->format_amount(\%myconfig, $form->{"exchangerate_$i"});
+
+ $exchangerate = qq|&nbsp;|;
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ if ($form->{"forex_$i"}) {
+ $exchangerate = qq|<input type=hidden name="exchangerate_$i" value=$form->{"exchangerate_$i"}>$form->{"exchangerate_$i"}|;
+ } else {
+ $exchangerate = qq|<input name="exchangerate_$i" size=10 value=$form->{"exchangerate_$i"}>|;
+ }
+ }
+
+ $exchangerate .= qq|
+<input type=hidden name="forex_$i" value=$form->{"forex_$i"}>
+|;
+
+ $column_data{"paid_$i"} = qq|<td align=center><input name="paid_$i" size=10 value=$form->{"paid_$i"}></td>|;
+ $column_data{"AP_paid_$i"} = qq|<td align=center><select name="AP_paid_$i">$form->{"selectAP_paid_$i"}</select></td>|;
+ $column_data{"exchangerate_$i"} = qq|<td align=center>$exchangerate</td>|;
+ $column_data{"datepaid_$i"} = qq|<td align=center><input name="datepaid_$i" size=11 title="($myconfig{'dateformat'})" value=$form->{"datepaid_$i"}></td>|;
+ $column_data{"source_$i"} = qq|<td align=center><input name="source_$i" size=10 value="$form->{"source_$i"}"></td>|;
+
+ map { print qq|$column_data{"${_}_$i"}\n| } @column_index;
+
+ print "
+ </tr>
+";
+ }
+
+ print qq|
+ <input type=hidden name=paidaccounts value=$form->{paidaccounts}>
+ <input type=hidden name=selectAP_paid value="$form->{selectAP_paid}">
+
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+|;
+
+}
+
+
+sub form_footer {
+
+ print qq|
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+|;
+
+ $transdate = $form->datetonum($form->{transdate}, \%myconfig);
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+
+ if ($form->{id}) {
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+|;
+
+ if (!$form->{revtrans}) {
+ if (!$form->{locked}) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Delete').qq|">
+|;
+ }
+ }
+
+ if ($transdate > $closedto) {
+ print qq|
+<input class=submit type=submit name=action value="|.$locale->text('Post as new').qq|">
+|;
+ }
+
+ } else {
+ if ($transdate > $closedto) {
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">|;
+ }
+ }
+
+ print "
+</form>
+
+</body>
+</html>
+";
+
+}
+
+
+sub update {
+ my $display = shift;
+
+ if ($display) {
+ goto TAXCALC;
+ }
+
+ $form->{invtotal} = 0;
+
+ $form->{exchangerate} = $form->parse_amount(\%myconfig, $form->{exchangerate});
+
+ @flds = qw(amount AP_amount projectnumber oldprojectnumber project_id);
+ $count = 0;
+ for $i (1 .. $form->{rowcount}) {
+ $form->{"amount_$i"} = $form->parse_amount(\%myconfig, $form->{"amount_$i"});
+ if ($form->{"amount_$i"}) {
+ push @a, {};
+ my $j = $#a;
+ map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds;
+ $count++;
+ }
+ }
+ $form->redo_rows(\@flds, \@a, $count, $form->{rowcount});
+ $form->{rowcount} = $count + 1;
+
+ map { $form->{invtotal} += $form->{"amount_$_"} } (1 .. $form->{rowcount});
+
+ $form->{exchangerate} = $exchangerate if ($form->{forex} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{transdate}, 'sell')));
+
+ $form->{invdate} = $form->{transdate};
+ &check_name(vendor);
+
+ &check_project;
+
+
+TAXCALC:
+ # recalculate taxes
+ if ($form->{taxincluded}) {
+ $taxrate = 0;
+
+ map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{taxaccounts};
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ $amount = ($form->{invtotal} * (1 - 1 / (1 + $taxrate)) * $form->{"${item}_rate"} / $taxrate) if $taxrate;
+ $form->{"tax_$item"} = $form->round_amount($amount, 2);
+ $taxdiff += ($amount - $form->{"tax_$item"});
+ if (abs $taxdiff >= 0.005) {
+ $form->{"tax_$item"} += $form->round_amount($taxdiff, 2);
+ $taxdiff = 0;
+ }
+ $form->{"selectAP_tax_$item"} = qq|<option>$item--$form->{"${item}_description"}|;
+ $totaltax += $form->{"tax_$item"};
+ }
+ } else {
+ foreach $item (split / /, $form->{taxaccounts}) {
+ $form->{"tax_$item"} = $form->round_amount($form->{invtotal} * $form->{"${item}_rate"}, 2);
+ $form->{"selectAP_tax_$item"} = qq|<option>$item--$form->{"${item}_description"}|;
+ $totaltax += $form->{"tax_$item"};
+ }
+ }
+
+ $form->{invtotal} = ($form->{taxincluded}) ? $form->{invtotal} : $form->{invtotal} + $totaltax;
+
+ for $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"}) {
+ map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(paid exchangerate);
+
+ $form->{"exchangerate_$i"} = $exchangerate if ($form->{"forex_$i"} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'sell')));
+ }
+ }
+
+ &display_form;
+
+}
+
+
+sub post {
+
+ # check if there is an invoice number, invoice and due date
+ $form->isblank("invnumber", $locale->text("Invoice Number missing!"));
+ $form->isblank("transdate", $locale->text("Invoice Date missing!"));
+ $form->isblank("duedate", $locale->text("Due Date missing!"));
+ $form->isblank("vendor", $locale->text('Vendor missing!'));
+
+
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+ $transdate = $form->datetonum($form->{transdate}, \%myconfig);
+
+ $form->error($locale->text('Cannot post transaction for a closed period!')) if ($transdate <= $closedto);
+
+ $form->isblank("exchangerate", $locale->text('Exchangerate missing!')) if ($form->{currency} ne $form->{defaultcurrency});
+
+ for $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"}) {
+ $datepaid = $form->datetonum($form->{"datepaid_$i"}, \%myconfig);
+
+ $form->isblank("datepaid_$i", $locale->text('Payment date missing!'));
+
+ $form->error($locale->text('Cannot post payment for a closed period!')) if ($datepaid <= $closedto);
+
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ $form->{"exchangerate_$i"} = $form->{exchangerate} if ($transdate == $datepaid);
+ $form->isblank("exchangerate_$i", $locale->text('Exchangerate for payment missing!'));
+ }
+
+ }
+ }
+
+
+ # if old vendor ne vendor redo form
+ ($vendor) = split /--/, $form->{vendor};
+ if ($form->{oldvendor} ne "$vendor--$form->{vendor_id}") {
+ &update;
+ exit;
+ }
+
+ $form->{id} = 0 if $form->{postasnew};
+
+ $form->redirect($locale->text('Transaction posted!')) if (AP->post_transaction(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot post transaction!'));
+
+}
+
+
+sub post_as_new {
+
+ $form->{postasnew} = 1;
+ &post;
+
+}
+
+
+sub delete {
+
+ $form->{title} = $locale->text('Confirm!');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+|;
+
+ foreach $key (keys %$form) {
+ print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
+ }
+
+ print qq|
+<h2 class=confirm>$form->{title}</h2>
+
+<h4>|.$locale->text('Are you sure you want to delete Transaction').qq| $form->{invnumber}</h4>
+
+<input name=action class=submit type=submit value="|.$locale->text('Yes').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub yes {
+
+ $form->redirect($locale->text('Transaction deleted!')) if (AP->delete_transaction(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot delete transaction!'));
+
+}
+
+
+sub search {
+
+ # setup vendor selection
+ $form->all_vc(\%myconfig, "vendor");
+
+ if (@{ $form->{all_vendor} }) {
+ map { $vendor .= "<option>$_->{name}--$_->{id}\n" } @{ $form->{all_vendor} };
+ $vendor = qq|<select name=vendor><option>\n$vendor\n</select>|;
+ } else {
+ $vendor = qq|<input name=vendor size=35>|;
+ }
+
+ $form->{title} = $locale->text('AP Transactions');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Vendor').qq|</th>
+ <td colspan=3>$vendor</td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Invoice Number').qq|</th>
+ <td colspan=3><input name=invnumber size=20></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Order Number').qq|</th>
+ <td colspan=3><input name=ordnumber size=20></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Notes').qq|</th>
+ <td colspan=3><input name=notes size=40></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('From').qq|</th>
+ <td><input name=transdatefrom size=11 title="$myconfig{dateformat}"></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=transdateto size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <input type=hidden name=sort value=transdate>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Include in Report').qq|</th>
+ <td>
+ <table width=100%>
+ <tr>
+ <td align=right><input name=open class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Open').qq|</td>
+ <td align=right><input name=closed class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Closed').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_id" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('ID').qq|</td>
+ <td align=right><input name="l_invnumber" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Invoice Number').qq|</td>
+ <td align=right><input name="l_ordnumber" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Order Number').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_name" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Vendor').qq|</td>
+ <td align=right><input name="l_transdate" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Invoice Date').qq|</td>
+ <td align=right><input name="l_netamount" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Amount').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_tax" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Tax').qq|</td>
+ <td align=right><input name="l_amount" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Total').qq|</td>
+ <td align=right><input name="l_datepaid" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Date Paid').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_paid" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Paid').qq|</td>
+ <td align=right><input name="l_duedate" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Due Date').qq|</td>
+ <td align=right><input name="l_due" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Amount Due').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_notes" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Notes').qq|</td>
+ <td align=right><input name="l_employee" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Employee').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_subtotal" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Subtotal').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<input type=hidden name=nextsub value=$form->{nextsub}>
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub ap_transactions {
+
+ $form->{vendor} = $form->unescape($form->{vendor});
+ ($form->{vendor}, $form->{vendor_id}) = split(/--/, $form->{vendor});
+
+ AP->ap_transactions(\%myconfig, \%$form);
+
+ $callback = "$form->{script}?action=ap_transactions&path=$form->{path}&login=$form->{login}&password=$form->{password}";
+ $href = $callback;
+
+
+ if ($form->{vendor}) {
+ $callback .= "&vendor=".$form->escape($form->{vendor});
+ $href .= "&vendor=".$form->escape($form->{vendor});
+ $option .= $locale->text('Vendor')." : $form->{vendor}";
+ }
+ if ($form->{invnumber}) {
+ $callback .= "&invnumber=$form->{invnumber}";
+ $href .= "&invnumber=".$form->escape($form->{invnumber});
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('Invoice Number')." : $form->{invnumber}";
+ }
+ if ($form->{ordnumber}) {
+ $callback .= "&ordnumber=$form->{ordnumber}";
+ $href .= "&ordnumber=".$form->escape($form->{ordnumber});
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('Order Number')." : $form->{ordnumber}";
+ }
+ if ($form->{notes}) {
+ $callback .= "&notes=$form->{notes}";
+ $href .= "&notes=".$form->escape($form->{notes});
+ $option .= "\n<br>" if $option;
+ $option .= $locale->text('Notes')." : $form->{notes}";
+ }
+
+ if ($form->{transdatefrom}) {
+ $callback .= "&transdatefrom=$form->{transdatefrom}";
+ $href .= "&transdatefrom=$form->{transdatefrom}";
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('From')." ".$locale->date(\%myconfig, $form->{transdatefrom}, 1);
+ }
+ if ($form->{transdateto}) {
+ $callback .= "&transdateto=$form->{transdateto}";
+ $href .= "&transdateto=$form->{transdateto}";
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('to')." ".$locale->date(\%myconfig, $form->{transdateto}, 1);
+ }
+ if ($form->{open}) {
+ $callback .= "&open=$form->{open}";
+ $href .= "&open=$form->{open}";
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('Open');
+ }
+ if ($form->{closed}) {
+ $callback .= "&closed=$form->{closed}";
+ $href .= "&closed=$form->{closed}";
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('Closed');
+ }
+
+ @columns = $form->sort_columns(qw(transdate id invnumber ordnumber name netamount tax amount paid datepaid due duedate notes employee));
+
+ foreach $item (@columns) {
+ if ($form->{"l_$item"} eq "Y") {
+ push @column_index, $item;
+
+ # add column to href and callback
+ $callback .= "&l_$item=Y";
+ $href .= "&l_$item=Y";
+ }
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ $callback .= "&l_subtotal=Y";
+ $href .= "&l_subtotal=Y";
+ }
+
+
+ $column_header{id} = qq|<th><a class=listheading href=$href&sort=id>|.$locale->text('ID').qq|</a></th>|;
+ $column_header{transdate} = qq|<th><a class=listheading href=$href&sort=transdate>|.$locale->text('Date').qq|</a></th>|;
+ $column_header{duedate} = qq|<th><a class=listheading href=$href&sort=duedate>|.$locale->text('Due Date').qq|</a></th>|;
+ $column_header{due} = qq|<th class=listheading>|.$locale->text('Amount Due').qq|</th>|;
+ $column_header{invnumber} = qq|<th><a class=listheading href=$href&sort=invnumber>|.$locale->text('Invoice').qq|</a></th>|;
+ $column_header{ordnumber} = qq|<th><a class=listheading href=$href&sort=ordnumber>|.$locale->text('Order').qq|</a></th>|;
+ $column_header{name} = qq|<th><a class=listheading href=$href&sort=name>|.$locale->text('Vendor').qq|</a></th>|;
+ $column_header{netamount} = qq|<th class=listheading>|.$locale->text('Amount').qq|</th>|;
+ $column_header{tax} = qq|<th class=listheading>|.$locale->text('Tax').qq|</th>|;
+ $column_header{amount} = qq|<th class=listheading>|.$locale->text('Total').qq|</th>|;
+ $column_header{paid} = qq|<th class=listheading>|.$locale->text('Paid').qq|</th>|;
+ $column_header{datepaid} = qq|<th><a class=listheading href=$href&sort=datepaid>|.$locale->text('Date Paid').qq|</a></th>|;
+ $column_header{notes} = qq|<th><a class=listheading>|.$locale->text('Notes').qq|</th>|;
+ $column_header{employee} = "<th><a class=listheading href=$href&sort=employee>".$locale->text('Employee')."</th>";
+
+
+ $form->{title} = $locale->text('AP Transactions');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$option</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+ map { print "\n$column_header{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ # add sort and escape callback
+ $form->{callback} = "$callback&sort=$form->{sort}";
+ $callback = $form->escape($form->{callback});
+
+ if (@{ $form->{AP} }) {
+ $sameitem = $form->{AP}->[0]->{$form->{sort}};
+ }
+
+ # sums and tax on reports by Antonio Gallardo
+ #
+ foreach $ap (@{ $form->{AP} }) {
+
+ if ($form->{l_subtotal} eq 'Y') {
+ if ($sameitem ne $ap->{$form->{sort}}) {
+ &ap_subtotal;
+ $sameitem = $ap->{$form->{sort}};
+ }
+ }
+
+ $column_data{netamount} = "<td align=right>".$form->format_amount(\%myconfig, $ap->{netamount}, 2, "&nbsp;")."</td>";
+ $column_data{tax} = "<td align=right>".$form->format_amount(\%myconfig, $ap->{amount} - $ap->{netamount}, 2, "&nbsp;") . "</td>";
+ $column_data{amount} = "<td align=right>".$form->format_amount(\%myconfig, $ap->{amount}, 2, "&nbsp;") . "</td>";
+ $column_data{paid} = "<td align=right>".$form->format_amount(\%myconfig, $ap->{paid}, 2, "&nbsp;")."</td>";
+ $column_data{due} = "<td align=right>".$form->format_amount(\%myconfig, $ap->{amount} - $ap->{paid}, 2, "&nbsp;")."</td>";
+
+ $totalnetamount += $ap->{netamount};
+ $totalamount += $ap->{amount};
+ $totalpaid += $ap->{paid};
+ $totaldue += ($ap->{amount} - $ap->{paid});
+
+ $subtotalnetamount += $ap->{netamount};
+ $subtotalamount += $ap->{amount};
+ $subtotalpaid += $ap->{paid};
+ $subtotaldue += ($ap->{amount} - $ap->{paid});
+
+ $column_data{transdate} = "<td>$ap->{transdate}&nbsp;</td>";
+ $column_data{duedate} = "<td>$ap->{duedate}&nbsp;</td>";
+ $column_data{datepaid} = "<td>$ap->{datepaid}&nbsp;</td>";
+
+ $module = ($ap->{invoice}) ? "ir.pl" : $form->{script};
+
+ $column_data{invnumber} = qq|<td><a href="$module?action=edit&path=$form->{path}&id=$ap->{id}&login=$form->{login}&password=$form->{password}&callback=$callback">$ap->{invnumber}</a></td>|;
+ $column_data{id} = "<td>$ap->{id}</td>";
+ $column_data{ordnumber} = "<td>$ap->{ordnumber}&nbsp;</td>";
+ $column_data{name} = "<td>$ap->{name}</td>";
+ $ap->{notes} =~ s/\r\n/<br>/g;
+ $column_data{notes} = "<td>$ap->{notes}&nbsp;</td>";
+ $column_data{employee} = "<td>$ap->{employee}&nbsp;</td>";
+
+ $i++;
+ $i %= 2;
+ print "
+ <tr class=listrow$i >
+";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ &ap_subtotal;
+ }
+
+ # print totals
+ print qq|
+ <tr class=listtotal>
+|;
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{netamount} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{tax} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalamount - $totalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{amount} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalamount, 2, "&nbsp;")."</th>";
+ $column_data{paid} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalpaid, 2, "&nbsp;")."</th>";
+ $column_data{due} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totaldue, 2, "&nbsp;")."</th>";
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<form method=post action=$form->{script}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input class=submit type=submit name=action value="|.$locale->text('AP Transaction').qq|">
+
+<input class=submit type=submit name=action value="|.$locale->text('Vendor Invoice').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub ap_subtotal {
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{netamount} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{tax} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalamount - $subtotalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{amount} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalamount, 2, "&nbsp;")."</th>";
+ $column_data{paid} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalpaid, 2, "&nbsp;")."</th>";
+ $column_data{due} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotaldue, 2, "&nbsp;")."</th>";
+
+ $subtotalnetamount = 0;
+ $subtotalamount = 0;
+ $subtotalpaid = 0;
+ $subtotaldue = 0;
+
+ print "<tr class=listsubtotal>";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+}
+
+
+
diff --git a/sql-ledger/bin/mozilla/ar.pl b/sql-ledger/bin/mozilla/ar.pl
new file mode 100644
index 0000000..341c038
--- /dev/null
+++ b/sql-ledger/bin/mozilla/ar.pl
@@ -0,0 +1,1135 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Accounts Receivables
+#
+#======================================================================
+
+
+use SL::AR;
+use SL::IS;
+use SL::PE;
+
+require "$form->{path}/arap.pl";
+
+1;
+# end of main
+
+# this is for our long dates
+# $locale->text('January')
+# $locale->text('February')
+# $locale->text('March')
+# $locale->text('April')
+# $locale->text('May ')
+# $locale->text('June')
+# $locale->text('July')
+# $locale->text('August')
+# $locale->text('September')
+# $locale->text('October')
+# $locale->text('November')
+# $locale->text('December')
+
+# this is for our short month
+# $locale->text('Jan')
+# $locale->text('Feb')
+# $locale->text('Mar')
+# $locale->text('Apr')
+# $locale->text('May')
+# $locale->text('Jun')
+# $locale->text('Jul')
+# $locale->text('Aug')
+# $locale->text('Sep')
+# $locale->text('Oct')
+# $locale->text('Nov')
+# $locale->text('Dec')
+
+
+sub add {
+
+ $form->{title} = "Add";
+ $form->{callback} = "$form->{script}?action=add&path=$form->{path}&login=$form->{login}&password=$form->{password}" unless $form->{callback};
+
+ &create_links;
+ &display_form;
+
+}
+
+
+sub edit {
+
+ $form->{title} = "Edit";
+
+ &create_links;
+ &display_form;
+
+}
+
+
+sub display_form {
+
+ &form_header;
+ &form_footer;
+
+}
+
+
+sub create_links {
+
+ $form->create_links("AR", \%myconfig, "customer");
+ $duedate = $form->{duedate};
+
+ $taxincluded = $form->{taxincluded};
+
+ IS->get_customer(\%myconfig, \%$form);
+
+ $form->{duedate} = $duedate;
+ $form->{oldcustomer} = "$form->{customer}--$form->{customer_id}";
+
+ # currencies
+ @curr = split /:/, $form->{currencies};
+ chomp $curr[0];
+ $form->{defaultcurrency} = $curr[0];
+
+ map { $form->{selectcurrency} .= "<option>$_\n" } @curr;
+
+ # customers
+ if (@{ $form->{all_customer} }) {
+ $form->{customer} = "$form->{customer}--$form->{customer_id}";
+ map { $form->{selectcustomer} .= "<option>$_->{name}--$_->{id}\n" } (@{ $form->{all_customer} });
+ }
+
+ # forex
+ $form->{forex} = $form->{exchangerate};
+ $exchangerate = ($form->{exchangerate}) ? $form->{exchangerate} : 1;
+
+ foreach $key (keys %{ $form->{AR_links} }) {
+
+ foreach $ref (@{ $form->{AR_links}{$key} }) {
+ if ($key eq 'AR_tax') {
+ $form->{"selectAR_tax_$ref->{accno}"} = "<option>$ref->{accno}--$ref->{description}\n";
+ next;
+ }
+ $form->{"select$key"} .= "<option>$ref->{accno}--$ref->{description}\n";
+ }
+
+ # if there is a value we have an old entry
+ for $i (1 .. scalar @{ $form->{acc_trans}{$key} }) {
+ if ($key eq "AR_paid") {
+ $form->{"AR_paid_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{accno}--$form->{acc_trans}{$key}->[$i-1]->{description}";
+ # reverse paid
+ $form->{"paid_$i"} = $form->{acc_trans}{$key}->[$i-1]->{amount} * -1;
+ $form->{"datepaid_$i"} = $form->{acc_trans}{$key}->[$i-1]->{transdate};
+ $form->{"source_$i"} = $form->{acc_trans}{$key}->[$i-1]->{source};
+
+ $form->{"forex_$i"} = $form->{"exchangerate_$i"} = $form->{acc_trans}{$key}->[$i-1]->{exchangerate};
+
+ $form->{paidaccounts}++;
+ } else {
+
+ $akey = $key;
+ $akey =~ s/AR_//;
+
+ if ($key eq "AR_tax") {
+
+ $form->{"${key}_$form->{acc_trans}{$key}->[$i-1]->{accno}"} = "$form->{acc_trans}{$key}->[$i-1]->{accno}--$form->{acc_trans}{$key}->[$i-1]->{description}";
+ $form->{"${akey}_$form->{acc_trans}{$key}->[$i-1]->{accno}"} = $form->round_amount($form->{acc_trans}{$key}->[$i-1]->{amount} / $exchangerate, 2);
+ $totaltax += $form->{"${akey}_$form->{acc_trans}{$key}->[$i-1]->{accno}"};
+ } else {
+ $form->{"${akey}_$i"} = $form->round_amount($form->{acc_trans}{$key}->[$i-1]->{amount} / $exchangerate, 2);
+ if ($akey eq 'amount') {
+ $form->{rowcount}++;
+ $totalamount += $form->{"${akey}_$i"};
+
+ $form->{"oldprojectnumber_$i"} = $form->{"projectnumber_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{projectnumber}";
+ $form->{"project_id_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{project_id}";
+ }
+ $form->{"${key}_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{accno}--$form->{acc_trans}{$key}->[$i-1]->{description}";
+ }
+ }
+ }
+ }
+
+ $form->{taxincluded} = $taxincluded if ($form->{id});
+ $form->{paidaccounts} = 1 if not defined $form->{paidaccounts};
+
+ if ($form->{taxincluded} && $totalamount) {
+ # add tax to amounts and invtotal
+ for $i (1 .. $form->{rowcount}) {
+ $taxamount = $totaltax * $form->{"amount_$i"} / $totalamount;
+ $tax = $form->round_amount($taxamount, 2);
+ $diff += ($taxamount - $tax);
+ $form->{"amount_$i"} += $tax;
+ }
+ $form->{amount_1} += $form->round_amount($diff, 2);
+ }
+
+ $form->{invtotal} = $totalamount + $totaltax;
+ $form->{rowcount}++ if $form->{id};
+
+ $form->{AR} = $form->{AR_1};
+
+ $form->{locked} = ($form->datetonum($form->{transdate}, \%myconfig) <= $form->datetonum($form->{closedto}, \%myconfig));
+
+}
+
+
+sub form_header {
+
+ $title = $form->{title};
+ $form->{title} = $locale->text("$title Accounts Receivables Transaction");
+
+ $form->{taxincluded} = ($form->{taxincluded}) ? "checked" : "";
+
+# $locale->text('Add Accounts Receivables Transaction')
+# $locale->text('Edit Accounts Receivables Transaction')
+
+ # set option selected
+ foreach $item (qw(AR customer currency)) {
+ $form->{"select$item"} =~ s/ selected//;
+ $form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
+ }
+
+ # format amounts
+ $form->{exchangerate} = $form->format_amount(\%myconfig, $form->{exchangerate});
+
+ $form->{creditlimit} = $form->format_amount(\%myconfig, $form->{creditlimit}, 0, "0");
+ $form->{creditremaining} = $form->format_amount(\%myconfig, $form->{creditremaining}, 0, "0");
+
+ $exchangerate = qq|
+<input type=hidden name=forex value=$form->{forex}>
+|;
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ if ($form->{forex}) {
+ $exchangerate .= qq|
+ <th align=right>|.$locale->text('Exchangerate').qq|</th>
+ <td><input type=hidden name=exchangerate value=$form->{exchangerate}>$form->{exchangerate}</td>
+|;
+ } else {
+ $exchangerate .= qq|
+ <th align=right>|.$locale->text('Exchangerate').qq|</th>
+ <td><input name=exchangerate size=10 value=$form->{exchangerate}></td>
+|;
+ }
+ }
+
+ $taxincluded = "";
+ if ($form->{taxaccounts}) {
+ $taxincluded = qq|
+ <tr>
+ <td align=right><input name=taxincluded class=checkbox type=checkbox value=1 $form->{taxincluded}></td>
+ <th align=left nowrap>|.$locale->text('Tax Included').qq|</th>
+ </tr>
+|;
+ }
+
+
+ if (($rows = $form->numtextrows($form->{notes}, 50)) < 2) {
+ $rows = 2;
+ }
+ $notes = qq|<textarea name=notes rows=$rows cols=50 wrap=soft>$form->{notes}</textarea>|;
+
+
+ $form->header;
+
+ $n = ($form->{creditremaining} =~ /-/) ? "0" : "1";
+
+ $customer = ($form->{selectcustomer}) ? qq|<select name=customer>$form->{selectcustomer}</select>| : qq|<input name=customer value="$form->{customer}" size=35>|;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=id value=$form->{id}>
+<input type=hidden name=sort value=$form->{sort}>
+<input type=hidden name=closedto value=$form->{closedto}>
+<input type=hidden name=locked value=$form->{locked}>
+<input type=hidden name=title value="$title">
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr valign=top>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align="right" nowrap>|.$locale->text('Customer').qq|</th>
+ <td colspan=3>$customer</td>
+ <input type=hidden name=selectcustomer value="$form->{selectcustomer}">
+ <input type=hidden name=oldcustomer value="$form->{oldcustomer}">
+ <input type=hidden name=customer_id value="$form->{customer_id}">
+ <input type=hidden name=terms value=$form->{terms}>
+ </tr>
+ <tr>
+ <td></td>
+ <td colspan=3>
+ <table width=100%>
+ <tr>
+ <th align=left nowrap>|.$locale->text('Credit Limit').qq|</th>
+ <td>$form->{creditlimit}</td>
+ <th align=left nowrap>|.$locale->text('Remaining').qq|</th>
+ <td class="plus$n">$form->{creditremaining}</td>
+ <input type=hidden name=creditlimit value=$form->{creditlimit}>
+ <input type=hidden name=creditremaining value=$form->{creditremaining}>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ $taxincluded
+ <tr>
+ <th align=right>|.$locale->text('Currency').qq|</th>
+ <td><select name=currency>$form->{selectcurrency}</select></td>
+ <input type=hidden name=selectcurrency value="$form->{selectcurrency}">
+ <input type=hidden name=defaultcurrency value=$form->{defaultcurrency}>
+ <input type=hidden name=fxgain_accno value=$form->{fxgain_accno}>
+ <input type=hidden name=fxloss_accno value=$form->{fxloss_accno}>
+ $exchangerate
+ </tr>
+ </table>
+ </td>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Invoice Number').qq|</th>
+ <td><input name=invnumber size=11 value="$form->{invnumber}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Order Number').qq|</th>
+ <td><input name=ordnumber size=11 value="$form->{ordnumber}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Invoice Date').qq|</th>
+ <td><input name=transdate size=11 title="($myconfig{'dateformat'})" value=$form->{transdate}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Due Date').qq|</th>
+ <td><input name=duedate size=11 title="$myconfig{'dateformat'}" value=$form->{duedate}></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+
+<input type=hidden name=selectAR_amount value="$form->{selectAR_amount}">
+<input type=hidden name=rowcount value=$form->{rowcount}>
+|;
+
+ $amount = $locale->text('Amount');
+ $project = $locale->text('Project');
+
+ for $i (1 .. $form->{rowcount}) {
+
+ $form->{"selectAR_amount"} =~ s/ selected//;
+ $form->{"selectAR_amount"} =~ s/option>\Q$form->{"AR_amount_$i"}\E/option selected>$form->{"AR_amount_$i"}/;
+
+ # format amounts
+ $form->{"amount_$i"} = $form->format_amount(\%myconfig, $form->{"amount_$i"}, 2);
+
+ print qq|
+ <tr>
+ <th align=right>$amount</th>
+ <td><input name="amount_$i" size=10 value=$form->{"amount_$i"}></td>
+ <th>$project</th>
+ <td><input name="projectnumber_$i" size=20 value="$form->{"projectnumber_$i"}">
+ <input type=hidden name="project_id_$i" value=$form->{"project_id_$i"}>
+ <input type=hidden name="oldprojectnumber_$i" value="$form->{"oldprojectnumber_$i"}"></td>
+ <td width=50%><select name="AR_amount_$i">$form->{"selectAR_amount"}</select></td>
+ </tr>
+|;
+ $amount = "";
+ $project = "";
+ }
+
+ $taxlabel = ($form->{taxincluded}) ? $locale->text('Tax Included') : $locale->text('Tax');
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+
+ $form->{"tax_$item"} = $form->format_amount(\%myconfig, $form->{"tax_$item"}, 2);
+ print qq|
+ <tr>
+ <th align=right nowrap>$taxlabel</th>
+ <td><input name="tax_$item" size=10 value=$form->{"tax_$item"}></td>
+ <td colspan=2></td>
+ <td><select name="AR_tax_$item">$form->{"selectAR_tax_$item"}</select></td>
+ </tr>
+ <input type=hidden name="${item}_rate" value="$form->{"${item}_rate"}">
+ <input type=hidden name="${item}_description" value="$form->{"${item}_description"}">
+ <input type=hidden name="selectAR_tax_$item" value="$form->{"selectAR_tax_$item"}">
+|;
+
+ }
+
+ $form->{invtotal} = $form->format_amount(\%myconfig, $form->{invtotal}, 2);
+
+ print qq|
+ <tr>
+
+ <th align=right>|.$locale->text('Total').qq|</th>
+ <th align=left>$form->{invtotal}</th>
+
+ <input type=hidden name=oldinvtotal value=$form->{oldinvtotal}>
+ <input type=hidden name=oldtotalpaid value=$form->{oldtotalpaid}>
+
+ <input type=hidden name=taxaccounts value="$form->{taxaccounts}">
+
+ <td colspan=2></td>
+ <td><select name=AR>$form->{selectAR}</select></td>
+ <input type=hidden name=selectAR value="$form->{selectAR}">
+
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Notes').qq|</th>
+ <td colspan=4>$notes</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th class=listheading colspan=5>|.$locale->text('Payments').qq|</th>
+ </tr>
+|;
+
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ @column_index = qw(datepaid source paid AR_paid);
+ } else {
+ @column_index = qw(datepaid source paid exchangerate AR_paid);
+ }
+
+ $column_data{datepaid} = "<th>".$locale->text('Date')."</th>";
+ $column_data{paid} = "<th>".$locale->text('Amount')."</th>";
+ $column_data{exchangerate} = "<th>".$locale->text('Exch')."</th>";
+ $column_data{AR_paid} = "<th>".$locale->text('Account')."</th>";
+ $column_data{source} = "<th>".$locale->text('Source')."</th>";
+
+ print "
+ <tr>
+";
+ map { print "$column_data{$_}\n" } @column_index;
+ print "
+ </tr>
+";
+
+ $form->{paidaccounts}++ if ($form->{"paid_$form->{paidaccounts}"});
+ for $i (1 .. $form->{paidaccounts}) {
+ print "
+ <tr>
+";
+
+ $form->{"selectAR_paid_$i"} = $form->{selectAR_paid};
+ $form->{"selectAR_paid_$i"} =~ s/option>\Q$form->{"AR_paid_$i"}\E/option selected>$form->{"AR_paid_$i"}/;
+
+ # format amounts
+ $form->{"paid_$i"} = $form->format_amount(\%myconfig, $form->{"paid_$i"}, 2);
+ $form->{"exchangerate_$i"} = $form->format_amount(\%myconfig, $form->{"exchangerate_$i"});
+
+ $exchangerate = qq|&nbsp;|;
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ if ($form->{"forex_$i"}) {
+ $exchangerate = qq|<input type=hidden name="exchangerate_$i" value=$form->{"exchangerate_$i"}>$form->{"exchangerate_$i"}|;
+ } else {
+ $exchangerate = qq|<input name="exchangerate_$i" size=10 value=$form->{"exchangerate_$i"}>|;
+ }
+ }
+
+ $exchangerate .= qq|
+<input type=hidden name="forex_$i" value=$form->{"forex_$i"}>
+|;
+
+ $column_data{"paid_$i"} = qq|<td align=center><input name="paid_$i" size=10 value=$form->{"paid_$i"}></td>|;
+ $column_data{"AR_paid_$i"} = qq|<td align=center><select name="AR_paid_$i">$form->{"selectAR_paid_$i"}</select></td>|;
+ $column_data{"exchangerate_$i"} = qq|<td align=center>$exchangerate</td>|;
+ $column_data{"datepaid_$i"} = qq|<td align=center><input name="datepaid_$i" size=11 value=$form->{"datepaid_$i"}></td>|;
+ $column_data{"source_$i"} = qq|<td align=center><input name="source_$i" size=10 value="$form->{"source_$i"}"></td>|;
+
+ map { print qq|$column_data{"${_}_$i"}\n| } @column_index;
+
+ print "
+ </tr>
+";
+ }
+
+ print qq|
+<input type=hidden name=paidaccounts value=$form->{paidaccounts}>
+<input type=hidden name=selectAR_paid value="$form->{selectAR_paid}">
+
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+|;
+
+}
+
+
+sub form_footer {
+
+ print qq|
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+|;
+
+ $transdate = $form->datetonum($form->{transdate}, \%myconfig);
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+
+ if ($form->{id}) {
+
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+|;
+
+ if (!$form->{revtrans}) {
+ if (!$form->{locked}) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Delete').qq|">
+|;
+ }
+ }
+
+ if ($transdate > $closedto) {
+ print qq|
+<input class=submit type=submit name=action value="|.$locale->text('Post as new').qq|">
+|;
+ }
+
+ } else {
+ if ($transdate > $closedto) {
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">|;
+ }
+ }
+
+ print "
+</form>
+
+</body>
+</html>
+";
+
+}
+
+
+sub update {
+ my $display = shift;
+
+ if ($display) {
+ goto TAXCALC;
+ }
+
+ $form->{invtotal} = 0;
+
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(exchangerate creditlimit creditremaining);
+
+ @flds = qw(amount AR_amount projectnumber oldprojectnumber project_id);
+ $count = 0;
+ @a = ();
+ for $i (1 .. $form->{rowcount}) {
+ $form->{"amount_$i"} = $form->parse_amount(\%myconfig, $form->{"amount_$i"});
+ if ($form->{"amount_$i"}) {
+ push @a, {};
+ $j = $#a;
+
+ map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds;
+ $count++;
+ }
+ }
+
+ $form->redo_rows(\@flds, \@a, $count, $form->{rowcount});
+ $form->{rowcount} = $count + 1;
+
+ map { $form->{invtotal} += $form->{"amount_$_"} } (1 .. $form->{rowcount});
+
+ $form->{exchangerate} = $exchangerate if ($form->{forex} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{transdate}, 'buy')));
+
+
+ $form->{invdate} = $form->{transdate};
+ &check_name(customer);
+
+ &check_project;
+
+
+TAXCALC:
+ # recalculate taxes
+ if ($form->{taxincluded}) {
+ $taxrate = 0;
+
+ map { $taxrate += $form->{"${_}_rate"} } split / /, $form->{taxaccounts};
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ $amount = ($form->{invtotal} * (1 - 1 / (1 + $taxrate)) * $form->{"${item}_rate"} / $taxrate) if $taxrate;
+ $form->{"tax_$item"} = $form->round_amount($amount, 2);
+ $taxdiff += ($amount - $form->{"tax_$item"});
+ if (abs $taxdiff >= 0.005) {
+ $form->{"tax_$item"} += $form->round_amount($taxdiff, 2);
+ $taxdiff = 0;
+ }
+ $form->{"selectAR_tax_$item"} = qq|<option>$item--$form->{"${item}_description"}|;
+ $totaltax += $form->{"tax_$item"};
+ }
+ } else {
+ foreach $item (split / /, $form->{taxaccounts}) {
+ $form->{"tax_$item"} = $form->round_amount($form->{invtotal} * $form->{"${item}_rate"}, 2);
+ $form->{"selectAR_tax_$item"} = qq|<option>$item--$form->{"${item}_description"}|;
+ $totaltax += $form->{"tax_$item"};
+ }
+ }
+
+ $form->{invtotal} = ($form->{taxincluded}) ? $form->{invtotal} : $form->{invtotal} + $totaltax;
+
+ for $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"}) {
+ map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(paid exchangerate);
+
+ $totalpaid += $form->{"paid_$i"};
+
+ $form->{"exchangerate_$i"} = $exchangerate if ($form->{"forex_$i"} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy')));
+ }
+ }
+
+ $form->{creditremaining} -= ($form->{invtotal} - $totalpaid + $form->{oldtotalpaid} - $form->{oldinvtotal});
+ $form->{oldinvtotal} = $form->{invtotal};
+ $form->{oldtotalpaid} = $totalpaid;
+
+ &display_form;
+
+}
+
+
+sub post {
+
+ # check if there is an invoice number, invoice and due date
+ $form->isblank("invnumber", $locale->text('Invoice Number missing!'));
+ $form->isblank("transdate", $locale->text('Invoice Date missing!'));
+ $form->isblank("duedate", $locale->text('Due Date missing!'));
+ $form->isblank("customer", $locale->text('Customer missing!'));
+
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+ $transdate = $form->datetonum($form->{transdate}, \%myconfig);
+
+ $form->error($locale->text('Cannot post transaction for a closed period!')) if ($transdate <= $closedto);
+
+ $form->isblank("exchangerate", $locale->text('Exchangerate missing!')) if ($form->{currency} ne $form->{defaultcurrency});
+
+ for $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"}) {
+ $datepaid = $form->datetonum($form->{"datepaid_$i"}, \%myconfig);
+
+ $form->isblank("datepaid_$i", $locale->text('Payment date missing!'));
+
+ $form->error($locale->text('Cannot post payment for a closed period!')) if ($datepaid <= $closedto);
+
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ $form->{"exchangerate_$i"} = $form->{exchangerate} if ($transdate == $datepaid);
+ $form->isblank("exchangerate_$i", $locale->text('Exchangerate for payment missing!'));
+ }
+ }
+ }
+
+ # if oldcustomer ne customer redo form
+ ($customer) = split /--/, $form->{customer};
+ if ($form->{oldcustomer} ne "$customer--$form->{customer_id}") {
+ &update;
+ exit;
+ }
+
+ $form->{id} = 0 if $form->{postasnew};
+
+ $form->redirect($locale->text('Transaction posted!')) if (AR->post_transaction(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot post transaction!'));
+
+}
+
+
+sub post_as_new {
+
+ $form->{postasnew} = 1;
+ &post;
+
+}
+
+
+sub delete {
+
+ $form->{title} = $locale->text('Confirm!');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+|;
+
+ foreach $key (keys %$form) {
+ print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
+ }
+
+ print qq|
+<h2 class=confirm>$form->{title}</h2>
+
+<h4>|.$locale->text('Are you sure you want to delete Transaction').qq| $form->{invnumber}</h4>
+
+<input name=action class=submit type=submit value="|.$locale->text('Yes').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub yes {
+
+ $form->redirect($locale->text('Transaction deleted!')) if (AR->delete_transaction(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot delete transaction!'));
+
+}
+
+
+sub search {
+
+ # setup customer selection
+ $form->all_vc(\%myconfig, "customer");
+
+ if (@{ $form->{all_customer} }) {
+ map { $customer .= "<option>$_->{name}--$_->{id}\n" } @{ $form->{all_customer} };
+ $customer = qq|<select name=customer><option>\n$customer</select>|;
+ } else {
+ $customer = qq|<input name=customer size=35>|;
+ }
+
+ $form->{title} = $locale->text('AR Transactions');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr><th class=listtop>$form->{title}</th></tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Customer').qq|</th>
+ <td colspan=3>$customer</td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Invoice Number').qq|</th>
+ <td colspan=3><input name=invnumber size=20></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Order Number').qq|</th>
+ <td colspan=3><input name=ordnumber size=20></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Notes').qq|</th>
+ <td colspan=3><input name=notes size=40></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('From').qq|</th>
+ <td><input name=transdatefrom size=11 title="$myconfig{dateformat}"></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=transdateto size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <input type=hidden name=sort value=transdate>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Include in Report').qq|</th>
+ <td>
+ <table width=100%>
+ <tr>
+ <td align=right><input name=open class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Open').qq|</td>
+ <td align=right><input name=closed class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Closed').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_id" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('ID').qq|</td>
+ <td align=right><input name="l_invnumber" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Invoice Number').qq|</td>
+ <td align=right><input name="l_ordnumber" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Order Number').qq|</td>
+ <td align=right><input name="l_transdate" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Invoice Date').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_name" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Customer').qq|</td>
+ <td align=right><input name="l_netamount" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Amount').qq|</td>
+ <td align=right><input name="l_tax" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Tax').qq|</td>
+ <td align=right><input name="l_amount" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Total').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_datepaid" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Date Paid').qq|</td>
+ <td align=right><input name="l_paid" class=checkbox type=checkbox value=Y checked></td>
+ <td nowrap>|.$locale->text('Paid').qq|</td>
+ <td align=right><input name="l_duedate" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Due Date').qq|</td>
+ <td align=right><input name="l_due" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Amount Due').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_notes" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Notes').qq|</td>
+ <td align=right><input name="l_employee" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Salesperson').qq|</td>
+ <td align=right><input name="l_shippingpoint" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Ship via').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_subtotal" class=checkbox type=checkbox value=Y></td>
+ <td nowrap>|.$locale->text('Subtotal').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=nextsub value=$form->{nextsub}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub ar_transactions {
+
+ $form->{customer} = $form->unescape($form->{customer});
+ ($form->{customer}, $form->{customer_id}) = split(/--/, $form->{customer});
+
+ AR->ar_transactions(\%myconfig, \%$form);
+
+ $callback = "$form->{script}?action=ar_transactions&path=$form->{path}&login=$form->{login}&password=$form->{password}";
+ $href = $callback;
+
+ if ($form->{customer}) {
+ $callback .= "&customer=".$form->escape($form->{customer});
+ $href .= "&customer=".$form->escape($form->{customer});
+ $option = $locale->text('Customer')." : $form->{customer}";
+ }
+ if ($form->{invnumber}) {
+ $callback .= "&invnumber=$form->{invnumber}";
+ $href .= "&invnumber=".$form->escape($form->{invnumber});
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('Invoice Number')." : $form->{invnumber}";
+ }
+ if ($form->{ordnumber}) {
+ $callback .= "&ordnumber=$form->{ordnumber}";
+ $href .= "&ordnumber=".$form->escape($form->{ordnumber});
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('Order Number')." : $form->{ordnumber}";
+ }
+ if ($form->{notes}) {
+ $callback .= "&notes=$form->{notes}";
+ $href .= "&notes=".$form->escape($form->{notes});
+ $option .= "\n<br>" if $option;
+ $option .= $locale->text('Notes')." : $form->{notes}";
+ }
+
+ if ($form->{transdatefrom}) {
+ $callback .= "&transdatefrom=$form->{transdatefrom}";
+ $href .= "&transdatefrom=$form->{transdatefrom}";
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('From')."&nbsp;".$locale->date(\%myconfig, $form->{transdatefrom}, 1);
+ }
+ if ($form->{transdateto}) {
+ $callback .= "&transdateto=$form->{transdateto}";
+ $href .= "&transdateto=$form->{transdateto}";
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('to')."&nbsp;".$locale->date(\%myconfig, $form->{transdateto}, 1);
+ }
+ if ($form->{open}) {
+ $callback .= "&open=$form->{open}";
+ $href .= "&open=$form->{open}";
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('Open');
+ }
+ if ($form->{closed}) {
+ $callback .= "&closed=$form->{closed}";
+ $href .= "&closed=$form->{closed}";
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('Closed');
+ }
+
+ @columns = $form->sort_columns(qw(transdate id invnumber ordnumber name netamount tax amount paid datepaid due duedate notes employee shippingpoint));
+
+ foreach $item (@columns) {
+ if ($form->{"l_$item"} eq "Y") {
+ push @column_index, $item;
+
+ # add column to href and callback
+ $callback .= "&l_$item=Y";
+ $href .= "&l_$item=Y";
+ }
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ $callback .= "&l_subtotal=Y";
+ $href .= "&l_subtotal=Y";
+ }
+
+
+ $column_header{id} = "<th><a class=listheading href=$href&sort=id>".$locale->text('ID')."</a></th>";
+ $column_header{transdate} = "<th><a class=listheading href=$href&sort=transdate>".$locale->text('Date')."</a></th>";
+ $column_header{duedate} = "<th><a class=listheading href=$href&sort=duedate>".$locale->text('Due Date')."</a></th>";
+ $column_header{invnumber} = "<th><a class=listheading href=$href&sort=invnumber>".$locale->text('Invoice')."</a></th>";
+ $column_header{ordnumber} = "<th><a class=listheading href=$href&sort=ordnumber>".$locale->text('Order')."</a></th>";
+ $column_header{name} = "<th><a class=listheading href=$href&sort=name>".$locale->text('Customer')."</a></th>";
+ $column_header{netamount} = "<th class=listheading>" . $locale->text('Amount') . "</th>";
+ $column_header{tax} = "<th class=listheading>" . $locale->text('Tax') . "</th>";
+ $column_header{amount} = "<th class=listheading>" . $locale->text('Total') . "</th>";
+ $column_header{paid} = "<th class=listheading>" . $locale->text('Paid') . "</th>";
+ $column_header{datepaid} = "<th><a class=listheading href=$href&sort=datepaid>" . $locale->text('Date Paid') . "</a></th>";
+ $column_header{due} = "<th class=listheading>" . $locale->text('Amount Due') . "</th>";
+ $column_header{notes} = "<th class=listheading>".$locale->text('Notes')."</th>";
+ $column_header{employee} = "<th class=listheading><a class=listheading href=$href&sort=employee>".$locale->text('Salesperson')."</th>";
+
+ $column_header{shippingpoint} = "<th class=listheading><a class=listheading href=$href&sort=shippingpoint>" . $locale->text('Ship via') . "</a></th>";
+
+
+ $form->{title} = $locale->text('AR Transactions');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$option</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+ map { print "\n$column_header{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+
+ # add sort and escape callback, this one we use for the add sub
+ $form->{callback} = $callback .= "&sort=$form->{sort}";
+
+ # escape callback for href
+ $callback = $form->escape($callback);
+
+ if (@{ $form->{AR} }) {
+ $sameitem = $form->{AR}->[0]->{$form->{sort}};
+ }
+
+ # sums and tax on reports by Antonio Gallardo
+ #
+ foreach $ar (@{ $form->{AR} }) {
+
+ if ($form->{l_subtotal} eq 'Y') {
+ if ($sameitem ne $ar->{$form->{sort}}) {
+ &ar_subtotal;
+ }
+ }
+
+ $column_data{netamount} = "<td align=right>".$form->format_amount(\%myconfig, $ar->{netamount}, 2, "&nbsp;")."</td>";
+ $column_data{tax} = "<td align=right>".$form->format_amount(\%myconfig, $ar->{amount} - $ar->{netamount}, 2, "&nbsp;")."</td>";
+ $column_data{amount} = "<td align=right>".$form->format_amount(\%myconfig, $ar->{amount}, 2, "&nbsp;")."</td>";
+ $column_data{paid} = "<td align=right>".$form->format_amount(\%myconfig, $ar->{paid}, 2, "&nbsp;")."</td>";
+ $column_data{due} = "<td align=right>".$form->format_amount(\%myconfig, $ar->{amount} - $ar->{paid}, 2, "&nbsp;")."</td>";
+
+ $subtotalnetamount += $ar->{netamount};
+ $subtotalamount += $ar->{amount};
+ $subtotalpaid += $ar->{paid};
+ $subtotaldue += $ar->{amount} - $ar->{paid};
+
+ $totalnetamount += $ar->{netamount};
+ $totalamount += $ar->{amount};
+ $totalpaid += $ar->{paid};
+ $totaldue += ($ar->{amount} - $ar->{paid});
+
+ $column_data{transdate} = "<td>$ar->{transdate}&nbsp;</td>";
+ $column_data{id} = "<td>$ar->{id}</td>";
+ $column_data{datepaid} = "<td>$ar->{datepaid}&nbsp;</td>";
+ $column_data{duedate} = "<td>$ar->{duedate}&nbsp;</td>";
+
+ $module = ($ar->{invoice}) ? "is.pl" : $form->{script};
+
+ $column_data{invnumber} = "<td><a href=$module?action=edit&id=$ar->{id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ar->{invnumber}</a></td>";
+ $column_data{ordnumber} = "<td>$ar->{ordnumber}&nbsp;</td>";
+ $column_data{name} = "<td>$ar->{name}</td>";
+ $ar->{notes} =~ s/\r\n/<br>/g;
+ $column_data{notes} = "<td>$ar->{notes}&nbsp;</td>";
+ $column_data{shippingpoint} = "<td>$ar->{shippingpoint}&nbsp;</td>";
+ $column_data{employee} = "<td>$ar->{employee}&nbsp;</td>";
+
+ $i++; $i %= 2;
+ print "
+ <tr class=listrow$i>
+";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ &ar_subtotal;
+ }
+
+ # print totals
+ print qq|
+ <tr class=listtotal>
+|;
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{netamount} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{tax} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalamount - $totalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{amount} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalamount, 2, "&nbsp;")."</th>";
+ $column_data{paid} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalpaid, 2, "&nbsp;")."</th>";
+ $column_data{due} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totaldue, 2, "&nbsp;")."</th>";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<form method=post action=$form->{script}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input class=submit type=submit name=action value="|.$locale->text('AR Transaction').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Sales Invoice').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub ar_subtotal {
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{tax} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalamount - $subtotalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{amount} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalamount, 2, "&nbsp;")."</th>";
+ $column_data{paid} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalpaid, 2, "&nbsp;")."</th>";
+ $column_data{due} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotaldue, 2, "&nbsp;")."</th>";
+
+ $subtotalnetamount = 0;
+ $subtotalamount = 0;
+ $subtotalpaid = 0;
+ $subtotaldue = 0;
+
+ $sameitem = $ar->{$form->{sort}};
+
+ print "<tr class=listsubtotal>";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+print "
+</tr>
+";
+
+}
+
+
+
diff --git a/sql-ledger/bin/mozilla/arap.pl b/sql-ledger/bin/mozilla/arap.pl
new file mode 100644
index 0000000..fecd926
--- /dev/null
+++ b/sql-ledger/bin/mozilla/arap.pl
@@ -0,0 +1,406 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# common routines for gl, ar, ap, is, ir, oe
+#
+
+# any custom scripts for this one
+if (-f "$form->{path}/custom_arap.pl") {
+ eval { require "$form->{path}/custom_arap.pl"; };
+}
+if (-f "$form->{path}/$form->{login}_arap.pl") {
+ eval { require "$form->{path}/$form->{login}_arap.pl"; };
+}
+
+
+1;
+# end of main
+
+
+sub check_name {
+ my ($name) = @_;
+
+ my ($new_name, $new_id) = split /--/, $form->{$name};
+ my $i = 0;
+
+ # if we use a selection
+ if ($form->{"select$name"}) {
+ if ($form->{"old$name"} ne $form->{$name}) {
+ # this is needed for is, ir and oe
+ map { delete $form->{"${_}_rate"} } (split / /, $form->{taxaccounts});
+
+ # for credit calculations
+ $form->{oldinvtotal} = 0;
+ $form->{oldtotalpaid} = 0;
+
+ $form->{"${name}_id"} = $new_id;
+ $form->{"old$name"} = "$new_name--$new_id";
+
+ IS->get_customer(\%myconfig, \%$form) if ($name eq 'customer');
+ IR->get_vendor(\%myconfig, \%$form) if ($name eq 'vendor');
+
+ $i = 1;
+ }
+ } else {
+
+ # check name, combine name and id
+ if ($form->{"old$name"} ne qq|$form->{$name}--$form->{"${name}_id"}|) {
+ # this is needed for is, ir and oe
+ map { delete $form->{"${_}_rate"} } (split / /, $form->{taxaccounts});
+
+ # for credit calculations
+ $form->{oldinvtotal} = 0;
+ $form->{oldtotalpaid} = 0;
+
+ # return one name or a list of names in $form->{name_list}
+ if (($i = $form->get_name(\%myconfig, $name)) > 1) {
+ &select_name($name);
+ exit;
+ }
+
+ if ($i == 1) {
+ # we got one name
+ $form->{"${name}_id"} = $form->{name_list}[0]->{id};
+ $form->{$name} = $form->{name_list}[0]->{name};
+ $form->{"old$name"} = qq|$form->{$name}--$form->{"${name}_id"}|;
+
+ IS->get_customer(\%myconfig, \%$form) if ($name eq 'customer');
+ IR->get_vendor(\%myconfig, \%$form) if ($name eq 'vendor');
+
+ } else {
+ # name is not on file
+ $msg = ucfirst $name . " not on file!";
+ $form->error($locale->text($msg));
+ }
+ }
+ }
+
+ $i;
+
+}
+
+# $locale->text('Customer not on file!')
+# $locale->text('Vendor not on file!')
+
+
+
+sub select_name {
+ my ($table) = @_;
+
+ @column_index = qw(ndx name address);
+
+ $label = ucfirst $table;
+ $column_data{ndx} = qq|<th>&nbsp;</th>|;
+ $column_data{name} = qq|<th>|.$locale->text($label).qq|</th>|;
+ $column_data{address} = qq|<th>|.$locale->text('Address').qq|</th>|;
+
+ # list items with radio button on a form
+ $form->header;
+
+ $title = $locale->text('Select from one of the names below');
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$title</th>
+ </tr>
+ <tr space=5></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ my $i = 0;
+ foreach $ref (@{ $form->{name_list} }) {
+ $checked = ($i++) ? "" : "checked";
+
+ $ref->{name} =~ s/"/&quot;/g;
+
+ $column_data{ndx} = qq|<td><input name=ndx class=radio type=radio value=$i $checked></td>|;
+ $column_data{name} = qq|<td><input name="new_name_$i" type=hidden value="$ref->{name}">$ref->{name}</td>|;
+ $column_data{address} = qq|<td>$ref->{address}</td>|;
+
+ $j++; $j %= 2;
+ print qq|
+ <tr class=listrow$j>|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+
+<input name="new_id_$i" type=hidden value=$ref->{id}>
+
+|;
+
+ }
+
+ print qq|
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input name=lastndx type=hidden value=$i>
+
+|;
+
+ # delete action variable
+ delete $form->{action};
+ delete $form->{name_list};
+
+ # save all other form variables
+ foreach $key (keys %${form}) {
+ $form->{$key} =~ s/"/&quot;/g;
+ print qq|<input name=$key type=hidden value="$form->{$key}">\n|;
+ }
+
+ print qq|
+<input type=hidden name=nextsub value=name_selected>
+
+<input type=hidden name=vc value=$table>
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub name_selected {
+
+ # replace the variable with the one checked
+
+ # index for new item
+ $i = $form->{ndx};
+
+ $form->{$form->{vc}} = $form->{"new_name_$i"};
+ $form->{"$form->{vc}_id"} = $form->{"new_id_$i"};
+ $form->{"old$form->{vc}"} = qq|$form->{$form->{vc}}--$form->{"$form->{vc}_id"}|;
+
+ # delete all the new_ variables
+ for $i (1 .. $form->{lastndx}) {
+ map { delete $form->{"new_${_}_$i"} } (id, name);
+ }
+
+ map { delete $form->{$_} } qw(ndx lastndx nextsub);
+
+ IS->get_customer(\%myconfig, \%$form) if ($form->{vc} eq 'customer');
+ IR->get_vendor(\%myconfig, \%$form) if ($form->{vc} eq 'vendor');
+
+ &update(1);
+
+}
+
+
+sub add_transaction {
+ my ($module) = @_;
+
+ delete $form->{script};
+ $form->{action} = "add";
+ $form->{type} = "invoice" if $module =~ /(is|ir)/;
+
+ $form->{callback} = $form->escape($form->{callback},1);
+ map { $argv .= "$_=$form->{$_}&" } keys %$form;
+
+ exec ("perl", "$module.pl", $argv);
+
+}
+
+
+
+sub check_project {
+
+ for $i (1 .. $form->{rowcount}) {
+ $form->{"project_id_$i"} = "" unless $form->{"projectnumber_$i"};
+ if ($form->{"projectnumber_$i"} ne $form->{"oldprojectnumber_$i"}) {
+ if ($form->{"projectnumber_$i"}) {
+ # get new project
+ $form->{projectnumber} = $form->{"projectnumber_$i"};
+ if (($rows = PE->projects(\%myconfig, $form)) > 1) {
+ # check form->{project_list} how many there are
+ $form->{rownumber} = $i;
+ &select_project;
+ exit;
+ }
+
+ if ($rows == 1) {
+ $form->{"project_id_$i"} = $form->{project_list}->[0]->{id};
+ $form->{"projectnumber_$i"} = $form->{project_list}->[0]->{projectnumber};
+ $form->{"oldprojectnumber_$i"} = $form->{project_list}->[0]->{projectnumber};
+ } else {
+ # not on file
+ $form->error($locale->text('Project not on file!'));
+ }
+ }
+ }
+ }
+
+}
+
+
+sub select_project {
+
+ @column_index = qw(ndx projectnumber description);
+
+ $column_data{ndx} = qq|<th>&nbsp;</th>|;
+ $column_data{projectnumber} = qq|<th>|.$locale->text('Number').qq|</th>|;
+ $column_data{description} = qq|<th>|.$locale->text('Description').qq|</th>|;
+
+ # list items with radio button on a form
+ $form->header;
+
+ $title = $locale->text('Select from one of the projects below');
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=rownumber value=$form->{rownumber}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$title</th>
+ </tr>
+ <tr space=5></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ my $i = 0;
+ foreach $ref (@{ $form->{project_list} }) {
+ $checked = ($i++) ? "" : "checked";
+
+ $ref->{name} =~ s/"/&quot;/g;
+
+ $column_data{ndx} = qq|<td><input name=ndx class=radio type=radio value=$i $checked></td>|;
+ $column_data{projectnumber} = qq|<td><input name="new_projectnumber_$i" type=hidden value="$ref->{projectnumber}">$ref->{projectnumber}</td>|;
+ $column_data{description} = qq|<td>$ref->{description}</td>|;
+
+ $j++; $j %= 2;
+ print qq|
+ <tr class=listrow$j>|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+
+<input name="new_id_$i" type=hidden value=$ref->{id}>
+
+|;
+
+ }
+
+ print qq|
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input name=lastndx type=hidden value=$i>
+
+|;
+
+ # delete action variable
+ delete $form->{action};
+ delete $form->{project_list};
+
+ # save all other form variables
+ foreach $key (keys %${form}) {
+ $form->{$key} =~ s/"/&quot;/g;
+ print qq|<input name=$key type=hidden value="$form->{$key}">\n|;
+ }
+
+ print qq|
+<input type=hidden name=nextsub value=project_selected>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub project_selected {
+
+ # replace the variable with the one checked
+
+ # index for new item
+ $i = $form->{ndx};
+
+ $form->{"projectnumber_$form->{rownumber}"} = $form->{"new_projectnumber_$i"};
+ $form->{"oldprojectnumber_$form->{rownumber}"} = $form->{"new_projectnumber_$i"};
+ $form->{"project_id_$form->{rownumber}"} = $form->{"new_id_$i"};
+
+ # delete all the new_ variables
+ for $i (1 .. $form->{lastndx}) {
+ map { delete $form->{"new_${_}_$i"} } qw(id projectnumber description);
+ }
+
+ map { delete $form->{$_} } qw(ndx lastndx nextsub);
+
+ &update;
+
+}
+
+
+sub continue { &{ $form->{nextsub} } };
+sub gl_transaction { &add };
+sub ar_transaction { &add_transaction(ar) };
+sub ap_transaction { &add_transaction(ap) };
+sub sales_invoice { &add_transaction(is) };
+sub vendor_invoice { &add_transaction(ir) };
+
diff --git a/sql-ledger/bin/mozilla/ca.pl b/sql-ledger/bin/mozilla/ca.pl
new file mode 100644
index 0000000..ed31005
--- /dev/null
+++ b/sql-ledger/bin/mozilla/ca.pl
@@ -0,0 +1,413 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# module for Chart of Accounts, Income Statement and Balance Sheet
+# search and edit transactions posted by the GL, AR and AP
+#
+#======================================================================
+
+
+use SL::CA;
+
+1;
+# end of main
+
+# this is for our long dates
+# $locale->text('January')
+# $locale->text('February')
+# $locale->text('March')
+# $locale->text('April')
+# $locale->text('May ')
+# $locale->text('June')
+# $locale->text('July')
+# $locale->text('August')
+# $locale->text('September')
+# $locale->text('October')
+# $locale->text('November')
+# $locale->text('December')
+
+# this is for our short month
+# $locale->text('Jan')
+# $locale->text('Feb')
+# $locale->text('Mar')
+# $locale->text('Apr')
+# $locale->text('May')
+# $locale->text('Jun')
+# $locale->text('Jul')
+# $locale->text('Aug')
+# $locale->text('Sep')
+# $locale->text('Oct')
+# $locale->text('Nov')
+# $locale->text('Dec')
+
+
+sub chart_of_accounts {
+
+ CA->all_accounts(\%myconfig, \%$form);
+
+ @column_index = qw(accno gifi_accno description debit credit);
+
+ $column_header{accno} = qq|<th class=listheading>|.$locale->text('Account').qq|</th>\n|;
+ $column_header{gifi_accno} = qq|<th class=listheading>|.$locale->text('GIFI').qq|</th>\n|;
+ $column_header{description} = qq|<th class=listheading>|.$locale->text('Description').qq|</th>\n|;
+ $column_header{debit} = qq|<th class=listheading>|.$locale->text('Debit').qq|</th>\n|;
+ $column_header{credit} = qq|<th class=listheading>|.$locale->text('Credit').qq|</th>\n|;
+
+
+ $form->{title} = $locale->text('Chart of Accounts');
+
+ $colspan = $#column_index + 1;
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr><th class=listtop colspan=$colspan>$form->{title}</font></th></tr>
+ <tr height="5"></tr>
+ <tr class=listheading>|;
+
+ map { print $column_header{$_} } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+
+ foreach $ca (@{ $form->{CA} }) {
+
+ $description = $form->escape($ca->{description});
+ $gifi_description = $form->escape($ca->{gifi_description});
+
+ $href = qq|$form->{script}?path=$form->{path}&action=list&accno=$ca->{accno}&login=$form->{login}&password=$form->{password}&description=$description&gifi_accno=$ca->{gifi_accno}&gifi_description=$gifi_description|;
+
+ if ($ca->{charttype} eq "H") {
+ print qq|<tr class=listheading>|;
+ map { $column_data{$_} = "<th class=listheading>$ca->{$_}</th>"; } qw(accno description);
+ $column_data{gifi_accno} = "<th class=listheading>$ca->{gifi_accno}&nbsp;</font></th>";
+ } else {
+ $i++; $i %= 2;
+ print qq|<tr class=listrow$i>|;
+ $column_data{accno} = "<td><a href=$href>$ca->{accno}</a></td>";
+ $column_data{gifi_accno} = "<td><a href=$href&accounttype=gifi>$ca->{gifi_accno}</a>&nbsp;</td>";
+ $column_data{description} = "<td>$ca->{description}</td>";
+ }
+
+ $column_data{debit} = "<td align=right>".$form->format_amount(\%myconfig, $ca->{debit}, 2, "&nbsp;")."</td>\n";
+ $column_data{credit} = "<td align=right>".$form->format_amount(\%myconfig, $ca->{credit}, 2, "&nbsp;")."</td>\n";
+
+ $totaldebit += $ca->{debit};
+ $totalcredit += $ca->{credit};
+
+ map { print $column_data{$_} } @column_index;
+
+ print qq|
+</tr>
+|;
+ }
+
+ map { $column_data{$_} = "<td>&nbsp;</td>"; } qw(accno gifi_accno description);
+
+ $column_data{debit} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totaldebit, 2, 0)."</font></th>";
+ $column_data{credit} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalcredit, 2, 0)."</font></th>";
+
+ print "<tr class=listtotal>";
+
+ map { print $column_data{$_} } @column_index;
+
+ print qq|
+</tr>
+<tr>
+ <td colspan=$colspan><hr size=3 noshade></td>
+</tr>
+</table>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub list {
+
+ $form->{title} = $locale->text('List Transactions');
+ if ($form->{accounttype} eq 'gifi') {
+ $form->{title} .= " - ".$locale->text('GIFI')." $form->{gifi_accno}";
+ } else {
+ $form->{title} .= " - ".$locale->text('Account')." $form->{accno}";
+ }
+
+ $form->header;
+
+ map { $form->{$_} =~ s/"/&quot;/g; } qw(description gifi_description);
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=accno value=$form->{accno}>
+<input type=hidden name=description value="$form->{description}">
+<input type=hidden name=sort value=transdate>
+
+<input type=hidden name=accounttype value=$form->{accounttype}>
+<input type=hidden name=gifi_accno value=$form->{gifi_accno}>
+<input type=hidden name=gifi_description value="$form->{gifi_description}">
+
+<table border=0 width=100%>
+ <tr><th class=listtop>$form->{title}</font></th></tr>
+ <tr height="5"></tr
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('From').qq|</th>
+ <td><input name=fromdate size=11 title="$myconfig{dateformat}"></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=todate size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Include in Report').qq|</th>
+ <td colspan=3>
+ <input name=l_subtotal class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Subtotal').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr><td><hr size=3 noshade></td></tr>
+</table>
+
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=password value=$form->{password}>
+
+<br><input class=submit type=submit name=action value="|.$locale->text('List Transactions').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub list_transactions {
+
+ CA->all_transactions(\%myconfig, \%$form);
+
+ $description = $form->escape($form->{description});
+ $gifi_description = $form->escape($form->{gifi_description});
+
+ # construct href
+ $href = "$form->{script}?path=$form->{path}&action=list_transactions&accno=$form->{accno}&login=$form->{login}&password=$form->{password}&fromdate=$form->{fromdate}&todate=$form->{todate}&description=$description&accounttype=$form->{accounttype}&gifi_accno=$form->{gifi_accno}&gifi_description=$gifi_description&l_heading=$form->{l_heading}&l_subtotal=$form->{l_subtotal}";
+
+ # construct callback
+ $callback = "rp.pl?path=$form->{path}&action=generate_trial_balance&login=$form->{login}&password=$form->{password}&fromdate=$form->{fromdate}&todate=$form->{todate}&l_heading=$form->{l_heading}&l_subtotal=$form->{l_subtotal}&accounttype=$form->{accounttype}";
+
+ # figure out which column comes first
+ $column_header{transdate} = qq|<th><a class=listheading href=$href&sort=transdate>|.$locale->text('Date').qq|</a></th>|;
+ $column_header{reference} = qq|<th><a class=listheading href=$href&sort=reference>|.$locale->text('Reference').qq|</a></th>|;
+ $column_header{description} = qq|<th><a class=listheading href=$href&sort=description>|.$locale->text('Description').qq|</a></th>|;
+ $column_header{debit} = qq|<th class=listheading>|.$locale->text('Debit').qq|</th>|;
+ $column_header{credit} = qq|<th class=listheading>|.$locale->text('Credit').qq|</th>|;
+ $column_header{balance} = qq|<th class=listheading>|.$locale->text('Balance').qq|</th>|;
+
+ @column_index = $form->sort_columns(qw(transdate reference description debit credit));
+
+ if ($form->{accounttype} eq 'gifi') {
+ map { $form->{$_} = $form->{"gifi_$_"} } qw(accno description);
+ }
+ if ($form->{accno}) {
+ push @column_index, "balance";
+ }
+
+ $form->{title} = ($form->{accounttype} eq 'gifi') ? $locale->text('GIFI') : $locale->text('Account');
+
+ $form->{title} .= " $form->{accno} - $form->{description}";
+
+
+ if ($form->{fromdate} || $form->{todate}) {
+ if ($form->{fromdate}) {
+ $fromdate = $locale->date(\%myconfig, $form->{fromdate}, 1);
+ }
+ if ($form->{todate}) {
+ $todate = $locale->date(\%myconfig, $form->{todate}, 1);
+ }
+
+ $form->{period} = "$fromdate - $todate";
+ } else {
+ $form->{period} = $locale->date(\%myconfig, $form->current_date(\%myconfig),1);
+ }
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</font></th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$form->{period}</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+map { print "$column_header{$_}\n" } @column_index;
+
+print qq|
+ </tr>
+|;
+
+ # add sort to callback
+ $callback = $form->escape($callback . "&sort=$form->{sort}");
+
+ if (@{ $form->{CA} }) {
+ $sameitem = $form->{CA}->[0]->{$form->{sort}};
+ }
+
+ $ml = ($form->{category} =~ /(A|E)/) ? -1 : 1;
+ if ($form->{accno} && $form->{balance}) {
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{balance} = "<td align=right>".$form->format_amount(\%myconfig, $form->{balance} * $ml, 2, 0)."</td>";
+
+ $i++; $i %= 2;
+ print qq|
+ <tr class=listrow$i>
+|;
+ map { print $column_data{$_} } @column_index;
+ print qq|
+ </tr>
+|;
+ }
+
+ foreach $ca (@{ $form->{CA} }) {
+
+ if ($form->{l_subtotal} eq 'Y') {
+ if ($sameitem ne $ca->{$form->{sort}}) {
+ &ca_subtotal;
+ }
+ }
+
+ # construct link to source
+ $href = "<a href=$ca->{module}.pl?path=$form->{path}&action=edit&id=$ca->{id}&login=$form->{login}&password=$form->{password}&callback=$callback>$ca->{reference}</a>";
+
+
+ $column_data{debit} = "<td align=right>".$form->format_amount(\%myconfig, $ca->{debit}, 2, "&nbsp;")."</td>";
+ $column_data{credit} = "<td align=right>".$form->format_amount(\%myconfig, $ca->{credit}, 2, "&nbsp;")."</td>";
+
+ $form->{balance} += $ca->{amount};
+ $column_data{balance} = "<td align=right>".$form->format_amount(\%myconfig, $form->{balance} * $ml, 2, 0)."</td>";
+
+ $subtotaldebit += $ca->{debit};
+ $subtotalcredit += $ca->{credit};
+
+ $totaldebit += $ca->{debit};
+ $totalcredit += $ca->{credit};
+
+ $column_data{transdate} = qq|<td>$ca->{transdate}</td>|;
+ $column_data{reference} = qq|<td>$href</td>|;
+ $column_data{description} = qq|<td>$ca->{description}</td>|;
+
+ $i++; $i %= 2;
+ print qq|
+ <tr class=listrow$i>
+|;
+
+ map { print $column_data{$_} } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ }
+
+
+ if ($form->{l_subtotal} eq 'Y') {
+ &ca_subtotal;
+ }
+
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{debit} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totaldebit, 2, "&nbsp;")."</font></th>";
+ $column_data{credit} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalcredit, 2, "&nbsp;")."</font></th>";
+ $column_data{balance} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $form->{balance} * $ml, 2, 0)."</font></th>";
+
+ print qq|
+ <tr class=listtotal>
+|;
+
+ map { print $column_data{$_} } @column_index;
+
+ print qq|
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub ca_subtotal {
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{debit} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotaldebit, 2, "&nbsp;") . "</font></th>";
+ $column_data{credit} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalcredit, 2, "&nbsp;") . "</font></th>";
+
+ $subtotaldebit = 0;
+ $subtotalcredit = 0;
+
+ $sameitem = $ca->{$form->{sort}};
+
+ print qq|
+ <tr class=listsubtotal>
+|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+}
+
diff --git a/sql-ledger/bin/mozilla/cp.pl b/sql-ledger/bin/mozilla/cp.pl
new file mode 100644
index 0000000..911b701
--- /dev/null
+++ b/sql-ledger/bin/mozilla/cp.pl
@@ -0,0 +1,528 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Payment module
+#
+#======================================================================
+
+
+use SL::CP;
+use SL::IS;
+use SL::IR;
+
+require "$form->{path}/arap.pl";
+
+1;
+# end of main
+
+
+sub payment {
+
+ # setup customer/vendor selection for open invoices
+ CP->get_openvc(\%myconfig, \%$form);
+
+ if ($form->{"all_$form->{vc}"}) {
+ map { $form->{"select$form->{vc}"} .= "<option>$_->{name}--$_->{id}\n" } @{ $form->{"all_$form->{vc}"} };
+ }
+
+ $form->{arap} = ($form->{vc} eq 'customer') ? "AR" : "AP";
+
+ CP->paymentaccounts(\%myconfig, \%$form);
+
+ map { $form->{selectaccount} .= "<option>$_->{accno}--$_->{description}\n" } @{ $form->{PR} };
+
+ # currencies
+ @curr = split /:/, $form->{currencies};
+ chomp $curr[0];
+ $form->{defaultcurrency} = $form->{currency} = $form->{oldcurrency} = $curr[0];
+
+ map { $form->{selectcurrency} .= "<option>$_\n" } @curr;
+
+ $form->{media} = "screen";
+
+ &form_header;
+ &list_invoices;
+ &form_footer;
+
+}
+
+
+
+sub form_header {
+
+ $vclabel = ucfirst $form->{vc};
+ $vclabel = $locale->text($vclabel);
+
+ if ($form->{vc} eq 'customer') {
+ $form->{title} = $locale->text('Receipt');
+ $rclabel = $locale->text('Reference');
+ $form->{type} = 'receipt';
+ } else {
+ $form->{title} = $locale->text('Payment');
+ $rclabel = $locale->text('Check');
+ $form->{type} = 'check';
+ }
+
+# $locale->text('Customer')
+# $locale->text('Vendor')
+
+ if ($form->{$form->{vc}} eq "") {
+ map { $form->{"addr$_"} = "" } (1 .. 4);
+ }
+
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ $form->{exchangerate} = $form->format_amount(\%myconfig, $form->{exchangerate});
+ if ($form->{forex}) {
+ $exchangerate = qq|
+ <tr>
+ <th align=right nowrap>|.$locale->text('Exchangerate').qq|</th>
+ <td colspan=3><input type=hidden name=exchangerate size=10 value=$form->{exchangerate}>$form->{exchangerate}</td>
+ </tr>
+|;
+ } else {
+ $exchangerate = qq|
+ <tr>
+ <th align=right nowrap>|.$locale->text('Exchangerate').qq|</th>
+ <td colspan=3><input name=exchangerate size=10 value=$form->{exchangerate}></td>
+ </tr>
+|;
+ }
+ }
+
+ foreach $item ($form->{vc}, account, currency) {
+ $form->{"select$item"} =~ s/ selected//;
+ $form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
+ }
+
+ $vc = ($form->{"select$form->{vc}"}) ? qq|<select name=$form->{vc}>$form->{"select$form->{vc}"}\n</select>| : qq|<input name=$form->{vc} size=35 value="$form->{$form->{vc}}">|;
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=defaultcurrency value=$form->{defaultcurrency}>
+<input type=hidden name=closedto value=$form->{closedto}>
+<input type=hidden name=vc value=$form->{vc}>
+<input type=hidden name=type value=$form->{type}>
+
+<table border=0 width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right>$vclabel</th>
+ <td>$vc</td>
+ <input type=hidden name="select$form->{vc}" value="$form->{"select$form->{vc}"}">
+ <input type=hidden name="$form->{vc}_id" value=$form->{"$form->{vc}_id"}>
+ <input type=hidden name="old$form->{vc}" value="$form->{"old$form->{vc}"}">
+ </tr>
+ <tr valign=top>
+ <th align=right nowrap>|.$locale->text('Address').qq|</th>
+ <td>
+ <table>
+ <tr>
+ <td>$form->{addr1}</td>
+ </tr>
+ <tr>
+ <td>$form->{addr2}</td>
+ </tr>
+ <tr>
+ <td>$form->{addr3}</td>
+ </tr>
+ <tr>
+ <td>$form->{addr4}</td>
+ </tr>
+ </table>
+ </td>
+ <input type=hidden name=addr1 value="$form->{addr1}">
+ <input type=hidden name=addr2 value="$form->{addr2}">
+ <input type=hidden name=addr3 value="$form->{addr3}">
+ <input type=hidden name=addr4 value="$form->{addr4}">
+ </tr>
+ </table>
+ </td>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Account').qq|</th>
+ <td colspan=3><select name=account>$form->{selectaccount}</select>
+ <input type=hidden name=selectaccount value="$form->{selectaccount}">
+ </td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Date').qq|</th>
+ <td><input name=datepaid value="$form->{datepaid}" title="$myconfig{dateformat}" size=11></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Currency').qq|</th>
+ <td><select name=currency>$form->{selectcurrency}</select></td>
+ <input type=hidden name=selectcurrency value="$form->{selectcurrency}">
+ <input type=hidden name=oldcurrency value=$form->{oldcurrency}>
+ </tr>
+ $exchangerate
+ <tr>
+ <th align=right nowrap>$rclabel</th>
+ <td colspan=3><input name=source value="$form->{source}" size=10></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Amount').qq|</th>
+ <td colspan=3><input name=amount size=10 value=|.$form->format_amount(\%myconfig, $form->{amount}, 2).qq|></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('From').qq|</th>
+ <td><input name=transdatefrom size=11 title="$myconfig{dateformat}" value=$form->{transdatefrom}></td>
+ <th align=right nowrap>|.$locale->text('to').qq|</th>
+ <td><input name=transdateto size=11 title="$myconfig{dateformat}" value=$form->{transdateto}></td>
+ <input type=hidden name=oldtransdatefrom value=$form->{oldtransdatefrom}>
+ <input type=hidden name=oldtransdateto value=$form->{oldtransdateto}>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+
+}
+
+
+sub list_invoices {
+
+ @column_index = qw(invnumber transdate amount due paid selectpaid);
+
+ $colspan = $#column_index + 1;
+
+ print qq|
+ <input type=hidden name=column_index value="id @column_index">
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th class=listheading colspan=$colspan>|.$locale->text('Invoices').qq|</th>
+ </tr>
+|;
+
+ $column_data{invnumber} = qq|<th nowrap>|.$locale->text('Invoice')."</th>";
+ $column_data{transdate} = qq|<th nowrap>|.$locale->text('Date')."</th>";
+ $column_data{amount} = qq|<th nowrap>|.$locale->text('Amount')."</th>";
+ $column_data{due} = qq|<th nowrap>|.$locale->text('Due')."</th>";
+ $column_data{paid} = qq|<th nowrap>|.$locale->text('Applied')."</th>";
+ $column_data{selectpaid} = qq|<th nowrap>|.$locale->text('Paid in full')."</th>";
+
+ print qq|
+ <tr>
+|;
+ map { print "$column_data{$_}\n" } @column_index;
+ print qq|
+ </tr>
+|;
+
+ for $i (1 .. $form->{rowcount}) {
+
+ $form->{"selectpaid_$i"} = "checked" if $form->{"selectpaid_$i"};
+ map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(amount due paid);
+
+ $totalamount += $form->{"amount_$i"};
+ $totaldue += $form->{"due_$i"};
+ $totalpaid += $form->{"paid_$i"};
+
+ map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}, 2) } qw(amount due paid);
+
+ $column_data{invnumber} = qq|<td>$form->{"invnumber_$i"}</td>
+ <input type=hidden name="invnumber_$i" value="$form->{"invnumber_$i"}">
+ <input type=hidden name="id_$i" value=$form->{"id_$i"}>|;
+ $column_data{transdate} = qq|<td width=15%>$form->{"transdate_$i"}</td>
+ <input type=hidden name="transdate_$i" value=$form->{"transdate_$i"}>|;
+ $column_data{amount} = qq|<td align=right width=15%>$form->{"amount_$i"}</td>
+ <input type=hidden name="amount_$i" value=$form->{"amount_$i"}>|;
+ $column_data{due} = qq|<td align=right width=15%>$form->{"due_$i"}</td>
+ <input type=hidden name="due_$i" value=$form->{"due_$i"}>|;
+
+ $column_data{paid} = qq|<td align=right width=15%>|;
+ if ($form->{"selectpaid_$i"}) {
+ $column_data{paid} .= qq|<input type=hidden name="paid_$i" value=$form->{"paid_$i"}>$form->{"paid_$i"}</td>|;
+ } else {
+ $column_data{paid} .= qq|<input name="paid_$i" size=10 value=$form->{"paid_$i"}></td>|;
+ }
+ $column_data{selectpaid} = qq|<td align=center width=10%><input name="selectpaid_$i" type=checkbox class=checkbox $form->{"selectpaid_$i"}></td>|;
+
+ $j++; $j %= 2;
+ print qq|
+ <tr class=listrow$j>
+|;
+ map { print "$column_data{$_}\n" } @column_index;
+ print qq|
+ </tr>
+|;
+ }
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{amount} = qq|<th align=right>|.$form->format_amount(\%myconfig, $totalamount, 2, "&nbsp;").qq|</th>|;
+ $column_data{due} = qq|<th align=right>|.$form->format_amount(\%myconfig, $totaldue, 2, "&nbsp;").qq|</th>|;
+ $column_data{paid} = qq|<th align=right>|.$form->format_amount(\%myconfig, $totalpaid, 2, "&nbsp;").qq|</th>|;
+
+ print qq|
+ <tr class=listtotal>
+|;
+ map { print "$column_data{$_}\n" } @column_index;
+ print qq|
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+
+}
+
+
+sub form_footer {
+
+ $form->{OP}{$form->{media}} = "checked";
+
+ print qq|
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+<input type=hidden name=rowcount value=$form->{rowcount}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Post').qq|">|;
+
+ if ($latex) {
+ print qq|
+<input class=submit type=submit name=action value="|.$locale->text('Print').qq|">
+<input class=radio type=radio name=media value=screen $form->{OP}{screen}> |.$locale->text('Screen');
+
+ if ($myconfig{printer}) {
+ print qq|
+<input class=radio type=radio name=media value=printer $form->{OP}{printer}> |.$locale->text('Printer');
+ }
+ }
+
+ print qq|
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub update {
+ my ($new_name_selected) = @_;
+
+ # get customer and invoices
+ $updated = &check_name($form->{vc});
+
+ $updated = 1 if (($form->{oldtransdatefrom} ne $form->{transdatefrom}) || ($form->{oldtransdateto} ne $form->{transdateto}));
+ $form->{oldtransdatefrom} = $form->{transdatefrom};
+ $form->{oldtransdateto} = $form->{transdateto};
+
+ if ($new_name_selected || $updated) {
+ CP->get_openinvoices(\%myconfig, \%$form);
+ $updated = 1;
+ }
+
+ if ($form->{currency} ne $form->{oldcurrency}) {
+ $form->{oldcurrency} = $form->{currency};
+ if (!$updated) {
+ CP->get_openinvoices(\%myconfig, \%$form);
+ $updated = 1;
+ }
+ }
+
+ # check currency
+ $buysell = ($form->{vc} eq 'customer') ? "buy" : "sell";
+
+ $form->{exchangerate} = $exchangerate if ($form->{forex} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{datepaid}, $buysell)));
+
+ $amount = $form->{amount} = $form->parse_amount(\%myconfig, $form->{amount});
+
+ if ($updated) {
+ $form->{rowcount} = 0;
+
+ $i = 0;
+ foreach $ref (@{ $form->{PR} }) {
+ $i++;
+ $form->{"id_$i"} = $ref->{id};
+ $form->{"invnumber_$i"} = $ref->{invnumber};
+ $form->{"transdate_$i"} = $ref->{transdate};
+ $ref->{exchangerate} = 1 unless $ref->{exchangerate};
+ $form->{"amount_$i"} = $ref->{amount} / $ref->{exchangerate};
+ $form->{"due_$i"} = $form->round_amount(($ref->{amount} - $ref->{paid}) / $ref->{exchangerate}, 2);
+ $amount = $form->round_amount($amount - $form->{"due_$i"}, 2);
+ $form->{"selectpaid_$i"} = 1 if $amount > 0;
+
+ map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}, 2) } qw(amount due paid);
+
+ }
+ $form->{rowcount} = $i;
+ }
+
+ # recalculate
+ $amount = $form->{amount};
+ for $i (1 .. $form->{rowcount}) {
+
+ map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(amount due paid);
+
+ if ($form->{"selectpaid_$i"}) {
+ $amount -= $form->{"due_$i"};
+
+ if ($amount < 0) {
+ $form->{"selectpaid_$i"} = 0;
+ } else {
+ $form->{"paid_$i"} = $form->{"due_$i"};
+ }
+ }
+
+ map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}, 2) } qw(amount due paid);
+
+ }
+
+ &form_header;
+ &list_invoices;
+ &form_footer;
+
+}
+
+
+sub post {
+
+ &check_form;
+
+ $form->redirect($locale->text('Payment posted!')) if (CP->process_payment(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot post payment!'));
+
+}
+
+
+sub print {
+
+ &check_form;
+
+ ($whole, $form->{decimal}) = split /\./, $form->{amount};
+
+ $form->{amount} = $form->format_amount(\%myconfig, $form->{amount}, 2);
+ $m = "*" x (24 - length $form->{amount});
+ $form->{amount} = $locale->text($form->{currency})."$m$form->{amount}";
+
+ $form->{decimal} .= "00";
+ $form->{decimal} = substr($form->{decimal}, 0, 2);
+
+ $check = new CP $myconfig{countrycode};
+ $check->init;
+ $form->{text_amount} = $check->num2text($whole);
+
+ &{ "$form->{vc}_details" };
+
+ $form->{format} = ($form->{media} eq 'screen') ? "pdf" : "postscript";
+ $form->{templates} = "$myconfig{templates}";
+ $form->{IN} = "$form->{type}.tex";
+ $form->{OUT} = "| $myconfig{printer}" if ($form->{media} eq 'printer');
+
+ $form->{company} = $myconfig{company};
+ $form->{address} = $myconfig{address};
+
+ @a = qw(name invnumber company address text_amount addr1 addr2 addr3 addr4);
+ $form->format_string(@a);
+
+ $form->parse_template(\%myconfig, $userspath);
+
+ $form->{callback} = "";
+
+ $label = uc $form->{type};
+
+# $locale->text('Check printed!')
+# $locale->text('Check printing failed!')
+# $locale->text('Receipt printed!')
+# $locale->text('Receipt printing failed!')
+
+ $form->redirect($locale->text("$label printed!"));
+ $form->error($locale->text("$label printing failed!"));
+
+}
+
+
+sub customer_details { IS->customer_details(\%myconfig, \%$form) };
+sub vendor_details { IR->vendor_details(\%myconfig, \%$form) };
+
+
+sub check_form {
+
+ # construct callback
+ $form->{callback} = "$form->{script}?action=payment&vc=$form->{vc}&path=$form->{path}&login=$form->{login}&password=$form->{password}";
+
+ $form->redirect unless $form->{rowcount};
+
+ if ($form->{currency} ne $form->{oldcurrency}) {
+ &update;
+ exit;
+ }
+
+ $form->error($locale->text('Date missing!')) unless $form->{datepaid};
+ $form->error($locale->text('Amount missing!')) unless $form->{amount};
+
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+ $datepaid = $form->datetonum($form->{datepaid}, \%myconfig);
+
+ $form->error($locale->text('Cannot process payment for a closed period!')) if ($datepaid <= $closedto);
+
+ $form->{amount} = $form->parse_amount(\%myconfig, $form->{amount});
+ for $i (1 .. $form->{rowcount}) {
+ $totalpaid += $form->parse_amount(\%myconfig, $form->{"paid_$i"});
+ if ($form->{"paid_$i"}) {
+ push(@{ $form->{paid} }, $form->{"paid_$i"});
+ push(@{ $form->{due} }, $form->{"due_$i"});
+ push(@{ $form->{invnumber} }, $form->{"invnumber_$i"});
+ push(@{ $form->{invdate} }, $form->{"transdate_$i"});
+ }
+ }
+
+ $totalpaid = $form->round_amount($totalpaid, 2);
+
+ $form->error($locale->text('Nothing applied!')) unless $totalpaid;
+ $form->error($locale->text('Amount does not equal applied!')) if ($form->{amount} != $totalpaid);
+
+}
+
+
diff --git a/sql-ledger/bin/mozilla/ct.pl b/sql-ledger/bin/mozilla/ct.pl
new file mode 100644
index 0000000..3dbb565
--- /dev/null
+++ b/sql-ledger/bin/mozilla/ct.pl
@@ -0,0 +1,631 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors: Reed White <alta@alta-research.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# customer/vendor module
+#
+#======================================================================
+
+# $locale->text('Customers')
+# $locale->text('Vendors')
+
+use SL::CT;
+
+1;
+# end of main
+
+
+
+sub add {
+
+ $form->{title} = "Add";
+
+ $form->{callback} = "$form->{script}?action=add&db=$form->{db}&path=$form->{path}&login=$form->{login}&password=$form->{password}" unless $form->{callback};
+
+ CT->taxaccounts(\%myconfig, \%$form);
+
+ &form_header;
+ &form_footer;
+
+}
+
+
+sub search {
+
+ $label = ucfirst $form->{db};
+ $form->{title} = $locale->text($label."s");
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=db value=$form->{db}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Number').qq|</th>
+ <td><input name=$form->{db}number size=35></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Name').qq|</th>
+ <td><input name=name size=35></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Contact').qq|</th>
+ <td><input name=contact size=35></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('E-mail').qq|</th>
+ <td><input name=email size=35></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td><input name=status class=radio type=radio value=all checked>&nbsp;|.$locale->text('All').qq|
+ <input name=status class=radio type=radio value=orphaned>&nbsp;|.$locale->text('Orphaned').qq|</td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Include in Report').qq|</th>
+ <td>
+ <input name="l_$form->{db}number" type=checkbox class=checkbox value=Y>&nbsp;|.$locale->text('Number').qq|
+ <input name="l_name" type=checkbox class=checkbox value=Y checked>&nbsp;|.$locale->text('Name').qq|
+ <input name="l_address" type=checkbox class=checkbox value=Y>&nbsp;|.$locale->text('Address').qq|<br>
+ <input name="l_contact" type=checkbox class=checkbox value=Y checked>&nbsp;|.$locale->text('Contact').qq|
+ <input name="l_phone" type=checkbox class=checkbox value=Y checked>&nbsp;|.$locale->text('Phone').qq|
+ <input name="l_fax" type=checkbox class=checkbox value=Y>&nbsp;|.$locale->text('Fax').qq|
+ <input name="l_email" type=checkbox class=checkbox value=Y checked>&nbsp;|.$locale->text('E-mail').qq|
+ <input name="l_cc" type=checkbox class=checkbox value=Y>&nbsp;|.$locale->text('Cc').qq|
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=nextsub value=list_names>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input type=submit class=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+}
+
+
+sub list_names {
+
+ CT->search(\%myconfig, \%$form);
+
+ $callback = "$form->{script}?action=list_names&db=$form->{db}&path=$form->{path}&login=$form->{login}&password=$form->{password}&status=$form->{status}";
+ $href = $callback;
+
+ @columns = $form->sort_columns(name, "$form->{db}number", address, contact, phone, fax, email, cc);
+
+ foreach $item (@columns) {
+ if ($form->{"l_$item"} eq "Y") {
+ push @column_index, $item;
+
+ # add column to href and callback
+ $callback .= "&l_$item=Y";
+ $href .= "&l_$item=Y";
+ }
+ }
+
+ if ($form->{status} eq 'all') {
+ $option = $locale->text('All');
+ }
+ if ($form->{status} eq 'orphaned') {
+ $option .= $locale->text('Orphaned');
+ }
+ if ($form->{name}) {
+ $callback .= "&name=$form->{name}";
+ $href .= "&name=".$form->escape($form->{name});
+ $option .= "\n<br>".$locale->text('Name')." : $form->{name}";
+ }
+ if ($form->{contact}) {
+ $callback .= "&contact=$form->{contact}";
+ $href .= "&contact=".$form->escape($form->{contact});
+ $option .= "\n<br>".$locale->text('Contact')." : $form->{contact}";
+ }
+ if ($form->{"$form->{db}number"}) {
+ $callback .= qq|&$form->{db}number=$form->{"$form->{db}number"}|;
+ $href .= "&$form->{db}number=".$form->escape($form->{"$form->{db}number"});
+ $option .= "\n<br>".$locale->text('Number').qq| : $form->{"$form->{db}number"}|;
+ }
+ if ($form->{email}) {
+ $callback .= "&email=$form->{email}";
+ $href .= "&email=".$form->escape($form->{email});
+ $option .= "\n<br>".$locale->text('E-mail')." : $form->{email}";
+ }
+
+ $form->{callback} = "$callback&sort=$form->{sort}";
+ $callback = $form->escape($form->{callback});
+
+ $column_header{"$form->{db}number"} = qq|<th><a class=listheading href=$href&sort=$form->{db}number>|.$locale->text('Number').qq|</a></th>|;
+ $column_header{name} = qq|<th><a class=listheading href=$href&sort=name>|.$locale->text('Name').qq|</a></th>|;
+ $column_header{address} = qq|<th><a class=listheading href=$href&sort=address>|.$locale->text('Address').qq|</a></th>|;
+ $column_header{contact} = qq|<th><a class=listheading href=$href&sort=contact>|.$locale->text('Contact').qq|</a></th>|;
+ $column_header{phone} = qq|<th><a class=listheading href=$href&sort=phone>|.$locale->text('Phone').qq|</a></th>|;
+ $column_header{fax} = qq|<th><a class=listheading href=$href&sort=fax>|.$locale->text('Fax').qq|</a></th>|;
+ $column_header{email} = qq|<th><a class=listheading href=$href&sort=email>|.$locale->text('E-mail').qq|</a></th>|;
+ $column_header{cc} = qq|<th><a class=listheading href=$href&sort=cc>|.$locale->text('Cc').qq|</a></th>|;
+
+ $label = ucfirst $form->{db}."s";
+ $form->{title} = $locale->text($label);
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$option</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+ map { print "$column_header{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ foreach $ref (@{ $form->{CT} }) {
+
+ map { $column_data{$_} = "<td>$ref->{$_}&nbsp;</td>" } ("$form->{db}number", address, contact, phone, fax);
+
+ $column_data{name} = "<td><a href=$form->{script}?action=edit&id=$ref->{id}&db=$form->{db}&path=$form->{path}&login=$form->{login}&password=$form->{password}&status=$form->{status}&callback=$callback>$ref->{name}&nbsp;</td>";
+
+ $column_data{email} = ($ref->{email}) ? qq|<td><a href="mailto:$ref->{email}">$ref->{email}</a></td>| : "<td>&nbsp;</td>";
+ $column_data{cc} = ($ref->{cc}) ? qq|<td><a href="mailto:$ref->{cc}">$ref->{cc}</a></td>| : "<td>&nbsp;</td>";
+
+ $i++; $i %= 2;
+ print "
+ <tr class=listrow$i>
+";
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ }
+
+ print qq|
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<form method=post action=$form->{script}>
+
+<input name=callback type=hidden value="$form->{callback}">
+<input name=db type=hidden value=$form->{db}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input class=submit type=submit name=action value="|.$locale->text('Add').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub edit {
+
+# $locale->text('Edit Customer')
+# $locale->text('Edit Vendor')
+
+ CT->get_tuple(\%myconfig, \%$form);
+
+ # format " into &quot;
+ map { $form->{$_} =~ s/"/&quot;/g } keys %$form;
+
+ $form->{title} = "Edit";
+
+ # format discount
+ $form->{discount} *= 100;
+
+ &form_header;
+ &form_footer;
+
+}
+
+
+sub form_header {
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ if (($form->{tax}{$item}{taxable}) || !($form->{id})) {
+ $taxable .= qq| <input name="tax_$item" value=1 class=checkbox type=checkbox checked>&nbsp;<b>$form->{tax}{$item}{description}</b>|;
+ } else {
+ $taxable .= qq| <input name="tax_$item" value=1 class=checkbox type=checkbox>&nbsp;<b>$form->{tax}{$item}{description}</b>|;
+ }
+ }
+
+ $tax = qq|
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Taxable').qq|</th>
+ <td>$taxable</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+
+ $form->{taxincluded} = ($form->{taxincluded}) ? "checked" : "";
+ $form->{creditlimit} = $form->format_amount(\%myconfig, $form->{creditlimit}, 0);
+
+ if ($myconfig{admin}) {
+ $bcc = qq|
+ <tr>
+ <th align=right nowrap>|.$locale->text('Bcc').qq|</th>
+ <td><input name=bcc size=35 value="$form->{bcc}"></td>
+ </tr>
+|;
+ }
+
+
+ $label = ucfirst $form->{db};
+ $form->{title} = $locale->text("$form->{title} $label");
+
+ if ($form->{db} eq 'customer') {
+ $creditlimit = qq|
+ <th align=right>|.$locale->text('Credit Limit').qq|</th>
+ <td><input name=creditlimit size=9 value="$form->{creditlimit}"></td>
+ <th align=right>|.$locale->text('Discount').qq|</th>
+ <td><input name=discount size=4 value="$form->{discount}"></td>
+ <th>%</th>
+|;
+ }
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+ <th class=listheading colspan=2 width=50%">&nbsp;</th>
+ <th class=listheading width=50%">|.$locale->text('Ship to').qq|</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Number').qq|</th>
+ <td><input name="$form->{db}number" size=35 maxsize=35 value="$form->{"$form->{db}number"}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Name').qq|</th>
+ <td><input name=name size=35 maxsize=35 value="$form->{name}"></td>
+ <td><input name=shiptoname size=35 maxsize=35 value="$form->{shiptoname}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Address').qq|</th>
+ <td><input name=addr1 size=35 maxsize=35 value="$form->{addr1}"></td>
+ <td><input name=shiptoaddr1 size=35 maxsize=35 value="$form->{shiptoaddr1}"></td>
+ </tr>
+ <tr>
+ <th></th>
+ <td><input name=addr2 size=35 maxsize=35 value="$form->{addr2}"></td>
+ <td><input name=shiptoaddr2 size=35 maxsize=35 value="$form->{shiptoaddr2}"></td>
+ </tr>
+ <tr>
+ <th></th>
+ <td><input name=addr3 size=35 maxsize=35 value="$form->{addr3}"></td>
+ <td><input name=shiptoaddr3 size=35 maxsize=35 value="$form->{shiptoaddr3}"></td>
+ </tr>
+ <tr>
+ <th></th>
+ <td><input name=addr4 size=35 maxsize=35 value="$form->{addr4}"></td>
+ <td><input name=shiptoaddr4 size=35 maxsize=35 value="$form->{shiptoaddr4}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Contact').qq|</th>
+ <td><input name=contact size=35 maxsize=35 value="$form->{contact}"></td>
+ <td><input name=shiptocontact size=35 maxsize=35 value="$form->{shiptocontact}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Phone').qq|</th>
+ <td><input name=phone size=20 maxsize=20 value="$form->{phone}"></td>
+ <td><input name=shiptophone size=20 maxsize=20 value="$form->{shiptophone}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Fax').qq|</th>
+ <td><input name=fax size=20 maxsize=20 value="$form->{fax}"></td>
+ <td><input name=shiptofax size=20 maxsize=20 value="$form->{shiptofax}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('E-mail').qq|</th>
+ <td><input name=email size=35 value="$form->{email}"></td>
+ <td><input name=shiptoemail size=35 value="$form->{shiptoemail}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Cc').qq|</th>
+ <td><input name=cc size=35 value="$form->{cc}"></td>
+ </tr>
+ $bcc
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=right>|.$locale->text('Terms: Net').qq|</th>
+ <td><input name=terms size=2 value="$form->{terms}"></td>
+ <th>|.$locale->text('days').qq|</th>
+ $creditlimit
+ <td><input name=taxincluded class=checkbox type=checkbox value=1 $form->{taxincluded}></td>
+ <th align=left>|.$locale->text('Tax Included').qq|</th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ $tax
+ <tr>
+ <th align=left nowrap>|.$locale->text('Notes').qq|</th>
+ </tr>
+ <tr>
+ <td><textarea name=notes rows=3 cols=60 wrap=soft>$form->{notes}</textarea></td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+|;
+
+}
+
+
+
+sub form_footer {
+
+ $label = ucfirst $form->{db};
+
+ print qq|
+<input name=id type=hidden value=$form->{id}>
+<input name=taxaccounts type=hidden value="$form->{taxaccounts}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input type=hidden name=callback value="$form->{callback}">
+<input type=hidden name=db value=$form->{db}>
+
+<br>
+
+<input class=submit type=submit name=action value="|.$locale->text("Save").qq|">
+<input class=submit type=submit name=action value="|.$locale->text("Invoice").qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Order').qq|">
+|;
+
+ if ($form->{id} && $form->{status} eq 'orphaned') {
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Delete').qq|">\n|;
+ }
+
+ print qq|
+
+ </form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub invoice { &{ "$form->{db}_invoice" } };
+
+sub customer_invoice {
+
+ $form->isblank("name", $locale->text("Name missing!"));
+ CT->save_customer(\%myconfig, \%$form);
+
+ delete $form->{script};
+
+ $form->{action} = "add";
+ $form->{callback} = $form->escape($form->{callback},1);
+
+ $form->{customer} = $form->{name};
+ $form->{customer_id} = $form->{id};
+ $form->{vc} = 'customer';
+
+ delete $form->{id};
+
+ map { $argv .= "$_=$form->{$_}&" } keys %$form;
+
+ exec ("perl", "is.pl", $argv);
+
+}
+
+
+sub vendor_invoice {
+
+ $form->isblank("name", $locale->text("Name missing!"));
+ CT->save_vendor(\%myconfig, \%$form);
+
+ delete $form->{script};
+
+ $form->{action} = "add";
+ $form->{callback} = $form->escape($form->{callback},1);
+
+ $form->{vendor} = $form->{name};
+ $form->{vendor_id} = $form->{id};
+ $form->{vc} = 'vendor';
+
+ delete $form->{id};
+
+ map { $argv .= "$_=$form->{$_}&" } keys %$form;
+
+ exec ("perl", "ir.pl", $argv);
+
+}
+
+
+sub order { &{ "$form->{db}_order" } };
+
+sub customer_order {
+
+ $form->isblank("name", $locale->text("Name missing!"));
+ CT->save_customer(\%myconfig, \%$form);
+
+ delete $form->{script};
+
+ $form->{action} = "add";
+ $form->{callback} = $form->escape($form->{callback},1);
+
+ $form->{customer} = $form->{name};
+ $form->{customer_id} = $form->{id};
+ $form->{vc} = 'customer';
+
+ $form->{type} = 'sales_order';
+
+ delete $form->{id};
+
+ map { $argv .= "$_=$form->{$_}&" } keys %$form;
+
+ exec ("perl", "oe.pl", $argv);
+
+}
+
+
+sub vendor_order {
+
+ $form->isblank("name", $locale->text("Name missing!"));
+ CT->save_vendor(\%myconfig, \%$form);
+
+ delete $form->{script};
+
+ $form->{action} = "add";
+ $form->{callback} = $form->escape($form->{callback},1);
+
+ $form->{vendor} = $form->{name};
+ $form->{vendor_id} = $form->{id};
+ $form->{vc} = 'vendor';
+
+ $form->{type} = 'purchase_order';
+
+ delete $form->{id};
+
+ map { $argv .= "$_=$form->{$_}&" } keys %$form;
+
+ exec ("perl", "oe.pl", $argv);
+
+}
+
+
+sub save { &{ "save_$form->{db}" } };
+
+sub save_customer {
+
+ $form->isblank("name", $locale->text("Name missing!"));
+ CT->save_customer(\%myconfig, \%$form);
+ $form->redirect($locale->text('Customer saved!'));
+
+}
+
+
+sub save_vendor {
+
+ $form->isblank("name", $locale->text("Name missing!"));
+ CT->save_vendor(\%myconfig, \%$form);
+ $form->redirect($locale->text('Vendor saved!'));
+
+}
+
+
+sub delete { &{ "delete_$form->{db}" } };
+
+sub delete_customer {
+
+ $rc = CT->delete_customer(\%myconfig, \%$form);
+
+ $form->error($locale->text('Transactions exist, cannot delete customer!')) if ($rc == -1);
+ $form->redirect($locale->text('Customer deleted!')) if $rc;
+ $form->error($locale->text('Cannot delete customer!'));
+
+}
+
+
+sub delete_vendor {
+
+ $rc = CT->delete_vendor(\%myconfig, \%$form);
+
+ $form->error($locale->text('Transactions exist, cannot delete vendor!')) if ($rc == -1);
+ $form->redirect($locale->text('Vendor deleted!')) if $rc;
+ $form->error($locale->text('Cannot delete vendor!'));
+
+}
+
+
+sub continue { &{ $form->{nextsub} } };
+
+
diff --git a/sql-ledger/bin/mozilla/gl.pl b/sql-ledger/bin/mozilla/gl.pl
new file mode 100644
index 0000000..0d2dd46
--- /dev/null
+++ b/sql-ledger/bin/mozilla/gl.pl
@@ -0,0 +1,806 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Genereal Ledger
+#
+#======================================================================
+
+
+use SL::GL;
+use SL::PE;
+
+require "$form->{path}/arap.pl";
+
+1;
+# end of main
+
+
+# this is for our long dates
+# $locale->text('January')
+# $locale->text('February')
+# $locale->text('March')
+# $locale->text('April')
+# $locale->text('May ')
+# $locale->text('June')
+# $locale->text('July')
+# $locale->text('August')
+# $locale->text('September')
+# $locale->text('October')
+# $locale->text('November')
+# $locale->text('December')
+
+# this is for our short month
+# $locale->text('Jan')
+# $locale->text('Feb')
+# $locale->text('Mar')
+# $locale->text('Apr')
+# $locale->text('May')
+# $locale->text('Jun')
+# $locale->text('Jul')
+# $locale->text('Aug')
+# $locale->text('Sep')
+# $locale->text('Oct')
+# $locale->text('Nov')
+# $locale->text('Dec')
+
+
+sub add {
+
+ $form->{title} = "Add";
+
+ $form->{callback} = "$form->{script}?action=add&path=$form->{path}&login=$form->{login}&password=$form->{password}" unless $form->{callback};
+
+ # we use this only to set a default date
+ GL->transaction(\%myconfig, \%$form);
+
+ map { $chart .= "<option>$_->{accno}--$_->{description}" } @{ $form->{chart} };
+ $form->{chart} = $chart;
+
+ $form->{rowcount} = 4;
+ &display_form;
+
+}
+
+
+sub edit {
+
+ GL->transaction(\%myconfig, \%$form);
+
+ map { $chart .= "<option>$_->{accno}--$_->{description}" } @{ $form->{chart} };
+ $form->{chart} = $chart;
+
+ $form->{locked} = ($form->datetonum($form->{transdate}, \%myconfig) <= $form->datetonum($form->{closedto}, \%myconfig));
+
+ $form->{title} = "Edit";
+
+ &form_header;
+
+ $i = 1;
+ foreach $ref (@{ $form->{GL} }) {
+ $form->{"accno_$i"} = $ref->{accno};
+ $form->{"oldprojectnumber_$i"} = $form->{"projectnumber_$i"} = $ref->{projectnumber};
+ $form->{"project_id_$i"} = $ref->{project_id};
+
+ if ($ref->{amount} < 0) {
+ $form->{totaldebit} -= $ref->{amount};
+ $form->{"debit_$i"} = $form->format_amount(\%myconfig, $ref->{amount} * -1, 2);
+ } else {
+ $form->{totalcredit} += $ref->{amount};
+ $form->{"credit_$i"} = ($ref->{amount} > 0) ? $form->format_amount(\%myconfig, $ref->{amount}, 2) : "";
+ }
+
+ &form_row($i++);
+ }
+
+ &form_row($i);
+
+ &form_footer;
+
+}
+
+
+
+sub search {
+
+ $form->{title} = $locale->text('General Ledger')." ".$locale->text('Reports');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=sort value=transdate>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Reference').qq|</th>
+ <td><input name=reference size=20></td>
+ <th align=right>|.$locale->text('Source').qq|</th>
+ <td><input name=source size=20></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Description').qq|</th>
+ <td colspan=3><input name=description size=40></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Notes').qq|</th>
+ <td colspan=3><input name=notes size=40></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('From').qq|</th>
+ <td><input name=datefrom size=11 title="$myconfig{dateformat}"></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=dateto size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Include in Report').qq|</th>
+ <td colspan=3>
+ <table>
+ <tr>
+ <td>
+ <input name="category" class=radio type=radio value=X checked>&nbsp;|.$locale->text('All').qq|
+ <input name="category" class=radio type=radio value=A>&nbsp;|.$locale->text('Asset').qq|
+ <input name="category" class=radio type=radio value=L>&nbsp;|.$locale->text('Liability').qq|
+ <input name="category" class=radio type=radio value=Q>&nbsp;|.$locale->text('Equity').qq|
+ <input name="category" class=radio type=radio value=I>&nbsp;|.$locale->text('Income').qq|
+ <input name="category" class=radio type=radio value=E>&nbsp;|.$locale->text('Expense').qq|
+ </td>
+ </tr>
+ <tr>
+ <table>
+ <tr>
+ <td align=right><input name="l_id" class=checkbox type=checkbox value=Y></td>
+ <td>|.$locale->text('ID').qq|</td>
+ <td align=right><input name="l_transdate" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Date').qq|</td>
+ <td align=right><input name="l_reference" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Reference').qq|</td>
+ <td align=right><input name="l_description" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Description').qq|</td>
+ <td align=right><input name="l_notes" class=checkbox type=checkbox value=Y></td>
+ <td>|.$locale->text('Notes').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_debit" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Debit').qq|</td>
+ <td align=right><input name="l_credit" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Credit').qq|</td>
+ <td align=right><input name="l_source" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Source').qq|</td>
+ <td align=right><input name="l_accno" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Account').qq|</td>
+ <td align=right><input name="l_gifi_accno" class=checkbox type=checkbox value=Y></td>
+ <td>|.$locale->text('GIFI').qq|</td>
+ </tr>
+ <tr>
+ <td align=right><input name="l_subtotal" class=checkbox type=checkbox value=Y></td>
+ <td>|.$locale->text('Subtotal').qq|</td>
+ </tr>
+ </table>
+ </tr>
+ </table>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=nextsub value=generate_report>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+}
+
+
+sub generate_report {
+
+ GL->all_transactions(\%myconfig, \%$form);
+
+ $callback = "$form->{script}?action=generate_report&path=$form->{path}&login=$form->{login}&password=$form->{password}";
+
+ %acctype = ( 'A' => $locale->text('Asset'),
+ 'L' => $locale->text('Liability'),
+ 'Q' => $locale->text('Equity'),
+ 'I' => $locale->text('Income'),
+ 'E' => $locale->text('Expense'),
+ );
+
+ $form->{title} = $locale->text('General Ledger');
+
+ $ml = ($form->{ml} =~ /(A|E)/) ? -1 : 1;
+
+ unless ($form->{category} eq 'X') {
+ $form->{title} .= " : ".$locale->text($acctype{$form->{category}});
+ }
+ if ($form->{accno}) {
+ $callback .= "&accno=$form->{accno}";
+ $option = $locale->text('Account')." : $form->{accno} $form->{account_description}";
+ }
+ if ($form->{gifi_accno}) {
+ $callback .= "&gifi_accno=$form->{gifi_accno}";
+ $option .= "\n<br>" if $option;
+ $option .= $locale->text('GIFI')." : $form->{gifi_accno} $form->{gifi_account_description}";
+ }
+ if ($form->{source}) {
+ $callback .= "&source=".$form->escape($form->{source});
+ $option .= "\n<br>" if $option;
+ $option .= $locale->text('Source')." : $form->{source}";
+ }
+ if ($form->{reference}) {
+ $callback .= "&reference=".$form->escape($form->{reference});
+ $option .= "\n<br>" if $option;
+ $option .= $locale->text('Reference')." : $form->{reference}";
+ }
+ if ($form->{description}) {
+ $callback .= "&description=".$form->escape($form->{description});
+ $option .= "\n<br>" if $option;
+ $option .= $locale->text('Description')." : $form->{description}";
+ }
+ if ($form->{notes}) {
+ $callback .= "&notes=".$form->escape($form->{notes});
+ $option .= "\n<br>" if $option;
+ $option .= $locale->text('Notes')." : $form->{notes}";
+ }
+
+ if ($form->{datefrom}) {
+ $callback .= "&datefrom=$form->{datefrom}";
+ $option .= "\n<br>" if $option;
+ $option .= $locale->text('From')." ".$locale->date(\%myconfig, $form->{datefrom}, 1);
+ }
+ if ($form->{dateto}) {
+ $callback .= "&dateto=$form->{dateto}";
+ if ($form->{datefrom}) {
+ $option .= " ";
+ } else {
+ $option .= "\n<br>" if $option;
+ }
+ $option .= $locale->text('to')." ".$locale->date(\%myconfig, $form->{dateto}, 1);
+ }
+
+
+ @columns = $form->sort_columns(qw(transdate id reference description notes source debit credit accno gifi_accno));
+
+ if ($form->{accno} || $form->{gifi_accno}) {
+ @columns = grep !/(accno|gifi_accno)/, @columns;
+ push @columns, "balance";
+ $form->{l_balance} = "Y";
+ }
+
+ $href = "$callback&sort=$form->{sort}"; # needed for accno
+
+ foreach $item (@columns) {
+ if ($form->{"l_$item"} eq "Y") {
+ push @column_index, $item;
+
+ # add column to href and callback
+ $callback .= "&l_$item=Y";
+ $href .= "&l_$item=Y";
+ }
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ $callback .= "&l_subtotal=Y";
+ $href .= "&l_subtotal=Y";
+ }
+
+ $callback .= "&category=$form->{category}";
+ $href .= "&category=$form->{category}";
+
+ $column_header{id} = "<th><a class=listheading href=$callback&sort=id>".$locale->text('ID')."</a></th>";
+ $column_header{transdate} = "<th><a class=listheading href=$callback&sort=transdate>".$locale->text('Date')."</a></th>";
+ $column_header{reference} = "<th><a class=listheading href=$callback&sort=reference>".$locale->text('Reference')."</a></th>";
+ $column_header{source} = "<th><a class=listheading href=$callback&sort=source>".$locale->text('Source')."</a></th>";
+ $column_header{description} = "<th><a class=listheading href=$callback&sort=description>".$locale->text('Description')."</a></th>";
+ $column_header{notes} = "<th class=listheading>".$locale->text('Notes')."</th>";
+ $column_header{debit} = "<th class=listheading>".$locale->text('Debit')."</th>";
+ $column_header{credit} = "<th class=listheading>".$locale->text('Credit')."</th>";
+ $column_header{accno} = "<th><a class=listheading href=$callback&sort=accno>".$locale->text('Account')."</a></th>";
+ $column_header{gifi_accno} = "<th><a class=listheading href=$callback&sort=gifi_accno>".$locale->text('GIFI')."</a></th>";
+ $column_header{balance} = "<th class=listheading>".$locale->text('Balance')."</th>";
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$option</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+map { print "$column_header{$_}\n" } @column_index;
+
+print "
+ </tr>
+";
+
+ # add sort to callback
+ $form->{callback} = "$callback&sort=$form->{sort}";
+ $callback = $form->escape($form->{callback});
+
+ # initial item for subtotals
+ if (@{ $form->{GL} }) {
+ $sameitem = $form->{GL}->[0]->{$form->{sort}};
+ }
+
+ if (($form->{accno} || $form->{gifi_accno}) && $form->{balance}) {
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+ $column_data{balance} = "<td align=right>".$form->format_amount(\%myconfig, $form->{balance} * $ml, 2, 0)."</td>";
+
+ $i++; $i %= 2;
+ print qq|
+ <tr class=listrow$i>
+|;
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+ }
+
+ foreach $ref (@{ $form->{GL} }) {
+
+ # if item ne sort print subtotal
+ if ($form->{l_subtotal} eq 'Y') {
+ if ($sameitem ne $ref->{$form->{sort}}) {
+ &gl_subtotal;
+ }
+ }
+
+ $form->{balance} += $ref->{amount};
+
+ $subtotaldebit += $ref->{debit};
+ $subtotalcredit += $ref->{credit};
+
+ $totaldebit += $ref->{debit};
+ $totalcredit += $ref->{credit};
+
+ $ref->{debit} = $form->format_amount(\%myconfig, $ref->{debit}, 2, "&nbsp;");
+ $ref->{credit} = $form->format_amount(\%myconfig, $ref->{credit}, 2, "&nbsp;");
+
+ $column_data{id} = "<td>$ref->{id}</td>";
+ $column_data{transdate} = "<td>$ref->{transdate}</td>";
+ $column_data{reference} = "<td><a href=$ref->{module}.pl?action=edit&id=$ref->{id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ref->{reference}</td>";
+ $column_data{description} = "<td>$ref->{description}&nbsp;</td>";
+ $column_data{source} = "<td>$ref->{source}&nbsp;</td>";
+ $column_data{notes} = "<td>$ref->{notes}&nbsp;</td>";
+ $column_data{debit} = "<td align=right>$ref->{debit}</td>";
+ $column_data{credit} = "<td align=right>$ref->{credit}</td>";
+ $column_data{accno} = "<td><a href=$href&accno=$ref->{accno}&callback=$callback>$ref->{accno}</a></td>";
+ $column_data{gifi_accno} = "<td><a href=$href&gifi_accno=$ref->{gifi_accno}&callback=$callback>$ref->{gifi_accno}</a>&nbsp;</td>";
+ $column_data{balance} = "<td align=right>".$form->format_amount(\%myconfig, $form->{balance} * $ml, 2, 0)."</td>";
+
+ $i++; $i %= 2;
+ print "
+ <tr class=listrow$i>";
+ map { print "$column_data{$_}\n" } @column_index;
+ print "</tr>";
+
+ }
+
+
+ &gl_subtotal if ($form->{l_subtotal} eq 'Y');
+
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{debit} = "<th align=right>".$form->format_amount(\%myconfig, $totaldebit, 2, "&nbsp;")."</th>";
+ $column_data{credit} = "<th align=right>".$form->format_amount(\%myconfig, $totalcredit, 2, "&nbsp;")."</th>";
+ $column_data{balance} = "<th align=right>".$form->format_amount(\%myconfig, $form->{balance} * $ml, 2, 0)."</th>";
+
+ print qq|
+ <tr class=listtotal>
+|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+
+<form method=post action=$form->{script}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input class=submit type=submit name=action value="|.$locale->text('GL Transaction').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('AR Transaction').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('AP Transaction').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Sales Invoice').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Vendor Invoice').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub gl_subtotal {
+
+ $subtotaldebit = $form->format_amount(\%myconfig, $subtotaldebit, 2, "&nbsp;");
+ $subtotalcredit = $form->format_amount(\%myconfig, $subtotalcredit, 2, "&nbsp;");
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } qw(transdate id reference source description accno);
+ $column_data{debit} = "<th class=listsubtotal align=right>$subtotaldebit</td>";
+ $column_data{credit} = "<th class=listsubtotal align=right>$subtotalcredit</td>";
+
+
+ print "<tr class=listsubtotal>";
+ map { print "$column_data{$_}\n" } @column_index;
+ print "</tr>";
+
+ $subtotaldebit = 0;
+ $subtotalcredit = 0;
+
+ $sameitem = $ref->{$form->{sort}};
+
+}
+
+
+sub update {
+
+ @a = ();
+ $count = 0;
+ @flds = (qw(accno debit credit projectnumber project_id));
+
+ for $i (1 .. $form->{rowcount}) {
+ unless (($form->{"debit_$i"} eq "") && ($form->{"credit_$i"} eq "")) {
+ # take accno apart
+ ($form->{"accno_$i"}) = split(/--/, $form->{"accno_$i"});
+
+ push @a, {};
+ $j = $#a;
+
+ map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds;
+ $count++;
+ }
+ }
+
+ for $i (1 .. $count) {
+ $j = $i - 1;
+ map { $form->{"${_}_$i"} = $a[$j]->{$_} } @flds;
+ }
+
+ for $i ($count + 1 .. $form->{rowcount}) {
+ map { delete $form->{"${_}_$i"} } @flds;
+ }
+
+ $form->{rowcount} = $count;
+
+ &check_project;
+
+ &display_form;
+
+}
+
+
+sub display_form {
+
+ &form_header;
+
+ $form->{rowcount}++;
+ $form->{totaldebit} = 0;
+ $form->{totalcredit} = 0;
+
+ for $i (1 .. $form->{rowcount}) {
+ $form->{totaldebit} += $form->parse_amount(\%myconfig, $form->{"debit_$i"});
+ $form->{totalcredit} += $form->parse_amount(\%myconfig, $form->{"credit_$i"});
+
+ &form_row($i);
+ }
+
+ &form_footer;
+
+}
+
+
+sub form_row {
+ my $i = shift;
+
+ my $chart = $form->{chart};
+ $chart =~ s/<option>$form->{"accno_$i"}/<option selected>$form->{"accno_$i"}/;
+
+ print qq|<tr>
+ <td><select name="accno_$i">$chart</select></td>
+ <td><input name="debit_$i" size=12 value=$form->{"debit_$i"}></td>
+ <td><input name="credit_$i" size=12 value=$form->{"credit_$i"}></td>
+ <td><input name="projectnumber_$i" size=12 value="$form->{"projectnumber_$i"}">
+ <input type=hidden name="project_id_$i" value=$form->{"project_id_$i"}>
+ <input type=hidden name="oldprojectnumber_$i" value="$form->{"oldprojectnumber_$i"}"></td>
+</tr>
+<input type=hidden name=rowcount value=$i>
+
+|;
+
+}
+
+
+sub form_header {
+
+ $title = $form->{title};
+ $form->{title} = $locale->text("$title General Ledger Transaction");
+
+# $locale->text('Add General Ledger Transaction')
+# $locale->text('Edit General Ledger Transaction')
+
+ map { $form->{$_} =~ s/"/&quot;/g } qw(reference description chart);
+
+ if (($rows = $form->numtextrows($form->{description}, 50)) > 1) {
+ $description = qq|<textarea name=description rows=$rows cols=50 wrap=soft>$form->{description}</textarea>|;
+ } else {
+ $description = qq|<input name=description size=50 value="$form->{description}">|;
+ }
+
+ if (($rows = $form->numtextrows($form->{notes}, 50)) > 1) {
+ $notes = qq|<textarea name=notes rows=$rows cols=50 wrap=soft>$form->{notes}</textarea>|;
+ } else {
+ $notes = qq|<input name=notes size=50 value="$form->{notes}">|;
+ }
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input name=id type=hidden value=$form->{id}>
+
+<input name=chart type=hidden value="$form->{chart}">
+<input type=hidden name=closedto value=$form->{closedto}>
+<input type=hidden name=locked value=$form->{locked}>
+<input type=hidden name=title value="$title">
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=right>|.$locale->text('Reference').qq|</th>
+ <td><input name=reference size=20 value="$form->{reference}"></td>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Date').qq|</th>
+ <td><input name=transdate size=11 title="$myconfig{dateformat}" value=$form->{transdate}></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Description').qq|</th>
+ <td colspan=2>$description</td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Notes').qq|</th>
+ <td colspan=2>$notes</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+ <th class=listheading>|.$locale->text('Account').qq|</th>
+ <th class=listheading>|.$locale->text('Debit').qq|</th>
+ <th class=listheading>|.$locale->text('Credit').qq|</th>
+ <th class=listheading>|.$locale->text('Project').qq|</th>
+ </tr>
+|;
+
+}
+
+
+sub form_footer {
+
+ ($dec) = ($form->{totaldebit} =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ map { $form->{$_} = $form->format_amount(\%myconfig, $form->{$_}, $decimalplaces, "&nbsp;") } qw(totaldebit totalcredit);
+
+ print qq|
+ <tr class=listtotal>
+ <th>&nbsp;</th>
+ <th class=listtotal align=right>$form->{totaldebit}</th>
+ <th class=listtotal align=right>$form->{totalcredit}</th>
+ <th>&nbsp;</th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<br>
+|;
+
+ $transdate = $form->datetonum($form->{transdate}, \%myconfig);
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+
+ if ($form->{id}) {
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+|;
+
+ if (!$form->{revtrans}) {
+ if (!$form->{locked}) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Delete').qq|">
+|;
+ }
+ }
+
+ if ($transdate > $closedto) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Post as new').qq|">
+|;
+ }
+
+ } else {
+ if ($transdate > $closedto) {
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">|;
+ }
+ }
+
+ print "</form>
+
+</body>
+</html>
+";
+
+}
+
+
+sub delete {
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+|;
+
+ map { $form->{$_} =~ s/"/&quot;/g } qw(reference description chart);
+
+ foreach $key (keys %$form) {
+ print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
+ }
+
+ print qq|
+<h2 class=confirm>|.$locale->text('Confirm!').qq|</h2>
+
+<h4>|.$locale->text('Are you sure you want to delete Transaction').qq| $form->{reference}</h4>
+
+<input name=action class=submit type=submit value="|.$locale->text('Yes').qq|">
+</form>
+|;
+
+}
+
+
+sub yes {
+
+ $form->redirect($locale->text('Transaction deleted!')) if (GL->delete_transaction(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot delete transaction!'));
+
+}
+
+
+sub post {
+
+ # check if there is something in reference and date
+ $form->isblank("reference", $locale->text('Reference missing!'));
+ $form->isblank("transdate", $locale->text('Transaction Date missing!'));
+
+ $transdate = $form->datetonum($form->{transdate}, \%myconfig);
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+
+ # check project
+ &check_project;
+
+ # this is just for the wise guys
+ $form->error($locale->text('Cannot post transaction for a closed period!')) if ($transdate <= $closedto);
+
+ if (($errno = GL->post_transaction(\%myconfig, \%$form)) <= -1) {
+ $errno *= -1;
+ $err[1] = $locale->text('Cannot have a value in both Debit and Credit!');
+ $err[2] = $locale->text('Debit and credit out of balance!');
+ $err[3] = $locale->text('Cannot post a transaction without a value!');
+
+ $form->error($err[$errno]);
+ }
+
+ $form->redirect($locale->text('Transaction posted!'));
+
+}
+
+
+sub post_as_new {
+
+ $form->{id} = 0;
+ &post;
+
+}
+
+
diff --git a/sql-ledger/bin/mozilla/ic.pl b/sql-ledger/bin/mozilla/ic.pl
new file mode 100644
index 0000000..797daee
--- /dev/null
+++ b/sql-ledger/bin/mozilla/ic.pl
@@ -0,0 +1,1638 @@
+#=====================================================================
+# SQL-Ledger, Accounting
+# Copyright (c) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Inventory Control module
+#
+#======================================================================
+
+
+use SL::IC;
+
+require "$form->{path}/io.pl";
+
+1;
+# end of main
+
+
+
+sub add {
+
+ $form->{title} = $locale->text('Add ' . ucfirst $form->{item});
+
+ $form->{callback} = "$form->{script}?action=add&item=$form->{item}&path=$form->{path}&login=$form->{login}&password=$form->{password}" unless $form->{callback};
+
+ $form->{unit} = ($form->{item} eq 'service') ? $locale->text('hr') : $locale->text('ea');
+
+ &link_part;
+
+ &display_form;
+
+}
+
+
+sub search {
+
+ $form->{title} = (ucfirst $form->{searchitems})."s";
+ $form->{title} = $locale->text($form->{title});
+
+# $locale->text('Parts')
+# $locale->text('Services')
+
+ unless ($form->{searchitems} eq 'service') {
+
+ $onhand = qq|
+ <input name=itemstatus class=radio type=radio value=onhand>&nbsp;|.$locale->text('On Hand').qq|
+ <input name=itemstatus class=radio type=radio value=short>&nbsp;|.$locale->text('Short').qq|
+|;
+
+ $makemodel = qq|
+ <tr>
+ <th width="1%" align=right nowrap>|.$locale->text('Make').qq|</th>
+ <td><input name=make size=20></td>
+ <th width="1%" align=right nowrap>|.$locale->text('Model').qq|</th>
+ <td><input name=model size=20></td>
+ </tr>
+|;
+ }
+
+ if ($form->{searchitems} eq 'assembly') {
+
+ $form->{title} = $locale->text('Assemblies');
+
+ $toplevel = qq|
+ <tr>
+ <td></td>
+ <td colspan=3>
+ <input name=none class=radio type=radio value=1 checked>&nbsp;|.$locale->text('Top Level').qq|
+ <input name=bom class=checkbox type=checkbox value=1>&nbsp;|.$locale->text('Individual Items').qq|
+ </td>
+ </tr>
+|;
+
+ $bought = qq|
+ <tr>
+ <td></td>
+ <td colspan=3>
+ <table>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <td><input name=sold class=checkbox type=checkbox value=1></td>
+ <td nowrap>|.$locale->text('Sold').qq|</td>
+ </tr>
+ <tr>
+ <td colspan=2><hr size=1 noshade></td>
+ </tr>
+ <tr>
+ <td><input name=ordered class=checkbox type=checkbox value=1></td>
+ <td nowrap>|.$locale->text('Ordered').qq|</td>
+ </tr>
+ </table>
+ </td>
+ <td width=5%>&nbsp;</td>
+ <th>|.$locale->text('From').qq|</th>
+ <td><input name=transdatefrom size=11 title="$myconfig{dateformat}"></td>
+ <th>|.$locale->text('to').qq|</th>
+ <td><input name=transdateto size=11 title="$myconfig{dateformat}"></td>
+
+ <td><input name=closed class=checkbox type=checkbox value=1>&nbsp;|.$locale->text('Closed').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+
+ } else {
+
+ $bought = qq|
+ <tr>
+ <td></td>
+ <td colspan=3>
+ <table>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <td><input name=bought class=checkbox type=checkbox value=1></td>
+ <td nowrap>|.$locale->text('Bought').qq|</td>
+ <td><input name=sold class=checkbox type=checkbox value=1></td>
+ <td nowrap>|.$locale->text('Sold').qq|</td>
+ </tr>
+ <tr>
+ <td colspan=4><hr size=1 noshade></td>
+ </tr>
+ <tr>
+ <td><input name=onorder class=checkbox type=checkbox value=1></td>
+ <td nowrap>|.$locale->text('On Order').qq|</td>
+ <td><input name=ordered class=checkbox type=checkbox value=1></td>
+ <td nowrap>|.$locale->text('Ordered').qq|</td>
+ </tr>
+ </table>
+ </td>
+ <td width=5%>&nbsp;</td>
+ <td>
+ <table>
+ <tr>
+ <th>|.$locale->text('From').qq|</th>
+ <td><input name=transdatefrom size=11 title="$myconfig{dateformat}"></td>
+ <th>|.$locale->text('to').qq|</th>
+ <td><input name=transdateto size=11 title="$myconfig{dateformat}"></td>
+
+ <td><input name=closed class=checkbox type=checkbox value=1>&nbsp;|.$locale->text('Closed').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+ }
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=searchitems value=$form->{searchitems}>
+<input type=hidden name=title value="$form->{title}">
+
+<table width="100%">
+ <tr><th class=listtop>$form->{title}</th></tr>
+ <tr height="5"></tr>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th width=1% align=right nowrap>|.$locale->text('Number').qq|</th>
+ <td><input name=partnumber size=20></td>
+ <th align=right nowrap>|.$locale->text('Description').qq|</th>
+ <td><input name=description size=40></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Group').qq|</th>
+ <td><input name=partsgroup size=20></td>
+ </tr>
+ $makemodel
+ <tr>
+ <th align=right nowrap>|.$locale->text('Drawing').qq|</th>
+ <td><input name=drawing size=20></td>
+ <th align=right nowrap>|.$locale->text('Microfiche').qq|</th>
+ <td><input name=microfiche size=20></td>
+ </tr>
+ $toplevel
+ <tr>
+ <td></td>
+ <td colspan=3>
+ <input name=itemstatus class=radio type=radio value=active checked>&nbsp;|.$locale->text('Active').qq|
+ $onhand
+ <input name=itemstatus class=radio type=radio value=obsolete>&nbsp;|.$locale->text('Obsolete').qq|
+ <input name=itemstatus class=radio type=radio value=orphaned>&nbsp;|.$locale->text('Orphaned').qq|
+ </td>
+ </tr>
+ $bought
+ <tr>
+ <td></td>
+ <td colspan=3>
+ <hr size=1 noshade>
+ </td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Include in Report').qq|</th>
+ <td colspan=3>
+ <table>
+ <tr>
+ <td><input name=l_partnumber class=checkbox type=checkbox value=Y checked>&nbsp;|.$locale->text('Number').qq|</td>
+ <td><input name=l_description class=checkbox type=checkbox value=Y checked>&nbsp;|.$locale->text('Description').qq|</td>
+ <td><input name=l_unit class=checkbox type=checkbox value=Y checked>&nbsp;|.$locale->text('Unit of measure').qq|</td>
+ </tr>
+ <tr>
+ <td><input name=l_listprice class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('List Price').qq|</td>
+ <td><input name=l_sellprice class=checkbox type=checkbox value=Y checked>&nbsp;|.$locale->text('Sell Price').qq|</td>
+ <td><input name=l_lastcost class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Last Cost').qq|</td>
+ <td><input name=l_linetotal class=checkbox type=checkbox value=Y checked>&nbsp;|.$locale->text('Line Total').qq|</td>
+ </tr>
+ <tr>
+ <td><input name=l_priceupdate class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Updated').qq|</td>
+ <td><input name=l_bin class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Bin').qq|</td>
+ <td><input name=l_rop class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('ROP').qq|</td>
+ <td><input name=l_weight class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Weight').qq|</td>
+ </tr>
+ <tr>
+ <td><input name=l_image class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Image').qq|</td>
+ <td><input name=l_drawing class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Drawing').qq|</td>
+ <td><input name=l_microfiche class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Microfiche').qq|</td>
+ <td><input name=l_partsgroup class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Group').qq|</td>
+ </tr>
+ <tr>
+ <td><input name=l_subtotal class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Subtotal').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr><td colspan=4><hr size=3 noshade></td></tr>
+</table>
+
+<input type=hidden name=nextsub value=generate_report>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub generate_report {
+
+ # setup $form->{sort}
+ unless ($form->{sort}) {
+ if ($form->{description} && !($form->{partnumber})) {
+ $form->{sort} = "description";
+ } else {
+ $form->{sort} = "partnumber";
+ }
+ }
+
+ $callback = "$form->{script}?action=generate_report&path=$form->{path}&login=$form->{login}&password=$form->{password}&searchitems=$form->{searchitems}&itemstatus=$form->{itemstatus}&bom=$form->{bom}&l_linetotal=$form->{l_linetotal}&title=".$form->escape($form->{title},1);
+
+ IC->all_parts(\%myconfig, \%$form);
+
+
+ if ($form->{itemstatus} eq 'active') {
+ $option .= $locale->text('Active')." : ";
+ }
+ if ($form->{itemstatus} eq 'obsolete') {
+ $option .= $locale->text('Obsolete')." : ";
+ }
+ if ($form->{itemstatus} eq 'orphaned') {
+ $option .= $locale->text('Orphaned')." : ";
+ }
+ if ($form->{itemstatus} eq 'onhand') {
+ $option .= $locale->text('On Hand')." : ";
+ $form->{l_onhand} = "Y";
+ }
+ if ($form->{itemstatus} eq 'short') {
+ $option .= $locale->text('Short')." : ";
+ $form->{l_onhand} = "Y";
+ }
+ if ($form->{onorder}) {
+ $form->{l_ordnumber} = "Y";
+ $callback .= "&onorder=$form->{onorder}";
+ $option .= $locale->text('On Order')." : ";
+ }
+ if ($form->{ordered}) {
+ $form->{l_ordnumber} = "Y";
+ $callback .= "&ordered=$form->{ordered}";
+ $option .= $locale->text('Ordered')." : ";
+ }
+ if ($form->{closed}) {
+ $callback .= "&closed=$form->{closed}";
+ $option .= $locale->text('Closed')." : ";
+ }
+ if ($form->{bought}) {
+ $form->{l_invnumber} = "Y";
+ $callback .= "&bought=$form->{bought}";
+ $option .= $locale->text('Bought')." : ";
+ }
+ if ($form->{sold}) {
+ $form->{l_invnumber} = "Y";
+ $callback .= "&sold=$form->{sold}";
+ $option .= $locale->text('Sold')." : ";
+ }
+ if ($form->{bought} || $form->{sold} || $form->{onorder} || $form->{ordered}) {
+
+ $form->{l_lastcost} = "";
+ if ($form->{transdatefrom}) {
+ $callback .= "&transdatefrom=$form->{transdatefrom}";
+ $option .= "\n<br>".$locale->text('From')."&nbsp;".$locale->date(\%myconfig, $form->{transdatefrom}, 1);
+ }
+ if ($form->{transdateto}) {
+ $callback .= "&transdateto=$form->{transdateto}";
+ $option .= "\n<br>".$locale->text('to')."&nbsp;".$locale->date(\%myconfig, $form->{transdateto}, 1);
+ }
+ }
+
+ $option .= "<br>";
+
+ if ($form->{partnumber}) {
+ $callback .= "&partnumber=$form->{partnumber}";
+ $option .= $locale->text('Number').qq| : $form->{partnumber}<br>|;
+ }
+ if ($form->{description}) {
+ $callback .= "&description=$form->{description}";
+ $option .= $locale->text('Description').qq| : $form->{description}<br>|;
+ }
+ if ($form->{make}) {
+ $callback .= "&make=$form->{make}";
+ $option .= $locale->text('Make').qq| : $form->{make}<br>|;
+ }
+ if ($form->{model}) {
+ $callback .= "&model=$form->{model}";
+ $option .= $locale->text('Model').qq| : $form->{model}<br>|;
+ }
+ if ($form->{drawing}) {
+ $callback .= "&drawing=$form->{drawing}";
+ $option .= $locale->text('Drawing').qq| : $form->{drawing}<br>|;
+ }
+ if ($form->{microfiche}) {
+ $callback .= "&microfiche=$form->{microfiche}";
+ $option .= $locale->text('Microfiche').qq| : $form->{microfiche}<br>|;
+ }
+ if ($form->{partsgroup}) {
+ $callback .= "&partsgroup=$form->{partsgroup}";
+ $option .= $locale->text('Group').qq| : $form->{partsgroup}<br>|;
+ }
+
+
+ @columns = $form->sort_columns(qw(partnumber description partsgroup bin onhand rop unit listprice linetotallistprice sellprice linetotalsellprice lastcost linetotallastcost priceupdate weight image drawing microfiche invnumber ordnumber));
+
+ if ($form->{l_linetotal}) {
+ $form->{l_onhand} = "Y";
+ $form->{l_linetotalsellprice} = "Y" if $form->{l_sellprice};
+ if ($form->{l_lastcost}) {
+ $form->{l_linetotallastcost} = "Y";
+ if (($form->{searchitems} eq 'assembly') && !$form->{bom}) {
+ $form->{l_linetotallastcost} = "";
+ }
+ }
+ $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
+ }
+
+ if ($form->{searchitems} eq 'service') {
+ # remove bin, weight and rop from list
+ map { $form->{"l_$_"} = "" } qw(bin weight rop);
+
+ $form->{l_onhand} = "";
+ # qty is irrelevant unless bought or sold
+ if ($form->{bought} || $form->{sold} || $form->{onorder} || $form->{ordered}) {
+ $form->{l_onhand} = "Y";
+ } else {
+ $form->{l_linetotalsellprice} = "";
+ $form->{l_linetotallastcost} = "";
+ }
+ }
+
+ $form->{l_lastcost} = "" if ($form->{searchitems} eq 'assembly' && !$form->{bom});
+
+ foreach $item (@columns) {
+ if ($form->{"l_$item"} eq "Y") {
+ push @column_index, $item;
+
+ # add column to callback
+ $callback .= "&l_$item=Y";
+ }
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ $callback .= "&l_subtotal=Y";
+ }
+
+ $column_header{partnumber} = qq|<th nowrap><a class=listheading href=$callback&sort=partnumber>|.$locale->text('Number').qq|</a></th>|;
+ $column_header{description} = qq|<th nowrap><a class=listheading href=$callback&sort=description>|.$locale->text('Description').qq|</a></th>|;
+ $column_header{partsgroup} = qq|<th nowrap><a class=listheading href=$callback&sort=partsgroup>|.$locale->text('Group').qq|</a></th>|;
+ $column_header{bin} = qq|<th><a class=listheading href=$callback&sort=bin>|.$locale->text('Bin').qq|</a></th>|;
+ $column_header{priceupdate} = qq|<th nowrap><a class=listheading href=$callback&sort=priceupdate>|.$locale->text('Updated').qq|</a></th>|;
+ $column_header{onhand} = qq|<th class=listheading nowrap>|.$locale->text('Qty').qq|</th>|;
+ $column_header{unit} = qq|<th class=listheading nowrap>|.$locale->text('Unit').qq|</th>|;
+ $column_header{listprice} = qq|<th class=listheading nowrap>|.$locale->text('List Price').qq|</th>|;
+ $column_header{lastcost} = qq|<th class=listheading nowrap>|.$locale->text('Last Cost').qq|</th>|;
+ $column_header{rop} = qq|<th class=listheading nowrap>|.$locale->text('ROP').qq|</th>|;
+ $column_header{weight} = qq|<th class=listheading nowrap>|.$locale->text('Weight').qq|</th>|;
+
+ $column_header{invnumber} = qq|<th nowrap><a class=listheading href=$callback&sort=invnumber>|.$locale->text('Invoice Number').qq|</a></th>|;
+ $column_header{ordnumber} = qq|<th nowrap><a class=listheading href=$callback&sort=ordnumber>|.$locale->text('Order Number').qq|</a></th>|;
+
+ $column_header{sellprice} = qq|<th class=listheading nowrap>|.$locale->text('Sell Price').qq|</th>|;
+ $column_header{linetotalsellprice} = qq|<th class=listheading nowrap>|.$locale->text('Extended').qq|</th>|;
+ $column_header{linetotallastcost} = qq|<th class=listheading nowrap>|.$locale->text('Extended').qq|</th>|;
+ $column_header{linetotallistprice} = qq|<th class=listheading nowrap>|.$locale->text('Extended').qq|</th>|;
+
+ $column_header{image} = qq|<th class=listheading nowrap>|.$locale->text('Image').qq|</a></th>|;
+ $column_header{drawing} = qq|<th nowrap><a class=listheading href=$callback&sort=drawing>|.$locale->text('Drawing').qq|</a></th>|;
+ $column_header{microfiche} = qq|<th nowrap><a class=listheading href=$callback&sort=microfiche>|.$locale->text('Microfiche').qq|</a></th>|;
+
+ $form->header;
+ $colspan = $#column_index + 1;
+
+ print qq|
+<body>
+
+<table width=100%>
+<tr><th class=listtop colspan=$colspan>$form->{title}</th></tr>
+<tr height="5"></tr>
+
+<tr><td colspan=$colspan>$option</td></tr>
+
+ <tr class=listheading>
+|;
+
+ map { print "\n$column_header{$_}" } @column_index;
+
+ print qq|
+ </tr>
+ |;
+
+
+ # add order to callback
+ $form->{callback} = $callback .= "&sort=$form->{sort}";
+
+ # escape callback for href
+ $callback = $form->escape($callback);
+
+ if (@{ $form->{parts} }) {
+ $sameitem = $form->{parts}->[0]->{$form->{sort}};
+ }
+
+ foreach $ref (@{ $form->{parts} }) {
+
+ if ($form->{l_subtotal} eq 'Y' && !$ref->{assemblyitem}) {
+ if ($sameitem ne $ref->{$form->{sort}}) {
+ &parts_subtotal;
+ $sameitem = $ref->{$form->{sort}};
+ }
+ }
+
+ $ref->{exchangerate} = 1 unless $ref->{exchangerate};
+ $ref->{sellprice} *= $ref->{exchangerate};
+ $ref->{listprice} *= $ref->{exchangerate};
+ $ref->{lastcost} *= $ref->{exchangerate};
+
+ $align = "left";
+ $onhand = $ref->{onhand};
+
+ if ($ref->{assemblyitem}) {
+ $align = "right";
+ $onhand = 0 if ($form->{sold});
+ }
+
+ $column_data{partnumber} = "<td align=$align><a href=$form->{script}?action=edit&id=$ref->{id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ref->{partnumber}&nbsp;</a></td>";
+ $column_data{description} = "<td>$ref->{description}&nbsp;</td>";
+ $column_data{partsgroup} = "<td>$ref->{partsgroup}&nbsp;</td>";
+
+ $column_data{onhand} = "<td align=right>".$form->format_amount(\%myconfig, $onhand, '', "&nbsp;")."</td>";
+ $column_data{sellprice} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{sellprice}, 2, "&nbsp;") . "</td>";
+ $column_data{listprice} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{listprice}, 2, "&nbsp;") . "</td>";
+ $column_data{lastcost} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{lastcost}, 2, "&nbsp;") . "</td>";
+
+ $column_data{linetotalsellprice} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{onhand} * $ref->{sellprice}, 2, "&nbsp;")."</td>";
+ $column_data{linetotallastcost} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{onhand} * $ref->{lastcost}, 2, "&nbsp;")."</td>";
+ $column_data{linetotallistprice} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{onhand} * $ref->{listprice}, 2, "&nbsp;")."</td>";
+
+ if (!$ref->{assemblyitem}) {
+ $totalsellprice += $onhand * $ref->{sellprice};
+ $totallastcost += $onhand * $ref->{lastcost};
+ $totallistprice += $onhand * $ref->{listprice};
+
+ $subtotalonhand += $onhand;
+ $subtotalsellprice += $onhand * $ref->{sellprice};
+ $subtotallastcost += $onhand * $ref->{lastcost};
+ $subtotallistprice += $onhand * $ref->{listprice};
+ }
+
+ $column_data{rop} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{rop}, '', "&nbsp;")."</td>";
+ $column_data{weight} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{weight}, '', "&nbsp;")."</td>";
+ $column_data{unit} = "<td>$ref->{unit}&nbsp;</td>";
+ $column_data{bin} = "<td>$ref->{bin}&nbsp;</td>";
+ $column_data{priceupdate} = "<td>$ref->{priceupdate}&nbsp;</td>";
+
+ $column_data{invnumber} = ($ref->{module} ne 'oe') ? "<td><a href=$ref->{module}.pl?action=edit&type=invoice&id=$ref->{trans_id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ref->{invnumber}&nbsp;</a></td>" : "<td>$ref->{invnumber}&nbsp;</td>";
+ $column_data{ordnumber} = ($ref->{module} eq 'oe') ? "<td><a href=$ref->{module}.pl?action=edit&type=$ref->{type}&id=$ref->{trans_id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ref->{ordnumber}&nbsp;</a></td>" : "<td>$ref->{ordnumber}&nbsp;</td>";
+
+ $column_data{image} = ($ref->{image}) ? "<td><a href=$ref->{image}><img src=$ref->{image} height=32 border=0></a></td>" : "<td>&nbsp;</td>";
+ $column_data{drawing} = ($ref->{drawing}) ? "<td><a href=$ref->{drawing}>$ref->{drawing}</a></td>" : "<td>&nbsp;</td>";
+ $column_data{microfiche} = ($ref->{microfiche}) ? "<td><a href=$ref->{microfiche}>$ref->{microfiche}</a></td>" : "<td>&nbsp;</td>";
+
+ $i++; $i %= 2;
+ print "<tr class=listrow$i>";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ }
+
+
+ if ($form->{l_subtotal} eq 'Y') {
+ &parts_subtotal;
+ }
+
+ if ($form->{"l_linetotal"}) {
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+ $column_data{linetotalsellprice} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalsellprice, 2, "&nbsp;")."</th>";
+ $column_data{linetotallastcost} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totallastcost, 2, "&nbsp;")."</th>";
+ $column_data{linetotallistprice} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totallistprice, 2, "&nbsp;")."</th>";
+
+ print "<tr class=listtotal>";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|</tr>
+ |;
+ }
+
+ print qq|
+ <tr><td colspan=$colspan><hr size=3 noshade></td></tr>
+</table>
+
+|;
+
+
+ print qq|
+
+<br>
+
+<form method=post action=$form->{script}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=item value=$form->{searchitems}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input class=submit type=submit name=action value="|.$locale->text('Add').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub parts_subtotal {
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+ $subtotalonhand = 0 if ($form->{searchitems} eq 'assembly' && $form->{bom});
+
+ $column_data{onhand} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalonhand, '', "&nbsp;")."</th>";
+ $column_data{sellprice} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalsellprice, 2, "&nbsp;")."</th>";
+ $column_data{listprice} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotallistprice, 2, "&nbsp;")."</th>";
+ $column_data{lastcost} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotallastcost, 2, "&nbsp;")."</th>";
+
+ $subtotalonhand = 0;
+ $subtotalsellprice = 0;
+ $subtotallistprice = 0;
+ $subtotallastcost = 0;
+
+ print "<tr class=listsubtotal>";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+}
+
+
+
+sub edit {
+
+ IC->get_part(\%myconfig, \%$form);
+
+ $form->{title} = $locale->text('Edit '.ucfirst $form->{item});
+
+ &link_part;
+ &display_form;
+
+}
+
+
+
+sub link_part {
+
+ IC->create_links("IC", \%myconfig, \%$form);
+
+ # parts and assemblies have the same links
+ $item = $form->{item};
+ if ($form->{item} eq 'assembly') {
+ $item = 'part';
+ }
+
+ # build the popup menus
+ $form->{taxaccounts} = "";
+ foreach $key (keys %{ $form->{IC_links} }) {
+ foreach $ref (@{ $form->{IC_links}{$key} }) {
+ # if this is a tax field
+ if ($key =~ /IC_tax/) {
+ if ($key =~ /$item/) {
+ $form->{taxaccounts} .= "$ref->{accno} ";
+ $form->{"IC_tax_$ref->{accno}_description"} = "$ref->{accno}--$ref->{description}";
+
+ if ($form->{id}) {
+ if ($form->{amount}{$ref->{accno}}) {
+ $form->{"IC_tax_$ref->{accno}"} = "checked";
+ }
+ } else {
+ $form->{"IC_tax_$ref->{accno}"} = "checked";
+ }
+ }
+ } else {
+
+ $form->{"select$key"} .= "<option>$ref->{accno}--$ref->{description}\n";
+ if ($form->{amount}{$key} eq $ref->{accno}) {
+ $form->{$key} = "$ref->{accno}--$ref->{description}";
+ }
+
+ }
+ }
+ }
+ chop $form->{taxaccounts};
+
+ if (($form->{item} eq "part") || ($form->{item} eq "assembly")) {
+ $form->{selectIC_income} = $form->{selectIC_sale};
+ $form->{selectIC_expense} = $form->{selectIC_cogs};
+ $form->{IC_income} = $form->{IC_sale};
+ $form->{IC_expense} = $form->{IC_cogs};
+ }
+
+ delete $form->{IC_links};
+ delete $form->{amount};
+
+}
+
+
+
+sub form_header {
+
+ ($dec) = ($form->{sellprice} =~ /\.(\d+)/);
+ $dec = length $dec;
+ my $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ map { $form->{$_} = $form->format_amount(\%myconfig, $form->{$_}, $decimalplaces)} qw(listprice sellprice);
+
+ ($dec) = ($form->{lastcost} =~ /\.(\d+)/);
+ $dec = length $dec;
+ my $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ $form->{lastcost} = $form->format_amount(\%myconfig, $form->{lastcost}, $decimalplaces);
+
+ map { $form->{$_} = $form->format_amount(\%myconfig, $form->{$_}) } qw(weight rop stock);
+
+ foreach $item (qw(partnumber description unit notes)) {
+ $form->{$item} =~ s/"/&quot;/g;
+ }
+
+
+ if (($rows = $form->numtextrows($form->{notes}, 40)) < 2) {
+ $rows = 2;
+ }
+
+ $notes = qq|<textarea name=notes rows=$rows cols=40 wrap=soft>$form->{notes}</textarea>|;
+
+ if (($rows = $form->numtextrows($form->{description}, 40)) > 1) {
+ $description = qq|<textarea name="description" rows=$rows cols=40 wrap=soft>$form->{description}</textarea>|;
+ } else {
+ $description = qq|<input name=description size=40 value="$form->{description}">|;
+ }
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ $form->{"IC_tax_$item"} = ($form->{"IC_tax_$item"}) ? "checked" : "";
+ }
+
+
+ # set option
+ foreach $item (qw(IC IC_income IC_expense)) {
+ if ($form->{$item}) {
+ if ($form->{id} && $form->{orphaned}) {
+ $form->{"select$item"} =~ s/ selected//;
+ $form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
+
+ } else {
+ $form->{"select$item"} = qq|<option selected>$form->{$item}|;
+ }
+ }
+ }
+
+ # tax fields
+ foreach $item (split / /, $form->{taxaccounts}) {
+ $tax .= qq|
+ <input class=checkbox type=checkbox name="IC_tax_$item" value=1 $form->{"IC_tax_$item"}>&nbsp;<b>$form->{"IC_tax_${item}_description"}</b>
+ <br><input type=hidden name=IC_tax_${item}_description value="$form->{"IC_tax_${item}_description"}">
+|;
+ }
+
+ $form->{obsolete} = "checked" if $form->{obsolete};
+
+ $lastcost = qq|
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('Last Cost').qq|</th>
+ <td><input name=lastcost size=11 value=$form->{lastcost}></td>
+ </tr>
+|;
+
+ if ($form->{item} eq "part") {
+
+ $linkaccounts = qq|
+ <tr>
+ <th width="1%" align=right>|.$locale->text('Inventory').qq|</th>
+ <td><select name=IC>$form->{selectIC}</select></td>
+ <input name=selectIC type=hidden value="$form->{selectIC}">
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Sales').qq|</th>
+ <td><select name=IC_income>$form->{selectIC_income}</select></td>
+ <input name=selectIC_income type=hidden value="$form->{selectIC_income}">
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('COGS').qq|</th>
+ <td><select name=IC_expense>$form->{selectIC_expense}</select></td>
+ <input name=selectIC_expense type=hidden value="$form->{selectIC_expense}">
+ </tr>
+|;
+
+ if ($tax) {
+ $linkaccounts .= qq|
+ <tr>
+ <th align=right>|.$locale->text('Tax').qq|</th>
+ <td>$tax</td>
+ </tr>
+|;
+ }
+
+ $weight = qq|
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('Weight').qq|</th>
+ <td>
+ <table>
+ <tr>
+ <td>
+ <input name=weight size=10 value=$form->{weight}>
+ </td>
+ <th>
+ &nbsp;
+ $form->{weightunit}
+ <input type=hidden name=weightunit value=$form->{weightunit}>
+ </th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+
+ }
+
+
+ if ($form->{item} eq "assembly") {
+
+ $lastcost = "";
+
+ $linkaccounts = qq|
+ <tr>
+ <th width="1%" align=right>|.$locale->text('Sales').qq|</th>
+ <td><select name=IC_income>$form->{selectIC_income}</select></td>
+ <input name=selectIC_income type=hidden value="$form->{selectIC_income}">
+ </tr>
+|;
+
+ if ($tax) {
+ $linkaccounts .= qq|
+ <tr>
+ <th align=right>|.$locale->text('Tax').qq|</th>
+ <td>$tax</td>
+ </tr>
+|;
+ }
+
+ $weight = qq|
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('Weight').qq|</th>
+ <td>
+ <table>
+ <tr>
+ <td>
+ &nbsp;$form->{weight}
+ <input type=hidden name=weight value=$form->{weight}>
+ </td>
+ <th>
+ &nbsp;
+ $form->{weightunit}
+ <input type=hidden name=weightunit value=$form->{weightunit}>
+ </th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+
+
+ }
+
+
+ if ($form->{item} eq "service") {
+
+ $linkaccounts = qq|
+ <tr>
+ <th width="1%" align=right>|.$locale->text('Income').qq|</th>
+ <td><select name=IC_income>$form->{selectIC_income}</select></td>
+ <input name=selectIC_income type=hidden value="$form->{selectIC_income}">
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Expense').qq|</th>
+ <td><select name=IC_expense>$form->{selectIC_expense}</select></td>
+ <input name=selectIC_expense type=hidden value="$form->{selectIC_expense}">
+ </tr>
+|;
+
+ if ($tax) {
+ $linkaccounts .= qq|
+ <tr>
+ <th align=right>|.$locale->text('Tax').qq|</th>
+ <td>$tax</td>
+ </tr>
+|;
+ }
+
+ }
+
+
+ if ($form->{item} ne 'service') {
+ $color = ($form->{onhand} > 0) ? "green" : "red";
+ $rop = qq|
+ <tr>
+ <th align="right" nowrap>|.$locale->text('On Hand').qq|</th>
+ <th align=left nowrap>&nbsp;|.$form->format_amount(\%myconfig, $form->{onhand}).qq|</th>
+ </tr>
+|;
+
+ if ($form->{item} eq 'assembly') {
+ $rop .= qq|
+ <tr>
+ <th align="right" nowrap>|.$locale->text('Stock').qq|</th>
+ <td><input name=stock size=10 value=$form->{stock}></td>
+ </tr>
+|;
+ }
+
+ $rop .= qq|
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('ROP').qq|</th>
+ <td><input name=rop size=10 value=$form->{rop}></td>
+ </tr>
+|;
+
+ $bin = qq|
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('Bin').qq|</th>
+ <td><input name=bin size=10 value=$form->{bin}></td>
+ </tr>
+|;
+
+ $imagelinks = qq|
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th width=1% align=right nowrap>|.$locale->text('Image').qq|</th>
+ <td width=70%><input name=image size=40 value="$form->{image}"></td>
+
+ </tr>
+ <tr>
+ <th width=1% align=right nowrap>|.$locale->text('Drawing').qq|</th>
+ <td width=70%><input name=drawing size=40 value="$form->{drawing}"></td>
+ <th width=1% align=right nowrap>|.$locale->text('Microfiche').qq|</th>
+ <td width=30%><input name=microfiche size=20 value="$form->{microfiche}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+
+ }
+
+ if ($form->{id}) {
+ $obsolete = qq|
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('Obsolete').qq|</th>
+ <td><input name=obsolete type=checkbox class=checkbox value=1 $form->{obsolete}></td>
+ </tr>
+|;
+ }
+
+
+
+# type=submit $locale->text('Add Part')
+# type=submit $locale->text('Add Service')
+# type=submit $locale->text('Add Assembly')
+
+# type=submit $locale->text('Edit Part')
+# type=submit $locale->text('Edit Service')
+# type=submit $locale->text('Edit Assembly')
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input name=id type=hidden value=$form->{id}>
+<input name=item type=hidden value=$form->{item}>
+<input name=title type=hidden value="$form->{title}">
+<input name=makemodel type=hidden value="$form->{makemodel}">
+<input name=alternate type=hidden value="$form->{alternate}">
+<input name=onhand type=hidden value=$form->{onhand}>
+<input name=orphaned type=hidden value=$form->{orphaned}>
+<input name=taxaccounts type=hidden value="$form->{taxaccounts}">
+<input name=rowcount type=hidden value=$form->{rowcount}>
+
+<table width="100%">
+ <tr><th class=listtop>$form->{title}</th></tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width="100%">
+ <tr valign=top>
+ <th align=left>|.$locale->text('Number').qq|</th>
+ <th align=left>|.$locale->text('Description').qq|</th>
+ <th align=left>|.$locale->text('Group').qq|</th>
+ </tr>
+ <tr valign=top>
+ <td><input name=partnumber value="$form->{partnumber}" size=20></td>
+ <td>$description</td>
+ <td><input name=partsgroup size=20 value="$form->{partsgroup}"></td>
+ <input type=hidden name=oldpartsgroup value="$form->{oldpartsgroup}">
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width="100%" height="100%">
+ <tr valign=top>
+ <td width=70%>
+ <table width="100%" height="100%">
+ <tr class="listheading">
+ <th class="listheading" align="center" colspan=2>|.$locale->text('Link Accounts').qq|</th>
+ </tr>
+ $linkaccounts
+ <tr>
+ <th align="left">|.$locale->text('Notes').qq|</th>
+ </tr>
+ <tr>
+ <td colspan=2>
+ $notes
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td width="30%">
+ <table width="100%">
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('Updated').qq|</th>
+ <td><input name=priceupdate size=11 title="$myconfig{dateformat}" value=$form->{priceupdate}></td>
+ </tr>
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('List Price').qq|</th>
+ <td><input name=listprice size=11 value=$form->{listprice}></td>
+ </tr>
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('Sell Price').qq|</th>
+ <td><input name=sellprice size=11 value=$form->{sellprice}></td>
+ </tr>
+ $lastcost
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('Unit').qq|</th>
+ <td><input name=unit size=5 maxsize=5 value="$form->{unit}"></td>
+ </tr>
+ $weight
+ $rop
+ $bin
+ $obsolete
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ $imagelinks
+|;
+}
+
+
+sub form_footer {
+
+ if ($form->{item} eq "assembly") {
+
+ print qq|
+ <tr>
+ <td>
+ <table width="100%">
+ <tr>
+ <th colspan=2 align=right>|.$locale->text('Total').qq|&nbsp;</th>
+ <th width="1%" align=right>|.$form->format_amount(\%myconfig, $form->{assemblytotal}, 2).qq|</th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <input type=hidden name=assembly_rows value=$form->{assembly_rows}>
+|;
+ }
+
+ print qq|
+ <input type=hidden name=path value=$form->{path}>
+ <input type=hidden name=login value=$form->{login}>
+ <input type=hidden name=password value=$form->{password}>
+ <input type=hidden name=callback value="$form->{callback}">
+ <input type=hidden name=previous_form value="$form->{previous_form}">
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+|;
+
+ if ($form->{item} ne "service") {
+ print qq|
+ <input type=hidden name=makemodel_rows value=$form->{makemodel_rows}>
+ |;
+ }
+
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Save').qq|">|;
+
+ if ($form->{id}) {
+
+ if (! $form->{previous_form}) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Save as new').qq|">|;
+ }
+
+ if ($form->{orphaned}) {
+ if (! $form->{previous_form}) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Delete').qq|">|;
+ }
+ }
+
+ }
+
+ print qq|
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub makemodel_row {
+ my ($numrows) = @_;
+
+ $form->{"make_$i"} =~ s/"/&quot;/g;
+ $form->{"model_$i"} =~ s/"/&quot;/g;
+
+ print qq|
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th class="listheading">|.$locale->text('Make').qq|</th>
+ <th class="listheading">|.$locale->text('Model').qq|</th>
+ </tr>
+|;
+
+ for $i (1 .. $numrows) {
+ print qq|
+ <tr>
+ <td width=50%><input name="make_$i" size=30 value="$form->{"make_$i"}"></td>
+ <td width=50%><input name="model_$i" size=30 value="$form->{"model_$i"}"></td>
+ </tr>
+|;
+ }
+
+ print qq|
+ </table>
+ </td>
+ </tr>
+|;
+
+}
+
+
+sub assembly_row {
+ my ($numrows) = @_;
+
+ @column_index = qw(runningnumber qty unit bom partnumber description partsgroup total);
+
+ if ($form->{previous_form}) {
+ $nochange = 1;
+ @column_index = qw(qty unit bom partnumber description partsgroup total);
+ } else {
+ # change callback
+ $form->{old_callback} = $form->{callback};
+ $callback = $form->{callback};
+ $form->{callback} = "$form->{script}?action=display_form";
+
+ # delete action
+ delete $form->{action};
+
+ $previous_form = "";
+ # save form variables in a previous_form variable
+ foreach $key (sort keys %$form) {
+ # escape ampersands
+ $form->{$key} =~ s/&/%26/g;
+ $previous_form .= qq|$key=$form->{$key}&|;
+ }
+ chop $previous_form;
+ $previous_form = $form->escape($form->escape($previous_form, 1));
+ $form->{callback} = $callback;
+
+ $form->{assemblytotal} = 0;
+ $form->{weight} = 0;
+
+ }
+
+ $column_header{runningnumber} = qq|<th nowrap width=5%>|.$locale->text('No.').qq|</th>|;
+ $column_header{qty} = qq|<th align=left nowrap width=10%>|.$locale->text('Qty').qq|</th>|;
+ $column_header{unit} = qq|<th align=left nowrap width=5%>|.$locale->text('Unit').qq|</th>|;
+ $column_header{partnumber} = qq|<th align=left nowrap width=20%>|.$locale->text('Number').qq|</th>|;
+ $column_header{description} = qq|<th nowrap width=50%>|.$locale->text('Description').qq|</th>|;
+ $column_header{total} = qq|<th align=right nowrap>|.$locale->text('Extended').qq|</th>|;
+ $column_header{bom} = qq|<th>|.$locale->text('BOM').qq|</th>|;
+ $column_header{partsgroup} = qq|<th>|.$locale->text('Group').qq|</th>|;
+
+ print qq|
+ <tr class=listheading>
+ <th class=listheading>|.$locale->text('Individual Items').qq|</th>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+|;
+
+ map { print "\n$column_header{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ for $i (1 .. $numrows) {
+ $form->{"partnumber_$i"} =~ s/"/&quot;/g;
+
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
+ $form->{assemblytotal} += $linetotal;
+
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+
+ $linetotal = $form->format_amount(\%myconfig, $linetotal, 2);
+
+ if (($i >= 1) && ($i == $numrows)) {
+
+ if ($nochange) {
+ map { $column_data{$_} = qq|<td></td>| } qw(qty unit partnumber description bom partsgroup);
+ } else {
+
+ map { $column_data{$_} = qq|<td></td>| } qw(runningnumber unit bom);
+
+ $column_data{qty} = qq|<td><input name="qty_$i" size=5 value="$form->{"qty_$i"}"></td>|;
+ $column_data{partnumber} = qq|<td><input name="partnumber_$i" size=15 value="$form->{"partnumber_$i"}"></td>|;
+ $column_data{description} = qq|<td><input name="description_$i" size=40 value="$form->{"description_$i"}"></td>|;
+ $column_data{partsgroup} = qq|<td><input name="partsgroup_$i" size=10 value="$form->{"partsgroup_$i"}"></td>|;
+
+ }
+
+ } else {
+
+ if ($form->{previous_form}) {
+ $column_data{partnumber} = qq|<td><input type=hidden name="partnumber_$i" value="$form->{"partnumber_$i"}">$form->{"partnumber_$i"}</td>|;
+ $column_data{qty} = qq|<td align=right><input type=hidden name="qty_$i" value="$form->{"qty_$i"}">$form->{"qty_$i"}</td>|;
+
+ $column_data{bom} = qq|<td align=center><input type=hidden name="bom_$i" value=$form->{"bom_$i"}>|;
+ $column_data{bom} .= ($form->{"bom_$i"}) ? "x" : "&nbsp;";
+ $column_data{bom} .= qq|</td>|;
+
+ $column_data{partsgroup} = qq|<td><input type=hidden name="partsgroup_$i" value="$form->{"partsgroup_$i"}">$form->{"partsgroup_$i"}</td>|;
+
+ } else {
+ $href = qq|$form->{script}?action=edit&id=$form->{"id_$i"}&path=$form->{path}&login=$form->{login}&password=$form->{password}&rowcount=$i&previous_form=$previous_form|;
+ $column_data{partnumber} = qq|<td><input type=hidden name="partnumber_$i" value="$form->{"partnumber_$i"}"><a href=$href>$form->{"partnumber_$i"}</a></td>|;
+ $column_data{runningnumber} = qq|<td><input name="runningnumber_$i" size=3 value="$i"}"></td>|;
+ $column_data{qty} = qq|<td><input name="qty_$i" size=5 value="$form->{"qty_$i"}"></td>|;
+
+ $form->{"bom_$i"} = ($form->{"bom_$i"}) ? "checked" : "";
+ $column_data{bom} = qq|<td align=center><input name="bom_$i" type=checkbox class=checkbox value=1 $form->{"bom_$i"}></td>|;
+
+ $column_data{partsgroup} = qq|<td><input type=hidden name="partsgroup_$i" value="$form->{"partsgroup_$i"}">$form->{"partsgroup_$i"}</td>|;
+
+ }
+
+ $column_data{unit} = qq|<td><input type=hidden name="unit_$i" value="$form->{"unit_$i"}">$form->{"unit_$i"}</td>|;
+ $column_data{description} = qq|<td><input type=hidden name="description_$i" value="$form->{"description_$i"}">$form->{"description_$i"}</td>|;
+ }
+
+ $column_data{total} = qq|<td align=right>$linetotal</td>|;
+
+ print qq|
+ <tr>|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+ <input type=hidden name="id_$i" value=$form->{"id_$i"}>
+ <input type=hidden name="sellprice_$i" value=$form->{"sellprice_$i"}>
+ <input type=hidden name="weight_$i" value=$form->{"weight_$i"}>
+|;
+ }
+
+ print qq|
+ </table>
+ </td>
+ </tr>
+|;
+
+}
+
+
+sub update {
+
+
+ if ($form->{item} eq "assembly") {
+
+ $i = $form->{assembly_rows};
+
+ # if last row is empty check the form otherwise retrieve item
+ if (($form->{"partnumber_$i"} eq "") && ($form->{"description_$i"} eq "") && ($form->{"partsgroup_$i"} eq "")) {
+
+ &check_form;
+
+ } else {
+
+ IC->assembly_item(\%myconfig, \%$form);
+
+ $rows = scalar @{ $form->{item_list} };
+
+ if ($rows) {
+ $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
+
+ if ($rows > 1) {
+ $form->{makemodel_rows}--;
+ &select_item;
+ exit;
+ } else {
+ map { $form->{item_list}[$i]{$_} =~ s/"/&quot;/g } qw(partnumber description unit partsgroup);
+ map { $form->{"${_}_$i"} = $form->{item_list}[0]{$_} } keys %{ $form->{item_list}[0] };
+ $form->{"runningnumber_$i"} = $form->{assembly_rows};
+ $form->{assembly_rows}++;
+
+ &check_form;
+
+ }
+
+ } else {
+
+ $form->{rowcount} = $i;
+ $form->{assembly_rows}++;
+
+ &new_item;
+
+ }
+ }
+ }
+
+ if ($form->{item} eq "part") {
+ &check_form;
+ }
+
+ if ($form->{item} eq 'service') {
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(sellprice listprice);
+
+ &form_header;
+ &form_footer;
+ }
+
+}
+
+
+sub save {
+
+ # check if there is a part number
+ $form->isblank("partnumber", $locale->text(ucfirst $form->{item}." Number missing!"));
+
+ if ($form->{obsolete}) {
+ $form->error($locale->text("Inventory quantity must be zero before you can set this $form->{item} obsolete!")) if ($form->{onhand});
+ }
+
+# expand dynamic strings
+# $locale->text('Inventory quantity must be zero before you can set this part obsolete!')
+# $locale->text('Inventory quantity must be zero before you can set this assembly obsolete!')
+# $locale->text('Part Number missing!')
+# $locale->text('Service Number missing!')
+# $locale->text('Assembly Number missing!')
+
+ # save part
+ $rc = IC->save(\%myconfig, \%$form);
+
+ $parts_id = $form->{id};
+
+ # load previous variables
+ if ($form->{previous_form}) {
+ # save the new form variables before splitting previous_form
+ map { $newform{$_} = $form->{$_} } keys %$form;
+
+ $previous_form = $form->unescape($form->{previous_form});
+
+ # don't trample on previous variables
+ map { delete $form->{$_} } keys %newform;
+
+ # now take it apart and restore original values
+ foreach $item (split /&/, $previous_form) {
+ ($key, $value) = split /=/, $item, 2;
+ $value =~ s/%26/&/g;
+ $form->{$key} = $value;
+ }
+
+ if ($form->{item} eq 'assembly') {
+ # undo formatting
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(listprice sellprice weight);
+
+ $form->{assembly_rows}--;
+ $i = $newform{rowcount};
+ $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
+
+ $form->{sellprice} -= $form->{"sellprice_$i"} * $form->{"qty_$i"};
+ $form->{weight} -= $form->{"weight_$i"} * $form->{"qty_$i"};
+
+ # change/add values for assembly item
+ map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit weight listprice sellprice inventory_accno income_accno expense_accno partsgroup);
+
+ # undo string formatting
+ map { $form->{"${_}_$i"} =~ s/''/'/g } qw(partnumber description unit bin);
+
+ $form->{sellprice} += $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
+ $form->{weight} += $form->{"weight_$i"} * $form->{"qty_$i"};
+
+ } else {
+ # set values for last invoice/order item
+ $i = $form->{rowcount};
+ $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
+
+ map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit listprice inventory_accno income_accno expense_accno sellprice);
+ $form->{"sellprice_$i"} = $newform{lastcost} if ($form->{vendor_id});
+
+ if ($form->{exchangerate} != 0) {
+ $form->{"sellprice_$i"} /= $form->{exchangerate};
+ }
+
+ map { $form->{"taxaccounts_$i"} .= "$_ " if ($newform{"IC_tax_$_"}) } split / /, $newform{taxaccounts};
+ chop $form->{"taxaccounts_$i"};
+
+ # credit remaining calculation
+ $amount = $form->{"sellprice_$i"} * (1 - $form->{"discount_$i"} / 100) * $form->{"qty_$i"};
+ map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"});
+ map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
+
+ $form->{creditremaining} -= $amount;
+
+ }
+
+ $form->{"id_$i"} = $parts_id;
+ delete $form->{action};
+
+ # restore original callback
+ $callback = $form->unescape($form->{callback});
+ $form->{callback} = $form->unescape($form->{old_callback});
+ delete $form->{old_callback};
+
+ $form->{makemodel_rows}--;
+
+ # put callback together
+ foreach $key (keys %$form) {
+ # do single escape for Apache 2.0
+ $value = $form->escape($form->{$key}, 1);
+ $callback .= qq|&$key=$value|;
+ }
+ $form->{callback} = $callback;
+ }
+
+ # redirect
+ $form->redirect;
+
+}
+
+
+sub save_as_new {
+
+ $form->{id} = 0;
+ &save;
+
+}
+
+
+sub delete {
+
+ $rc = IC->delete(\%myconfig, \%$form);
+
+ # redirect
+ $form->redirect($locale->text('Item deleted!')) if ($rc > 0);
+ $form->error($locale->text('Cannot delete item!'));
+
+}
+
+
+
+sub stock_assembly {
+
+ $form->{title} = $locale->text('Stock Assembly');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width="100%">
+ <tr><th class=listtop>$form->{title}</th></tr>
+ <tr height="5"></tr>
+ <tr valign=top>
+ <td>
+ <table width="100%">
+ <tr>
+ <th width="1%" align="right" nowrap="true">|.$locale->text('Number').qq|</th>
+ <td width="40%"><input name=partnumber size=20></td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <th align="right" nowrap="true">|.$locale->text('Description').qq|</th>
+ <td colspan="2"><input name=description size=40></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr><td><hr size=3 noshade></td></tr>
+</table>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input type=hidden name=nextsub value=list_assemblies>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+
+sub list_assemblies {
+
+ IC->retrieve_assemblies(\%myconfig, \%$form);
+
+ $column_header{partnumber} = qq|<th class=listheading>|.$locale->text('Number').qq|</th>|;
+ $column_header{description} = qq|<th class=listheading>|.$locale->text('Description').qq|</th>|;
+ $column_header{bin} = qq|<th class=listheading>|.$locale->text('Bin').qq|</th>|;
+ $column_header{onhand} = qq|<th class=listheading>|.$locale->text('Qty').qq|</th>|;
+ $column_header{rop} = qq|<th class=listheading>|.$locale->text('ROP').qq|</th>|;
+ $column_header{stock} = qq|<th class=listheading>|.$locale->text('Add').qq|</th>|;
+
+ @column_index = (qw(partnumber description bin onhand rop stock));
+
+ $form->{title} = $locale->text('Stock Assembly');
+
+ $form->{callback} = "$form->{script}?action=stock_assembly&path=$form->{path}&login=$form->{login}&password=$form->{password}";
+
+ $form->header;
+
+ $colspan = $#column_index + 1;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr><th class=listtop colspan=$colspan>$form->{title}</th></tr>
+ <tr size=5></tr>
+ <tr class=listheading>|;
+
+ map { print "\n$column_header{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ $i = 1;
+ foreach $ref (@{ $form->{assembly_items} }) {
+
+ map { $ref->{$_} =~ s/"/&quot;/g } qw(partnumber description);
+
+ # figure out how many to stock
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $ref->{rop} - $ref->{onhand});
+
+ $column_data{partnumber} = qq|<td width=20%>$ref->{partnumber}</td>|;
+ $column_data{description} = qq|<td width=50%>$ref->{description}&nbsp;</td>|;
+ $column_data{bin} = qq|<td>$ref->{bin}&nbsp;</td>|;
+ $column_data{onhand} = qq|<td align=right>|.$form->format_amount(\%myconfig, $ref->{onhand}, '', "&nbsp;").qq|</td>|;
+ $column_data{rop} = qq|<td align=right>|.$form->format_amount(\%myconfig, $ref->{rop}, '', "&nbsp;").qq|</td>|;
+ $column_data{stock} = qq|<td width=10%><input name="qty_$i" size=10 value=$form->{"qty_$i"}></td>|;
+
+ $j++; $j %= 2;
+ print qq|<tr class=listrow$j><input name="id_$i" type=hidden value=$ref->{id}>\n|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ $i++;
+
+ }
+
+ $i--;
+ print qq|
+ <tr>
+ <td colspan=6><hr size=3 noshade>
+ </tr>
+</table>
+<input name=rowcount type=hidden value="$i">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=nextsub value=restock_assemblies>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub restock_assemblies {
+
+ $form->redirect($locale->text('Assemblies restocked!')) if (IC->restock_assemblies(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot stock assemblies!'));
+
+}
+
+
+sub continue { &{ $form->{nextsub} } };
+
+
diff --git a/sql-ledger/bin/mozilla/io.pl b/sql-ledger/bin/mozilla/io.pl
new file mode 100644
index 0000000..751d9a2
--- /dev/null
+++ b/sql-ledger/bin/mozilla/io.pl
@@ -0,0 +1,1149 @@
+######################################################################
+# SQL-Ledger, Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+#
+# common routines used in is, ir, oe
+#
+#######################################################################
+
+# any custom scripts for this one
+if (-f "$form->{path}/custom_io.pl") {
+ eval { require "$form->{path}/custom_io.pl"; };
+}
+if (-f "$form->{path}/$form->{login}_io.pl") {
+ eval { require "$form->{path}/$form->{login}_io.pl"; };
+}
+
+
+1;
+# end of main
+
+
+# this is for our long dates
+# $locale->text('January')
+# $locale->text('February')
+# $locale->text('March')
+# $locale->text('April')
+# $locale->text('May ')
+# $locale->text('June')
+# $locale->text('July')
+# $locale->text('August')
+# $locale->text('September')
+# $locale->text('October')
+# $locale->text('November')
+# $locale->text('December')
+
+# this is for our short month
+# $locale->text('Jan')
+# $locale->text('Feb')
+# $locale->text('Mar')
+# $locale->text('Apr')
+# $locale->text('May')
+# $locale->text('Jun')
+# $locale->text('Jul')
+# $locale->text('Aug')
+# $locale->text('Sep')
+# $locale->text('Oct')
+# $locale->text('Nov')
+# $locale->text('Dec')
+
+
+sub display_row {
+ my $numrows = shift;
+
+ @column_index = (partnumber, description, qty);
+
+ if ($form->{type} eq "sales_order") {
+ if ($form->{id}) {
+ push @column_index, "ship";
+ $column_data{ship} = qq|<th class=listheading align=left width="auto">|.$locale->text('Ship').qq|</th>|;
+ }
+ }
+ if ($form->{type} eq "purchase_order") {
+ if ($form->{id}) {
+ push @column_index, "ship";
+ $column_data{ship} = qq|<th class=listheading align=left width="auto">|.$locale->text('Recd').qq|</th>|;
+ }
+ }
+
+ push @column_index, qw(unit sellprice);
+
+ if ($form->{script} eq 'is.pl' || $form->{type} eq 'sales_order') {
+ push @column_index, qw(discount);
+ }
+
+ push @column_index, "linetotal";
+
+ my $colspan = $#column_index + 1;
+
+
+ $form->{invsubtotal} = 0;
+ map { $form->{"${_}_base"} = 0 } (split / /, $form->{taxaccounts});
+
+ $column_data{partnumber} = qq|<th class=listheading nowrap>|.$locale->text('Number').qq|</th>|;
+ $column_data{description} = qq|<th class=listheading nowrap>|.$locale->text('Description').qq|</th>|;
+ $column_data{qty} = qq|<th class=listheading nowrap>|.$locale->text('Qty').qq|</th>|;
+ $column_data{unit} = qq|<th class=listheading nowrap>|.$locale->text('Unit').qq|</th>|;
+ $column_data{sellprice} = qq|<th class=listheading nowrap>|.$locale->text('Price').qq|</th>|;
+ $column_data{discount} = qq|<th class=listheading>%</th>|;
+ $column_data{linetotal} = qq|<th class=listheading nowrap>|.$locale->text('Extended').qq|</th>|;
+ $column_data{bin} = qq|<th class=listheading nowrap>|.$locale->text('Bin').qq|</th>|;
+
+ print qq|
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+
+ $projectnumber = $locale->text('Project');
+ $runningnumber = $locale->text('No.');
+ $partsgroup = $locale->text('Group');
+
+ if ($form->{type} =~ /_order/) {
+ $reqdate = $locale->text('Required by');
+ $delvar = "reqdate";
+ } else {
+ $deliverydate = $locale->text('Delivery Date');
+ $delvar = "deliverydate";
+ }
+
+
+ for $i (1 .. $numrows) {
+ # undo formatting
+ map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(qty ship discount sellprice);
+
+ ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ $discount = $form->round_amount($form->{"sellprice_$i"} * $form->{"discount_$i"}/100, $decimalplaces);
+ $linetotal = $form->round_amount($form->{"sellprice_$i"} - $discount, $decimalplaces);
+ $linetotal = $form->round_amount($linetotal * $form->{"qty_$i"}, 2);
+
+ # convert " to &quot;
+ map { $form->{"${_}_$i"} =~ s/"/&quot;/g } qw(partnumber description unit);
+
+ $column_data{partnumber} = qq|<td><input name="partnumber_$i" size=20 value="$form->{"partnumber_$i"}"></td>|;
+
+ if (($rows = $form->numtextrows($form->{"description_$i"}, 30, 6)) > 1) {
+ $column_data{description} = qq|<td><textarea name="description_$i" rows=$rows cols=30 wrap=soft>$form->{"description_$i"}</textarea></td>|;
+ } else {
+ $column_data{description} = qq|<td><input name="description_$i" size=30 value="$form->{"description_$i"}"></td>|;
+ }
+
+ $column_data{qty} = qq|<td align=right><input name="qty_$i" size=5 value=|.$form->format_amount(\%myconfig, $form->{"qty_$i"}).qq|></td>|;
+ $column_data{ship} = qq|<td align=right><input name="ship_$i" size=5 value=|.$form->format_amount(\%myconfig, $form->{"ship_$i"}).qq|></td>|;
+ $column_data{unit} = qq|<td><input name="unit_$i" size=5 maxsize=5 value="$form->{"unit_$i"}"></td>|;
+ $column_data{sellprice} = qq|<td align=right><input name="sellprice_$i" size=9 value=|.$form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces).qq|></td>|;
+ $column_data{discount} = qq|<td align=right><input name="discount_$i" size=3 value=|.$form->format_amount(\%myconfig, $form->{"discount_$i"}).qq|></td>|;
+ $column_data{linetotal} = qq|<td align=right>|.$form->format_amount(\%myconfig, $linetotal, 2).qq|</td>|;
+ $column_data{bin} = qq|<td>$form->{"bin_$i"}</td>|;
+
+ print qq|
+ <tr valign=top>|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+
+<input type=hidden name="id_$i" value=$form->{"id_$i"}>
+<input type=hidden name="inventory_accno_$i" value=$form->{"inventory_accno_$i"}>
+<input type=hidden name="bin_$i" value="$form->{"bin_$i"}">
+<input type=hidden name="income_accno_$i" value=$form->{"income_accno_$i"}>
+<input type=hidden name="expense_accno_$i" value=$form->{"expense_accno_$i"}>
+<input type=hidden name="listprice_$i" value="$form->{"listprice_$i"}">
+<input type=hidden name="assembly_$i" value="$form->{"assembly_$i"}">
+<input type=hidden name="taxaccounts_$i" value="$form->{"taxaccounts_$i"}">
+
+|;
+
+ # print second row
+ print qq|
+ <tr>
+ <td colspan=$colspan>
+ <table>
+ <tr>
+ <th>$runningnumber</th>
+ <td><input name="runningnumber_$i" size=3 value=$i></td>
+ <td width=20></td>
+ <th>$partsgroup</th>
+ <td><input name="partsgroup_$i" size=10 value="$form->{"partsgroup_$i"}">
+ <th>${$delvar}</th>
+ <td><input name="${delvar}_$i" size=11 title="$myconfig{dateformat}" value="$form->{"${delvar}_$i"}"></td>
+ <th>$projectnumber</th>
+ <td><input name="projectnumber_$i" size=10 value="$form->{"projectnumber_$i"}">
+ <input type=hidden name="oldprojectnumber_$i" value="$form->{"oldprojectnumber_$i"}">
+ <input type=hidden name="project_id_$i" value="$form->{"project_id_$i"}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=$colspan><hr size=1 noshade></td>
+ </tr>
+|;
+
+
+ map { $form->{"${_}_base"} += $linetotal } (split / /, $form->{"taxaccounts_$i"});
+
+ $form->{invsubtotal} += $linetotal;
+ }
+
+ print qq|
+ </table>
+ </td>
+ </tr>
+|;
+
+}
+
+
+sub select_item {
+
+ @column_index = qw(ndx partnumber description onhand sellprice);
+
+ $column_data{ndx} = qq|<th>&nbsp;</th>|;
+ $column_data{partnumber} = qq|<th class=listheading>|.$locale->text('Number').qq|</th>|;
+ $column_data{description} = qq|<th class=listheading>|.$locale->text('Description').qq|</th>|;
+ $column_data{sellprice} = qq|<th class=listheading>|.$locale->text('Price').qq|</th>|;
+ $column_data{onhand} = qq|<th class=listheading>|.$locale->text('Qty').qq|</th>|;
+
+
+ # list items with radio button on a form
+ $form->header;
+
+ $title = $locale->text('Select from one of the items below');
+ $colspan = $#column_index + 1;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop colspan=$colspan>$title</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr class=listheading>|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|</tr>|;
+
+ my $i = 0;
+ foreach $ref (@{ $form->{item_list} }) {
+ $checked = ($i++) ? "" : "checked";
+
+ map { $ref->{$_} =~ s/"/&quot;/g } qw(partnumber description unit);
+
+ $column_data{ndx} = qq|<td><input name=ndx class=radio type=radio value=$i $checked></td>|;
+ $column_data{partnumber} = qq|<td><input name="new_partnumber_$i" type=hidden value="$ref->{partnumber}">$ref->{partnumber}</td>|;
+ $column_data{description} = qq|<td><input name="new_description_$i" type=hidden value="$ref->{description}">$ref->{description}</td>|;
+ $column_data{sellprice} = qq|<td align=right><input name="new_sellprice_$i" type=hidden value=$ref->{sellprice}>|.$form->format_amount(\%myconfig, $ref->{sellprice}, 2, "&nbsp;").qq|</td>|;
+ $column_data{onhand} = qq|<td align=right><input name="new_onhand_$i" type=hidden value=$ref->{onhand}>|.$form->format_amount(\%myconfig, $ref->{onhand}, '', "&nbsp;").qq|</td>|;
+
+ $j++; $j %= 2;
+ print qq|
+<tr class=listrow$j>|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+</tr>
+
+<input name="new_bin_$i" type=hidden value="$ref->{bin}">
+<input name="new_listprice_$i" type=hidden value=$ref->{listprice}>
+<input name="new_inventory_accno_$i" type=hidden value=$ref->{inventory_accno}>
+<input name="new_income_accno_$i" type=hidden value=$ref->{income_accno}>
+<input name="new_expense_accno_$i" type=hidden value=$ref->{expense_accno}>
+<input name="new_unit_$i" type=hidden value="$ref->{unit}">
+<input name="new_weight_$i" type=hidden value="$ref->{weight}">
+<input name="new_assembly_$i" type=hidden value="$ref->{assembly}">
+<input name="new_taxaccounts_$i" type=hidden value="$ref->{taxaccounts}">
+<input name="new_partsgroup_$i" type=hidden value="$ref->{partsgroup}">
+
+<input name="new_id_$i" type=hidden value=$ref->{id}>
+
+|;
+
+ }
+
+ print qq|
+<tr><td colspan=8><hr size=3 noshade></td></tr>
+</table>
+
+<input name=lastndx type=hidden value=$i>
+
+|;
+
+ # delete action variable
+ delete $form->{action};
+ delete $form->{item_list};
+
+ # save all other form variables
+ foreach $key (keys %${form}) {
+ $form->{$key} =~ s/"/&quot;/g;
+ print qq|<input name=$key type=hidden value="$form->{$key}">\n|;
+ }
+
+ print qq|
+<input type=hidden name=nextsub value=item_selected>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub item_selected {
+
+ # replace the last row with the checked row
+ $i = $form->{rowcount};
+ $i = $form->{assembly_rows} if ($form->{item} eq 'assembly');
+
+ # index for new item
+ $j = $form->{ndx};
+
+ # if there was a price entered, override it
+ $sellprice = $form->parse_amount(\%myconfig, $form->{"sellprice_$i"});
+
+ map { $form->{"${_}_$i"} = $form->{"new_${_}_$j"} } qw(id partnumber description sellprice listprice inventory_accno income_accno expense_accno bin unit weight assembly taxaccounts partsgroup);
+
+ ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ if ($sellprice) {
+ $form->{"sellprice_$i"} = $sellprice;
+ } else {
+ # if there is an exchange rate adjust sellprice
+ if (($form->{exchangerate} * 1) != 0) {
+ $form->{"sellprice_$i"} /= $form->{exchangerate};
+ $form->{"sellprice_$i"} = $form->round_amount($form->{"sellprice_$i"}, $decimalplaces);
+ }
+ }
+
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(sellprice weight);
+
+ $form->{sellprice} += ($form->{"sellprice_$i"} * $form->{"qty_$i"});
+ $form->{weight} += ($form->{"weight_$i"} * $form->{"qty_$i"});
+
+ $amount = $form->{"sellprice_$i"} * (1 - $form->{"discount_$i"} / 100) * $form->{"qty_$i"};
+ map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"});
+ map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
+
+ $form->{creditremaining} -= $amount;
+
+ $form->{"runningnumber_$i"} = $i;
+
+ # delete all the new_ variables
+ for $i (1 .. $form->{lastndx}) {
+ map { delete $form->{"new_${_}_$i"} } qw(partnumber description sellprice bin listprice inventory_accno income_accno expense_accno unit assembly taxaccounts id);
+ }
+
+ map { delete $form->{$_} } qw(ndx lastndx nextsub);
+
+ if ($form->{item} eq 'assembly') {
+ map { $form->{"qty_$_"} = $form->parse_amount(\%myconfig, $form->{"qty_$_"}) } (1 .. $i);
+ } else {
+ # format amounts for invoice / order
+ map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}, $decimalplaces) } qw(sellprice listprice);
+ }
+
+ &display_form;
+
+}
+
+
+sub new_item {
+
+ # change callback
+ $form->{old_callback} = $form->escape($form->{callback},1);
+ $form->{callback} = $form->escape("$form->{script}?action=display_form",1);
+
+ # delete action
+ delete $form->{action};
+
+ # save all other form variables in a previous_form variable
+ foreach $key (keys %$form) {
+ # escape ampersands
+ $form->{$key} =~ s/&/%26/g;
+ $previous_form .= qq|$key=$form->{$key}&|;
+ }
+ chop $previous_form;
+ $previous_form = $form->escape($previous_form, 1);
+
+ $i = $form->{rowcount};
+ map { $form->{"${_}_$i"} =~ s/"/&quot;/g } qw(partnumber description);
+
+ $form->header;
+
+ print qq|
+<body>
+
+<h4 class=error>|.$locale->text('Item not on file!').qq|
+
+<p>
+|.$locale->text('What type of item is this?').qq|</h4>
+
+<form method=post action=ic.pl>
+
+<p>
+
+ <input class=radio type=radio name=item value=part checked>&nbsp;|.$locale->text('Part')
+.qq|<br>
+ <input class=radio type=radio name=item value=service>&nbsp;|.$locale->text('Service')
+
+.qq|
+<input type=hidden name=previous_form value="$previous_form">
+<input type=hidden name=partnumber value="$form->{"partnumber_$i"}">
+<input type=hidden name=description value="$form->{"description_$i"}">
+<input type=hidden name=rowcount value=$form->{rowcount}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input type=hidden name=nextsub value=add>
+
+<p>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub display_form {
+
+ &form_header;
+
+ $numrows = ++$form->{rowcount};
+ $subroutine = "display_row";
+
+ if ($form->{item} eq 'part') {
+ $numrows = ++$form->{makemodel_rows};
+ $subroutine = "makemodel_row";
+ }
+ if ($form->{item} eq 'assembly') {
+ $numrows = ++$form->{makemodel_rows};
+ $subroutine = "makemodel_row";
+
+ # create makemodel rows
+ &{ $subroutine }($numrows);
+
+ $numrows = ++$form->{assembly_rows};
+ $subroutine = "assembly_row";
+ }
+ if ($form->{item} eq 'service') {
+ $numrows = 0;
+ }
+
+ # create rows
+ &{ $subroutine }($numrows) if $numrows;
+
+ &form_footer;
+
+}
+
+
+
+sub check_form {
+
+ my @a = ();
+ my $count = 0;
+ my @flds = (qw(id partnumber description qty sellprice unit discount inventory_accno income_accno expense_accno listprice taxaccounts bin assembly weight projectnumber project_id oldprojectnumber runningnumber partsgroup));
+
+ # remove any makes or model rows
+ if ($form->{item} eq 'part') {
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(listprice sellprice lastcost weight rop);
+
+ @flds = (make, model);
+ for my $i (1 .. ($form->{makemodel_rows})) {
+ if (($form->{"make_$i"} ne "") || ($form->{"model_$i"} ne "")) {
+ push @a, {};
+ my $j = $#a;
+
+ map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds;
+ $count++;
+ }
+ }
+
+ $form->redo_rows(\@flds, \@a, $count, $form->{makemodel_rows});
+ $form->{makemodel_rows} = $count;
+
+ } elsif ($form->{item} eq 'assembly') {
+
+ $form->{sellprice} = 0;
+ $form->{weight} = 0;
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(listprice rop);
+
+ @flds = qw(id qty unit bom partnumber description sellprice weight runningnumber partsgroup);
+
+ for my $i (1 .. ($form->{assembly_rows} - 1)) {
+ if ($form->{"qty_$i"}) {
+ push @a, {};
+ my $j = $#a;
+
+ $form->{"qty_$i"} = $form->parse_amount(\%myconfig, $form->{"qty_$i"});
+
+ map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds;
+
+ $form->{sellprice} += ($form->{"qty_$i"} * $form->{"sellprice_$i"});
+ $form->{weight} += ($form->{"qty_$i"} * $form->{"weight_$i"});
+ $count++;
+ }
+ }
+
+ $form->{sellprice} = $form->round_amount($form->{sellprice}, 2);
+
+ $form->redo_rows(\@flds, \@a, $count, $form->{assembly_rows});
+ $form->{assembly_rows} = $count;
+
+ $count = 0;
+ @flds = qw(make model);
+ @a = ();
+
+ for my $i (1 .. ($form->{makemodel_rows})) {
+ if (($form->{"make_$i"} ne "") || ($form->{"model_$i"} ne "")) {
+ push @a, {};
+ my $j = $#a;
+
+ map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds;
+ $count++;
+ }
+ }
+
+ $form->redo_rows(\@flds, \@a, $count, $form->{makemodel_rows});
+ $form->{makemodel_rows} = $count;
+
+ } else {
+
+ # this section applies to invoices and orders
+ # remove any empty numbers
+
+ if ($form->{rowcount}) {
+ for my $i (1 .. $form->{rowcount} - 1) {
+ if ($form->{"partnumber_$i"}) {
+ push @a, {};
+ my $j = $#a;
+
+ map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds;
+ $count++;
+ }
+ }
+
+ $form->redo_rows(\@flds, \@a, $count, $form->{rowcount});
+ $form->{rowcount} = $count;
+
+ $form->{creditremaining} -= &invoicetotal;
+
+ }
+ }
+
+ &display_form;
+
+}
+
+
+sub invoicetotal {
+
+ $form->{oldinvtotal} = 0;
+ # add all parts and deduct paid
+ map { $form->{"${_}_base"} = 0 } split / /, $form->{taxaccounts};
+
+ my ($amount, $sellprice, $discount, $qty);
+
+ for my $i (1 .. $form->{rowcount}) {
+ $sellprice = $form->parse_amount(\%myconfig, $form->{"sellprice_$i"});
+ $discount = $form->parse_amount(\%myconfig, $form->{"discount_$i"});
+ $qty = $form->parse_amount(\%myconfig, $form->{"qty_$i"});
+
+ $amount = $sellprice * (1 - $discount / 100) * $qty;
+ map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"});
+ $form->{oldinvtotal} += $amount;
+ }
+
+ map { $form->{oldinvtotal} += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{taxaccounts} if !$form->{taxincluded};
+
+ $form->{oldtotalpaid} = 0;
+ for $i (1 .. $form->{paidaccounts}) {
+ $form->{oldtotalpaid} += $form->{"paid_$i"};
+ }
+
+ # return total
+ ($form->{oldinvtotal} - $form->{oldtotalpaid});
+
+}
+
+
+sub validate_items {
+
+ # check if items are valid
+ if ($form->{rowcount} == 1) {
+ &update;
+ exit;
+ }
+
+ for $i (1 .. $form->{rowcount} - 1) {
+ $form->isblank("partnumber_$i", $locale->text('Number missing in Row') . " $i");
+ }
+
+}
+
+
+sub order {
+
+ $form->{ordnumber} = $form->{invnumber};
+
+ $form->{id} = '';
+
+ if ($form->{script} eq 'ir.pl') {
+ $form->{title} = $locale->text('Add Purchase Order');
+ $form->{vc} = 'vendor';
+ $form->{type} = 'purchase_order';
+ $buysell = 'sell';
+ }
+ if ($form->{script} eq 'is.pl') {
+ $form->{title} = $locale->text('Add Sales Order');
+ $form->{vc} = 'customer';
+ $form->{type} = 'sales_order';
+ $buysell = 'buy';
+ }
+ $form->{script} = 'oe.pl';
+
+ $form->{shipto} = 1;
+
+ $form->{rowcount}--;
+
+ require "$form->{path}/$form->{script}";
+
+ map { $form->{"select$_"} = "" } ($form->{vc}, currency);
+
+ $currency = $form->{currency};
+
+ &order_links;
+
+ $form->{currency} = $currency;
+ $form->{exchangerate} = "";
+ $form->{forex} = "";
+ $form->{exchangerate} = $exchangerate if ($form->{forex} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{orddate}, $buysell)));
+
+ &prepare_order;
+ &display_form;
+
+}
+
+
+sub e_mail {
+
+
+ if ($myconfig{admin}) {
+ $bcc = qq|
+ <th align=right nowrap=true>|.$locale->text('Bcc').qq|</th>
+ <td><input name=bcc size=30 value="$form->{bcc}"></td>
+|;
+ }
+
+ if ($form->{type} eq 'packing_list') {
+ $form->{email} = $form->{shiptoemail} if $form->{shiptoemail};
+ }
+
+ $name = $form->{$form->{vc}};
+ $name =~ s/--.*//g;
+ $title = $locale->text('E-mail')." $name";
+
+ $form->{oldmedia} = $form->{media};
+ $form->{media} = "email";
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr class=listtop>
+ <th class=listtop>$title</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=right nowrap>|.$locale->text('To').qq|</th>
+ <td><input name=email size=30 value="$form->{email}"></td>
+ <th align=right nowrap>|.$locale->text('Cc').qq|</th>
+ <td><input name=cc size=30 value="$form->{cc}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Subject').qq|</th>
+ <td><input name=subject size=30 value="$form->{subject}"></td>
+ $bcc
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left nowrap>|.$locale->text('Message').qq|</th>
+ </tr>
+ <tr>
+ <td><textarea name=message rows=15 cols=60 wrap=soft>$form->{message}</textarea></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+|;
+
+ &print_options;
+
+ map { delete $form->{$_} } qw(action email cc bcc subject message type sendmode format);
+
+ # save all other variables
+ foreach $key (keys %$form) {
+ $form->{$key} =~ s/"/&quot;/g;
+ print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
+ }
+
+ print qq|
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=nextsub value=send_email>
+
+<br>
+<input name=action class=submit type=submit value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub send_email {
+
+ $old_form = new Form;
+ map { $old_form->{$_} = $form->{$_} } keys %$form;
+ $old_form->{media} = $form->{oldmedia};
+ &print_form($old_form);
+
+}
+
+
+
+sub print_options {
+
+ $form->{sendmode} = "attachment";
+ $form->{copies} = 3 unless $form->{copies};
+
+ $form->{PD}{$form->{type}} = "checked";
+ $form->{DF}{$form->{format}} = "checked";
+ $form->{OP}{$form->{media}} = "checked";
+ $form->{SM}{$form->{sendmode}} = "checked";
+
+ if ($form->{type} =~ /_order/) {
+ $order = qq|
+ <td align=right><input class=radio type=radio name=type value="$`_order" $form->{PD}{"$`_order"}></td><td>|.$locale->text('Order').qq|</td>
+|;
+ } else {
+ $invoice = qq|
+ <td align=right><input class=radio type=radio name=type value=invoice $form->{PD}{invoice}></td><td>|.$locale->text('Invoice').qq|</td>
+ <td align=right><input class=radio type=radio name=type value=packing_list $form->{PD}{packing_list}></td><td>|.$locale->text('Packing List').qq|</td>
+|;
+ }
+
+ if ($form->{media} eq 'email') {
+ $email = qq|
+ <td align=center><input class=radio type=radio name=sendmode value=attachment $form->{SM}{attachment}> |.$locale->text('Attachment')
+ .qq| <input class=radio type=radio name=sendmode value=inline $form->{SM}{inline}> |.$locale->text('In-line').qq|</td>
+|;
+ } else {
+ $screen = qq|
+ <td align=right><input class=radio type=radio name=media value=screen $form->{OP}{screen}></td>
+ <td>|.$locale->text('Screen').qq|</td>
+|;
+ }
+
+ print qq|
+<table width=100%>
+ <tr valign=top>
+ $invoice
+ $order
+ <td align=right><input class=radio type=radio name=format value=html $form->{DF}{html}></td>
+ <td>html</td>
+|;
+
+ if ($latex) {
+ print qq|
+ <td align=right><input class=radio type=radio name=format value=postscript $form->{DF}{postscript}></td>
+ <td>|.$locale->text('Postscript').qq|</td>
+ <td align=right><input class=radio type=radio name=format value=pdf $form->{DF}{pdf}></td>
+ <td>|.$locale->text('PDF').qq|</td>
+|;
+ }
+
+ print qq|
+ $screen
+|;
+
+ if ($screen) {
+ if ($myconfig{printer} && $latex) {
+ print qq|
+ <td align=right><input class=radio type=radio name=media value=printer $form->{OP}{printer}></td>
+ <td>|.$locale->text('Printer')
+ .qq| (|.$locale->text('Copies')
+ .qq| <input name=copies size=2 value=$form->{copies}>)</td>
+|;
+ }
+ }
+
+
+ $form->{groupitems} = "checked" if $form->{groupitems};
+
+ print qq|
+ $email
+ <td align=right><input name=groupitems type=checkbox class=checkbox $form->{groupitems}></td>
+ <td>|.$locale->text('Group Items').qq|</td>
+ </tr>
+</table>
+|;
+
+}
+
+
+sub print {
+
+ # if this goes to the printer pass through
+ if ($form->{media} eq 'printer') {
+ $form->error($locale->text('Select postscript or PDF!')) if ($form->{format} !~ /(postscript|pdf)/);
+
+ $old_form = new Form;
+ map { $old_form->{$_} = $form->{$_} } keys %$form;
+ }
+
+ &print_form($old_form);
+
+}
+
+
+sub print_form {
+ my $old_form = shift;
+
+ $inv = "inv";
+ $due = "due";
+
+ if ($form->{type} eq "invoice") {
+ $form->{label} = $locale->text('Invoice');
+ }
+ if ($form->{type} eq "packing_list") {
+ $form->{label} = $locale->text('Packing List');
+ }
+ if ($form->{type} eq 'sales_order') {
+ $inv = "ord";
+ $due = "req";
+ $form->{label} = $locale->text('Sales Order');
+ }
+ if ($form->{type} eq 'purchase_order') {
+ $inv = "ord";
+ $due = "req";
+ $form->{label} = $locale->text('Purchase Order');
+ }
+
+ $form->isblank("email", $locale->text('E-mail address missing!')) if ($form->{media} eq 'email');
+ $form->isblank("${inv}number", $locale->text($form->{label} .' Number missing!'));
+ $form->isblank("${inv}date", $locale->text($form->{label} .' Date missing!'));
+
+# $locale->text('Invoice Number missing!')
+# $locale->text('Invoice Date missing!')
+# $locale->text('Packing List Number missing!')
+# $locale->text('Packing List Date missing!')
+# $locale->text('Order Number missing!')
+# $locale->text('Order Date missing!')
+
+ &validate_items;
+
+ &{ "$form->{vc}_details" };
+
+ @a = ();
+ map { push @a, ("partnumber_$_", "description_$_") } (1 .. $form->{rowcount});
+ map { push @a, "${_}_description" } split / /, $form->{taxaccounts};
+ $form->format_string(@a);
+
+ # format payment dates
+ map { $form->{"datepaid_$_"} = $locale->date(\%myconfig, $form->{"datepaid_$_"}) } (1 .. $form->{paidaccounts});
+
+ # create the form variables for the invoice, packing list or order
+ if ($form->{type} =~ /order$/) {
+ OE->order_details(\%myconfig, \%$form);
+ } else {
+ IS->invoice_details(\%myconfig, \%$form);
+ }
+
+ $form->{"${inv}date"} = $locale->date(\%myconfig, $form->{"${inv}date"}, 1);
+ $form->{"${due}date"} = $locale->date(\%myconfig, $form->{"${due}date"}, 1);
+
+
+ @a = qw(name addr1 addr2 addr3 addr4);
+
+ $fillshipto = 1;
+ # if there is no shipto fill it in from billto
+ foreach $item (@a) {
+ if ($form->{"shipto$item"}) {
+ $fillshipto = 0;
+ last;
+ }
+ }
+
+ if ($fillshipto) {
+ if ($form->{type} eq 'purchase_order') {
+ $form->{shiptoname} = $myconfig{company};
+ $form->{shiptoaddr1} = $myconfig{address};
+ } else {
+ map { $form->{"shipto$_"} = $form->{$_} } @a;
+ }
+ }
+
+ $form->{notes} =~ s/^\s+//g;
+
+ # some of the stuff could have umlauts so we translate them
+ push @a, qw(shiptoname shiptoaddr1 shiptoaddr2 shiptoaddr3 shiptoaddr4 shippingpoint company address signature notes);
+
+ push @a, ("${inv}date", "${due}date");
+
+ $form->format_string(@a);
+
+
+ $form->{templates} = "$myconfig{templates}";
+ $form->{IN} = "$form->{type}.html";
+
+ if ($form->{format} eq 'postscript') {
+ $form->{postscript} = 1;
+ $form->{IN} =~ s/html$/tex/;
+ }
+ if ($form->{format} eq 'pdf') {
+ $form->{pdf} = 1;
+ $form->{IN} =~ s/html$/tex/;
+ }
+
+ $form->format_string(email, shiptoemail, cc, bcc) if $form->{format} =~ /(pdf|postscript)/;
+
+ if ($form->{media} eq 'printer') {
+ $form->{OUT} = "| $myconfig{printer}";
+ }
+
+ if ($form->{media} eq 'email') {
+ $form->{subject} = qq|$form->{label} $form->{"${inv}number"}| unless $form->{subject};
+
+ $form->{OUT} = "$sendmail";
+ }
+
+
+ $form->parse_template(\%myconfig, $userspath);
+
+ $form->{callback} = "";
+
+ # if we got back here restore the previous form
+ if ($form->{media} =~ /(printer|email)/) {
+ if ($old_form) {
+ # restore and display form
+ map { $form->{$_} = $old_form->{$_} } keys %$old_form;
+ $form->{rowcount}--;
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(exchangerate creditlimit creditremaining);
+
+ for $i (1 .. $form->{paidaccounts}) {
+ map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(paid exchangerate);
+ }
+
+ &display_form;
+ exit;
+ }
+
+ $msg = ($form->{media} eq 'printer') ? $locale->text('sent to printer') : $locale->text('emailed to')." $form->{email}";
+ $form->redirect(qq|$form->{label} $form->{"${inv}number"} $msg|);
+ }
+
+}
+
+
+sub customer_details {
+
+ IS->customer_details(\%myconfig, \%$form);
+
+}
+
+
+sub vendor_details {
+
+ IR->vendor_details(\%myconfig, \%$form);
+
+}
+
+
+sub post_as_new {
+
+ $form->{postasnew} = 1;
+ &post;
+
+}
+
+
+sub ship_to {
+
+ $title = $form->{title};
+ $form->{title} = $locale->text('Ship to');
+
+ $form->{rowcount}--;
+
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(exchangerate creditlimit creditremaining);
+
+ # get details for name
+ &{ "$form->{vc}_details" };
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <td>
+ <table>
+ <tr class=listheading>
+ <th class=listheading colspan=2 width=50%>|.$locale->text('To').qq|</th>
+ <th class=listheading width=50%>|.$locale->text('Ship to').qq|</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Number').qq|</th>
+ <td>$form->{"$form->{vc}number"}</td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Name').qq|</th>
+ <td>$form->{name}</td>
+ <td><input name=shiptoname size=35 maxsize=35 value="$form->{shiptoname}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Address').qq|</th>
+ <td>$form->{addr1}</td>
+ <td><input name=shiptoaddr1 size=35 maxsize=35 value="$form->{shiptoaddr1}"></td>
+ </tr>
+ <tr>
+ <th></th>
+ <td>$form->{addr2}</td>
+ <td><input name=shiptoaddr2 size=35 maxsize=35 value="$form->{shiptoaddr2}"></td>
+ </tr>
+ <tr>
+ <th></th>
+ <td>$form->{addr3}</td>
+ <td><input name=shiptoaddr3 size=35 maxsize=35 value="$form->{shiptoaddr3}"></td>
+ </tr>
+ <tr>
+ <th></th>
+ <td>$form->{addr4}</td>
+ <td><input name=shiptoaddr4 size=35 maxsize=35 value="$form->{shiptoaddr4}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Contact').qq|</th>
+ <td>$form->{contact}</td>
+ <td><input name=shiptocontact size=35 maxsize=35 value="$form->{shiptocontact}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Phone').qq|</th>
+ <td>$form->{"$form->{vc}phone"}</td>
+ <td><input name=shiptophone size=20 maxsize=20 value="$form->{shiptophone}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Fax').qq|</th>
+ <td>$form->{"$form->{vc}fax"}</td>
+ <td><input name=shiptofax size=20 maxsize=20 value="$form->{shiptofax}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('E-mail').qq|</th>
+ <td>$form->{email}</td>
+ <td><input name=shiptoemail size=35 value="$form->{shiptoemail}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+|;
+
+ # delete shipto
+ map { delete $form->{$_} } qw(shiptoname shiptoaddr1 shiptoaddr2 shiptoaddr3 shiptoaddr4 shiptocontact shiptophone shiptofax shiptoemail);
+ $form->{title} = $title;
+
+ foreach $key (keys %$form) {
+ $form->{$key} =~ s/"/&quot;/g;
+ print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
+ }
+
+ print qq|
+
+<input type=hidden name=nextsub value=display_form>
+
+<hr size=3 noshade>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
diff --git a/sql-ledger/bin/mozilla/ir.pl b/sql-ledger/bin/mozilla/ir.pl
new file mode 100644
index 0000000..ec7d18c
--- /dev/null
+++ b/sql-ledger/bin/mozilla/ir.pl
@@ -0,0 +1,653 @@
+#=====================================================================
+# SQL-Ledger, Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Inventory received module
+#
+#======================================================================
+
+
+use SL::IR;
+use SL::PE;
+
+require "$form->{path}/io.pl";
+require "$form->{path}/arap.pl";
+
+1;
+# end of main
+
+
+
+sub add {
+
+ $form->{title} = $locale->text('Add Vendor Invoice');
+
+ &invoice_links;
+ &prepare_invoice;
+ &display_form;
+
+}
+
+
+sub edit {
+
+ $form->{title} = $locale->text('Edit Vendor Invoice');
+
+ &invoice_links;
+ &prepare_invoice;
+ &display_form;
+
+}
+
+
+sub invoice_links {
+
+ # create links
+ $form->create_links("AP", \%myconfig, "vendor");
+
+ IR->get_vendor(\%myconfig, \%$form);
+ IR->retrieve_invoice(\%myconfig, \%$form);
+
+ # currencies
+ @curr = split /:/, $form->{currencies};
+ chomp $curr[0];
+ $form->{defaultcurrency} = $curr[0];
+
+ map { $form->{selectcurrency} .= "<option>$_\n" } @curr;
+
+ $form->{oldvendor} = "$form->{vendor}--$form->{vendor_id}";
+
+ # vendors
+ if (@{ $form->{all_vendor} }) {
+ $form->{vendor} = "$form->{vendor}--$form->{vendor_id}";
+ map { $form->{selectvendor} .= "<option>$_->{name}--$_->{id}\n" } (@{ $form->{all_vendor} });
+ }
+
+
+ # forex
+ $form->{forex} = $form->{exchangerate};
+ $exchangerate = ($form->{exchangerate}) ? $form->{exchangerate} : 1;
+
+ foreach $key (keys %{ $form->{AP_links} }) {
+
+ foreach $ref (@{ $form->{AP_links}{$key} }) {
+ $form->{"select$key"} .= "<option>$ref->{accno}--$ref->{description}\n";
+ }
+
+ if ($key eq "AP_paid") {
+ for $i (1 .. scalar @{ $form->{acc_trans}{$key} }) {
+ $form->{"AP_paid_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{accno}--$form->{acc_trans}{$key}->[$i-1]->{description}";
+ # reverse paid
+ $form->{"paid_$i"} = $form->{acc_trans}{$key}->[$i-1]->{amount};
+ $form->{"datepaid_$i"} = $form->{acc_trans}{$key}->[$i-1]->{transdate};
+ $form->{"forex_$i"} = $form->{"exchangerate_$i"} = $form->{acc_trans}{$key}->[$i-1]->{exchangerate};
+ $form->{"source_$i"} = $form->{acc_trans}{$key}->[$i-1]->{source};
+ $form->{paidaccounts} = $i;
+ }
+ } else {
+ $form->{$key} = "$form->{acc_trans}{$key}->[0]->{accno}--$form->{acc_trans}{$key}->[0]->{description}";
+ }
+ }
+
+ $form->{paidaccounts} = 1 unless (exists $form->{paidaccounts});
+
+ $form->{AP} = $form->{AP_1} unless $form->{id};
+
+ $form->{locked} = ($form->datetonum($form->{invdate}, \%myconfig) <= $form->datetonum($form->{closedto}, \%myconfig));
+
+}
+
+
+
+sub prepare_invoice {
+
+ if ($form->{id}) {
+
+ map { $form->{$_} =~ s/"/&quot;/g } qw(invnumber ordnumber);
+
+ foreach $ref (@{ $form->{invoice_details} }) {
+ $i++;
+ map { $form->{"${_}_$i"} = $ref->{$_} } keys %{ $ref };
+
+ ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ $form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+
+ $form->{rowcount} = $i;
+ }
+ }
+
+}
+
+
+
+sub form_header {
+
+ # set option selected
+ foreach $item (qw(AP vendor currency)) {
+ $form->{"select$item"} =~ s/ selected//;
+ $form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
+ }
+
+ $form->{exchangerate} = $form->format_amount(\%myconfig, $form->{exchangerate});
+
+ $exchangerate = "";
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ if ($form->{forex}) {
+ $exchangerate .= qq|
+ <th align=right nowrap>|.$locale->text('Exchangerate').qq|</th>
+ <td>$form->{exchangerate}<input type=hidden name=exchangerate value=$form->{exchangerate}></td>
+|;
+ } else {
+ $exchangerate .= qq|
+ <th align=right nowrap>|.$locale->text('Exchangerate').qq|</th>
+ <td><input name=exchangerate size=10 value=$form->{exchangerate}></td>
+|;
+ }
+ }
+ $exchangerate .= qq|
+<input type=hidden name=forex value=$form->{forex}>
+|;
+
+ $vendor = ($form->{selectvendor}) ? qq|<select name=vendor>$form->{selectvendor}</select>\n<input type=hidden name="selectvendor" value="$form->{selectvendor}">| : qq|<input name=vendor value="$form->{vendor}" size=35>|;
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=id value=$form->{id}>
+<input type=hidden name=title value="$form->{title}">
+<input type=hidden name=vc value="vendor">
+
+<input type=hidden name=closedto value=$form->{closedto}>
+<input type=hidden name=locked value=$form->{locked}>
+
+
+<table width=100%>
+ <tr class=listtop>
+ <th>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Record in').qq|</th>
+ <td colspan=3><select name=AP>$form->{selectAP}</select></td>
+ <input type=hidden name=selectAP value="$form->{selectAP}">
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Vendor').qq|</th>
+ <td colspan=3>$vendor</td>
+
+ <input type=hidden name=vendor_id value=$form->{vendor_id}>
+ <input type=hidden name=oldvendor value="$form->{oldvendor}">
+
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Currency').qq|</th>
+ <td><select name=currency>$form->{selectcurrency}</select></td>
+ $exchangerate
+ </tr>
+ </table>
+ </td>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Invoice Number').qq|</th>
+ <td><input name=invnumber size=11 value="$form->{invnumber}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Invoice Date').qq|</th>
+ <td><input name=invdate size=11 title="$myconfig{dateformat}" value=$form->{invdate}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Due Date').qq|</th>
+ <td><input name=duedate size=11 title="$myconfig{dateformat}" value=$form->{duedate}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Order Number').qq|</th>
+ <td><input name=ordnumber size=11 value="$form->{ordnumber}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+<input type=hidden name=selectcurrency value="$form->{selectcurrency}">
+<input type=hidden name=defaultcurrency value=$form->{defaultcurrency}>
+<input type=hidden name=fxgain_accno value=$form->{fxgain_accno}>
+<input type=hidden name=fxloss_accno value=$form->{fxloss_accno}>
+
+<input type=hidden name=taxpart value="$form->{taxpart}">
+<input type=hidden name=taxservice value="$form->{taxservice}">
+
+<input type=hidden name=taxaccounts value="$form->{taxaccounts}">
+|;
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ print qq|
+<input type=hidden name="${item}_rate" value=$form->{"${item}_rate"}>
+<input type=hidden name="${item}_description" value="$form->{"${item}_description"}">
+|;
+ }
+
+}
+
+
+
+sub form_footer {
+
+ $form->{invtotal} = $form->{invsubtotal};
+
+ if (($rows = $form->numtextrows($form->{notes}, 50, 8)) < 2) {
+ $rows = 2;
+ }
+ $notes = qq|<textarea name=notes rows=$rows cols=50 wrap=soft>$form->{notes}</textarea>|;
+
+
+ $form->{taxincluded} = ($form->{taxincluded}) ? "checked" : "";
+ if ($form->{taxaccounts}) {
+ $taxincluded = qq|
+ <input name=taxincluded class=checkbox type=checkbox value=1 $form->{taxincluded}> <b>|.$locale->text('Tax Included').qq|</b><br><br>
+|;
+ }
+
+ if (!$form->{taxincluded}) {
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ if ($form->{"${item}_base"}) {
+ $form->{invtotal} += $form->{"${item}_total"} = $form->round_amount($form->{"${item}_base"} * $form->{"${item}_rate"}, 2);
+ $form->{"${item}_total"} = $form->format_amount(\%myconfig, $form->{"${item}_total"}, 2);
+
+ $tax .= qq|
+ <tr>
+ <th align=right>$form->{"${item}_description"}</th>
+ <td align=right>$form->{"${item}_total"}</td>
+ </tr>
+|;
+ }
+ }
+
+ $form->{invsubtotal} = $form->format_amount(\%myconfig, $form->{invsubtotal}, 2, 0);
+
+ $subtotal = qq|
+ <tr>
+ <th align=right>|.$locale->text('Subtotal').qq|</th>
+ <td align=right>$form->{invsubtotal}</td>
+ </tr>
+|;
+
+ }
+
+
+ $form->{invtotal} = $form->format_amount(\%myconfig, $form->{invtotal}, 2, 0);
+
+ print qq|
+ <tr>
+ <td colspan=$colspan>
+ <table cellspacing="0">
+ <tr valign=bottom>
+ <td>
+ <table>
+ <tr>
+ <th align=left>|.$locale->text('Notes').qq|</th>
+ </tr>
+ <tr>
+ <td>$notes</td>
+ </tr>
+ </table>
+ </td>
+ <td colspan=2 align=right width=100%>
+ $taxincluded
+ <table width=100%>
+ $subtotal
+ $tax
+ <tr>
+ <th align=right>|.$locale->text('Total').qq|</th>
+ <td align=right>$form->{invtotal}</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=$colspan>
+ <table width=100%>
+ <tr>
+ <th colspan=5 class=listheading>|.$locale->text('Payments').qq|</th>
+ </tr>
+|;
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ @column_index = qw(datepaid source paid AP_paid);
+ } else {
+ @column_index = qw(datepaid source paid exchangerate AP_paid);
+ }
+
+ $column_data{datepaid} = "<th>".$locale->text('Date')."</th>";
+ $column_data{paid} = "<th>".$locale->text('Amount')."</th>";
+ $column_data{exchangerate} = "<th>".$locale->text('Exch')."</th>";
+ $column_data{AP_paid} = "<th>".$locale->text('Account')."</th>";
+ $column_data{source} = "<th>".$locale->text('Source')."</th>";
+
+ print qq|
+ <tr>
+|;
+ map { print "$column_data{$_}\n" } @column_index;
+ print qq|
+ </tr>
+|;
+
+ $form->{paidaccounts}++ if ($form->{"paid_$form->{paidaccounts}"});
+ for $i (1 .. $form->{paidaccounts}) {
+
+ print qq|
+ <tr>
+|;
+
+ $form->{"selectAP_paid_$i"} = $form->{selectAP_paid};
+ $form->{"selectAP_paid_$i"} =~ s/option>\Q$form->{"AP_paid_$i"}\E/option selected>$form->{"AP_paid_$i"}/;
+
+ # format amounts
+ $form->{"paid_$i"} = $form->format_amount(\%myconfig, $form->{"paid_$i"}, 2);
+ $form->{"exchangerate_$i"} = $form->format_amount(\%myconfig, $form->{"exchangerate_$i"});
+
+ $exchangerate = qq|&nbsp;|;
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ if ($form->{"forex_$i"}) {
+ $exchangerate = qq|<input type=hidden name="exchangerate_$i" value=$form->{"exchangerate_$i"}>$form->{"exchangerate_$i"}|;
+ } else {
+ $exchangerate = qq|<input name="exchangerate_$i" size=10 value=$form->{"exchangerate_$i"}>|;
+ }
+ }
+ $exchangerate .= qq|
+<input type=hidden name="forex_$i" value=$form->{"forex_$i"}>
+|;
+
+ $column_data{"paid_$i"} = qq|<td align=center><input name="paid_$i" size=11 value=$form->{"paid_$i"}></td>|;
+ $column_data{"exchangerate_$i"} = qq|<td align=center>$exchangerate</td>|;
+ $column_data{"AP_paid_$i"} = qq|<td align=center><select name="AP_paid_$i">$form->{"selectAP_paid_$i"}</select></td>|;
+ $column_data{"datepaid_$i"} = qq|<td align=center><input name="datepaid_$i" size=11 title="$myconfig{dateformat}" value=$form->{"datepaid_$i"}></td>|;
+ $column_data{"source_$i"} = qq|<td align=center><input name="source_$i" size=11 value=$form->{"source_$i"}></td>|;
+
+ map { print qq|$column_data{"${_}_$i"}\n| } @column_index;
+
+ print qq|
+ </tr>
+|;
+ }
+
+ print qq|
+ <input type=hidden name=paidaccounts value=$form->{paidaccounts}>
+ <input type=hidden name=selectAP_paid value="$form->{selectAP_paid}">
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+<br>
+|;
+
+ $invdate = $form->datetonum($form->{invdate}, \%myconfig);
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+
+ if ($form->{id}) {
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+|;
+
+ if (!$form->{revtrans}) {
+ if (!$form->{locked}) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Delete').qq|">
+|;
+ }
+ }
+
+ if ($invdate > $closedto) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Post as new').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Order').qq|">
+|;
+ }
+
+ } else {
+ if ($invdate > $closedto) {
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">|;
+ }
+ }
+
+print qq|
+
+<input type=hidden name=rowcount value=$form->{rowcount}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub update {
+
+ $form->{exchangerate} = $form->parse_amount(\%myconfig, $form->{exchangerate});
+
+ &check_name(vendor);
+
+ &check_project;
+
+ $form->{exchangerate} = $exchangerate if ($form->{forex} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, 'sell')));
+
+
+ for $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"}) {
+ map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(paid exchangerate);
+
+ $form->{"exchangerate_$i"} = $exchangerate if ($form->{"forex_$i"} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'sell')));
+ }
+ }
+
+ $i = $form->{rowcount};
+ $exchangerate = ($form->{exchangerate}) ? $form->{exchangerate} : 1;
+
+ if (($form->{"partnumber_$i"} eq "") && ($form->{"description_$i"} eq "") && ($form->{"partsgroup_$i"} eq "")) {
+
+ &check_form;
+
+ } else {
+
+ IR->retrieve_item(\%myconfig, \%$form);
+
+ my $rows = scalar @{ $form->{item_list} };
+
+ if ($rows) {
+ $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
+
+ if ($rows > 1) {
+
+ &select_item;
+ exit;
+
+ } else {
+ # override sellprice if there is one entered
+ $sellprice = $form->parse_amount(\%myconfig, $form->{"sellprice_$i"});
+
+ map { $form->{item_list}[$i]{$_} =~ s/"/&quot;/g } qw(partnumber description unit);
+
+ map { $form->{"${_}_$i"} = $form->{item_list}[0]{$_} } keys %{ $form->{item_list}[0] };
+
+ $s = ($sellprice) ? $sellprice : $form->{"sellprice_$i"};
+
+ ($dec) = ($s =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ if ($sellprice) {
+ $form->{"sellprice_$i"} = $sellprice;
+ } else {
+ # if there is an exchange rate adjust sellprice
+ $form->{"sellprice_$i"} /= $exchangerate;
+ }
+
+ $form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+ }
+
+ &display_form;
+
+ } else {
+ # ok, so this is a new part
+ # ask if it is a part or service item
+
+ if ($form->{"partsgroup_$i"} && ($form->{"partsnumber_$i"} eq "") && ($form->{"description_$i"} eq "")) {
+ $form->{rowcount}--;
+ $form->{"discount_$i"} = "";
+ &display_form;
+ } else {
+
+ $form->{"id_$i"} = 0;
+ $form->{"unit_$i"} = $locale->text('ea');
+
+ &new_item;
+
+ }
+ }
+ }
+}
+
+
+
+sub post {
+
+ $form->isblank("invnumber", $locale->text('Invoice Number missing!'));
+ $form->isblank("invdate", $locale->text('Invoice Date missing!'));
+ $form->isblank("vendor", $locale->text('Vendor missing!'));
+
+ # if the vendor changed get new values
+ if (&check_name(vendor)) {
+ &update;
+ exit;
+ }
+
+ &validate_items;
+
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+ $invdate = $form->datetonum($form->{invdate}, \%myconfig);
+
+ $form->error($locale->text('Cannot post invoice for a closed period!')) if ($invdate <= $closedto);
+
+ $form->isblank("exchangerate", $locale->text('Exchangerate missing!')) if ($form->{currency} ne $form->{defaultcurrency});
+
+ for $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"}) {
+ $datepaid = $form->datetonum($form->{"datepaid_$i"}, \%myconfig);
+
+ $form->isblank("datepaid_$i", $locale->text('Payment date missing!'));
+
+ $form->error($locale->text('Cannot post payment for a closed period!')) if ($datepaid <= $closedto);
+
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ $form->{"exchangerate_$i"} = $form->{exchangerate} if ($invdate == $datepaid);
+ $form->isblank("exchangerate_$i", $locale->text('Exchangerate for payment missing!'));
+ }
+ }
+ }
+
+
+ ($form->{AP}) = split /--/, $form->{AP};
+ ($form->{AP_paid}) = split /--/, $form->{AP_paid};
+
+ $form->{id} = 0 if $form->{postasnew};
+
+ $form->redirect($locale->text('Invoice posted!')) if (IR->post_invoice(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot post invoice!'));
+
+}
+
+
+
+sub delete {
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+|;
+
+ # delete action variable
+ delete $form->{action};
+
+ foreach $key (keys %$form) {
+ $form->{$key} =~ s/"/&quot;/g;
+ print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
+ }
+
+ print qq|
+<h2 class=confirm>|.$locale->text('Confirm!').qq|</h2>
+
+<h4>|.$locale->text('Are you sure you want to delete Invoice Number').qq| $form->{invnumber}</h4>
+<p>
+<input name=action class=submit type=submit value="|.$locale->text('Yes').qq|">
+</form>
+|;
+
+
+}
+
+
+
+sub yes {
+
+ $form->redirect($locale->text('Invoice deleted!')) if (IR->delete_invoice(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot delete invoice!'));
+
+}
+
+
diff --git a/sql-ledger/bin/mozilla/is.pl b/sql-ledger/bin/mozilla/is.pl
new file mode 100644
index 0000000..cca5813
--- /dev/null
+++ b/sql-ledger/bin/mozilla/is.pl
@@ -0,0 +1,739 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Inventory invoicing module
+#
+#======================================================================
+
+
+use SL::IS;
+use SL::PE;
+
+require "$form->{path}/io.pl";
+require "$form->{path}/arap.pl";
+
+
+1;
+# end of main
+
+
+
+sub add {
+
+ $form->{title} = $locale->text('Add Sales Invoice');
+
+ &invoice_links;
+ &prepare_invoice;
+ &display_form;
+
+}
+
+
+sub edit {
+
+ $form->{title} = $locale->text('Edit Sales Invoice');
+
+ &invoice_links;
+ &prepare_invoice;
+ &display_form;
+
+}
+
+
+sub invoice_links {
+
+ # create links
+ $form->create_links("AR", \%myconfig, "customer");
+
+ IS->get_customer(\%myconfig, \%$form);
+ IS->retrieve_invoice(\%myconfig, \%$form);
+
+ # currencies
+ @curr = split /:/, $form->{currencies};
+ chomp $curr[0];
+ $form->{defaultcurrency} = $curr[0];
+
+ map { $form->{selectcurrency} .= "<option>$_\n" } @curr;
+
+ $form->{oldcustomer} = "$form->{customer}--$form->{customer_id}";
+
+ if (@{ $form->{all_customer} }) {
+ $form->{customer} = qq|$form->{customer}--$form->{customer_id}|;
+ map { $form->{selectcustomer} .= "<option>$_->{name}--$_->{id}\n" } (@{ $form->{all_customer} });
+ }
+
+ # forex
+ $form->{forex} = $form->{exchangerate};
+ $exchangerate = ($form->{exchangerate}) ? $form->{exchangerate} : 1;
+
+ foreach $key (keys %{ $form->{AR_links} }) {
+
+ foreach $ref (@{ $form->{AR_links}{$key} }) {
+ $form->{"select$key"} .= "<option>$ref->{accno}--$ref->{description}\n";
+ }
+
+ if ($key eq "AR_paid") {
+ for $i (1 .. scalar @{ $form->{acc_trans}{$key} }) {
+ $form->{"AR_paid_$i"} = "$form->{acc_trans}{$key}->[$i-1]->{accno}--$form->{acc_trans}{$key}->[$i-1]->{description}";
+ # reverse paid
+ $form->{"paid_$i"} = $form->{acc_trans}{$key}->[$i-1]->{amount} * -1;
+ $form->{"datepaid_$i"} = $form->{acc_trans}{$key}->[$i-1]->{transdate};
+ $form->{"forex_$i"} = $form->{"exchangerate_$i"} = $form->{acc_trans}{$key}->[$i-1]->{exchangerate};
+ $form->{"source_$i"} = $form->{acc_trans}{$key}->[$i-1]->{source};
+ $form->{paidaccounts} = $i;
+ }
+ } else {
+ $form->{$key} = "$form->{acc_trans}{$key}->[0]->{accno}--$form->{acc_trans}{$key}->[0]->{description}";
+ }
+ }
+
+ $form->{paidaccounts} = 1 unless (exists $form->{paidaccounts});
+
+ $form->{AR} = $form->{AR_1} unless $form->{id};
+
+ $form->{locked} = ($form->datetonum($form->{invdate}, \%myconfig) <= $form->datetonum($form->{closedto}, \%myconfig));
+
+}
+
+
+sub prepare_invoice {
+
+ $form->{type} = "invoice";
+ $form->{format} = "html";
+ $form->{media} = "screen";
+
+ if ($form->{id}) {
+
+ map { $form->{$_} =~ s/"/&quot;/g } qw(invnumber ordnumber shippingpoint notes);
+
+ foreach $ref (@{ $form->{invoice_details} } ) {
+ $i++;
+ map { $form->{"${_}_$i"} = $ref->{$_} } keys %{ $ref };
+ $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{"discount_$i"} * 100);
+
+ ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ $form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+
+ map { $form->{"${_}_$i"} =~ s/"/&quot;/g } qw(partnumber description unit);
+ $form->{rowcount} = $i;
+ }
+ }
+
+}
+
+
+
+sub form_header {
+
+
+ # set option selected
+ foreach $item (qw(AR customer currency)) {
+ $form->{"select$item"} =~ s/ selected//;
+ $form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
+ }
+
+ $form->{exchangerate} = $form->format_amount(\%myconfig, $form->{exchangerate});
+
+ $form->{creditlimit} = $form->format_amount(\%myconfig, $form->{creditlimit}, 0, "0");
+ $form->{creditremaining} = $form->format_amount(\%myconfig, $form->{creditremaining}, 0, "0");
+
+
+ $exchangerate = "";
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ if ($form->{forex}) {
+ $exchangerate .= qq|<th align=right>|.$locale->text('Exchangerate').qq|</th><td>$form->{exchangerate}<input type=hidden name=exchangerate value=$form->{exchangerate}></td>|;
+ } else {
+ $exchangerate .= qq|<th align=right>|.$locale->text('Exchangerate').qq|</th><td><input name=exchangerate size=10 value=$form->{exchangerate}></td>|;
+ }
+ }
+ $exchangerate .= qq|
+<input type=hidden name=forex value=$form->{forex}>
+|;
+
+ $customer = ($form->{selectcustomer}) ? qq|<select name=customer>$form->{selectcustomer}</select>\n<input type=hidden name="selectcustomer" value="$form->{selectcustomer}">| : qq|<input name=customer value="$form->{customer}" size=35>|;
+
+ $n = ($form->{creditremaining} =~ /-/) ? "0" : "1";
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=id value=$form->{id}>
+
+<input type=hidden name=type value=$form->{type}>
+<input type=hidden name=media value=$form->{media}>
+<input type=hidden name=format value=$form->{format}>
+
+<input type=hidden name=title value="$form->{title}">
+<input type=hidden name=vc value="customer">
+<input type=hidden name=employee value="$form->{employee}">
+
+<input type=hidden name=discount value=$form->{discount}>
+<input type=hidden name=creditlimit value=$form->{creditlimit}>
+<input type=hidden name=creditremaining value=$form->{creditremaining}>
+
+<input type=hidden name=closedto value=$form->{closedto}>
+<input type=hidden name=locked value=$form->{locked}>
+
+<table width=100%>
+ <tr class=listtop>
+ <th class=listtop>$form->{title}</font></th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Record in').qq|</th>
+ <td colspan=3><select name=AR>$form->{selectAR}</select></td>
+ <input type=hidden name=selectAR value="$form->{selectAR}">
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Customer').qq|</th>
+ <td colspan=3>$customer</td>
+ <input type=hidden name=customer_id value=$form->{customer_id}>
+ <input type=hidden name=oldcustomer value="$form->{oldcustomer}">
+ </tr>
+ <tr>
+ <td></td>
+ <td colspan=3>
+ <table width=100%>
+ <tr>
+ <th align=left nowrap>|.$locale->text('Credit Limit').qq|</th>
+ <td>$form->{creditlimit}</td>
+ <th align=left nowrap>|.$locale->text('Remaining').qq|</th>
+ <td class="plus$n">$form->{creditremaining}</font></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Currency').qq|</th>
+ <td><select name=currency>$form->{selectcurrency}</select></td>
+ <input type=hidden name=selectcurrency value="$form->{selectcurrency}">
+ <input type=hidden name=defaultcurrency value=$form->{defaultcurrency}>
+ <input type=hidden name=fxgain_accno value=$form->{fxgain_accno}>
+ <input type=hidden name=fxloss_accno value=$form->{fxloss_accno}>
+ $exchangerate
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Ship via').qq|</th>
+ <td colspan=3><input name=shippingpoint size=35 value="$form->{shippingpoint}"></td>
+ </tr>
+ </table>
+ </td>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Invoice Number').qq|</th>
+ <td><input name=invnumber size=11 value="$form->{invnumber}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Invoice Date').qq|</th>
+ <td><input name=invdate size=11 title="$myconfig{dateformat}" value=$form->{invdate}></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Due Date').qq|</th>
+ <td><input name=duedate size=11 title="$myconfig{dateformat}" value=$form->{duedate}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Order Number').qq|</th>
+ <td><input name=ordnumber size=11 value="$form->{ordnumber}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ </td>
+ </tr>
+<!-- shipto are in hidden variables -->
+
+<input type=hidden name=shiptoname value="$form->{shiptoname}">
+<input type=hidden name=shiptoaddr1 value="$form->{shiptoaddr1}">
+<input type=hidden name=shiptoaddr2 value="$form->{shiptoaddr2}">
+<input type=hidden name=shiptoaddr3 value="$form->{shiptoaddr3}">
+<input type=hidden name=shiptoaddr4 value="$form->{shiptoaddr4}">
+<input type=hidden name=shiptocontact value="$form->{shiptocontact}">
+<input type=hidden name=shiptophone value="$form->{shiptophone}">
+<input type=hidden name=shiptofax value="$form->{shiptofax}">
+<input type=hidden name=shiptoemail value="$form->{shiptoemail}">
+
+<!-- email variables -->
+<input type=hidden name=message value="$form->{message}">
+<input type=hidden name=email value="$form->{email}">
+<input type=hidden name=subject value="$form->{subject}">
+<input type=hidden name=cc value="$form->{cc}">
+<input type=hidden name=bcc value="$form->{bcc}">
+
+<input type=hidden name=taxaccounts value="$form->{taxaccounts}">
+|;
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ print qq|
+<input type=hidden name="${item}_rate" value="$form->{"${item}_rate"}">
+<input type=hidden name="${item}_description" value="$form->{"${item}_description"}">
+<input type=hidden name="${item}_taxnumber" value="$form->{"${item}_taxnumber"}">
+|;
+ }
+
+}
+
+
+
+sub form_footer {
+
+ $form->{invtotal} = $form->{invsubtotal};
+
+ if (($rows = $form->numtextrows($form->{notes}, 50, 8)) < 2) {
+ $rows = 2;
+ }
+ $notes = qq|<textarea name=notes rows=$rows cols=50 wrap=soft>$form->{notes}</textarea>|;
+
+
+ $form->{taxincluded} = ($form->{taxincluded}) ? "checked" : "";
+
+ if ($form->{taxaccounts}) {
+ $taxincluded = qq|
+ <input name=taxincluded class=checkbox type=checkbox value=1 $form->{taxincluded}> <b>|.$locale->text('Tax Included').qq|</b><br><br>
+|;
+ }
+
+ if (!$form->{taxincluded}) {
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ if ($form->{"${item}_base"}) {
+ $form->{"${item}_total"} = $form->round_amount($form->{"${item}_base"} * $form->{"${item}_rate"}, 2);
+ $form->{invtotal} += $form->{"${item}_total"};
+ $form->{"${item}_total"} = $form->format_amount(\%myconfig, $form->{"${item}_total"}, 2);
+
+ $tax .= qq|
+ <tr>
+ <th align=right>$form->{"${item}_description"}</th>
+ <td align=right>$form->{"${item}_total"}</td>
+ </tr>
+|;
+ }
+ }
+
+ $form->{invsubtotal} = $form->format_amount(\%myconfig, $form->{invsubtotal}, 2, 0);
+
+ $subtotal = qq|
+ <tr>
+ <th align=right>|.$locale->text('Subtotal').qq|</th>
+ <td align=right>$form->{invsubtotal}</td>
+ </tr>
+|;
+
+ }
+
+ $form->{oldinvtotal} = $form->{invtotal};
+ $form->{invtotal} = $form->format_amount(\%myconfig, $form->{invtotal}, 2, 0);
+
+ print qq|
+ <tr>
+ <td>
+ <table width=100%>
+ <tr valign=bottom>
+ <td>
+ <table>
+ <tr>
+ <th align=left>|.$locale->text('Notes').qq|</th>
+ </tr>
+ <tr>
+ <td>$notes</td>
+ </tr>
+ </table>
+ </td>
+ <td align=right width=100%>
+ $taxincluded
+ <table width=100%>
+ $subtotal
+ $tax
+ <tr>
+ <th align=right>|.$locale->text('Total').qq|</th>
+ <td align=right>$form->{invtotal}</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+ <th class=listheading colspan=5>|.$locale->text('Payments')
+ .qq|</font></th>
+ </tr>
+|;
+
+ if ($form->{currency} eq $form->{defaultcurrency}) {
+ @column_index = qw(datepaid source paid AR_paid);
+ } else {
+ @column_index = qw(datepaid source paid exchangerate AR_paid);
+ }
+
+ $column_data{datepaid} = "<th>".$locale->text('Date')."</th>";
+ $column_data{paid} = "<th>".$locale->text('Amount')."</th>";
+ $column_data{exchangerate} = "<th>".$locale->text('Exch')."</th>";
+ $column_data{AR_paid} = "<th>".$locale->text('Account')."</th>";
+ $column_data{source} = "<th>".$locale->text('Source')."</th>";
+
+ print "
+ <tr>
+";
+ map { print "$column_data{$_}\n" } @column_index;
+ print "
+ </tr>
+";
+
+ $form->{paidaccounts}++ if ($form->{"paid_$form->{paidaccounts}"});
+ for $i (1 .. $form->{paidaccounts}) {
+
+ print "
+ <tr>\n";
+
+ $form->{"selectAR_paid_$i"} = $form->{selectAR_paid};
+ $form->{"selectAR_paid_$i"} =~ s/option>\Q$form->{"AR_paid_$i"}\E/option selected>$form->{"AR_paid_$i"}/;
+
+ # format amounts
+ $totalpaid += $form->{"paid_$i"};
+ $form->{"paid_$i"} = $form->format_amount(\%myconfig, $form->{"paid_$i"}, 2);
+ $form->{"exchangerate_$i"} = $form->format_amount(\%myconfig, $form->{"exchangerate_$i"});
+
+ $exchangerate = qq|&nbsp;|;
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ if ($form->{"forex_$i"}) {
+ $exchangerate = qq|<input type=hidden name="exchangerate_$i" value=$form->{"exchangerate_$i"}>$form->{"exchangerate_$i"}|;
+ } else {
+ $exchangerate = qq|<input name="exchangerate_$i" size=10 value=$form->{"exchangerate_$i"}>|;
+ }
+ }
+
+ $exchangerate .= qq|
+<input type=hidden name="forex_$i" value=$form->{"forex_$i"}>
+|;
+
+ $column_data{"paid_$i"} = qq|<td align=center><input name="paid_$i" size=11 value=$form->{"paid_$i"}></td>|;
+ $column_data{"exchangerate_$i"} = qq|<td align=center>$exchangerate</td>|;
+ $column_data{"AR_paid_$i"} = qq|<td align=center><select name="AR_paid_$i">$form->{"selectAR_paid_$i"}</select></td>|;
+ $column_data{"datepaid_$i"} = qq|<td align=center><input name="datepaid_$i" size=11 title="$myconfig{dateformat}" value=$form->{"datepaid_$i"}></td>|;
+ $column_data{"source_$i"} = qq|<td align=center><input name="source_$i" size=11 value="$form->{"source_$i"}"></td>|;
+
+ map { print qq|$column_data{"${_}_$i"}\n| } @column_index;
+ print "
+ </tr>\n";
+ }
+
+ print qq|
+<input type=hidden name=paidaccounts value=$form->{paidaccounts}>
+<input type=hidden name=selectAR_paid value="$form->{selectAR_paid}">
+<input type=hidden name=oldinvtotal value=$form->{oldinvtotal}>
+<input type=hidden name=oldtotalpaid value=$totalpaid>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+|;
+
+ &print_options;
+
+ print qq|
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+|;
+
+
+ $invdate = $form->datetonum($form->{invdate}, \%myconfig);
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+
+ if ($form->{id}) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Ship to').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Print').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('E-mail').qq|">
+|;
+
+ if (!$form->{revtrans}) {
+ if (!$form->{locked}) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Delete').qq|">
+|;
+ }
+ }
+
+ if ($invdate > $closedto) {
+ print qq|
+ <input class=submit type=submit name=action value="|.$locale->text('Post as new').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Order').qq|">
+|;
+ }
+
+ } else {
+ if ($invdate > $closedto) {
+ print qq|<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Ship to').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Print').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('E-mail').qq|">
+ <input class=submit type=submit name=action value="|.$locale->text('Post').qq|">|;
+ }
+ }
+
+ print qq|
+
+<input type=hidden name=rowcount value=$form->{rowcount}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub update {
+
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(exchangerate creditlimit creditremaining);
+
+ &check_name(customer);
+
+ &check_project;
+
+ $form->{exchangerate} = $exchangerate if ($form->{forex} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, 'buy')));
+
+ for $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"}) {
+ map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(paid exchangerate);
+
+ $form->{"exchangerate_$i"} = $exchangerate if ($form->{"forex_$i"} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{"datepaid_$i"}, 'buy')));
+ }
+ }
+
+ $i = $form->{rowcount};
+ $exchangerate = ($form->{exchangerate}) ? $form->{exchangerate} : 1;
+
+ # if last row empty, check the form otherwise retrieve new item
+ if (($form->{"partnumber_$i"} eq "") && ($form->{"description_$i"} eq "") && ($form->{"partsgroup_$i"} eq "")) {
+
+ $form->{creditremaining} += ($form->{oldinvtotal} - $form->{oldtotalpaid});
+ &check_form;
+
+ } else {
+
+ IS->retrieve_item(\%myconfig, \%$form);
+
+ $rows = scalar @{ $form->{item_list} };
+
+ $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{discount} * 100);
+
+ if ($rows) {
+ $form->{"qty_$i"} = ($form->{"qty_$i"} * 1) ? $form->{"qty_$i"} : 1;
+
+ if ($rows > 1) {
+
+ &select_item;
+ exit;
+
+ } else {
+
+ $sellprice = $form->parse_amount(\%myconfig, $form->{"sellprice_$i"});
+
+ map { $form->{item_list}[$i]{$_} =~ s/"/&quot;/g } qw(partnumber description unit);
+ map { $form->{"${_}_$i"} = $form->{item_list}[0]{$_} } keys %{ $form->{item_list}[0] };
+
+ $s = ($sellprice) ? $sellprice : $form->{"sellprice_$i"};
+ ($dec) = ($s =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ if ($sellprice) {
+ $form->{"sellprice_$i"} = $sellprice;
+ } else {
+ # if there is an exchange rate adjust sellprice
+ $form->{"sellprice_$i"} /= $exchangerate;
+ }
+
+ $form->{"listprice_$i"} /= $exchangerate;
+
+ $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * (1 - $form->{"discount_$i"} / 100);
+ map { $form->{"${_}_base"} = 0 } (split / /, $form->{taxaccounts});
+ map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"});
+ map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
+
+ $form->{creditremaining} -= $amount;
+
+
+ map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}, $decimalplaces) } qw(sellprice listprice);
+
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+
+ }
+
+ &display_form;
+
+ } else {
+ # ok, so this is a new part
+ # ask if it is a part or service item
+
+ if ($form->{"partsgroup_$i"} && ($form->{"partsnumber_$i"} eq "") && ($form->{"description_$i"} eq "")) {
+ $form->{rowcount}--;
+ $form->{"discount_$i"} = "";
+ &display_form;
+ } else {
+
+ $form->{"id_$i"} = 0;
+ $form->{"unit_$i"} = $locale->text('ea');
+
+ &new_item;
+
+ }
+ }
+ }
+}
+
+
+
+sub post {
+
+ $form->isblank("invnumber", $locale->text('Invoice Number missing!'));
+ $form->isblank("invdate", $locale->text('Invoice Date missing!'));
+ $form->isblank("customer", $locale->text('Customer missing!'));
+
+ # if oldcustomer ne customer redo form
+ if (&check_name(customer)) {
+ &update;
+ exit;
+ }
+
+ &validate_items;
+
+ $closedto = $form->datetonum($form->{closedto}, \%myconfig);
+ $invdate = $form->datetonum($form->{invdate}, \%myconfig);
+
+ $form->error($locale->text('Cannot post invoice for a closed period!')) if ($invdate <= $closedto);
+
+ $form->isblank("exchangerate", $locale->text('Exchangerate missing!')) if ($form->{currency} ne $form->{defaultcurrency});
+
+ for $i (1 .. $form->{paidaccounts}) {
+ if ($form->{"paid_$i"}) {
+ $datepaid = $form->datetonum($form->{"datepaid_$i"}, \%myconfig);
+
+ $form->isblank("datepaid_$i", $locale->text('Payment date missing!'));
+
+ $form->error($locale->text('Cannot post payment for a closed period!')) if ($datepaid <= $closedto);
+
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ $form->{"exchangerate_$i"} = $form->{exchangerate} if ($invdate == $datepaid);
+ $form->isblank("exchangerate_$i", $locale->text('Exchangerate for payment missing!'));
+ }
+ }
+ }
+
+
+ ($form->{AR}) = split /--/, $form->{AR};
+ ($form->{AR_paid}) = split /--/, $form->{AR_paid};
+
+ $form->{label} = $locale->text('Invoice');
+
+ $form->{id} = 0 if $form->{postasnew};
+
+ $form->redirect($locale->text('Invoice posted!')) if (IS->post_invoice(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot post invoice!'));
+
+}
+
+
+
+
+sub delete {
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+|;
+
+ # delete action variable
+ delete $form->{action};
+
+ foreach $key (keys %$form) {
+ $form->{$key} =~ s/"/&quot;/g;
+ print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
+ }
+
+ print qq|
+<h2 class=confirm>|.$locale->text('Confirm!').qq|</font></h2>
+
+<h4>|.$locale->text('Are you sure you want to delete Invoice Number').qq| $form->{invnumber}
+</h4>
+
+<p>
+<input name=action class=submit type=submit value="|.$locale->text('Yes').qq|">
+</form>
+|;
+
+
+}
+
+
+
+sub yes {
+
+ $form->redirect($locale->text('Invoice deleted!')) if (IS->delete_invoice(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot delete invoice!'));
+
+}
+
+
diff --git a/sql-ledger/bin/mozilla/login.pl b/sql-ledger/bin/mozilla/login.pl
new file mode 100644
index 0000000..3c36564
--- /dev/null
+++ b/sql-ledger/bin/mozilla/login.pl
@@ -0,0 +1,217 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#######################################################################
+
+
+use DBI;
+use SL::User;
+use SL::Form;
+
+
+$form = new Form;
+
+$locale = new Locale $language, "login";
+
+# customization
+if (-f "$form->{path}/custom_$form->{script}") {
+ eval { require "$form->{path}/custom_$form->{script}"; };
+ $form->error($@) if ($@);
+}
+
+# per login customization
+if (-f "$form->{path}/$form->{login}_$form->{script}") {
+ eval { require "$form->{path}/$form->{login}_$form->{script}"; };
+ $form->error($@) if ($@);
+}
+
+# window title bar, user info
+$form->{titlebar} = "SQL-Ledger ".$locale->text('Version'). " $form->{version}";
+
+if ($form->{action}) {
+ $form->{titlebar} .= " - $myconfig{name} - $myconfig{dbname}";
+ &{ $locale->findsub($form->{action}) };
+} else {
+ &login_screen;
+}
+
+
+1;
+
+
+sub login_screen {
+
+ if (-f "css/sql-ledger.css") {
+ $form->{stylesheet} = "sql-ledger.css";
+ }
+
+ $form->header;
+
+ print qq|
+<body class=login>
+
+<pre>
+
+</pre>
+
+<center>
+<table class=login border=3 cellpadding=20>
+ <tr>
+ <td class=login align=center><a href="http://www.sql-ledger.org" target=_top><img src=sql-ledger.png border=0></a>
+<h1 class=login align=center>|.$locale->text('Version').qq| $form->{version}
+</h1>
+
+<p>
+
+<form method=post action=$form->{script}>
+
+ <table width=100%>
+ <tr>
+ <td align=center>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Name').qq|</th>
+ <td><input class=login name=login size=30></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Password').qq|</th>
+ <td><input class=login type=password name=password size=30></td>
+ </tr>
+ <input type=hidden name=path value=$form->{path}>
+ </table>
+
+ <br>
+ <input type=submit name=action value="|.$locale->text('Login').qq|">
+
+ </td>
+ </tr>
+ </table>
+
+</form>
+
+ </td>
+ </tr>
+</table>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub login {
+
+ $form->error($locale->text('You did not enter a name!')) unless ($form->{login});
+
+ $user = new User $memberfile, $form->{login};
+
+ # if we get an error back, bale out
+ if (($errno = $user->login(\%$form, $userspath)) <= -1) {
+ $errno *= -1;
+ $err[1] = $locale->text('Incorrect Password!');
+ $err[2] = $locale->text('Incorrect Dataset version!');
+ $err[3] = qq|$form->{login} |.$locale->text('is not a member!');
+
+ $form->error($err[$errno]);
+ }
+
+ # made it this far, execute the menu
+ $argv = "login=$form->{login}&password=$form->{password}&path=$form->{path}&action=display";
+
+ exec ("perl", "menu.pl", $argv);
+
+}
+
+
+
+sub logout {
+
+ unlink "$userspath/$form->{login}.conf";
+
+ # remove the callback to display the message
+ $form->{callback} = "login.pl?path=$form->{path}&action=&login=";
+ $form->redirect($locale->text('You are logged out!'));
+
+}
+
+
+
+sub company_logo {
+
+ require "$userspath/$form->{login}.conf";
+ $locale = new Locale $myconfig{countrycode}, "login" unless ($language eq $myconfig{countrycode});
+
+ $myconfig{address} =~ s/\\n/<br>/g;
+ $myconfig{dbhost} = $locale->text('localhost') unless $myconfig{dbhost};
+
+ map { $form->{$_} = $myconfig{$_} } qw(charset stylesheet);
+
+ $form->{title} = $locale->text('About');
+
+
+ # create the logo screen
+ $form->header unless $form->{noheader};
+
+ print qq|
+<body>
+
+<pre>
+
+</pre>
+<center>
+<a href="http://www.sql-ledger.org" target=_top><img src=sql-ledger.png border=0></a>
+<h1 class=login>|.$locale->text('Version').qq| $form->{version}</h1>
+
+<p>
+|.$locale->text('Licensed to').qq|
+<p>
+<b>
+$myconfig{company}
+<br>$myconfig{address}
+</b>
+
+<p>
+<table>
+ <tr>
+ <th align=right>|.$locale->text('User').qq|</th>
+ <td>$myconfig{name}</td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Dataset').qq|</th>
+ <td>$myconfig{dbname}</td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Database Host').qq|</th>
+ <td>$myconfig{dbhost}</td>
+ </tr>
+</table>
+
+</center>
+
+</body>
+</html>
+|;
+
+}
+
+
+
diff --git a/sql-ledger/bin/mozilla/menu.pl b/sql-ledger/bin/mozilla/menu.pl
new file mode 100644
index 0000000..67c18bd
--- /dev/null
+++ b/sql-ledger/bin/mozilla/menu.pl
@@ -0,0 +1,160 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors: Christopher Browne
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#######################################################################
+#
+# two frame layout with refractured menu
+#
+# CHANGE LOG:
+# DS. 2002-03-25 Created
+#######################################################################
+
+$menufile = "menu.ini";
+use SL::Menu;
+
+
+1;
+# end of main
+
+
+sub display {
+
+ $framesize = ($ENV{HTTP_USER_AGENT} =~ /links/i) ? "240" : "135";
+
+ $form->header;
+
+ print qq|
+
+<FRAMESET COLS="$framesize,*" BORDER="1">
+
+ <FRAME NAME="acc_menu" SRC="$form->{script}?login=$form->{login}&password=$form->{password}&action=acc_menu&path=$form->{path}">
+ <FRAME NAME="main_window" SRC="login.pl?login=$form->{login}&password=$form->{password}&action=company_logo&path=$form->{path}">
+
+</FRAMESET>
+
+</BODY>
+</HTML>
+|;
+
+}
+
+
+
+sub acc_menu {
+
+ my $menu = new Menu "$menufile";
+ $menu = new Menu "custom_$menufile" if (-f "custom_$menufile");
+ $menu = new Menu "$form->{login}_$menufile" if (-f "$form->{login}_$menufile");
+
+ $form->{title} = $locale->text('Accounting Menu');
+
+ $form->header;
+
+ print qq|
+<body class=menu>
+
+|;
+
+ &section_menu($menu);
+
+ print qq|
+</body>
+</html>
+|;
+
+}
+
+
+sub section_menu {
+ my ($menu, $level) = @_;
+
+ # build tiered menus
+ my @menuorder = $menu->access_control(\%myconfig, $level);
+
+ while (@menuorder) {
+ $item = shift @menuorder;
+ $label = $item;
+ $label =~ s/$level--//g;
+
+ my $spacer = "&nbsp;" x (($item =~ s/--/--/g) * 2);
+
+ $label =~ s/.*--//g;
+ $label = $locale->text($label);
+ $label =~ s/ /&nbsp;/g;
+
+ $menu->{$item}{target} = "main_window" unless $menu->{$item}{target};
+
+ if ($menu->{$item}{submenu}) {
+ $menu->{$item}{$item} = !$form->{$item};
+
+ if ($form->{level} && $item =~ /^$form->{level}/) {
+
+ # expand menu
+ print qq|<br>\n$spacer|.$menu->menuitem(\%myconfig, \%$form, $item, $level).qq|$label</a>|;
+
+ # remove same level items
+ map { shift @menuorder } grep /^$item/, @menuorder;
+
+ &section_menu($menu, $item);
+
+ print qq|<br>\n|;
+
+ } else {
+
+ print qq|<br>\n$spacer|.$menu->menuitem(\%myconfig, \%$form, $item, $level).qq|$label&nbsp;...</a>|;
+
+ # remove same level items
+ map { shift @menuorder } grep /^$item/, @menuorder;
+
+ }
+
+
+ } else {
+
+ if ($menu->{$item}{module}) {
+ if ($form->{$item} && $form->{level} eq $item) {
+ $menu->{$item}{$item} = !$form->{$item};
+ print qq|<br>\n$spacer|.$menu->menuitem(\%myconfig, \%$form, $item, $level).qq|$label</a>|;
+
+ # remove same level items
+ map { shift @menuorder } grep /^$item/, @menuorder;
+
+ &section_menu($menu, $item);
+
+ } else {
+ print qq|<br>\n$spacer|.$menu->menuitem(\%myconfig, \%$form, $item, $level).qq|$label</a>|;
+ }
+
+ } else {
+
+ print qq|<br><b>$label</b>|;
+
+ &section_menu($menu, $item);
+
+ print qq|<br>\n|;
+
+ }
+ }
+ }
+}
+
+
diff --git a/sql-ledger/bin/mozilla/oe.pl b/sql-ledger/bin/mozilla/oe.pl
new file mode 100644
index 0000000..6a8326f
--- /dev/null
+++ b/sql-ledger/bin/mozilla/oe.pl
@@ -0,0 +1,1111 @@
+#=====================================================================
+# SQL-Ledger, Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Order entry module
+#
+#======================================================================
+
+
+use SL::OE;
+use SL::IR;
+use SL::IS;
+use SL::PE;
+
+require "$form->{path}/io.pl";
+require "$form->{path}/arap.pl";
+
+1;
+# end of main
+
+
+sub add {
+
+ if ($form->{type} eq 'purchase_order') {
+ $form->{title} = $locale->text('Add Purchase Order');
+ $form->{vc} = 'vendor';
+ }
+ if ($form->{type} eq 'sales_order') {
+ $form->{title} = $locale->text('Add Sales Order');
+ $form->{vc} = 'customer';
+ }
+
+ &order_links;
+ &prepare_order;
+ &display_form;
+
+}
+
+
+sub edit {
+
+ if ($form->{type} eq 'purchase_order') {
+ $form->{title} = $locale->text('Edit Purchase Order');
+ $form->{vc} = 'vendor';
+ }
+ if ($form->{type} eq 'sales_order') {
+ $form->{title} = $locale->text('Edit Sales Order');
+ $form->{vc} = 'customer';
+ }
+
+ &order_links;
+ &prepare_order;
+
+ &display_form;
+
+}
+
+
+sub order_links {
+
+ # get vendors / customers
+ $form->all_vc(\%myconfig, $form->{vc});
+
+ # retrieve order
+ OE->retrieve_order(\%myconfig, \%$form);
+
+ $taxincluded = $form->{taxincluded};
+ $form->{shipto} = 1 if $form->{id};
+
+ # get customer / vendor
+ if ($form->{type} eq 'purchase_order') {
+ IR->get_vendor(\%myconfig, \%$form);
+ }
+ if ($form->{type} eq 'sales_order') {
+ IS->get_customer(\%myconfig, \%$form);
+ }
+
+ ($form->{$form->{vc}}) = split /--/, $form->{$form->{vc}};
+ $form->{"old$form->{vc}"} = qq|$form->{$form->{vc}}--$form->{"$form->{vc}_id"}|;
+
+ # build the popup menus
+ if (@{ $form->{"all_$form->{vc}"} }) {
+ $form->{$form->{vc}} = qq|$form->{$form->{vc}}--$form->{"$form->{vc}_id"}|;
+ map { $form->{"select$form->{vc}"} .= "<option>$_->{name}--$_->{id}\n" } (@{ $form->{"all_$form->{vc}"} });
+ }
+
+ # currencies
+ @curr = split /:/, $form->{currencies};
+ chomp $curr[0];
+ $form->{defaultcurrency} = $curr[0];
+
+ map { $form->{selectcurrency} .= "<option>$_\n" } @curr;
+
+ $form->{taxincluded} = $taxincluded if ($form->{id});
+
+ # forex
+ $form->{forex} = $form->{exchangerate};
+
+}
+
+
+sub prepare_order {
+
+ $form->{format} = "html";
+ $form->{media} = "screen";
+
+ if ($form->{id}) {
+
+ map { $form->{$_} =~ s/"/&quot;/g } qw(invnumber shippingpoint notes shiptoname shiptoaddr1 shiptoaddr2 shiptoaddr3 shiptoaddr4 shiptocontact);
+
+ foreach $ref (@{ $form->{order_details} } ) {
+ $i++;
+ map { $form->{"${_}_$i"} = $ref->{$_} } keys %{ $ref };
+ $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{"discount_$i"} * 100);
+
+ ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ $form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+
+ map { $form->{"${_}_$i"} =~ s/"/&quot;/g } qw(partnumber description unit);
+ $form->{rowcount} = $i;
+ }
+ }
+
+}
+
+
+sub form_header {
+
+ $checkedopen = ($form->{closed}) ? "" : "checked";
+ $checkedclosed = ($form->{closed}) ? "checked" : "";
+
+ if ($form->{id}) {
+ $openclosed = qq|
+ <tr>
+ <td colspan=2 align=center>
+ <table>
+ <tr>
+ <th nowrap><input name=closed type=radio class=radio value=0 $checkedopen> |.$locale->text('Open').qq|</th>
+ <th nowrap><input name=closed type=radio class=radio value=1 $checkedclosed> |.$locale->text('Closed').qq|</th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+ }
+
+ # set option selected
+ foreach $item ($form->{vc}, currency) {
+ $form->{"select$item"} =~ s/ selected//;
+ $form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
+ }
+
+ $form->{exchangerate} = $form->format_amount(\%myconfig, $form->{exchangerate});
+
+ $form->{creditlimit} = $form->format_amount(\%myconfig, $form->{creditlimit}, 0, "0");
+ $form->{creditremaining} = $form->format_amount(\%myconfig, $form->{creditremaining}, 0, "0");
+
+ $exchangerate = qq|
+<input type=hidden name=forex value=$form->{forex}>
+|;
+
+ if ($form->{currency} ne $form->{defaultcurrency}) {
+ if ($form->{forex}) {
+ $exchangerate .= qq|<th align=right>|.$locale->text('Exchangerate').qq|</th><td>$form->{exchangerate}</td>
+ <input type=hidden name=exchangerate value=$form->{exchangerate}>
+|;
+ } else {
+ $exchangerate .= qq|<th align=right>|.$locale->text('Exchangerate').qq|</th><td><input name=exchangerate size=10 value=$form->{exchangerate}></td>|;
+ }
+ }
+
+
+ $vclabel = ucfirst $form->{vc};
+ $vclabel = $locale->text($vclabel);
+
+ if ($form->{type} eq 'sales_order') {
+
+ $n = ($form->{creditremaining} =~ /-/) ? "0" : "1";
+
+ $creditremaining = qq|
+ <tr>
+ <td></td>
+ <td colspan=3>
+ <table width=100%>
+ <tr>
+ <th align=left nowrap>|.$locale->text('Credit Limit').qq|</th>
+ <td>$form->{creditlimit}</td>
+ <th align=left nowrap>|.$locale->text('Remaining').qq|</th>
+ <td class="plus$n">$form->{creditremaining}</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+ }
+
+ $vc = ($form->{"select$form->{vc}"}) ? qq|<select name=$form->{vc}>$form->{"select$form->{vc}"}</select>\n<input type=hidden name="select$form->{vc}" value="$form->{"select$form->{vc}"}">| : qq|<input name=$form->{vc} value="$form->{$form->{vc}}" size=35>|;
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=id value=$form->{id}>
+
+<input type=hidden name=type value=$form->{type}>
+<input type=hidden name=media value=$form->{media}>
+<input type=hidden name=format value=$form->{format}>
+
+<input type=hidden name=vc value=$form->{vc}>
+<input type=hidden name=employee value="$form->{employee}">
+
+<input type=hidden name=title value="$form->{title}">
+
+<input type=hidden name=discount value=$form->{discount}>
+<input type=hidden name=creditlimit value=$form->{creditlimit}>
+<input type=hidden name=creditremaining value=$form->{creditremaining}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width="100%">
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right>$vclabel</th>
+ <td colspan=3>$vc</td>
+ <input type=hidden name=$form->{vc}_id value=$form->{"$form->{vc}_id"}>
+ <input type=hidden name="old$form->{vc}" value="$form->{"old$form->{vc}"}">
+ </tr>
+ $creditremaining
+ <tr>
+ <th align=right>|.$locale->text('Currency').qq|</th>
+ <td><select name=currency>$form->{selectcurrency}</select></td>
+ <input type=hidden name=selectcurrency value="$form->{selectcurrency}">
+ <input type=hidden name=defaultcurrency value=$form->{defaultcurrency}>
+ $exchangerate
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Ship via').qq|</th>
+ <td colspan=3><input name=shippingpoint size=35 value="$form->{shippingpoint}"></td>
+ </tr>
+ </table>
+ </td>
+ <td align=right>
+ <table width=100%>
+ $openclosed
+ <tr>
+ <th align=right nowrap>|.$locale->text('Order Number').qq|</th>
+ <td><input name=ordnumber size=11 value="$form->{ordnumber}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Order Date').qq|</th>
+ <td><input name=orddate size=11 title="$myconfig{dateformat}" value=$form->{orddate}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap=true>|.$locale->text('Required by').qq|</th>
+ <td><input name=reqdate size=11 title="$myconfig{dateformat}" value=$form->{reqdate}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Terms: Net').qq|</th>
+ <td nowrap=true><input name=terms size="3" maxlength="3" value=$form->{terms}> |.$locale->text('days').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+<!-- shipto are in hidden variables -->
+
+<input type=hidden name=shiptoname value="$form->{shiptoname}">
+<input type=hidden name=shiptoaddr1 value="$form->{shiptoaddr1}">
+<input type=hidden name=shiptoaddr2 value="$form->{shiptoaddr2}">
+<input type=hidden name=shiptoaddr3 value="$form->{shiptoaddr3}">
+<input type=hidden name=shiptoaddr4 value="$form->{shiptoaddr4}">
+<input type=hidden name=shiptocontact value="$form->{shiptocontact}">
+<input type=hidden name=shiptophone value="$form->{shiptophone}">
+<input type=hidden name=shiptofax value="$form->{shiptofax}">
+<input type=hidden name=shiptoemail value="$form->{shiptoemail}">
+
+<!-- email variables -->
+<input type=hidden name=message value="$form->{message}">
+<input type=hidden name=email value="$form->{email}">
+<input type=hidden name=subject value="$form->{subject}">
+<input type=hidden name=cc value="$form->{cc}">
+<input type=hidden name=bcc value="$form->{bcc}">
+
+<input type=hidden name=taxpart value="$form->{taxpart}">
+<input type=hidden name=taxservice value="$form->{taxservice}">
+
+<input type=hidden name=taxaccounts value="$form->{taxaccounts}">
+|;
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ print qq|
+<input type=hidden name="${item}_rate" value=$form->{"${item}_rate"}>
+<input type=hidden name="${item}_description" value="$form->{"${item}_description"}">
+|;
+ }
+
+}
+
+
+sub form_footer {
+
+ $form->{invtotal} = $form->{invsubtotal};
+
+ if (($rows = $form->numtextrows($form->{notes}, 50, 8)) < 2) {
+ $rows = 2;
+ }
+ $notes = qq|<textarea name=notes rows=$rows cols=50 wrap=soft>$form->{notes}</textarea>|;
+
+ $taxincluded = "";
+ $form->{taxincluded} = ($form->{taxincluded}) ? "checked" : "";
+ if ($form->{taxaccounts}) {
+ $taxincluded = qq|
+ <input name=taxincluded class=checkbox type=checkbox value=1 $form->{taxincluded}> <b>|.$locale->text('Tax Included').qq|</b><br><br>
+|;
+ }
+
+ if (!$form->{taxincluded}) {
+
+ foreach $item (split / /, $form->{taxaccounts}) {
+ if ($form->{"${item}_base"}) {
+ $form->{invtotal} += $form->{"${item}_total"} = $form->round_amount($form->{"${item}_base"} * $form->{"${item}_rate"}, 2);
+ $form->{"${item}_total"} = $form->format_amount(\%myconfig, $form->{"${item}_total"}, 2);
+
+ $tax .= qq|
+ <tr>
+ <th align=right>$form->{"${item}_description"}</th>
+ <td align=right>$form->{"${item}_total"}</td>
+ </tr>
+|;
+ }
+ }
+
+ $form->{invsubtotal} = $form->format_amount(\%myconfig, $form->{invsubtotal}, 2, 0);
+
+ $subtotal = qq|
+ <tr>
+ <th align=right>|.$locale->text('Subtotal').qq|</th>
+ <td align=right>$form->{invsubtotal}</td>
+ </tr>
+|;
+
+ }
+
+ $form->{oldinvtotal} = $form->{invtotal};
+ $form->{invtotal} = $form->format_amount(\%myconfig, $form->{invtotal}, 2, 0);
+
+ print qq|
+ <tr>
+ <td>
+ <table width=100%>
+ <tr valign=bottom>
+ <td>
+ <table>
+ <tr>
+ <th align=left>|.$locale->text('Notes').qq|</th>
+ </tr>
+ <tr>
+ <td>$notes</td>
+ </tr>
+ </table>
+ </td>
+ <td align=right width=100%>
+ $taxincluded
+ <table width=100%>
+ $subtotal
+ $tax
+ <tr>
+ <th align=right>|.$locale->text('Total').qq|</th>
+ <td align=right>$form->{invtotal}</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+<input type=hidden name=oldinvtotal value=$form->{oldinvtotal}>
+<input type=hidden name=oldtotalpaid value=$totalpaid>
+ <tr>
+ <td>
+|;
+
+ &print_options;
+
+ print qq|
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Update').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Ship to').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Print').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('E-mail').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Save').qq|">
+|;
+
+ if ($form->{id}) {
+ print qq|
+<input class=submit type=submit name=action value="|.$locale->text('Save as new').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Delete').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Invoice').qq|">
+|;
+ }
+
+ print qq|
+
+<input type=hidden name=rowcount value=$form->{rowcount}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub update {
+
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(exchangerate creditlimit creditremaining);
+
+ &check_name($form->{vc});
+
+ &check_project;
+
+ $buysell = 'buy';
+ $buysell = 'sell' if ($form->{vc} eq 'vendor');
+ $form->{exchangerate} = $exchangerate if ($form->{forex} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{orddate}, $buysell)));
+
+
+ my $i = $form->{rowcount};
+ $exchangerate = ($form->{exchangerate}) ? $form->{exchangerate} : 1;
+
+ if (($form->{"partnumber_$i"} eq "") && ($form->{"description_$i"} eq "") && ($form->{"partsgroup_$i"} eq "")) {
+
+ $form->{creditremaining} += ($form->{oldinvtotal} - $form->{oldtotalpaid});
+ &check_form;
+
+ } else {
+
+ if ($form->{type} eq 'purchase_order') {
+ IR->retrieve_item(\%myconfig, \%$form);
+ }
+ if ($form->{type} eq 'sales_order') {
+ IS->retrieve_item(\%myconfig, \%$form);
+ }
+
+ my $rows = scalar @{ $form->{item_list} };
+
+ $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{discount} * 100);
+
+ if ($rows) {
+ $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
+
+ if ($rows > 1) {
+
+ &select_item;
+ exit;
+
+ } else {
+
+ $sellprice = $form->parse_amount(\%myconfig, $form->{"sellprice_$i"});
+
+ map { $form->{item_list}[$i]{$_} =~ s/"/&quot;/g } qw(partnumber description unit);
+ map { $form->{"${_}_$i"} = $form->{item_list}[0]{$_} } keys %{ $form->{item_list}[0] };
+
+ $s = ($sellprice) ? $sellprice : $form->{"sellprice_$i"};
+
+ ($dec) = ($s =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ if ($sellprice) {
+ $form->{"sellprice_$i"} = $sellprice;
+ } else {
+ # if there is an exchange rate adjust sellprice
+ $form->{"sellprice_$i"} /= $exchangerate;
+ }
+
+ $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * (1 - $form->{"discount_$i"} / 100);
+ map { $form->{"${_}_base"} = 0 } (split / /, $form->{taxaccounts});
+ map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"});
+ map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{taxaccounts} if !$form->{taxincluded};
+
+ $form->{creditremaining} -= $amount;
+
+ $form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+ }
+
+ &display_form;
+
+ } else {
+ # ok, so this is a new part
+ # ask if it is a part or service item
+
+ if ($form->{"partsgroup_$i"} && ($form->{"partsnumber_$i"} eq "") && ($form->{"description_$i"} eq "")) {
+ $form->{rowcount}--;
+ $form->{"discount_$i"} = "";
+ &display_form;
+ } else {
+
+ $form->{"id_$i"} = 0;
+ $form->{"unit_$i"} = $locale->text('ea');
+
+ &new_item;
+
+ }
+ }
+ }
+}
+
+
+
+sub search {
+
+ if ($form->{type} eq 'purchase_order') {
+ $form->{title} = $locale->text('Purchase Orders');
+ $form->{vc} = 'vendor';
+ }
+ if ($form->{type} eq 'sales_order') {
+ $form->{title} = $locale->text('Sales Orders');
+ $form->{vc} = 'customer';
+ }
+
+ # setup vendor / customer selection
+ $form->all_vc(\%myconfig, "$form->{vc}");
+
+ map { $vc .= "<option>$_->{name}--$_->{id}\n" } @{ $form->{"all_$form->{vc}"} };
+
+ $vclabel = ucfirst $form->{vc};
+ $vclabel = $locale->text($vclabel);
+
+# $locale->text('Vendor')
+# $locale->text('Customer')
+
+ $vc = ($vc) ? qq|<select name=$form->{vc}><option>\n$vc</select>| : qq|<input name=$form->{vc} size=35>|;
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>$vclabel</th>
+ <td colspan=3>$vc</td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Order Number').qq|</th>
+ <td colspan=3><input name=ordnumber size=20></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('From').qq|</th>
+ <td><input name=transdatefrom size=11 title="$myconfig{dateformat}"></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=transdateto size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <input type=hidden name=sort value=transdate>
+ <tr>
+ <th align=right>|.$locale->text('Include in Report').qq|</th>
+ <td colspan=3>
+ <table>
+ <tr>
+ <td><input name="open" class=checkbox type=checkbox value=1 checked> |.$locale->text('Open').qq|</td>
+ <td><input name="closed" class=checkbox type=checkbox value=1 $form->{closed}> |.$locale->text('Closed').qq|</td>
+ </tr>
+ <tr>
+ <td><input name="l_id" class=checkbox type=checkbox value=Y> |.$locale->text('ID').qq|</td>
+ <td><input name="l_ordnumber" class=checkbox type=checkbox value=Y checked> |.$locale->text('Order Number').qq|</td>
+ <td><input name="l_transdate" class=checkbox type=checkbox value=Y checked> |.$locale->text('Order Date').qq|</td>
+ <td><input name="l_reqdate" class=checkbox type=checkbox value=Y checked> |.$locale->text('Required by').qq|</td>
+ </tr>
+ <tr>
+ <td><input name="l_name" class=checkbox type=checkbox value=Y checked> $vclabel</td>
+ <td><input name="l_netamount" class=checkbox type=checkbox value=Y> |.$locale->text('Amount').qq|</td>
+ <td><input name="l_tax" class=checkbox type=checkbox value=Y> |.$locale->text('Tax').qq|</td>
+ <td><input name="l_amount" class=checkbox type=checkbox value=Y checked> |.$locale->text('Total').qq|</td>
+ </tr>
+ <tr>
+ <td><input name="l_subtotal" class=checkbox type=checkbox value=Y> |.$locale->text('Subtotal').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr><td colspan=4><hr size=3 noshade></td></tr>
+</table>
+
+<br>
+<input type=hidden name=nextsub value=orders>
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+<input type=hidden name=vc value=$form->{vc}>
+<input type=hidden name=type value=$form->{type}>
+
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub orders {
+
+ $name = $form->{$form->{vc}};
+
+ # split vendor / customer
+ ($form->{$form->{vc}}, $form->{"$form->{vc}_id"}) = split(/--/, $form->{$form->{vc}});
+
+ OE->transactions(\%myconfig, \%$form);
+
+ # construct href
+ $href = "$form->{script}?path=$form->{path}&action=orders&type=$form->{type}&vc=$form->{vc}&login=$form->{login}&password=$form->{password}&transdatefrom=$form->{transdatefrom}&transdateto=$form->{transdateto}&open=$form->{open}&closed=$form->{closed}&ordnumber=" . $form->escape($form->{ordnumber}) . "&$form->{vc}=" . $form->escape($form->{$form->{vc}});
+
+ # construct callback
+ $name =~ s/&/_/g;
+ $callback = "$form->{script}?path=$form->{path}&action=orders&type=$form->{type}&vc=$form->{vc}&login=$form->{login}&password=$form->{password}&transdatefrom=$form->{transdatefrom}&transdateto=$form->{transdateto}&open=$form->{open}&closed=$form->{closed}&ordnumber=$form->{ordnumber}&$form->{vc}=$name";
+
+ @columns = $form->sort_columns(qw(transdate reqdate id ordnumber name netamount tax amount curr open closed));
+
+ $form->{l_open} = $form->{l_closed} = "Y" if ($form->{open} && $form->{closed}) ;
+
+ foreach $item (@columns) {
+ if ($form->{"l_$item"} eq "Y") {
+ push @column_index, $item;
+
+ # add column to href and callback
+ $callback .= "&l_$item=Y";
+ $href .= "&l_$item=Y";
+ }
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ $callback .= "&l_subtotal=Y";
+ $href .= "&l_subtotal=Y";
+ }
+
+
+ if ($form->{vc} eq 'vendor') {
+ $form->{title} = $locale->text('Purchase Orders');
+ $name = $locale->text('Vendor');
+ }
+ if ($form->{vc} eq 'customer') {
+ $form->{title} = $locale->text('Sales Orders');
+ $name = $locale->text('Customer');
+ }
+
+ $column_header{id} = qq|<th><a class=listheading href=$href&sort=id>|.$locale->text('ID').qq|</a></th>|;
+ $column_header{transdate} = qq|<th><a class=listheading href=$href&sort=transdate>|.$locale->text('Date').qq|</a></th>|;
+ $column_header{reqdate} = qq|<th><a class=listheading href=$href&sort=reqdate>|.$locale->text('Required by').qq|</a></th>|;
+ $column_header{ordnumber} = qq|<th><a class=listheading href=$href&sort=ordnumber>|.$locale->text('Order').qq|</a></th>|;
+ $column_header{name} = qq|<th><a class=listheading href=$href&sort=name>$name</a></th>|;
+ $column_header{netamount} = qq|<th class=listheading>|.$locale->text('Amount').qq|</th>|;
+ $column_header{tax} = qq|<th class=listheading>|.$locale->text('Tax').qq|</th>|;
+ $column_header{amount} = qq|<th class=listheading>|.$locale->text('Total').qq|</th>|;
+ $column_header{curr} = qq|<th class=listheading>|.$locale->text('Curr').qq|</th>|;
+ $column_header{open} = qq|<th class=listheading>|.$locale->text('O').qq|</th>|;
+ $column_header{closed} = qq|<th class=listheading>|.$locale->text('C').qq|</th>|;
+
+ if ($form->{open}) {
+ $option = $locale->text('Open');
+ }
+ if ($form->{closed}) {
+ $option .= " : " if $form->{open};
+ $option .= $locale->text('Closed');
+ }
+ if ($form->{$form->{vc}}) {
+ $option .= "\n<br>";
+ $option .= ucfirst $form->{vc};
+ $option .= " : $form->{$form->{vc}}";
+ }
+ if ($form->{transdatefrom}) {
+ $option .= "\n<br>".$locale->text('From')." ".$locale->date(\%myconfig, $form->{transdatefrom}, 1);
+ }
+ if ($form->{transdateto}) {
+ $option .= "\n<br>".$locale->text('to')." ".$locale->date(\%myconfig, $form->{transdateto}, 1);
+ }
+
+ $form->header;
+
+ $colspan = $#column_index + 1;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr><th class=listtop colspan=$colspan>$form->{title}</th></tr>
+ <tr height="5"></tr>
+ <tr>
+ <td colspan=$colspan>$option</td>
+ </tr>
+ <tr class=listheading>|;
+
+map { print "\n$column_header{$_}" } @column_index;
+
+print qq|
+ </tr>
+|;
+
+ # add sort and escape callback
+ $callback = $form->escape($callback . "&sort=$form->{sort}");
+
+ if (@{ $form->{OE} }) {
+ $sameitem = $form->{OE}->[0]->{$form->{sort}};
+ }
+
+ foreach $oe (@{ $form->{OE} }) {
+
+ if ($form->{l_subtotal} eq 'Y') {
+ if ($sameitem ne $oe->{$form->{sort}}) {
+ &subtotal;
+ $sameitem = $oe->{$form->{sort}};
+ }
+ }
+
+ map { $oe->{$_} *= $oe->{exchangerate} } (qw(netamount amount));
+
+ $column_data{netamount} = "<td align=right>".$form->format_amount(\%myconfig, $oe->{netamount}, 2, "&nbsp;")."</td>";
+ $column_data{tax} = "<td align=right>".$form->format_amount(\%myconfig, $oe->{amount} - $oe->{netamount}, 2, "&nbsp;")."</td>";
+ $column_data{amount} = "<td align=right>".$form->format_amount(\%myconfig, $oe->{amount}, 2, "&nbsp;")."</td>";
+
+ $totalnetamount += $oe->{netamount};
+ $totalamount += $oe->{amount};
+
+ $subtotalnetamount += $oe->{netamount};
+ $subtotalamount += $oe->{amount};
+
+ $column_data{id} = "<td>$oe->{id}</td>";
+ $column_data{transdate} = "<td>$oe->{transdate}&nbsp;</td>";
+ $column_data{reqdate} = "<td>$oe->{reqdate}&nbsp;</td>";
+
+ $column_data{ordnumber} = "<td><a href=oe.pl?path=$form->{path}&action=edit&type=$form->{type}&id=$oe->{id}&login=$form->{login}&password=$form->{password}&callback=$callback>$oe->{ordnumber}</a></td>";
+ $column_data{name} = "<td>$oe->{name}</td>";
+
+ if ($oe->{closed}) {
+ $column_data{closed} = "<td align=center>X</td>";
+ $column_data{open} = "<td>&nbsp;</td>";
+ } else {
+ $column_data{closed} = "<td>&nbsp;</td>";
+ $column_data{open} = "<td align=center>X</td>";
+ }
+
+ $i++; $i %= 2;
+ print "<tr class=listrow$i>";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ &subtotal;
+ }
+
+ # print totals
+ print qq|<tr class=listtotal>|;
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{netamount} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{tax} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalamount - $totalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{amount} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalamount, 2, "&nbsp;")."</th>";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+ <tr><td colspan=8><hr size=3 noshade></td></tr>
+</table>
+
+<br>
+<form method=post action=$form->{script}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=type value=$form->{type}>
+<input type=hidden name=vc value=$form->{vc}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input class=submit type=submit name=action value=|.$locale->text('Add').qq|
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub subtotal {
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{netamount} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{tax} = "<td class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalamount - $subtotalnetamount, 2, "&nbsp;")."</th>";
+ $column_data{amount} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalamount, 2, "&nbsp;")."</th>";
+
+ $subtotalnetamount = 0;
+ $subtotalamount = 0;
+
+ print "<tr class=listsubtotal>";
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+}
+
+
+sub save {
+
+ $form->isblank("ordnumber", $locale->text('Order Number missing!'));
+ $form->isblank("orddate", $locale->text('Order Date missing!'));
+
+ $msg = ucfirst $form->{vc};
+ $form->isblank($form->{vc}, $locale->text($msg . " missing!"));
+
+# $locale->text('Customer missing!');
+# $locale->text('Vendor missing!');
+
+ $form->isblank("exchangerate", $locale->text('Exchangerate missing!')) if ($form->{currency} ne $form->{defaultcurrency});
+
+ &validate_items;
+
+ # if the name changed get new values
+ if (&check_name($form->{vc})) {
+ &update;
+ exit;
+ }
+
+
+ # this is for the notes section for the [email] Subject
+ $form->{label} = ($form->{type} eq 'sales_order') ? $locale->text('Sales Order') : $locale->text('Purchase Order');
+
+ $form->{id} = 0 if $form->{saveasnew};
+
+ $form->redirect($locale->text('Order saved!')) if (OE->save_order(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot save order!'));
+
+}
+
+
+
+sub delete {
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+|;
+
+ # delete action variable
+ delete $form->{action};
+
+ foreach $key (keys %$form) {
+ $form->{$key} =~ s/"/&quot;/g;
+ print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
+ }
+
+ print qq|
+<h2 class=confirm>|.$locale->text('Confirm!').qq|</h2>
+
+<h4>|
+ .$locale->text('Are you sure you want to delete Order Number').qq| $form->{ordnumber}
+</h4>
+<p>
+<input name=action class=submit type=submit value="|.$locale->text('Yes').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+
+}
+
+
+
+sub yes {
+
+ $form->redirect($locale->text('Order deleted!')) if (OE->delete_order(\%myconfig, \%$form));
+ $form->error($locale->text('Cannot delete order!'));
+
+}
+
+
+sub invoice {
+
+ $form->isblank("ordnumber", $locale->text('Order Number missing!'));
+ $form->isblank("orddate", $locale->text('Order Date missing!'));
+
+
+ # if the name changed get new values
+ if (&check_name($form->{vc})) {
+ &update;
+ exit;
+ }
+
+ $form->{closed} = 1;
+ OE->save_order(\%myconfig, \%$form);
+
+ $form->{orddate} = $form->{transdate} = $form->{invdate} = $form->current_date(\%myconfig);
+ $form->{duedate} = $form->current_date(\%myconfig, $form->{invdate}, $form->{terms} * 1);
+
+ $form->{id} = '';
+ $form->{closed} = 0;
+ $form->{rowcount}--;
+ $form->{shipto} = 1;
+
+ &create_backorder;
+
+ if ($form->{type} eq 'purchase_order') {
+ $form->{title} = $locale->text('Add Vendor Invoice');
+ $form->{script} = 'ir.pl';
+ $script = "ir";
+ $buysell = 'sell';
+ }
+ if ($form->{type} eq 'sales_order') {
+ $form->{title} = $locale->text('Add Sales Invoice');
+ $form->{script} = 'is.pl';
+ $script = "is";
+ $buysell = 'buy';
+ }
+
+
+ # bo creates the id, reset it
+ map { $form->{$_} = "" } qw(id subject message cc bcc);
+ $form->{$form->{vc}} =~ s/--.*//g;
+ $form->{type} = "invoice";
+
+ # locale messages
+ $locale = new Locale "$myconfig{countrycode}", "$script";
+
+ require "$form->{path}/$form->{script}";
+
+ map { $form->{"select$_"} = "" } ($form->{vc}, currency);
+
+ map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) } qw(creditlimit creditremaining);
+
+ $currency = $form->{currency};
+ &invoice_links;
+
+ $form->{currency} = $currency;
+ $form->{exchangerate} = "";
+ $form->{forex} = "";
+ $form->{exchangerate} = $exchangerate if ($form->{forex} = ($exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, $buysell)));
+
+ $form->{creditremaining} -= ($form->{oldinvtotal} - $form->{ordtotal});
+
+ &prepare_invoice;
+
+ # format amounts
+ for $i (1 .. $form->{rowcount}) {
+ $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{"discount_$i"});
+
+ ($dec) = ($form->{"sellprice_$i"} =~ /\.(\d+)/);
+ $dec = length $dec;
+ $decimalplaces = ($dec > 2) ? $dec : 2;
+
+ $form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces);
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+
+ map { $form->{"${_}_$i"} =~ s/"/&quot;/g } qw(partnumber description unit);
+ }
+
+ &display_form;
+
+}
+
+
+sub create_backorder {
+
+ # figure out if we need to create a backorder
+ # items aren't saved if qty != 0
+
+ for $i (1 .. $form->{rowcount}) {
+ $totalqty += $qty = $form->parse_amount($myconfig, $form->{"qty_$i"});
+ $totalship += $ship = $form->parse_amount($myconfig, $form->{"ship_$i"});
+
+ $form->{"qty_$i"} = $qty - $ship;
+ }
+
+ if ($totalship == 0) {
+ map { $form->{"ship_$_"} = $form->{"qty_$_"} } (1 .. $form->{rowcount});
+ $form->{ordtotal} = 0;
+ return;
+ }
+
+ if ($totalqty == $totalship) {
+ map { $form->{"qty_$_"} = $form->{"ship_$_"} } (1 .. $form->{rowcount});
+ $form->{ordtotal} = 0;
+ return;
+ }
+
+ @flds = (qw(partnumber description qty ship unit sellprice discount id inventory_accno bin income_accno expense_accno listprice assembly taxaccounts));
+
+ OE->save_order(\%myconfig, \%$form);
+
+ # rebuild rows for invoice
+ @a = ();
+ $count = 0;
+
+ for $i (1 .. $form->{rowcount}) {
+
+ # reformat values if there was a backorder quantity
+ if ($form->{"qty_$i"}) {
+ $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{"discount_$i"});
+ $form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"});
+ }
+
+ $form->{"qty_$i"} = $form->{"ship_$i"};
+
+ if ($form->{"qty_$i"}) {
+ push @a, {};
+ $j = $#a;
+ map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds;
+ $count++;
+ }
+ }
+
+ $form->redo_rows(\@flds, \@a, $count, $form->{rowcount});
+ $form->{rowcount} = $count;
+
+}
+
+
+
+sub save_as_new {
+
+ $form->{saveasnew} = 1;
+ $form->{closed} = 0;
+ &save;
+
+}
+
+
diff --git a/sql-ledger/bin/mozilla/pe.pl b/sql-ledger/bin/mozilla/pe.pl
new file mode 100644
index 0000000..d8706d4
--- /dev/null
+++ b/sql-ledger/bin/mozilla/pe.pl
@@ -0,0 +1,549 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# project administration
+# partsgroup administration
+#
+#======================================================================
+
+
+use SL::PE;
+
+1;
+# end of main
+
+
+
+sub add {
+
+ $form->{title} = "Add";
+
+ # construct callback
+ $form->{callback} = "$form->{script}?action=add&type=$form->{type}&path=$form->{path}&login=$form->{login}&password=$form->{password}" unless $form->{callback};
+
+ &{ "form_$form->{type}_header" };
+ &{ "form_$form->{type}_footer" };
+
+}
+
+
+sub edit {
+
+ $form->{title} = "Edit";
+
+ if ($form->{type} eq 'project') {
+ PE->get_project(\%myconfig, \%$form);
+ }
+ if ($form->{type} eq 'partsgroup') {
+ PE->get_partsgroup(\%myconfig, \%$form);
+ }
+
+ &{ "form_$form->{type}_header" };
+ &{ "form_$form->{type}_footer" };
+
+}
+
+
+sub search {
+
+ if ($form->{type} eq 'project') {
+ $report = "project_report";
+ $sort = 'projectnumber';
+ $form->{title} = $locale->text('Projects');
+
+ $number = qq|
+ <tr>
+ <th align=right width=1%>|.$locale->text('Number').qq|</th>
+ <td><input name=projectnumber size=20></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Description').qq|</th>
+ <td><input name=description size=60></td>
+ </tr>
+|;
+
+ }
+ if ($form->{type} eq 'partsgroup') {
+ $report = "partsgroup_report";
+ $sort = 'partsgroup';
+ $form->{title} = $locale->text('Groups');
+
+ $number = qq|
+ <tr>
+ <th align=right width=1%>|.$locale->text('Group').qq|</th>
+ <td><input name=partsgroup size=20></td>
+ </tr>
+|;
+
+ }
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=sort value=$sort>
+<input type=hidden name=type value=$form->{type}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ $number
+ <tr>
+ <td></td>
+ <td><input name=status class=radio type=radio value=all checked>&nbsp;|.$locale->text('All').qq|
+ <input name=status class=radio type=radio value=orphaned>&nbsp;|.$locale->text('Orphaned').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=nextsub value=$report>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub project_report {
+
+ map { $form->{$_} = $form->unescape($form->{$_}) } (projectnumber, description);
+ PE->projects(\%myconfig, \%$form);
+
+ $callback = "$form->{script}?action=project_report&type=$form->{type}&path=$form->{path}&login=$form->{login}&password=$form->{password}&status=$form->{status}";
+ $href = $callback;
+
+ if ($form->{status} eq 'all') {
+ $option = $locale->text('All');
+ }
+ if ($form->{status} eq 'orphaned') {
+ $option .= $locale->text('Orphaned');
+ }
+ if ($form->{projectnumber}) {
+ $href .= "&projectnumber=".$form->escape($form->{projectnumber});
+ $callback .= "&projectnumber=$form->{projectnumber}";
+ $option .= "\n<br>".$locale->text('Project')." : $form->{projectnumber}";
+ }
+ if ($form->{description}) {
+ $href .= "&description=".$form->escape($form->{description});
+ $callback .= "&description=$form->{description}";
+ $option .= "\n<br>".$locale->text('Description')." : $form->{description}";
+ }
+
+
+ @column_index = $form->sort_columns(qw(projectnumber description));
+
+ $column_header{projectnumber} = qq|<th><a class=listheading href=$href&sort=projectnumber>|.$locale->text('Number').qq|</a></th>|;
+ $column_header{description} = qq|<th><a class=listheading href=$href&sort=description>|.$locale->text('Description').qq|</a></th>|;
+
+ $form->{title} = $locale->text('Projects');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$option</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+ map { print "$column_header{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ # escape callback
+ $form->{callback} = $callback .= "&sort=$form->{sort}";
+
+ # escape callback for href
+ $callback = $form->escape($callback);
+
+ foreach $ref (@{ $form->{project_list} }) {
+
+ $i++; $i %= 2;
+
+ print qq|
+ <tr valign=top class=listrow$i>
+|;
+
+ $column_data{projectnumber} = qq|<td><a href=$form->{script}?action=edit&type=$form->{type}&status=$form->{status}&id=$ref->{id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ref->{projectnumber}</td>|;
+ $column_data{description} = qq|<td>$ref->{description}&nbsp;</td>|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print "
+ </tr>
+";
+ }
+
+ print qq|
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<form method=post action=$form->{script}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=type value=$form->{type}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input class=submit type=submit name=action value="|.$locale->text('Add').qq|">
+
+</body>
+</html>
+|;
+
+}
+
+
+sub form_project_header {
+
+ $form->{title} = $locale->text("$form->{title} Project");
+
+# $locale->text('Add Project')
+# $locale->text('Edit Project')
+
+ $form->{description} =~ s/"/&quot;/g;
+
+ if (($rows = $form->numtextrows($form->{description}, 60)) > 1) {
+ $description = qq|<textarea name="description" rows=$rows cols=60 style="width: 100%" wrap=soft>$form->{description}</textarea>|;
+ } else {
+ $description = qq|<input name=description size=60 value="$form->{description}">|;
+ }
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=id value=$form->{id}>
+<input type=hidden name=type value=project>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Number').qq|</th>
+ <td><input name=projectnumber size=20 value="$form->{projectnumber}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Description').qq|</th>
+ <td>$description</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=2><hr size=3 noshade></td>
+ </tr>
+</table>
+|;
+
+}
+
+
+sub form_project_footer {
+
+ print qq|
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br><input type=submit class=submit name=action value="|.$locale->text('Save').qq|">
+|;
+
+ if ($form->{id} && $form->{orphaned}) {
+ print qq|
+<input type=submit class=submit name=action value="|.$locale->text('Delete').qq|">|;
+ }
+
+ print qq|
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub save {
+
+ if ($form->{type} eq 'project') {
+ $form->isblank("projectnumber", $locale->text('Project Number missing!'));
+ PE->save_project(\%myconfig, \%$form);
+ $form->redirect($locale->text('Project saved!'));
+ }
+ if ($form->{type} eq 'partsgroup') {
+ $form->isblank("partsgroup", $locale->text('Group missing!'));
+ PE->save_partsgroup(\%myconfig, \%$form);
+ $form->redirect($locale->text('Group saved!'));
+ }
+
+}
+
+
+sub delete {
+
+ PE->delete_tuple(\%myconfig, \%$form);
+
+ if ($form->{type} eq 'project') {
+ $form->redirect($locale->text('Project deleted!'));
+ }
+ if ($form->{type} eq 'partsgroup') {
+ $form->redirect($locale->text('Group deleted!'));
+ }
+
+}
+
+
+sub continue { &{ $form->{nextsub} } };
+
+
+sub partsgroup_report {
+
+ map { $form->{$_} = $form->unescape($form->{$_}) } (partsgroup);
+ PE->partsgroups(\%myconfig, \%$form);
+
+ $callback = "$form->{script}?action=partsgroup_report&type=$form->{type}&path=$form->{path}&login=$form->{login}&password=$form->{password}&status=$form->{status}";
+
+ if ($form->{status} eq 'all') {
+ $option = $locale->text('All');
+ }
+ if ($form->{status} eq 'orphaned') {
+ $option .= $locale->text('Orphaned');
+ }
+ if ($form->{partsgroup}) {
+ $callback .= "&partsgroup=$form->{partsgroup}";
+ $option .= "\n<br>".$locale->text('Group')." : $form->{partsgroup}";
+ }
+
+
+ @column_index = (partsgroup);
+
+ $column_header{partsgroup} = qq|<th class=listheading width=90%>|.$locale->text('Group').qq|</th>|;
+
+ $form->{title} = $locale->text('Groups');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$option</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+ map { print "$column_header{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ # escape callback
+ $form->{callback} = $callback;
+
+ # escape callback for href
+ $callback = $form->escape($callback);
+
+ foreach $ref (@{ $form->{item_list} }) {
+
+ $i++; $i %= 2;
+
+ print qq|
+ <tr valign=top class=listrow$i>
+|;
+
+
+ $column_data{partsgroup} = qq|<td><a href=$form->{script}?action=edit&type=$form->{type}&status=$form->{status}&id=$ref->{id}&path=$form->{path}&login=$form->{login}&password=$form->{password}&callback=$callback>$ref->{partsgroup}</td>|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print "
+ </tr>
+";
+ }
+
+ print qq|
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<form method=post action=$form->{script}>
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=type value=$form->{type}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input class=submit type=submit name=action value="|.$locale->text('Add').qq|">
+
+</body>
+</html>
+|;
+
+}
+
+
+sub form_partsgroup_header {
+
+ $form->{title} = $locale->text("$form->{title} Group");
+
+# $locale->text('Add Group')
+# $locale->text('Edit Group')
+
+ $form->{partsgroup} =~ s/"/&quot;/g;
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=id value=$form->{id}>
+<input type=hidden name=type value=$form->{type}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=right>|.$locale->text('Group').qq|</th>
+ <td><input name=partsgroup size=30 value="$form->{partsgroup}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=2><hr size=3 noshade></td>
+ </tr>
+</table>
+|;
+
+}
+
+
+sub form_partsgroup_footer {
+
+ print qq|
+
+<input name=callback type=hidden value="$form->{callback}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br><input type=submit class=submit name=action value="|.$locale->text('Save').qq|">
+|;
+
+ if ($form->{id} && $form->{orphaned}) {
+ print qq|
+<input type=submit class=submit name=action value="|.$locale->text('Delete').qq|">|;
+ }
+
+ print qq|
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
diff --git a/sql-ledger/bin/mozilla/rc.pl b/sql-ledger/bin/mozilla/rc.pl
new file mode 100644
index 0000000..cf2bc23
--- /dev/null
+++ b/sql-ledger/bin/mozilla/rc.pl
@@ -0,0 +1,371 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# Account reconciliation module
+#
+#======================================================================
+
+
+use SL::RC;
+
+
+1;
+# end of main
+
+
+sub reconciliation {
+
+ RC->paymentaccounts(\%myconfig, \%$form);
+
+ $selection = "";
+ map { $selection .= "<option>$_->{accno}--$_->{description}\n" } @{ $form->{PR} };
+
+ $form->{title} = $locale->text('Reconciliation');
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Account').qq|</th>
+ <td colspan=3><select name=accno>$selection</select>
+ </td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('From').qq|</th>
+ <td><input name=fromdate size=11 title="$myconfig{dateformat}"></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=todate size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<input type=hidden name=nextsub value=get_payments>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input type=submit class=submit name=action value="|.$locale->text('Continue').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub continue { &{ $form->{nextsub} } };
+
+
+sub get_payments {
+
+ ($form->{accno}, $form->{account}) = split /--/, $form->{accno};
+
+ RC->payment_transactions(\%myconfig, \%$form);
+
+ &display_form;
+
+}
+
+
+sub display_form {
+
+ @column_index = qw(cleared transdate source name credit debit balance);
+
+ $column_header{cleared} = "<th class=listheading>&nbsp;</th>";
+ $column_header{source} = "<th class=listheading>".$locale->text('Source')."</a></th>";
+ $column_header{name} = "<th class=listheading>".$locale->text('Description')."</a></th>";
+ $column_header{transdate} = "<th class=listheading>".$locale->text('Date')."</a></th>";
+
+ $column_header{debit} = "<th class=listheading>".$locale->text('Deposit')."</a></th>";
+ $column_header{credit} = "<th class=listheading>".$locale->text('Payment')."</a></th>";
+
+ $column_header{balance} = "<th class=listheading>".$locale->text('Balance')."</a></th>";
+
+ if ($form->{fromdate}) {
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('From')."&nbsp;".$locale->date(\%myconfig, $form->{fromdate}, 1);
+ }
+ if ($form->{todate}) {
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('to')."&nbsp;".$locale->date(\%myconfig, $form->{todate}, 1);
+ }
+
+ $form->{title} = "$form->{accno}--$form->{account}";
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$option</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+|;
+
+ map { print "\n$column_header{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ $form->{beginningbalance} *= -1;
+ $clearedbalance = $balance = $form->{beginningbalance};
+ $i = 0;
+ $id = 0;
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } qw(cleared transdate source name debit credit);
+ $column_data{balance} = "<td align=right>".$form->format_amount(\%myconfig, $balance, 2, 0)."</td>";
+ $j = 0;
+ print qq|
+ <tr class=listrow$j>
+|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+
+ foreach $ref (@{ $form->{PR} }) {
+
+ $balance += $ref->{amount} * -1;
+ $cleared += $ref->{amount} * -1 if $ref->{cleared};
+
+ $column_data{name} = "<td>$ref->{name}&nbsp;</td>";
+ $column_data{source} = qq|<td>$ref->{source}&nbsp;</a>
+ </td>|;
+ $column_data{transdate} = "<td>$ref->{transdate}&nbsp;</td>";
+
+ $column_data{debit} = "<td>&nbsp;</td>";
+ $column_data{credit} = "<td>&nbsp;</td>";
+
+ if ($ref->{amount} < 0) {
+ $totaldebits += $ref->{amount} * -1;
+ $column_data{debit} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{amount} * -1, 2, "&nbsp;")."</td>";
+ } else {
+ $totalcredits += $ref->{amount};
+ $column_data{credit} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{amount}, 2, "&nbsp;")."</td>";
+ }
+
+ $column_data{balance} = "<td align=right>".$form->format_amount(\%myconfig, $balance, 2, 0)."</td>";
+
+ if ($ref->{fx_transaction}) {
+ $i++ unless $id == $ref->{id};
+ $fx_transaction = 1;
+ $fx += $ref->{amount} * -1;
+ $column_data{cleared} = qq|<td align=center>&nbsp;
+ <input type=hidden name="fxoid_$i" value=$ref->{oid}>
+ </td>|;
+ } else {
+ $i++ unless ($fx_transaction && $id == $ref->{id});
+ $fx_transaction = 0;
+ $column_data{cleared} = qq|<td>
+ <input name="cleared_$i" type=checkbox class=checkbox value=1 $ref->{cleared}>
+ <input type=hidden name="oid_$i" value=$ref->{oid}>
+ </td>|;
+ }
+ $id = $ref->{id};
+
+ $j++; $j %= 2;
+ print qq|
+ <tr class=listrow$j>
+|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ }
+
+ # print totals
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{debit} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totaldebits, 2, "&nbsp;")."</th>";
+ $column_data{credit} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalcredits, 2, "&nbsp;")."</th>";
+
+ print qq|
+ <tr class=listtotal>
+|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ $form->{statementbalance} = $form->parse_amount(\%myconfig, $form->{statementbalance});
+ $difference = $form->format_amount(\%myconfig, $form->{statementbalance} - $clearedbalance - $cleared, 2, 0);
+
+ $form->{statementbalance} = $form->format_amount(\%myconfig, $form->{statementbalance}, 2, 0);
+
+ $clearedbalance = $form->format_amount(\%myconfig, $clearedbalance, 2, 0);
+
+ if ($fx) {
+ $fx = $form->format_amount(\%myconfig, $fx, 2, 0);
+ $exchdiff = qq|
+ <th align=right nowrap>|.$locale->text('Exchangerate Difference').qq|</th>
+ <td width=10%></td>
+ <td align=right>$fx</td>
+|;
+ }
+
+ print qq|
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Cleared Balance').qq|</th>
+ <td width=10%></td>
+ <td align=right>$clearedbalance</td>
+ </tr>
+ <tr>
+ $exchdiff
+ </tr>
+ </table>
+ </td>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Statement Balance').qq|</th>
+ <td width=10%></td>
+ <td align=right><input name=statementbalance size=11 value=$form->{statementbalance}></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Difference').qq|</th>
+ <td width=10%></td>
+ <td align=right><input name=none size=11 value=$difference></td>
+ <input type=hidden name=difference value=$difference>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=rowcount value=$i>
+<input type=hidden name=accno value=$form->{accno}>
+<input type=hidden name=account value="$form->{account}">
+
+<input type=hidden name=fromdate value=$form->{fromdate}>
+<input type=hidden name=todate value=$form->{todate}>
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input type=submit class=submit name=action value="|.$locale->text('Update').qq|">
+<input type=submit class=submit name=action value="|.$locale->text('Select all').qq|">
+<input type=submit class=submit name=action value="|.$locale->text('Done').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub update {
+
+ RC->payment_transactions(\%myconfig, \%$form);
+
+ foreach $ref (@{ $form->{PR} }) {
+ if (!$ref->{fx_transaction}) {
+ $i++;
+ $ref->{cleared} = "checked" if $form->{"cleared_$i"};
+ }
+ }
+
+ &display_form;
+
+}
+
+
+sub select_all {
+
+ RC->payment_transactions(\%myconfig, \%$form);
+
+ map { $_->{cleared} = "checked" unless $_->{fx_transaction} } @{ $form->{PR} };
+
+ &display_form;
+
+}
+
+
+sub done {
+
+ $form->{callback} = "$form->{script}?path=$form->{path}&action=reconciliation&login=$form->{login}&password=$form->{password}";
+
+ $form->error($locale->text('Out of balance!')) if ($form->{difference} *= 1);
+
+ RC->reconcile(\%myconfig, \%$form);
+ $form->redirect;
+
+}
+
+
diff --git a/sql-ledger/bin/mozilla/rp.pl b/sql-ledger/bin/mozilla/rp.pl
new file mode 100644
index 0000000..41cff8c
--- /dev/null
+++ b/sql-ledger/bin/mozilla/rp.pl
@@ -0,0 +1,1730 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (c) 1998-2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors: Antonio Gallardo <agssa@ibw.com.ni>
+# Benjamin Lee <benjaminlee@consultant.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# module for preparing Income Statement and Balance Sheet
+#
+#======================================================================
+
+
+use SL::RP;
+
+1;
+# end of main
+
+# this is for our long dates
+# $locale->text('January')
+# $locale->text('February')
+# $locale->text('March')
+# $locale->text('April')
+# $locale->text('May ')
+# $locale->text('June')
+# $locale->text('July')
+# $locale->text('August')
+# $locale->text('September')
+# $locale->text('October')
+# $locale->text('November')
+# $locale->text('December')
+
+# this is for our short month
+# $locale->text('Jan')
+# $locale->text('Feb')
+# $locale->text('Mar')
+# $locale->text('Apr')
+# $locale->text('May')
+# $locale->text('Jun')
+# $locale->text('Jul')
+# $locale->text('Aug')
+# $locale->text('Sep')
+# $locale->text('Oct')
+# $locale->text('Nov')
+# $locale->text('Dec')
+
+# $locale->text('Balance Sheet')
+# $locale->text('Income Statement')
+# $locale->text('Trial Balance')
+# $locale->text('AR Aging')
+# $locale->text('AP Aging')
+# $locale->text('Tax collected')
+# $locale->text('Tax paid')
+# $locale->text('Receipts')
+# $locale->text('Payments')
+
+
+sub report {
+
+ %title = ( 'balance_sheet' => 'Balance Sheet',
+ 'income_statement' => 'Income Statement',
+ 'trial_balance' => 'Trial Balance',
+ 'ar_aging' => 'AR Aging',
+ 'ap_aging' => 'AP Aging',
+ 'tax_collected' => 'Tax collected',
+ 'tax_paid' => 'Tax paid',
+ 'receipts' => 'Receipts',
+ 'payments' => 'Payments',
+ );
+
+ $form->{title} = $locale->text($title{$form->{report}});
+
+ $form->header;
+
+ $gifi = qq|
+<tr>
+ <th align=right>|.$locale->text('Accounts').qq|</th>
+ <td><input name=accounttype class=radio type=radio value=standard checked> |.$locale->text('Standard').qq|
+
+ <input name=accounttype class=radio type=radio value=gifi> |.$locale->text('GIFI').qq|
+ </td>
+</tr>
+|;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<input type=hidden name=title value="$form->{title}">
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table>
+|;
+
+ if ($form->{report} eq "income_statement") {
+ print qq|
+ <input type=hidden name=nextsub value=generate_income_statement>
+ <tr>
+ <th align=right>|.$locale->text('From').qq|</th>
+ <td><input name=fromdate size=11 title="$myconfig{dateformat}" value=$form->{fromdate}></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=todate size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <tr>
+ <th colspan=4>|.$locale->text('Compare to').qq|</th>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('From').qq|</th>
+ <td><input name=comparefromdate size=11 title="$myconfig{dateformat}"></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=comparetodate size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Decimalplaces').qq|</th>
+ <td><input name=decimalplaces size=3 maxsize=1></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Include in Report').qq|</th>
+ <td colspan=3><input name=l_heading class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Heading').qq|</td>
+ <td><input name=l_subtotal class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Subtotal').qq|</td>
+ </tr>
+|;
+ }
+
+
+ if ($form->{report} eq "balance_sheet") {
+ print qq|
+ <input type=hidden name=nextsub value=generate_balance_sheet>
+ <tr>
+ <th align=right>|.$locale->text('as at').qq|</th>
+ <td><input name=asofdate size=11 title="$myconfig{dateformat}" value=$form->{asofdate}></td>
+ <th align=right nowrap>|.$locale->text('Compare to').qq|</th>
+ <td><input name=compareasofdate size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Decimalplaces').qq|</th>
+ <td><input name=decimalplaces size=3 maxsize=1></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Include in Report').qq|</th>
+ <td><input name=l_heading class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Heading').qq|</td>
+ <td><input name=l_subtotal class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Subtotal').qq|</td>
+ </tr>
+|;
+ }
+
+
+ if ($form->{report} eq "trial_balance") {
+ print qq|
+ <input type=hidden name=nextsub value=generate_trial_balance>
+ <tr>
+ <th align=right>|.$locale->text('From').qq|</th>
+ <td><input name=fromdate size=11 title="$myconfig{dateformat}" value=$form->{fromdate}></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=todate size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Include in Report').qq|</th>
+ <td><input name=l_heading class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Heading').qq|
+ <input name=l_subtotal class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Subtotal').qq|</td>
+ </tr>
+|;
+ }
+
+
+ if (($form->{report} eq "tax_paid") || ($form->{report} eq "tax_collected")) {
+ $gifi = "";
+
+ $form->{db} = ($form->{report} eq "tax_collected") ? "ar" : "ap";
+
+ RP->get_taxaccounts(\%myconfig, \%$form);
+
+ print qq|
+ <input type=hidden name=nextsub value=generate_tax_report>
+ <tr>
+ <th align=right>|.$locale->text('From').qq|</th>
+ <td><input name=fromdate size=11 title="$myconfig{dateformat}" value=$form->{fromdate}></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=todate size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Cash based').qq|</th>
+ <td><input name=cashbased class=checkbox type=checkbox value=Y></td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('Report for').qq|</th>
+ <td>
+|;
+
+ $checked = "checked";
+ foreach $item (@{ $form->{taxaccounts} }) {
+ ($accno, $description) = split /--/, $item;
+
+ print qq|<input name=accno class=radio type=radio value=$accno $checked>&nbsp;$description
+
+ <input name="${accno}_description" type=hidden value="$description">|;
+
+ $checked = "";
+ }
+
+ print qq|
+ <input type=hidden name=db value=$form->{db}>
+ <input type=hidden name=sort value=transdate>
+
+ </td>
+ </tr>
+|;
+
+
+ if (@{ $form->{gifi_taxaccounts} }) {
+ print qq|
+ <tr>
+ <th align=right>|.$locale->text('GIFI').qq|</th>
+ <td>
+|;
+
+ foreach $item (@{ $form->{gifi_taxaccounts} }) {
+ ($accno, $description) = split /--/, $item;
+
+ print qq|<input name=accno class=radio type=radio value="gifi_$accno" $checked>&nbsp;$description
+
+ <input name="gifi_${accno}_description" type=hidden value="$description">|;
+
+ }
+
+ print qq|
+ </td>
+ </tr>
+|;
+ }
+
+
+print qq|
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <th align=right>|.$locale->text('Include in Report').qq|</th>
+ <td>
+ <table>
+ <tr>
+ <td><input name="l_id" class=checkbox type=checkbox value=Y></td>
+ <td>|.$locale->text('ID').qq|</td>
+ <td><input name="l_invnumber" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Invoice').qq|</td>
+ <td><input name="l_transdate" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Date').qq|</td>
+ </tr>
+ <tr>
+ <td><input name="l_name" class=checkbox type=checkbox value=Y checked></td>
+ <td>|;
+
+ if ($form->{db} eq 'ar') {
+ print $locale->text('Customer');
+ }
+ if ($form->{db} eq 'ap') {
+ print $locale->text('Vendor');
+ }
+
+ print qq|</td>
+ <td><input name="l_netamount" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Amount').qq|</td>
+ <td><input name="l_tax" class=checkbox type=checkbox value=Y checked></td>
+ <td>|.$locale->text('Tax').qq|</td>
+ <td><input name="l_amount" class=checkbox type=checkbox value=Y></td>
+ <td>|.$locale->text('Total').qq|</td>
+ </tr>
+ <tr>
+ <td><input name="l_subtotal" class=checkbox type=checkbox value=Y></td>
+ <td>|.$locale->text('Subtotal').qq|</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+|;
+
+ }
+
+
+ if (($form->{report} eq "ar_aging") || ($form->{report} eq "ap_aging")) {
+ $gifi = "";
+
+ if ($form->{report} eq 'ar_aging') {
+ $label = $locale->text('Customer');
+ $form->{vc} = 'customer';
+ } else {
+ $label = $locale->text('Vendor');
+ $form->{vc} = 'vendor';
+ }
+
+ $nextsub = "generate_$form->{report}";
+
+ # setup vc selection
+ $form->all_vc(\%myconfig, $form->{vc});
+
+ map { $vc .= "<option>$_->{name}--$_->{id}\n" } @{ $form->{"all_$form->{vc}"} };
+
+ $vc = ($vc) ? qq|<select name=$form->{vc}><option>\n$vc</select>| : qq|<input name=$form->{vc} size=35>|;
+
+ print qq|
+ <tr>
+ <th align=right>|.$locale->text($label).qq|</th>
+ <td>$vc</td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=todate size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <input type=hidden name=type value=statement>
+ <input type=hidden name=format value=html>
+ <input type=hidden name=media value=screen>
+
+ <input type=hidden name=nextsub value=$nextsub>
+ <input type=hidden name=action value=$nextsub>
+|;
+ }
+
+# above action can be removed if there is more than one input field
+
+
+ if (($form->{report} eq "receipts") || ($form->{report} eq "payments")) {
+ $gifi = "";
+
+ $form->{db} = ($form->{report} eq "receipts") ? "ar" : "ap";
+
+ RP->paymentaccounts(\%myconfig, \%$form);
+
+ $selection = "<option>\n";
+ foreach $ref (@{ $form->{PR} }) {
+ $paymentaccounts .= "$ref->{accno} ";
+ $selection .= "<option>$ref->{accno}--$ref->{description}\n";
+ }
+
+ chop $paymentaccounts;
+
+ print qq|
+ <input type=hidden name=nextsub value=list_payments>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Account').qq|</th>
+ <td colspan=3><select name=account>$selection</select>
+ <input type=hidden name=paymentaccounts value="$paymentaccounts">
+ </td>
+ </tr>
+ <tr>
+ <th align=right>|.$locale->text('From').qq|</th>
+ <td><input name=fromdate size=11 title="$myconfig{dateformat}" value=$form->{fromdate}></td>
+ <th align=right>|.$locale->text('to').qq|</th>
+ <td><input name=todate size=11 title="$myconfig{dateformat}"></td>
+ </tr>
+ <input type=hidden name=db value=$form->{db}>
+ <input type=hidden name=sort value=transdate>
+|;
+
+ }
+
+
+ print qq|
+
+$gifi
+
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<br>
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<input type=submit class=submit name=action value="|.$locale->text('Continue').qq|">
+
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub continue { &{$form->{nextsub}} };
+
+
+sub generate_income_statement {
+
+ $form->{padding} = "&nbsp;&nbsp;";
+ $form->{bold} = "<b>";
+ $form->{endbold} = "</b>";
+ $form->{br} = "<br>";
+
+ RP->income_statement(\%myconfig, \%$form);
+
+
+ $form->{period} = $locale->date(\%myconfig, $form->current_date(\%myconfig), 1);
+ $form->{todate} = $form->current_date(\%myconfig) unless $form->{todate};
+
+ # if there are any dates construct a where
+ if ($form->{fromdate} || $form->{todate}) {
+
+ unless ($form->{todate}) {
+ $form->{todate} = $form->current_date(\%myconfig);
+ }
+
+ $longtodate = $locale->date(\%myconfig, $form->{todate}, 1);
+ $shorttodate = $locale->date(\%myconfig, $form->{todate});
+
+ $longfromdate = $locale->date(\%myconfig, $form->{fromdate}, 1);
+ $shortfromdate = $locale->date(\%myconfig, $form->{fromdate});
+
+ $form->{this_period} = "$shortfromdate<br>\n$shorttodate";
+ $form->{period} = $locale->text('for Period').qq|<br>\n$longfromdate |.$locale->text('to').qq| $longtodate|;
+ }
+
+ if ($form->{comparefromdate} || $form->{comparetodate}) {
+ $longcomparefromdate = $locale->date(\%myconfig, $form->{comparefromdate}, 1);
+ $shortcomparefromdate = $locale->date(\%myconfig, $form->{comparefromdate});
+
+ $longcomparetodate = $locale->date(\%myconfig, $form->{comparetodate}, 1);
+ $shortcomparetodate = $locale->date(\%myconfig, $form->{comparetodate});
+
+ $form->{last_period} = "$shortcomparefromdate<br>\n$shortcomparetodate";
+ $form->{period} .= "<br>\n$longcomparefromdate ".$locale->text('to').qq| $longcomparetodate|;
+ }
+
+
+ # setup variables for the form
+ @a = qw(company address businessnumber);
+ map { $form->{$_} = $myconfig{$_} } @a;
+ $form->{address} =~ s/\\n/<br>/g;
+
+ $form->{templates} = $myconfig{templates};
+
+ $form->{IN} = "income_statement.html";
+
+ $form->parse_template;
+
+}
+
+
+sub generate_balance_sheet {
+
+ $form->{padding} = "&nbsp;&nbsp;";
+ $form->{bold} = "<b>";
+ $form->{endbold} = "</b>";
+ $form->{br} = "<br>";
+
+ RP->balance_sheet(\%myconfig, \%$form);
+
+ $form->{asofdate} = $form->current_date(\%myconfig) unless $form->{asofdate};
+ $form->{period} = $locale->date(\%myconfig, $form->current_date(\%myconfig), 1);
+
+ # define Retained Earnings account
+ $padding = ($form->{l_heading}) ? $form->{padding} : "";
+ push(@{$form->{equity_account}}, $padding.$locale->text('Retained Earnings'));
+
+ $form->{this_period} = $locale->date(\%myconfig, $form->{asofdate});
+ $form->{last_period} = $locale->date(\%myconfig, $form->{compareasofdate});
+
+ $form->{IN} = "balance_sheet.html";
+
+ # setup company variables for the form
+ map { $form->{$_} = $myconfig{$_} } (qw(company address businessnumber nativecurr));
+ $form->{address} =~ s/\\n/<br>/g;
+
+ $form->{templates} = $myconfig{templates};
+
+ $form->parse_template;
+
+}
+
+
+# Antonio Gallardo
+#
+# D.S. Feb 16, 2001
+# included links to display transactions for period entered
+# added headers and subtotals
+#
+sub generate_trial_balance {
+
+ # get for each account initial balance, debits and credits
+ RP->trial_balance_details(\%myconfig, \%$form);
+
+ $form->{nextsub} = "generate_trial_balance";
+ $form->{title} = $locale->text('Trial Balance');
+ &list_accounts;
+
+}
+
+
+sub list_accounts {
+
+ $title = $form->escape($form->{title});
+
+ if ($form->{projectnumber}) {
+ $options .= $locale->text('Project Number')." : $form->{projectnumber}<br>";
+ $projectnumber = $form->escape($form->{projectnumber});
+ }
+
+ # if there are any dates
+ if ($form->{fromdate} || $form->{todate}) {
+ if ($form->{fromdate}) {
+ $fromdate = $locale->date(\%myconfig, $form->{fromdate}, 1);
+ }
+ if ($form->{todate}) {
+ $todate = $locale->date(\%myconfig, $form->{todate}, 1);
+ }
+
+ $form->{period} = "$fromdate - $todate";
+ } else {
+ $form->{period} = $locale->date(\%myconfig, $form->current_date(\%myconfig), 1);
+ }
+
+ $options .= $form->{period};
+
+ @column_index = qw(accno description begbalance debit credit endbalance);
+
+ $column_header{accno} = qq|<th class=listheading>|.$locale->text('Account').qq|</th>|;
+ $column_header{description} = qq|<th class=listheading>|.$locale->text('Description').qq|</th>|;
+ $column_header{debit} = qq|<th class=listheading>|.$locale->text('Debit').qq|</th>|;
+ $column_header{credit} = qq|<th class=listheading>|.$locale->text('Credit').qq|</th>|;
+ $column_header{begbalance} = qq|<th class=listheading>|.$locale->text('Balance').qq|</th>|;
+ $column_header{endbalance} = qq|<th class=listheading>|.$locale->text('Balance').qq|</th>|;
+
+
+ if ($form->{accounttype} eq 'gifi') {
+ $column_header{accno} = qq|<th class=listheading>|.$locale->text('GIFI').qq|</th>|;
+ }
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$options</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>|;
+
+ map { print "$column_header{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+
+
+ # sort the whole thing by account numbers and display
+ foreach $ref (sort { $a->{accno} cmp $b->{accno} } @{ $form->{TB} }) {
+
+ $description = $form->escape($ref->{description});
+
+ $href = qq|ca.pl?path=$form->{path}&action=list_transactions&accounttype=$form->{accounttype}&login=$form->{login}&password=$form->{password}&fromdate=$form->{fromdate}&todate=$form->{todate}&sort=transdate&l_heading=$form->{l_heading}&l_subtotal=$form->{l_subtotal}&projectnumber=$projectnumber&project_id=$form->{project_id}&title=$title&nextsub=$form->{nextsub}|;
+
+ if ($form->{accounttype} eq 'gifi') {
+ $href .= "&gifi_accno=$ref->{accno}&gifi_description=$description";
+ $na = $locale->text('N/A');
+ map { $ref->{$_} = $na } qw(accno description) unless $ref->{accno};
+ } else {
+ $href .= "&accno=$ref->{accno}&description=$description";
+ }
+
+ $ml = ($ref->{category} =~ /(A|E)/) ? -1 : 1;
+
+ $debit = $form->format_amount(\%myconfig, $ref->{debit}, 2, "&nbsp;");
+ $credit = $form->format_amount(\%myconfig, $ref->{credit}, 2, "&nbsp;");
+ $begbalance = $form->format_amount(\%myconfig, $ref->{balance} * $ml, 2, "&nbsp;");
+ $endbalance = $form->format_amount(\%myconfig, ($ref->{balance} + $ref->{amount}) * $ml, 2, "&nbsp;");
+
+ next if ($ref->{debit} == 0 && $ref->{credit} == 0);
+
+ if ($ref->{charttype} eq "H" && $subtotal && $form->{l_subtotal}) {
+ map { $column_data{$_} = "<th>&nbsp;</th>" } qw(accno begbalance endbalance);
+
+ $subtotalbegbalance = $form->format_amount(\%myconfig, $subtotalbegbalance, 2, "&nbsp;");
+ $subtotalendbalance = $form->format_amount(\%myconfig, $subtotalendbalance, 2, "&nbsp;");
+ $subtotaldebit = $form->format_amount(\%myconfig, $subtotaldebit, 2, "&nbsp;");
+ $subtotalcredit = $form->format_amount(\%myconfig, $subtotalcredit, 2, "&nbsp;");
+ $column_data{description} = "<th>$subtotaldescription</th>";
+ $column_data{begbalance} = "<th align=right>$subtotalbegbalance</th>";
+ $column_data{endbalance} = "<th align=right>$subtotalendbalance</th>";
+ $column_data{debit} = "<th align=right>$subtotaldebit</th>";
+ $column_data{credit} = "<th align=right>$subtotalcredit</th>";
+
+ print qq|
+ <tr class=listsubtotal>
+|;
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+ }
+
+ if ($ref->{charttype} eq "H") {
+ $subtotal = 1;
+ $subtotaldescription = $ref->{description};
+ $subtotaldebit = $ref->{debit};
+ $subtotalcredit = $ref->{credit};
+ $subtotalbegbalance = 0;
+ $subtotalendbalance = 0;
+
+ next unless $form->{l_heading};
+
+ map { $column_data{$_} = "<th>&nbsp;</th>" } qw(accno debit credit begbalance endbalance);
+ $column_data{description} = "<th class=listheading>$ref->{description}</th>";
+ }
+
+ if ($ref->{charttype} eq "A") {
+ $column_data{accno} = "<td><a href=$href>$ref->{accno}</a></td>";
+ $column_data{description} = "<td>$ref->{description}</td>";
+ $column_data{debit} = "<td align=right>$debit</td>";
+ $column_data{credit} = "<td align=right>$credit</td>";
+ $column_data{begbalance} = "<td align=right>$begbalance</td>";
+ $column_data{endbalance} = "<td align=right>$endbalance</td>";
+
+ $totaldebit += $ref->{debit};
+ $totalcredit += $ref->{credit};
+
+ $subtotalbegbalance += $ref->{balance} * $ml;
+ $subtotalendbalance += ($ref->{balance} + $ref->{amount}) * $ml;
+
+ }
+
+ if ($ref->{charttype} eq "H") {
+ print qq|
+ <tr class=listheading>
+|;
+ }
+ if ($ref->{charttype} eq "A") {
+ $i++; $i %= 2;
+ print qq|
+ <tr class=listrow$i>
+|;
+ }
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+ }
+
+
+ # print last subtotal
+ if ($subtotal && $form->{l_subtotal}) {
+ map { $column_data{$_} = "<th>&nbsp;</th>" } qw(accno begbalance endbalance);
+ $subtotalbegbalance = $form->format_amount(\%myconfig, $subtotalbegbalance, 2, "&nbsp;");
+ $subtotalendbalance = $form->format_amount(\%myconfig, $subtotalendbalance, 2, "&nbsp;");
+ $subtotaldebit = $form->format_amount(\%myconfig, $subtotaldebit, 2, "&nbsp;");
+ $subtotalcredit = $form->format_amount(\%myconfig, $subtotalcredit, 2, "&nbsp;");
+ $column_data{description} = "<th>$subdescription</th>";
+ $column_data{begbalance} = "<th align=right>$subtotalbegbalance</th>";
+ $column_data{endbalance} = "<th align=right>$subtotalendbalance</th>";
+ $column_data{debit} = "<th align=right>$subtotaldebit</th>";
+ $column_data{credit} = "<th align=right>$subtotalcredit</th>";
+
+ print qq|
+ <tr class=listsubtotal>
+|;
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+ }
+
+ $totaldebit = $form->format_amount(\%myconfig, $totaldebit, 2, "&nbsp;");
+ $totalcredit = $form->format_amount(\%myconfig, $totalcredit, 2, "&nbsp;");
+
+ map { $column_data{$_} = "<th>&nbsp;</th>" } qw(accno description begbalance endbalance);
+
+ $column_data{debit} = qq|<th align=right class=listtotal>$totaldebit</th>|;
+ $column_data{credit} = qq|<th align=right class=listtotal>$totalcredit</th>|;
+
+ print qq|
+ <tr class=listtotal>
+|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+</body>
+</html>
+|;
+
+}
+
+
+
+sub generate_ar_aging {
+
+ # split customer
+ ($form->{customer}) = split(/--/, $form->{customer});
+
+ $form->{ct} = "customer";
+ $form->{arap} = "ar";
+
+ $form->{callback} = qq|$form->{script}?path=$form->{path}&action=generate_ar_aging&login=$form->{login}&password=$form->{password}&todate=$form->{todate}&customer=|.$form->escape($form->{customer});
+
+ RP->aging(\%myconfig, \%$form);
+ &aging;
+
+}
+
+
+sub generate_ap_aging {
+
+ # split vendor
+ ($form->{vendor}) = split(/--/, $form->{vendor});
+
+ $form->{ct} = "vendor";
+ $form->{arap} = "ap";
+
+ $form->{callback} = qq|$form->{script}?path=$form->{path}&action=generate_ap_aging&login=$form->{login}&password=$form->{password}&todate=$form->{todate}&vendor=|.$form->escape($form->{vendor});
+
+ RP->aging(\%myconfig, \%$form);
+ &aging;
+
+}
+
+
+sub aging {
+
+
+ $form->header;
+
+ $column_header{statement} = qq|<th class=listheading>&nbsp;</th>|;
+ $column_header{ct} = qq|<th class=listheading>|.$locale->text(ucfirst $form->{ct}).qq|</th>|;
+ $column_header{invnumber} = qq|<th class=listheading>|.$locale->text('Invoice').qq|</th>|;
+ $column_header{transdate} = qq|<th class=listheading>|.$locale->text('Date').qq|</th>|;
+ $column_header{duedate} = qq|<th class=listheading>|.$locale->text('Due').qq|</th>|;
+ $column_header{c0} = qq|<th class=listheading>|.$locale->text('Current').qq|</th>|;
+ $column_header{c30} = qq|<th class=listheading>30</th>|;
+ $column_header{c60} = qq|<th class=listheading>60</th>|;
+ $column_header{c90} = qq|<th class=listheading>90</th>|;
+
+ @column_index = (qw(statement ct invnumber transdate duedate c0 c30 c60 c90));
+
+
+ if ($form->{arap} eq 'ar') {
+ if ($form->{customer}) {
+ $option .= "\n<br>" if $option;
+ $option .= $form->{customer};
+ }
+ }
+ if ($form->{arap} eq 'ap') {
+ shift @column_index;
+ if ($form->{vendor}) {
+ $option .= "\n<br>" if $option;
+ $option .= $form->{vendor};
+ }
+ }
+
+ $todate = $locale->date(\%myconfig, $form->{todate}, 1);
+ $option .= "\n<br>" if $option;
+ $option .= $locale->text('for Period')." ".$locale->text('to')." $todate";
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$option</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+ map { print "$column_header{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+
+ $ctid = 0;
+ $subtotal = 0;
+ $i = 0;
+
+ foreach $ref (@{ $form->{AG} }) {
+
+ if ($ctid != $ref->{ctid}) {
+
+ $i++;
+
+ if ($subtotal) {
+ $c0subtotal = $form->format_amount(\%myconfig, $c0subtotal, 2, "&nbsp");
+ $c30subtotal = $form->format_amount(\%myconfig, $c30subtotal, 2, "&nbsp");
+ $c60subtotal = $form->format_amount(\%myconfig, $c60subtotal, 2, "&nbsp");
+ $c90subtotal = $form->format_amount(\%myconfig, $c90subtotal, 2, "&nbsp");
+ }
+
+ $column_data{ct} = qq|<th>&nbsp;</th>|;
+ $column_data{invnumber} = qq|<th>&nbsp;</th>|;
+ $column_data{transdate} = qq|<th>&nbsp;</th>|;
+ $column_data{duedate} = qq|<th>&nbsp;</th>|;
+ $column_data{c0} = qq|<th class=listsubtotal align=right>$c0subtotal</th>|;
+ $column_data{c30} = qq|<th class=listsubtotal align=right>$c30subtotal</th>|;
+ $column_data{c60} = qq|<th class=listsubtotal align=right>$c60subtotal</th>|;
+ $column_data{c90} = qq|<th class=listsubtotal align=right>$c90subtotal</th>|;
+
+ if ($subtotal) {
+ # print subtotals
+ print qq|
+ <tr class=listsubtotal>
+|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ $column_data{statement} = qq|<td>&nbsp;</td>|;
+
+ print qq|
+ </tr>
+|;
+ }
+
+ $subtotal = 1;
+
+ $c0subtotal = 0;
+ $c30subtotal = 0;
+ $c60subtotal = 0;
+ $c90subtotal = 0;
+
+ $column_data{ct} = qq|<td>$ref->{name}</td>|;
+ $column_data{statement} = qq|<td><input name="statement_$i" type=checkbox class=checkbox value=1 $ref->{checked}>
+ <input type=hidden name="$form->{ct}_id_$i" value=$ref->{ctid}>
+ </td>|;
+ }
+
+ $c0subtotal += $ref->{c0};
+ $c30subtotal += $ref->{c30};
+ $c60subtotal += $ref->{c60};
+ $c90subtotal += $ref->{c90};
+
+ $c0total += $ref->{c0};
+ $c30total += $ref->{c30};
+ $c60total += $ref->{c60};
+ $c90total += $ref->{c90};
+
+ $ref->{c0} = $form->format_amount(\%myconfig, $ref->{c0}, 2, "&nbsp;");
+ $ref->{c30} = $form->format_amount(\%myconfig, $ref->{c30}, 2, "&nbsp;");
+ $ref->{c60} = $form->format_amount(\%myconfig, $ref->{c60}, 2, "&nbsp;");
+ $ref->{c90} = $form->format_amount(\%myconfig, $ref->{c90}, 2, "&nbsp;");
+
+ $href = qq|$ref->{module}.pl?path=$form->{path}&action=edit&id=$ref->{id}&login=$form->{login}&password=$form->{password}&callback=|.$form->escape($form->{callback});
+
+ $column_data{invnumber} = qq|<td><a href=$href>$ref->{invnumber}</a></td>|;
+ $column_data{transdate} = qq|<td>$ref->{transdate}</td>|;
+ $column_data{duedate} = qq|<td>$ref->{duedate}&nbsp;</td>|;
+ $column_data{c0} = qq|<td align=right>$ref->{c0}</td>|;
+ $column_data{c30} = qq|<td align=right>$ref->{c30}</td>|;
+ $column_data{c60} = qq|<td align=right>$ref->{c60}</td>|;
+ $column_data{c90} = qq|<td align=right>$ref->{c90}</td>|;
+
+ $j++; $j %= 2;
+ print qq|
+ <tr class=listrow$j>
+|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ $column_data{ct} = qq|<td>&nbsp;</td>|;
+ $column_data{statement} = qq|<td>&nbsp;</td>|;
+
+ $ctid = $ref->{ctid};
+
+ }
+
+ # print subtotals
+ $c0subtotal = $form->format_amount(\%myconfig, $c0subtotal, 2, "&nbsp;");
+ $c30subtotal = $form->format_amount(\%myconfig, $c30subtotal, 2, "&nbsp;");
+ $c60subtotal = $form->format_amount(\%myconfig, $c60subtotal, 2, "&nbsp;");
+ $c90subtotal = $form->format_amount(\%myconfig, $c90subtotal, 2, "&nbsp;");
+
+ print qq|
+ <tr class=listsubtotal>
+|;
+
+ map { $column_data{$_} = qq|<th>&nbsp;</th>| } @column_index;
+
+ $column_data{c0} = qq|<th class=listsubtotal align=right>$c0subtotal</th>|;
+ $column_data{c30} = qq|<th class=listsubtotal align=right>$c30subtotal</th>|;
+ $column_data{c60} = qq|<th class=listsubtotal align=right>$c60subtotal</th>|;
+ $column_data{c90} = qq|<th class=listsubtotal align=right>$c90subtotal</th>|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+
+ print qq|
+ </tr>
+ <tr class=listtotal>
+|;
+
+ $c0total = $form->format_amount(\%myconfig, $c0total, 2, "&nbsp;");
+ $c30total = $form->format_amount(\%myconfig, $c30total, 2, "&nbsp;");
+ $c60total = $form->format_amount(\%myconfig, $c60total, 2, "&nbsp;");
+ $c90total = $form->format_amount(\%myconfig, $c90total, 2, "&nbsp;");
+
+ $column_data{c0} = qq|<th class=listtotal align=right>$c0total</th>|;
+ $column_data{c30} = qq|<th class=listtotal align=right>$c30total</th>|;
+ $column_data{c60} = qq|<th class=listtotal align=right>$c60total</th>|;
+ $column_data{c90} = qq|<th class=listtotal align=right>$c90total</th>|;
+
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+
+ print qq|
+ <input type=hidden name=rowcount value=$i>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+|;
+
+ &print_options if ($form->{arap} eq 'ar');
+
+ print qq|
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+|;
+
+ if ($form->{arap} eq 'ar') {
+ print qq|
+<input type=hidden name=todate value=$form->{todate}>
+
+<input type=hidden name=title value="$form->{title}">
+
+<input type=hidden name=arap value=$form->{arap}>
+<input type=hidden name=ct value=$form->{ct}>
+<input type=hidden name=$form->{ct} value="$form->{$form->{ct}}">
+
+<input type=hidden name=path value=$form->{path}>
+<input type=hidden name=login value=$form->{login}>
+<input type=hidden name=password value=$form->{password}>
+
+<br>
+<input class=submit type=submit name=action value="|.$locale->text('Select all').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('Print').qq|">
+<input class=submit type=submit name=action value="|.$locale->text('E-mail').qq|">
+|;
+ }
+
+ print qq|
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub select_all {
+
+ RP->aging(\%myconfig, \%$form);
+
+ map { $_->{checked} = "checked" } @{ $form->{AG} };
+
+ &aging;
+
+}
+
+
+sub print_options {
+
+ $form->{sendmode} = "attachment";
+ $form->{copies} = 2 unless $form->{copies};
+
+ $form->{PD}{$form->{type}} = "checked";
+ $form->{DF}{$form->{format}} = "checked";
+ $form->{OP}{$form->{media}} = "checked";
+ $form->{SM}{$form->{sendmode}} = "checked";
+
+
+ if ($form->{media} eq 'email') {
+ $email = qq|
+ <td><input class=radio type=radio name=sendmode value=attachment $form->{SM}{attachment}> |.$locale->text('Attachment')
+ .qq| <input class=radio type=radio name=sendmode value=inline $form->{SM}{inline}> |.$locale->text('In-line').qq|</td>
+|;
+ } else {
+ $screen = qq|
+ <td><input class=radio type=radio name=media value=screen $form->{OP}{screen}></td>
+ <td>|.$locale->text('Screen').qq|</td>
+|;
+ }
+
+ print qq|
+<table width=100%>
+ <tr valign=top>
+ <td><input class=radio type=radio name=type value=statement $form->{PD}{statement}></td><td>|.$locale->text('Statement').qq|</td>
+ <td><input class=radio type=radio name=format value=html $form->{DF}{html}></td>
+ <td>html</td>
+|;
+
+ if ($latex) {
+ print qq|
+ <td><input class=radio type=radio name=format value=postscript $form->{DF}{postscript}></td>
+ <td>|.$locale->text('Postscript').qq|</td>
+ <td><input class=radio type=radio name=format value=pdf $form->{DF}{pdf}></td>
+ <td>|.$locale->text('PDF').qq|</td>
+|;
+ }
+
+ print qq|
+ $screen
+|;
+
+ if ($screen) {
+ if ($myconfig{printer} && $latex) {
+ print qq|
+ <td><input class=radio type=radio name=media value=printer $form->{OP}{printer}></td>
+ <td>|.$locale->text('Printer')
+ .qq| (|.$locale->text('Copies')
+ .qq| <input name=copies size=2 value=$form->{copies}>)</td>
+|;
+ }
+ }
+
+ print qq|
+ $email
+ </tr>
+</table>
+|;
+
+}
+
+
+sub e_mail {
+
+ # get name and email addresses
+ for $i (1 .. $form->{rowcount}) {
+ if ($form->{"statement_$i"}) {
+ $form->{"$form->{ct}_id"} = $form->{"$form->{ct}_id_$i"};
+ RP->get_customer(\%myconfig, \%$form);
+ $selected = 1;
+ last;
+ }
+ }
+
+ $form->error($locale->text('Nothing selected!')) unless $selected;
+
+ if ($myconfig{admin}) {
+ $bcc = qq|
+ <th align=right nowrap=true>|.$locale->text('Bcc').qq|</th>
+ <td><input name=bcc size=30 value="$form->{bcc}"></td>
+|;
+ }
+
+ $title = $locale->text('E-mail Statement to')." $form->{$form->{ct}}";
+
+ $form->{media} = "email";
+
+ $form->header;
+
+ print qq|
+<body>
+
+<form method=post action=$form->{script}>
+
+<table width=100%>
+ <tr class=listtop>
+ <th class=listtop>$title</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=right nowrap>|.$locale->text('E-mail').qq|</th>
+ <td><input name=email size=30 value="$form->{email}"></td>
+ <th align=right nowrap>|.$locale->text('Cc').qq|</th>
+ <td><input name=cc size=30 value="$form->{cc}"></td>
+ </tr>
+ <tr>
+ <th align=right nowrap>|.$locale->text('Subject').qq|</th>
+ <td><input name=subject size=30 value="$form->{subject}"></td>
+ $bcc
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left nowrap>|.$locale->text('Message').qq|</th>
+ </tr>
+ <tr>
+ <td><textarea name=message rows=15 cols=60 wrap=soft>$form->{message}</textarea></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+|;
+
+ &print_options;
+
+ map { delete $form->{$_} } qw(action email cc bcc subject message type sendmode format);
+
+ # save all other variables
+ foreach $key (keys %$form) {
+ $form->{$key} =~ s/"/&quot;/g;
+ print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
+ }
+
+ print qq|
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+<input type=hidden name=nextsub value=send_email>
+
+<br>
+<input name=action class=submit type=submit value="|.$locale->text('Continue').qq|">
+</form>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub send_email {
+
+ $form->{OUT} = "$sendmail";
+
+ $form->{subject} = $locale->text('Statement').qq| - $form->{todate}| unless $form->{subject};
+
+ RP->aging(\%myconfig, \%$form);
+
+ $form->{"statement_1"} = 1;
+
+ &print_form;
+
+ $form->redirect($locale->text('Statement sent to')." $form->{$form->{ct}}");
+
+}
+
+
+
+sub print {
+
+ if ($form->{media} eq 'printer') {
+ $form->error($locale->text('Select postscript or PDF!')) if ($form->{format} !~ /(postscript|pdf)/);
+ }
+
+ for $i (1 .. $form->{rowcount}) {
+ if ($form->{"statement_$i"}) {
+ $form->{"$form->{ct}_id"} = $form->{"$form->{ct}_id_$i"};
+ $selected = 1;
+ last;
+ }
+ }
+
+ $form->error($locale->text('Nothing selected!')) unless $selected;
+
+
+ if ($form->{media} eq 'printer') {
+ $form->{OUT} = "| $myconfig{printer}";
+ $form->{"$form->{ct}_id"} = "";
+ } else {
+ $form->{"statement_1"} = 1;
+ }
+
+ RP->aging(\%myconfig, \%$form);
+
+ &print_form;
+
+ $form->redirect($locale->text('Statements sent to printer!')) if ($form->{media} eq 'printer');
+
+}
+
+
+sub print_form {
+
+ $form->{statementdate} = $locale->date(\%myconfig, $form->{todate}, 1);
+
+ $form->{templates} = "$myconfig{templates}";
+
+ # setup variables for the form
+ @a = qw(company address businessnumber tel fax);
+ map { $form->{$_} = $myconfig{$_} } @a;
+ $form->format_string(@a);
+
+ $form->{IN} = "$form->{type}.html";
+
+ if ($form->{format} eq 'postscript') {
+ $form->{postscript} = 1;
+ $form->{IN} =~ s/html$/tex/;
+ }
+ if ($form->{format} eq 'pdf') {
+ $form->{pdf} = 1;
+ $form->{IN} =~ s/html$/tex/;
+ }
+
+ $i = 0;
+ while (@{ $form->{AG} }) {
+
+ $ref = shift @{ $form->{AG} };
+
+ if ($ctid != $ref->{ctid}) {
+
+ $ctid = $ref->{ctid};
+ $i++;
+
+ if ($form->{"statement_$i"}) {
+
+ @a = (name, addr1, addr2, addr3, addr4, contact, "$form->{ct}phone", "$form->{ct}fax");
+ map { $form->{$_} = $ref->{$_} } @a;
+ $form->format_string(@a);
+
+ $form->{$form->{ct}} = $form->{name};
+ $form->{"$form->{ct}_id"} = $ref->{ctid};
+
+ map { $form->{$_} = () } qw(invnumber invdate duedate);
+ $form->{total} = 0;
+ foreach $item (qw(c0 c30 c60 c90)) {
+ $form->{$item} = ();
+ $form->{"${item}total"} = 0;
+ }
+
+ &statement_details($ref);
+
+ while ($ref) {
+
+ if (scalar (@{ $form->{AG} }) > 0) {
+ # one or more left to go
+ if ($ctid == $form->{AG}->[0]->{ctid}) {
+ $ref = shift @{ $form->{AG} };
+ &statement_details($ref);
+ # any more?
+ $ref = scalar (@{ $form->{AG} });
+ } else {
+ $ref = 0;
+ }
+ } else {
+ # set initial ref to 0
+ $ref = 0;
+ }
+
+ }
+
+ map { $form->{"${_}total"} = $form->format_amount(\%myconfig, $form->{"${_}total"}, 2) } (c0, c30, c60, c90, "");
+
+ $form->parse_template(\%myconfig, $userspath);
+
+ }
+ }
+ }
+
+}
+
+
+sub statement_details {
+ my ($ref) = @_;
+
+ push @{ $form->{invnumber} }, $ref->{invnumber};
+ push @{ $form->{invdate} }, $ref->{transdate};
+ push @{ $form->{duedate} }, $ref->{duedate};
+
+ foreach $item (qw(c0 c30 c60 c90)) {
+ $ref->{$item} = $form->round_amount($ref->{$item} / $ref->{exchangerate}, 2);
+ $form->{"${item}total"} += $ref->{$item};
+ $form->{total} += $ref->{$item};
+ push @{ $form->{$item} }, $form->format_amount(\%myconfig, $ref->{$item}, 2);
+ }
+
+}
+
+
+sub generate_tax_report {
+
+ RP->tax_report(\%myconfig, \%$form);
+
+ $descvar = "$form->{accno}_description";
+ $description = $form->escape($form->{$descvar});
+
+ # construct href
+ $href = "$form->{script}?path=$form->{path}&action=generate_tax_report&login=$form->{login}&password=$form->{password}&fromdate=$form->{fromdate}&todate=$form->{todate}&db=$form->{db}&accno=$form->{accno}&$descvar=$description";
+
+ # construct callback
+ $callback = $href;
+
+
+ @columns = $form->sort_columns(qw(id transdate invnumber name netamount tax amount));
+
+ foreach $item (@columns) {
+ if ($form->{"l_$item"} eq "Y") {
+ push @column_index, $item;
+
+ # add column to href and callback
+ $callback .= "&l_$item=Y";
+ $href .= "&l_$item=Y";
+ }
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ $callback .= "&l_subtotal=Y";
+ $href .= "&l_subtotal=Y";
+ }
+
+
+ # if there are any dates
+ if ($form->{fromdate} || $form->{todate}) {
+ if ($form->{fromdate}) {
+ $fromdate = $locale->date(\%myconfig, $form->{fromdate}, 1);
+ }
+ if ($form->{todate}) {
+ $todate = $locale->date(\%myconfig, $form->{todate}, 1);
+ }
+
+ $form->{period} = "$fromdate - $todate";
+ } else {
+ $form->{period} = $locale->date(\%myconfig, $form->current_date(\%myconfig), 1);
+ }
+
+ $form->{title} = $locale->text('GIFI')." - " if ($form->{accno} =~ /^gifi_/);
+ $form->{title} = qq|$form->{"$form->{accno}_description"} |;
+ if ($form->{db} eq 'ar') {
+ $form->{title} .= $locale->text('collected on sales');
+ $name = $locale->text('Customer');
+ $invoice = 'is.pl';
+ $arap = 'ar.pl';
+ }
+ if ($form->{db} eq 'ap') {
+ $form->{title} .= $locale->text('paid on purchases');
+ $name = $locale->text('Vendor');
+ $invoice = 'ir.pl';
+ $arap = 'ap.pl';
+ }
+
+
+ $column_header{id} = qq|<th><a class=listheading href=$href&sort=id>|.$locale->text('ID').qq|</th>|;
+ $column_header{invnumber} = qq|<th><a class=listheading href=$href&sort=invnumber>|.$locale->text('Invoice').qq|</th>|;
+ $column_header{transdate} = qq|<th><a class=listheading href=$href&sort=transdate>|.$locale->text('Date').qq|</th>|;
+ $column_header{netamount} = qq|<th class=listheading>|.$locale->text('Amount').qq|</th>|;
+ $column_header{tax} = qq|<th class=listheading>|.$locale->text('Tax').qq|</th>|;
+ $column_header{amount} = qq|<th class=listheading>|.$locale->text('Total').qq|</th>|;
+
+ $column_header{name} = qq|<th><a class=listheading href=$href&sort=name>$name</th>|;
+
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop colspan=$colspan>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$form->{period}</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+ map { print "$column_header{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ # add sort and escape callback
+ $callback = $form->escape($callback . "&sort=$form->{sort}");
+
+ if (@{ $form->{TR} }) {
+ $sameitem = $form->{TR}->[0]->{$form->{sort}};
+ }
+
+ foreach $ref (@{ $form->{TR} }) {
+
+ $module = ($ref->{invoice}) ? $invoice : $arap;
+
+ if ($form->{l_subtotal} eq 'Y') {
+ if ($sameitem ne $ref->{$form->{sort}}) {
+ &tax_subtotal;
+ $sameitem = $ref->{$form->{sort}};
+ }
+ }
+
+ $totalnetamount += $ref->{netamount};
+ $totaltax += $ref->{tax};
+ $ref->{amount} = $ref->{netamount} + $ref->{tax};
+
+ $subtotalnetamount += $ref->{netamount};
+ $subtotaltax += $ref->{tax};
+
+ map { $ref->{$_} = $form->format_amount(\%myconfig, $ref->{$_}, 2, "&nbsp;"); } qw(netamount tax amount);
+
+ $column_data{id} = qq|<td>$ref->{id}</td>|;
+ $column_data{invnumber} = qq|<td><a href=$module?path=$form->{path}&action=edit&id=$ref->{id}&login=$form->{login}&password=$form->{password}&callback=$callback>$ref->{invnumber}</a></td>|;
+ $column_data{transdate} = qq|<td>$ref->{transdate}</td>|;
+ $column_data{name} = qq|<td>$ref->{name}&nbsp;</td>|;
+
+ map { $column_data{$_} = qq|<td align=right>$ref->{$_}</td>| } qw(netamount tax amount);
+
+ $i++; $i %= 2;
+ print qq|
+ <tr class=listrow$i>
+|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ }
+
+ if ($form->{l_subtotal} eq 'Y') {
+ &tax_subtotal;
+ }
+
+
+ map { $column_data{$_} = qq|<th>&nbsp;</th>| } @column_index;
+
+ print qq|
+ </tr>
+ <tr class=listtotal>
+|;
+
+ $total = $form->format_amount(\%myconfig, $totalnetamount + $totaltax, 2, "&nbsp;");
+ $totalnetamount = $form->format_amount(\%myconfig, $totalnetamount, 2, "&nbsp;");
+ $totaltax = $form->format_amount(\%myconfig, $totaltax, 2, "&nbsp;");
+
+ $column_data{netamount} = qq|<th class=listtotal align=right>$totalnetamount</th>|;
+ $column_data{tax} = qq|<th class=listtotal align=right>$totaltax</th>|;
+ $column_data{amount} = qq|<th class=listtotal align=right>$total</th>|;
+
+ map { print "$column_data{$_}\n" } @column_index;
+
+
+ print qq|
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+</body>
+</html>
+|;
+
+}
+
+
+sub tax_subtotal {
+
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $subtotalnetamount = $form->format_amount(\%myconfig, $subtotalnetamount, 2, "&nbsp;");
+ $subtotaltax = $form->format_amount(\%myconfig, $subtotaltax, 2, "&nbsp;");
+ $subtotal = $form->format_amount(\%myconfig, $subtotalnetamount + $subtotaltax, 2, "&nbsp;");
+
+ $column_data{netamount} = "<th class=listsubtotal align=right>$subtotalnetamount</th>";
+ $column_data{tax} = "<th class=listsubtotal align=right>$subtotaltax</th>";
+ $column_data{amount} = "<th class=listsubtotal align=right>$subtotal</th>";
+
+ $subtotalnetamount = 0;
+ $subtotaltax = 0;
+
+ print qq|
+ <tr class=listsubtotal>
+|;
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+}
+
+
+
+sub list_payments {
+
+ if ($form->{account}) {
+ ($form->{paymentaccounts}) = split /--/, $form->{account};
+ }
+
+ RP->payments(\%myconfig, \%$form);
+
+ @columns = $form->sort_columns(qw(transdate invnumber name paid source));
+
+ # construct href
+ $href = "$form->{script}?path=$form->{path}&action=list_payments&login=$form->{login}&password=$form->{password}&fromdate=$form->{fromdate}&todate=$form->{todate}&db=$form->{db}&title=".$form->escape($form->{title})."&account=".$form->escape($form->{account});
+
+ $form->{paymentaccounts} =~ s/ /%20/g;
+ $href .= "&paymentaccounts=$form->{paymentaccounts}";
+
+
+ # construct callback
+ $form->{callback} = "$href&sort=$form->{sort}";
+ $callback = $form->escape($form->{callback});
+
+
+ $column_header{name} = "<th><a class=listheading href=$href&sort=name>".$locale->text('Description')."</a></th>";
+ $column_header{invnumber} = "<th><a class=listheading href=$href&sort=invnumber>".$locale->text('Invoice')."</a></th>";
+ $column_header{transdate} = "<th><a class=listheading href=$href&sort=transdate>".$locale->text('Date')."</a></th>";
+ $column_header{paid} = "<th class=listheading>".$locale->text('Amount')."</a></th>";
+ $column_header{source} = "<th><a class=listheading href=$href&sort=source>".$locale->text('Source')."</a></th>";
+
+
+ if ($form->{fromdate}) {
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('From')."&nbsp;".$locale->date(\%myconfig, $form->{fromdate}, 1);
+ }
+ if ($form->{todate}) {
+ $option .= "\n<br>" if ($option);
+ $option .= $locale->text('to')."&nbsp;".$locale->date(\%myconfig, $form->{todate}, 1);
+ }
+
+ @column_index = @columns;
+ $colspan = $#column_index + 1;
+
+ $form->header;
+
+ print qq|
+<body>
+
+<table width=100%>
+ <tr>
+ <th class=listtop>$form->{title}</th>
+ </tr>
+ <tr height="5"></tr>
+ <tr>
+ <td>$option</td>
+ </tr>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr class=listheading>
+|;
+
+ map { print "\n$column_header{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+
+ foreach $ref (sort { $a->{accno} cmp $b->{accno} } @{ $form->{PR} }) {
+
+ print qq|
+ <tr>
+ <th colspan=$colspan align=left>$ref->{accno}--$ref->{description}</th>
+ </tr>
+|;
+
+ foreach $payment (@{ $form->{$ref->{id}} }) {
+
+ $module = $payment->{module};
+ $module = 'is' if ($payment->{invoice} && $payment->{module} eq 'ar');
+ $module = 'ir' if ($payment->{invoice} && $payment->{module} eq 'ap');
+
+ $href = qq|${module}.pl?path=$form->{path}&action=edit&id=$payment->{id}&login=$form->{login}&password=$form->{password}&callback=$callback|;
+
+
+ $column_data{name} = "<td>$payment->{name}&nbsp;</td>";
+ $column_data{invnumber} = qq|<td><a href=$href>$payment->{invnumber}</a></td>|;
+ $column_data{transdate} = "<td>$payment->{transdate}&nbsp;</td>";
+ $column_data{paid} = "<td align=right>".$form->format_amount(\%myconfig, $payment->{paid}, 2, "&nbsp;")."</td>";
+ $column_data{source} = "<td>$payment->{source}&nbsp;</td>";
+
+ $subtotalpaid += $payment->{paid};
+ $totalpaid += $payment->{paid};
+
+ $i++; $i %= 2;
+ print qq|
+ <tr class=listrow$i>
+|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ }
+
+ # print subtotals
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{paid} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotalpaid, 2, "&nbsp;")."</th>";
+
+ print qq|
+ <tr class=listsubtotal>
+|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+|;
+
+ $subtotalpaid = 0;
+
+ }
+
+
+ # print total
+ map { $column_data{$_} = "<td>&nbsp;</td>" } @column_index;
+
+ $column_data{paid} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $totalpaid, 2, "&nbsp;")."</th>";
+
+ print qq|
+ <tr class=listtotal>
+|;
+
+ map { print "\n$column_data{$_}" } @column_index;
+
+ print qq|
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><hr size=3 noshade></td>
+ </tr>
+</table>
+
+</body>
+</html>
+|;
+
+}
+
+
+
diff --git a/sql-ledger/css/sql-ledger.css b/sql-ledger/css/sql-ledger.css
new file mode 100644
index 0000000..20a59cf
--- /dev/null
+++ b/sql-ledger/css/sql-ledger.css
@@ -0,0 +1,113 @@
+/* stylesheet for sql-ledger */
+
+/* general stuff */
+A:link { color: #a0522d; text-decoration: none; }
+A:visited { color: #a0522d; text-decoration: none; }
+A:active { color: #a0522d; text-decoration: underline; }
+A:hover { color: white;
+ background-color: rgb(187,187,187);
+ text-decoration: none;
+}
+
+body {
+ font-family: Verdana, Arial, Helvetica;
+ font-size: 10pt;
+ background-color: white;
+ color: black
+}
+
+td {
+ font-family: Verdana, Arial, Helvetica;
+ font-size: 10pt;
+}
+
+/* login and admin */
+.login {
+ font-family: Verdana, Arial, Helvetica;
+}
+body.login {
+ background: #5a7d9b;
+ color: black;
+}
+h1.login {
+ font-size: 18pt;
+}
+table.login {
+ background-color: #FBFFE7;
+ padding: 20px;
+}
+td.login {
+ text-align: center;
+}
+th.login {
+ text-align: right;
+}
+
+body.admin {
+ background-color: #FBFFE7;
+ color: black;
+}
+
+body.menu {
+ background-color: #FBFFE7;
+ font-family: Verdana, Arial, Helvetica;
+ font-size: 10pt;
+ color: black;
+}
+
+
+.listtop { font-size: 10pt; background-color: black; color: white; }
+.listheading { font-size: 10pt; background-color: #336666; color: white; }
+A.listheading:link, A.listheading:active, A.listheading:visited {
+ color: white;
+ text-decoration: none; }
+.listrow1 { background-color: #e6e6fa; color: black; vertical-align: top; }
+.listrow0 { background-color: #ffe4e1; color: black; vertical-align: top; }
+.listsubtotal { font-size: 10pt; background-color: #5a7d9b; color: white; }
+.listtotal { font-size: 10pt; background-color: black; color: white; }
+
+.submit {
+ font-size: 12pt
+ font-family: Verdana, Arial, Helvetica;
+ color: #000080;
+}
+.checkbox, .radio {
+ font-family: Verdana, Arial, Helvetica;
+ color: #778899;
+}
+
+.plus0 { /* font color for negative numbers */
+ color: red;
+}
+
+.plus1 {
+ color: green;
+}
+
+h2.confirm {
+ color: blue;
+ font-size: 14pt;
+}
+
+h2.error {
+ color: red;
+ font-size: 14pt;
+}
+
+
+/* media stuff */
+
+@media screen {
+ .noscreen { /* items with this class won't display */
+ display: none;
+ }
+}
+
+@media print {
+ .noprint { /* items with this class won't print */
+ display: none;
+ }
+}
+
+
+
diff --git a/sql-ledger/doc/COPYING b/sql-ledger/doc/COPYING
new file mode 100644
index 0000000..083bb41
--- /dev/null
+++ b/sql-ledger/doc/COPYING
@@ -0,0 +1,355 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>GNU General Public License</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=ffffff>
+
+
+<pre>
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ &lt;one line to give the program's name and a brief idea of what it does.&gt;
+ Copyright (C) 19yy &lt;name of author&gt;
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ &lt;signature of Ty Coon&gt;, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+
+</BODY>
+</HTML>
+
diff --git a/sql-ledger/doc/README b/sql-ledger/doc/README
new file mode 100644
index 0000000..7585f53
--- /dev/null
+++ b/sql-ledger/doc/README
@@ -0,0 +1,287 @@
+ SQL-Ledger Accounting
+ Version 2.0
+
+
+DESCRIPTION:
+------------
+SQL-Ledger is a double-entry accounting program written
+in perl. It has been tested with PostgreSQL, Oracle,
+Apache, Netscape, Mozilla, Galeon, Explorer, Links, Lynx,
+Konqueror, Voyager, W3M and Opera clients on Linux, FreeBSD,
+Solaris, Windows and Mac computers.
+
+Data is stored in a SQL server, either locally or remote,
+the display is through a text or GUI web browser. The system
+is linked by a chart of accounts. All transactions for AR,
+AP and GL are stored in a transaction table. Hyper-links
+from the chart of accounts let you view transactions posted
+through AR, AP and GL.
+
+Configuration files let you specify to which SQL server
+to connect to, personal preferences such as company name,
+language, number and date format, etc.
+
+The admin script can be used to create, edit or delete users
+and to create and delete datasets and to setup the Chart
+of Accounts and templates needed for the system.
+It can be used for PostgreSQL and Oracle. If you want to
+use another SQL server the tables and chart of accounts
+must be created by hand.
+
+You can have a group of users using the same dataset and
+templates for generating Invoices, Income Statements and
+Balance Sheets or a different set altogether.
+
+Templates are supplied in html and tex format to generate
+most of the forms. Forms can be printed to screen, sent
+to a printer or to a mailer agent. To use the tex forms
+latex must be installed. Most systems have a latex binary
+installed by default. Latex is also available for Windows
+and the Mac so we stay compatible across all major platforms.
+
+
+COPYRIGHT:
+----------
+You may distribute under the terms of the GNU License.
+
+
+LATEST VERSION:
+---------------
+available from http://www.sql-ledger.org
+
+
+PLATFORMS:
+----------
+Non specific, see requirements.
+
+
+REQUIREMENTS:
+-------------
+1 - Perl, 5+
+2 - http server (Apache, NCSA, httpi, ...)
+3 - SQL Server with transaction support (PostgreSQL 7.0+, Oracle)
+4 - DBD (DBD-Pg, DBD-Oracle)
+5 - DBI
+6 - LaTeX (optional)
+
+
+FOREIGN LANGUAGE SUPPORT:
+-------------------------
+All the required files are in locale/country_code
+The main files are 'all' and 'missing'. You can enter
+translated strings in either file. When you are done
+run locales.pl from the command line to rebuild the
+required files.
+
+Some of the translation files are not 100% complete.
+If strings are missing, English is used instead.
+
+
+INSTALLATION:
+-------------
+unpack the tar.gz file in /usr/local
+
+ tar xzvf sql-ledger-x.x.x.tar.gz
+
+you should now have everything in /usr/local/sql-ledger
+
+copy sql-ledger.conf.default to sql-ledger.conf
+
+edit sql-ledger.conf
+
+create a file sql-ledger-httpd.conf in the same location
+where your httpd.conf is and copy the next section into the file
+
+ Alias /sql-ledger/ /usr/local/sql-ledger/
+ <Directory /usr/local/sql-ledger>
+ AddHandler cgi-script .pl
+ Options ExecCGI Includes FollowSymlinks
+ </Directory>
+
+ <Directory /usr/local/sql-ledger/users>
+ Order Deny,Allow
+ Deny from All
+ </Directory>
+
+edit httpd.conf and add
+
+ # SQL-Ledger
+ Include <ServerRoot>/sql-ledger-httpd.conf
+
+Note: Replace <ServerRoot> with the server's root directory!
+
+restart your web server.
+
+
+Note: /usr/local/sql-ledger is only a suggested
+path, you can install in any directory.
+
+
+INSTALLATION WITH setup.pl:
+---------------------------
+Make a directory
+
+ mkdir /usr/local/sql-ledger
+
+Copy setup.pl to /usr/local/sql-ledger
+
+run setup.pl as root and follow the prompts.
+
+Go to the next step, "PREPARE YOUR SQL SERVER".
+
+
+SET PERMISSION:
+---------------
+change directory to /usr/local/sql-ledger
+
+# chown nobody:nobody users templates
+
+replace nobody:nobody with the web server
+user of your system. Some systems use
+apache:apache, www, www-data, ...
+
+
+PREPARE YOUR SQL SERVER:
+------------------------
+
+ PostgreSQL:
+ -----------
+ add one database user with create database privileges
+ to manage the datasets and tables for SQL-Ledger
+
+ # su postgres
+ $ createuser -d sql-ledger
+
+ if you use passwords to access postgres set the user up with a password
+ $ createuser -d -P sql-ledger
+
+ Answer no to the following question.
+ Shall the new user be allowed to create more new users? (y/n) n
+
+ You can add more database users to keep datasets
+ separated. Each dataset belongs to one company.
+
+
+ ORACLE:
+ -------
+ add one user and one tablespace
+ all datasets share the same tablespace
+
+
+SETUP A DATABASE AND THE TABLES:
+--------------------------------
+Load your web browser and connect to
+http://localhost/sql-ledger/admin.pl
+
+Tables are created with the "Database
+Administration" function.
+
+Select the "Database Administration" link,
+enter a host, port and user you created in the
+previous step.
+
+The "Create Dataset" link queries the server
+for existing datasets and displays them in a
+column. Then you enter a name for the new
+dataset and select one of the Chart of Accounts
+and click on Continue.
+Your new dataset and the tables will be created
+and the selected Chart of Accounts loaded. The
+owner of the tables is the user you entered in
+the previous screen.
+
+NOTE: Be patient, some of the charts are really
+big and take some time to create.
+
+The "Delete Dataset" link queries the server
+for datasets which are in use by SQL-Ledger
+and are not used by any members. This may
+take a while to figure out. "Be patient".
+If there are any datasets not in use, you get
+a screen with the datasets listed where you
+can select the one you want to delete.
+
+NOTE: you cannot manage any other datasets
+from this interface, only the datasets used
+by SQL-Ledger.
+
+
+SETUP A USER:
+-------------
+Load your web browser and connect to
+http://localhost/sql-ledger/admin.pl
+
+Click on "Add User". In the Database
+section select the driver and enter
+the user you used to create the dataset.
+
+
+LOAD THE ACCOUNTING PROGRAM:
+----------------------------
+Load your web browser and connect to
+http://localhost/sql-ledger/login.pl
+
+
+UPGRADING TO A NEWER VERSION:
+-----------------------------
+1. unpack the new version over top
+2. check the doc directory for specific notes
+3. load admin.pl
+ click on "Database Administration"
+ enter the dba in the "Connect to" field
+ click on "Update Dataset"
+ select the datasets and click "Continue"
+
+
+UPGRADING WITH setup.pl:
+------------------------
+run setup.pl from the command line and follow
+the prompts.
+
+
+INSTALLATION CHECKLIST:
+-----------------------
+1. untar SL somewhere
+2. change permissions for the users and templates directory
+3. edit httpd.conf
+4. edit sql-ledger.conf
+5. a) add the database user sql-ledger in PostgreSQL
+ b) add a tablespace and the database user sql-ledger in Oracle
+6. load admin.pl
+7. create datasets for the companies
+8. add users
+
+ In the Database section enter
+
+ a) PostgreSQL
+
+ Host: for local connections leave empty
+ Dataset: the dataset created in step 7
+ Port: for local connections leave empty
+ User: sql-ledger
+ Password: password for sql-ledger
+
+ b) Oracle
+
+ SID: system ID
+ Port: the port Oracle is listening on
+ Dataset: the dataset created in step 7
+ Password: password for connection
+
+
+IF SOMETHING DOESN'T WORK:
+--------------------------
+There is a FAQ online which addresses various questions.
+see http://www.sql-ledger.org/misc/faq.html
+
+There are also several mailing lists at
+http://www.sql-ledger.org/misc/mailinglist.html
+where you can go for help.
+
+If you require support you can order online at
+http://www.sql-ledger.com/misc/support.html
+
+
+=====================================================================
+December 4, 2002
+
diff --git a/sql-ledger/doc/UPGRADE-1.6-1.8 b/sql-ledger/doc/UPGRADE-1.6-1.8
new file mode 100644
index 0000000..b5631b2
--- /dev/null
+++ b/sql-ledger/doc/UPGRADE-1.6-1.8
@@ -0,0 +1,61 @@
+Upgrading from version 1.6 to 1.8
+
+1. make a backup copy of your databases and SQL-Ledger, just in case!
+ $ cd /usr/local/www/sql-ledger
+ $ pg_dump database > db.out
+ $ tar cvf ~/sql-ledger.tar .
+
+2. install SQL-Ledger over top of your old installation
+ $ cd /usr/local/www
+ $ tar zxvf sql-ledger-1.8.0.tar.gz
+
+3. change the tables to the new layout
+ $ cd sql-ledger/sql
+ $ psql database < upgrade-1.6-1.8.sql
+
+4. copy the new master templates to your template directory
+ $ cd ../templates
+
+ $ cp Default-email_purchase_order.html your_template_dir/email_purchase_order.html
+ $ cp Default-purchase_order.html your_template_dir/purchase_order.html
+ $ cp Default-email_sales_order.html your_template_dir/email_sales_order.html
+ $ cp Default-sales_order.html your_template_dir/sales_order.html
+
+5. Two new accounts were hopefully added to your chart of accounts
+ One account for Foreign Exchange Gains and one for
+ Foreign Exchange Losses
+ edit and change to suit your COA. You can safely change
+ the account number too.
+
+6. Edit your preferences
+
+ In field 'Stylesheet' enter -> sql-ledger.css
+ Stylesheet is in the css directory
+
+ Add your foreign currencies in the Currencies field
+ The first currency in the list is your default
+ i.e CDN:USD:EUR:YEN
+ If you used a nativecurr than it should be listed in the
+ new currencies field.
+
+7. <%nativecurr%> has changed to <%currency%>
+ edit all your templates and change nativecurr to currency
+
+8. I also added four more variables which can be used in your templates.
+ <%contact%>, <%shiptocontact%>, <%shiptophone%>, <%shiptofax%>
+
+9. Nameing convention for templates has changed from an
+ underscore to a minus sign. If you designed your own
+ master templates rename the templates from
+ industry_invoice.html to industry-invoice.html,
+ industry_packing_list.html to industry-packing_list.html, etc.
+ The minus sign is used to separate the name and list them in
+ the setup screen.
+
+ This change only applies to the master templates in the
+ templates root directory NOT the individual templates which
+ are used by users.
+
+It looks more than it really is. Steps 1 to 4 are important,
+the rest is for fine tuning and info.
+
diff --git a/sql-ledger/doc/UPGRADE-1.8-1.8.3 b/sql-ledger/doc/UPGRADE-1.8-1.8.3
new file mode 100644
index 0000000..babed37
--- /dev/null
+++ b/sql-ledger/doc/UPGRADE-1.8-1.8.3
@@ -0,0 +1,23 @@
+Upgrading from version 1.8.(0-2) to 1.8.3
+
+1. install SQL-Ledger over top of your old installation
+ $ cd /usr/local
+ $ tar zxvf sql-ledger-1.8.3.tar.gz
+
+2. copy sql-ledger.conf.default to sql-ledger.conf
+ $ cp sql-ledger.conf.default sql-ledger.conf
+
+ if you modified sql-ledger.conf merge the changes from the
+ .default file rather than copying over top.
+
+3. copy the new master templates to your template directory
+ $ cd ../templates
+
+ $ cp Default-invoice.tex your_template_dir/invoice.tex
+ $ cp Default-packing_list.tex your_template_dir/packing_list.tex
+ $ cp Default-purchase_order.tex your_template_dir/purchase_order.tex
+ $ cp Default-sales_order.tex your_template_dir/sales_order.tex
+
+4. edit sql-ledger.conf
+ instructions are in the file
+
diff --git a/sql-ledger/doc/UPGRADE-1.8.3-1.8.4 b/sql-ledger/doc/UPGRADE-1.8.3-1.8.4
new file mode 100644
index 0000000..c3ecdf5
--- /dev/null
+++ b/sql-ledger/doc/UPGRADE-1.8.3-1.8.4
@@ -0,0 +1,10 @@
+Upgrading from version 1.8.3 to 1.8.4
+
+1. install SQL-Ledger over top of your old installation
+ $ cd /usr/local
+ $ tar zxvf sql-ledger-1.8.4.tar.gz
+
+2. update the tables with the admin script
+
+ You will not be able to log in until you upgraded the tables.
+
diff --git a/sql-ledger/doc/UPGRADE-1.8.4-1.8.5 b/sql-ledger/doc/UPGRADE-1.8.4-1.8.5
new file mode 100644
index 0000000..e8c32e1
--- /dev/null
+++ b/sql-ledger/doc/UPGRADE-1.8.4-1.8.5
@@ -0,0 +1,18 @@
+Upgrading from version 1.8.4 to 1.8.5
+
+1. install SQL-Ledger over top of your old installation
+ $ cd /usr/local
+ $ tar zxvf sql-ledger-1.8.5.tar.gz
+
+2. update the tables with the admin script
+
+ You will not be able to log in until you upgraded the tables.
+
+
+There are two new variables (<%customernumber%> and <%vendornumber%>)
+which can be used in the forms. These may be used instead of the
+internally generated customer_id and vendor_id.
+
+Typically these numbers are used to retrieve a customer, vendor
+by some ID. In most counter operations the phone number is used.
+
diff --git a/sql-ledger/doc/UPGRADE-1.8.5-1.8.7 b/sql-ledger/doc/UPGRADE-1.8.5-1.8.7
new file mode 100644
index 0000000..992238c
--- /dev/null
+++ b/sql-ledger/doc/UPGRADE-1.8.5-1.8.7
@@ -0,0 +1,6 @@
+Upgrading from version 1.8.5 to 1.8.7
+
+1. install SQL-Ledger over top of your old installation
+ $ cd /usr/local
+ $ tar zxvf sql-ledger-1.8.7.tar.gz
+
diff --git a/sql-ledger/doc/UPGRADE-1.8.7-2.0.0 b/sql-ledger/doc/UPGRADE-1.8.7-2.0.0
new file mode 100644
index 0000000..e16ba75
--- /dev/null
+++ b/sql-ledger/doc/UPGRADE-1.8.7-2.0.0
@@ -0,0 +1,20 @@
+Upgrading to Version 2.0.0
+
+1. install SQL-Ledger over top of your old installation
+ $ cd /usr/local
+ $ tar zxvf sql-ledger-2.0.0.tar.gz
+
+2. load admin.pl and update the tables
+
+ You will not be able to log in until the tables are up to date.
+
+3. copy the new templates to your personal template directory
+
+ $ cd templates
+ $ cp Default-check.tex dir/check.tex
+ $ cp Default-receipt.tex dir/receipt.tex
+ $ cp Default-statement.html dir/statement.html
+ $ cp Default-statement.tex dir/statement.tex
+
+ replace 'dir' with your directory name
+
diff --git a/sql-ledger/doc/UPGRADE-2.0-2.0.8 b/sql-ledger/doc/UPGRADE-2.0-2.0.8
new file mode 100644
index 0000000..6ddff62
--- /dev/null
+++ b/sql-ledger/doc/UPGRADE-2.0-2.0.8
@@ -0,0 +1,8 @@
+Upgrading from version 2.0.[0-7] to 2.0.8
+
+1. install SQL-Ledger over top of your old installation
+ $ cd /usr/local
+ $ tar zxvf sql-ledger-2.0.8.tar.gz
+
+2. update your datasets with the admin script
+
diff --git a/sql-ledger/doc/copyright b/sql-ledger/doc/copyright
new file mode 100644
index 0000000..d493a3d
--- /dev/null
+++ b/sql-ledger/doc/copyright
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2003, Dieter Simader
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/doc/faq.html b/sql-ledger/doc/faq.html
new file mode 100644
index 0000000..0f6f237
--- /dev/null
+++ b/sql-ledger/doc/faq.html
@@ -0,0 +1,747 @@
+<ul>
+<p><li><h4>Sub-menus and Apache 2.0</h4>
+Some versions of Apache 2.0 (2.0.44+) don't expand sub-menus and generate
+a 500 error at various points. This stems from workaround developed for
+earlier versions of Apache 2.0. It looks like this workaround must now be
+disabled. If you get an error or the sub-menus don't expand edit
+SL/Form.pm and comment lines 80-82.
+<pre>
+ # for Apache 2 we escape strings twice
+# if (($ENV{SERVER_SOFTWARE} =~ /Apache\/2/) && !$beenthere) {
+# $str = $self->escape($str, 1);
+# }
+</pre>
+
+
+<p><li><h4>About installation</h4>
+The easiest is to use the setup.pl script as root.
+You don't need to know very much about your system, just login as root,
+run 'perl setup.pl' and follow the prompts.
+<p>setup.pl does not check for missing software packages and it is your
+responsibility to make sure you have the required pieces
+installed either from source or from a package supplied with your distro.
+
+<p>Requirements are clearly indicated in the README file and on the
+download page.
+
+
+<p><li><h4>IDENT Authentication failed for user "postgres"</h4>
+
+This error has everything to do with the way the distros set up
+access rights for postgres. They are way too restrictive and leave you
+wondering what to do next.
+
+<p>Do yourself a favour and change authentication in pg_hba.conf to
+
+<pre>
+local all trust</pre>
+
+<p>until you have figured what all this stuff in pg_hba.conf does.
+
+<p><b>NOBODY</b>, I repeat, <b>NOBODY</b>, from the Internet will be able to
+connect to postgres. You can't even connect from the inside LAN, the only
+one who is allowed to connect are clients originating from localhost.
+
+<p>Read a bit about the different authentication settings and change
+them as you see fit.
+It is all described in detail in pg_hba.conf
+
+<p>If you can't find the file, there is a wonderful utility called find.
+Use it.
+<pre>
+# find /usr/local -type f -name 'pg_hba.conf'
+</pre>
+
+
+<p><li><h4>DBD-Pg for Mandrake 9.0</h4>
+Mandrake did not package a compiled DBD-Pg package again, so install DBD-Pg
+from the source package.
+Install perl-DBD-Pg-1.01-4mdk.i586.rpm from the 'contrib' area.
+(Mandrake / 9.0 / contrib / RPMS)
+
+<p><li><h4>LaTeX error</h4>
+If for some reason LaTeX produces an error message check for strange
+characters in your account description and parts description
+and use \usepackage[latin1]{inputenc} in the preamble.
+
+
+<p><li><h4>LaTeX templates</h4>
+If you don't want to edit tex code by hand,
+you could use Lyx, Abiword, or any WYSIWYG editor capable of exporting
+latex code.
+To do that you must change the tokens for parameters <% and %> to something
+like << and >>. % is the comment character in tex. There is also a
+pagebreak block which must be commented out.
+When you are done with the changes
+replace << and >> with <% and %> and uncomment the pagebreak block.
+
+<p>LaTeX is difficult but it also offers a much superior interface to produce
+professionally looking forms in postscript and PDF format.
+Unfortunately with power comes some pain too.
+
+
+<p><li><h4>W3M</h4>
+pass terminal=mozilla when you start w3m
+<pre>$ w3m -F http://localhost/sql-ledger/login.pl?terminal=mozilla</pre>
+
+To use without frames
+<pre>$ w3m http://localhost/sql-ledger/login.pl?terminal=lynx</pre>
+
+<p><li><h4>PDF option disappeared</h4>
+Edit sql-ledger.conf and set $latex = 1;
+<br>sql-ledger.conf is perl code, check if it compiles, if it does not
+the internal defaults are used which set $latex to 0, hence no PDF option.
+
+<p><li><h4>SQL-Ledger on Mac Os X 10.1.5</h4>
+Jaume Teixi put together
+<a href=http://www.rocacorbit.com/techdocs/sql_ledger_os_x.html>
+installation instructions</a> to run SL on a Mac.
+<br>The instructions are for 1.8.5 however they still apply to any of the
+newer versions.
+
+<p><li><h4>Installation on Windows (WIN32)</h4>
+<ul>
+<li>install Apache, perl,
+<a href=http://techdocs.postgresql.org/guides/InstallingOnWindows>Postgres</a>
+or Oracle, DBI and the appropriate DBD
+module
+<br>if you can't compile DBD-Pg here is a precompiled
+<a href=http://www.edmund-mergl.de/export/>DBD-Pg module</a>
+<li>download the latest version of <a href=/cgi-bin/nav.pl?page=source/index.html&title=Download>SQL-Ledger</a>
+<li>extract the files to c:\apache\sql-ledger
+<li>download
+<a href=../source/sql-ledger-windows.tar.gz>sql-ledger-windows.tar.gz</a>
+and extract the files to c:\apache\sql-ledger
+ <br>the shebang line is changed to c:\perl\bin\perl and the symlinks
+ are regular files
+<br>answer with 'Yes' to overwrite existing files.
+<li>edit c:\apache\conf\httpd.conf and add
+<pre>
+Alias /sql-ledger/ "C:/apache/sql-ledger/"
+&lt;Directory "c:/apache/sql-ledger"&gt;
+ AllowOverride All
+ AddHandler cgi-script .pl
+ Options +ExecCGI
+ Order Allow,Deny
+ Allow from All
+&lt;/Directory&gt;
+
+&lt;Directory "c:/apache/sql-ledger/users"&gt;
+ Order Deny,Allow
+ Deny from All
+&lt;/Directory&gt;
+</pre>
+
+<li>start Apache
+<li>start Postgres|Oracle
+<li>connect to http://localhost/sql-ledger/admin.pl and setup users
+and datasets
+<li>connect to http://localhost/sql-ledger/login.pl and login
+
+</ul>
+
+<p><li><h4>Installation on Windows /w cygwin</h4>
+<ul>
+<li>install <a href=http://sources.redhat.com/cygwin/>cygwin</a>
+Apache, perl, postgres, gcc and lynx
+<li>install <a href=http://search.cpan.org/search?module=DBI>DBI</a>
+<li>tar zxvf DBI-1.30.tar.gz
+<li>cd DBI-1.30
+<li>perl Makefile.PL
+<li>make install
+<li>install <a href=http://search.cpan.org/search?dist=DBD-Pg>DBD-Pg</a>
+<li>tar -zxvf DBD-Pg-1.13.tar.gz
+<li>export POSTGRES_INCLUDE=/usr/include/postgresql
+<li>export POSTGRES_LIB=/usr/lib/postgresql
+<li>cd DBD-Pg-1.13
+<li>perl Makefile.PL
+<li>make install
+<li>edit /etc/apache/httpd.conf and add
+<pre>
+AddHandler cgi-script .pl
+Alias /sql-ledger/ /var/www/sql-ledger/
+&lt;Directory /var/www/sql-ledger&gt;
+ Options +ExecCGI
+&lt;/Directory&gt;
+
+&lt;Directory /var/www/sql-ledger/users&gt;
+ Order Deny,Allow
+ Deny from All
+&lt/Directory&gt;
+</pre>
+<li>install SQL-Ledger
+<li>cd /var/www
+<li>mkdir sql-ledger
+<li>download <a href=/cgi-bin/download.pl?setup.pl>setup.pl</a> and save the file
+in /var/www/sql-ledger
+<li>cd /var/www/sql-ledger
+<li>perl setup.pl
+</ul>
+
+<p><li><h4>What do I enter for the language</h4>
+If you use English, nothing, if you want to use a foreign language for
+the login screen and admin stuff enter the language code. All the
+language specific files are in the locale directory. The long form for
+the language is in the LANGUAGE file.
+
+<p><li><h4>Mandrake 9.0 permission denied error</h4>
+Mandrake says to add this to your commonhttpd.conf
+<pre>
+&lt;Directory /usr/local/sql-ledger&gt;
+ AllowOverride All
+ Options -MultiViews -Indexes -FollowSymLinks
+ Order allow,deny
+ Allow from all
+&lt;/Directory&gt;
+
+The way apache starts is it:
+Blocks all access to the physical file system /
+Opens access to the physical file system /var/www/html
+Opens access to the physical file system /var/www/perl
+Opens access to the physical file system /var/www/cgi-bin
+Opens access to the physical file system /var/www/protected-cgi-bin
+Opens access to the physical file system /home/*/public_html
+Opens access to the physical file system /home/*/public_html/cgi-bin
+Opens access to the physical file system /var/www/icons
+Opens access to the physical file system /usr/share/doc
+
+Since you're trying to access files outside of those allowed paths, you
+have to specifically allow it. It's done this way because of some past
+exploits with the pathnames. Rather than trust that there will never be
+another bug within apache that will let you get somewhere you don't
+want, you set it up securely out of the box so that apache won't let
+itself go somewhere that you don't want it to.
+</pre>
+
+
+<p><li><h4>Incorrect Dataset version</h4>
+The dataset you are trying to use is not compatible with the version.
+When you upgrade datasets use the same database user in the "User"
+field as the one listed in the Database section for the user.
+
+
+<p><li><h4>Mandrake 8.2</h4>
+Mandrake did not include the package "perl-DBD-Pg-1.01-1mdk.i586.rpm"
+You can install the package from Mandrake 8.1
+
+
+<p><li><h4>printing to a printer</h4>
+Setup a printer in the "Printer" field in the users preferences.
+i.e lpr -Plaser
+and set $latex = 1 in sql-ledger.conf
+LaTeX must be installed for this to work.
+
+<p>To send the document to the printer check the "Postscript" or "PDF" format,
+enter the number of copies and click on the "Print" button.
+
+<p>The printer field is available only when you edit the user's
+preferences with admin.pl.
+
+<p>Note: html format is for screen preview. Use your browser's
+print function.
+
+
+<p><li><h4>beginning balances</h4>
+Add a GL Journal entry and enter the beginning balance for your accounts.
+Use your balance sheet. If you also want to add open invoices, add the invoices
+and make the appropriate adjustments. Your balance sheet includes these
+amounts!
+
+
+<p><li><h4>cost for parts and service</h4>
+the cost will be updated when you purchase goods and services. You can
+enter the cost manually. This is so you can have a cost on file without
+making a purchase.
+
+
+<p><li><h4>establish a beginning inventory</h4>
+add the parts with a purchase invoice. Use the <b>real cost</b> for the items
+not zero. If you use zero cost then the cost of goods will be zero when you
+sell the item.
+
+
+<p><li><h4>Assemblies</h4>
+Assemblies are manufactured goods assembled from parts, services and
+assemblies. Because you do not buy assemblies you 'stock assemblies' by
+adding assembled units to your inventory. The quantity for individual parts
+is reduced and the quantity for the assembly increased. To disassemble an
+assembly you simply return the parts to inventory by entering a negative
+quantity for the number of assemblies to stock.
+
+
+<p><li><h4>customizing SQL-Ledger</h4>
+The <a href=/cgi-bin/nav.pl?page=feature/api.html&title=Application%20Interface>application interface</a>
+consists of a global and private interface.
+
+
+<p><li><h4>DBD-Pg not installed</h4>
+
+Most modern distributions now package DBD-Pg. If it is
+not packaged follow this recipe to get it working.
+
+<ul>
+ <li>check if you have the header files for PostgreSQL
+ <br>$ find / -name 'libpq-fe.h'
+ <br>if nothing shows up install the development package for PostgreSQL
+ <li>download and untar DBD-Pg
+ <li>set the environment variables POSTGRES_LIB and POSTGRES_INCLUDE
+ <li>cd to DBD-Pg directory
+ <br>as ordinary user
+ <br>$ perl Makefile.PL
+ <br>$ make
+ <br>$ make test
+ <br>if all went well su to root
+ <br># make install
+ <li>remove DBD-Pg
+</ul>
+
+
+<p><li><h4>SuSE 8.1 installation</h4>
+<ol>
+<li>Install the following using YaST2:
+
+<p>- perl-DBD-Pg
+<br>- postgresql
+<br>- postgresql-contrib
+<br>- postgresql-devl
+<br>- postgresql-docs
+<br>- postgresql-libs
+<br>- postgresql-perl
+<br>- postgresql-server
+<br>- postgresql-test
+
+<p><li>Setup directories and paths for PostgreSQL:
+
+<p>> sux - (change to root)
+
+<p>- If not done by the installation, setup disk directory for your db:
+<br># mkdir /var/lib/pgsql/data
+<br># chown postgres /var/lib/pgsql/data
+
+<p><li>Initialize the database, and start it, as below:
+<p>Note that there are man pages for initdb and pg_ctl.
+
+<p># touch /var/log/pgsql
+<br># chown postgres:postgres /var/log/pgsql
+<br># sux postgres
+
+<p>- Initialize postgres:
+<br>> /usr/bin/initdb -D /var/lib/pgsql/data
+<br>(creating ... Success...)
+
+<p>- Start the postgres daemon:
+<br>> /usr/bin/pg_ctl -D /var/lib/pgsql/data -l /var/log/pgsql start (start db)
+<br>(postmaster successfully started)
+
+<p><li>Quick-test the server (still as user postgres):
+
+<p>- > psql -d template1
+<br>(Welcome ... \q to exit psql)
+<br>\q
+
+<p>- Try setting up another db user:
+
+<p>> createuser &lt;db-user&gt; (&lt;db-user&gt; should match an existing Linux user)
+<br>Shall the new user be allowed to create databases? (y/n) y
+<br>Shall the new user be allowed to create more new users? (y/n) n
+
+<p>Unless a problem with DBD::Pg (perl interface), postgres is ready to go.
+
+<p><li>If a previous sql-ledger database needs to be installed,
+<br>do the following as postgres user. Steps for dumping the old db,
+ and building the new follow:
+
+<p>> sux postgres
+<br>> psql template1
+<br>=# CREATE DATABASE my_database; (create your database)
+<br>=# \q
+<br>> cd /var/lib/pgsql/backups (assuming your backups are here)
+<br>The next command should have been performed earlier from the
+ previous installed version of postgres and your database:
+<br>> pg_dump -d my_database.sql.bak (from previous ver postgres)
+<br>> cp my_database.sql.bak my_database.sql
+<br>- Use vi to change all occurrances of 'current_date' to current_date
+ in file my_database.sql .
+<br>The vi command for this is :g/'current_date'/s//current_date/g
+<br>> psql my_database < my_database.sql > my_database.log
+<br>- Check my_database.log for errors.
+
+<p><li>Download setup.pl and run it as root while on line to the internet:
+
+<p># mkdir /usr/local/sql-ledger
+<br># cd /usr/local/sql-ledger
+<br># ./setup.pl
+<br>- Enter i
+<br>- Enter httpd owner and group if different than displayed default.
+<br>(Download occurs and status is displayed...)
+
+<p><li>Setup the new sql-ledger with database.
+
+<p>- Surf to http://my_computer/sql-ledger/admin.pl
+<br>- Click enter (no password needed).
+<br>->Database Administration
+<br>- Leave fields Host and Port enpty for local installations.
+<br> - Enter your database name in the "Connect to" field.
+<br> - Enter the database user you setup (postgres, sql-ledger, etc.)
+<br> - Enter a password, only if a password is assigned to the database.
+<br> - To update an existing sql-ledger database: ->Update Database
+<br> Should see: The following Datasets need to be updated.
+<br> ->Continue
+<br> Do more admin. You will need to setup at least one login.
+<br> To exit: ->Database Admin
+
+<p><li>See if it works:
+
+<p> - Surf to http://my_computer/sql-ledger/login.pl
+<br> - Enter the login name you just created. Main menu screen should appear.
+</ol>
+
+
+
+<p><li><h4>Redhat Installation</h4>
+
+<ul>
+<li>Install apache1.3.12-25.i386.rpm
+<li>Install perl5.6.0-9.i386.rpm
+<li>Install postgresql-7.0.2-17.i386.rpm
+<li>Install postgresql-server-7.0.2-17.i386.rpm
+<li>Install postgresql-devel-7.0.2-17.i386.rpm (POSTGRES_INCLUDE)
+<li>tar xvzf DBI-1.14.tar.gz
+<li>cd DBI-1.14
+<li>perl Makefile.PL
+<li>make
+<li>make install
+<li>cd ..
+<li>tar xvzf DBD-Pg-0.95
+<li>cd DBD-Pg-0.95
+<li>export POSTGRES_LIB=/usr/lib/pgsql
+<li>export POSTGRES_INCLUDE=/usr/include/pgsql
+<li>perl Makefile.PL
+<li>make
+<li>make install
+<li>install SQL-Ledger
+</ul>
+
+<p>Some of the applications have newer versions however the installation
+instructions remain the same. Just substitute the old version with a newer
+version.
+
+
+<p><li><h4>Debian Installation</h4>
+
+<ul>
+<li>unpack into /usr/local/www/sql-ledger
+<li>install postgresql (Dselect)
+<li>install apache (Dselect)
+<li>install libdbi-perl (Dselect)
+<li>install libdbd-pg-perl (Dselect)
+<li>install libpgperl (Dselect)
+<li>modify /etc/postgresql/postgresql.conf
+ <br>TCPIP_SOCKET = 1
+<li>create a user for managing SQL-Ledger databases
+<br>from root
+<br>su postgres
+<br>$ createuser -d sql-ledger
+<br>if you use passwords to access postgres set the user up with a password
+<br>$ createuser -d -P sql-ledger
+<li>change /etc/apache/httpd.conf and add
+<pre>
+AddHandler cgi-script .pl
+Alias /sql-ledger/ /usr/local/www/sql-ledger/
+&lt;Directory /usr/local/www/sql-ledger&gt;
+ Options +ExecCGI
+&lt;/Directory&gt;
+
+&lt;Directory /usr/local/www/sql-ledger/users&gt;
+ Order Deny,Allow
+ Deny from All
+&lt;/Directory&gt;
+</pre>
+<li>restart apache
+<li>change fileownership of users and templates to www-data
+ <br>chown www-data: users templates
+<li>From browser enter http://localhost/sql-ledger/admin.pl
+<li>Login as the postgres user (account manager) you have created (above)
+<br>Create a DB
+<br>Create users
+
+<li>then enter http://localhost/sql-ledger/login.pl
+<br>Login as one of the users you have just created
+
+</ul>
+
+<p>
+The long version was provided by Gordon Haverland.
+<p>
+<ul>
+<li>You need to unpack the SQL-Ledger package (compressed tar archive)
+ someplace. Unpacking it in<pre>
+ /usr/local/www/sql-ledger.</pre>
+ Remember where you have unpacked it.
+<li>SQL-Ledger requires that the PostgreSQL database be installed.
+This is a very full-featured database, and has many associated
+packages. SQL-Ledger requires version 7.0 or better. The name
+of the basic package on Debian is postgresql. To find if you
+already have postgresql installed, and if so what version, the
+following command should work:<pre>
+ dpkg -l | grep -i 'ii postgresql '</pre>
+ A typical response would be:<pre>
+ ii postgresql 7.1.3-5 Object....[stuff deleted]</pre>
+ Indicating, that version 7.1.3 is installed (the -5 is a
+ Debian patch level). You can use dselect or apt-get to install
+ postgresql if you need to. You can visit the Debian maintainer's
+ page for much more information on related packages at<pre>
+ http://people.debian.org/~elphick/postgresql/</pre>
+ Older versions of Debian's PostgreSQL installation use a file
+ called postmaster.init, while newer versions use a file called
+ postmaster.conf, either residing in /etc/postgresql.
+<li>SQL-Ledger requires a HTTP server (or daemon) which is capable of
+ handling CGI scripts. Apache is the one which is recommended,
+ version 1.3 or better. Debian calls the base package apache.
+ Debian has two alternative versions of Apache, one with mod-perl
+ (apache-perl) support compiled in, and the other with SSL
+ (secure sockets layer - apache-ssl) support. SQL-Ledger doesn't
+ require mod-perl or SSL support, but works with either if
+ you need it installed for other functions you have. Older versions
+ of Debian Apache installations, spread the configuration of the
+ server across 3 files (srm.conf, access.conf and httpd.conf).
+ Newer versions have consolidated all of this to httpd.conf.
+<li>SQL-Ledger uses the Data Base Interface perl module for communication
+ with PostgreSQL. The CPAN (Comprehensive Perl Archive Network)
+ name for this module is DBI. Debian calls this module
+ libdbi-perl. You should probably deselect (or apt-get) the
+ Debian version of this module to minimize upgrading headaches in
+ the future.
+<li>DBI requires the use of an implementation specific Data Base
+ Driver. In our case, we need the PostgreSQL specific one.
+ CPAN calls this module DBD::PG, Debian calls it libdbd-pg-perl.
+ You should use dselect (or apt-get) to install it.
+<li>One more layer of Perl - PostgreSQL support is needed. Debian
+ calls this last package libpgperl. Use dselect or apt-get to
+ install it. (You should be able to install all 5 packages at
+ one time.)
+<li>We need to allow your PostgreSQL database to accept queries
+ in a network manner. To do this, we need to change the value
+ of the TCPIP_SOCKET to 1. In newer
+ PostgreSQL installs, this variable will be someplace in
+ /etc/postgresql/postgreslq.conf (older installs will be
+ postmaster.init, same directory. Note: you shouldn't have
+ both files there.) Start up your favorite text editor, find
+ the line with that variable on it, change the "no" to a "yes",
+ and make sure the line isn't commented out (a "#" in front
+ of it on the same line).
+<li>PostgreSQL has a set of users and passwords independent of
+ normal user logins. We need to set up a PostgreSQL user
+ to "own" the SQL-Ledger data (choose a name that makes sense
+ to you, it shouldn't be "root" or "postgres"). The (PostgreSQL)
+ program for doing this is called "createuser". To make this
+ SQL-Ledger owner user, we first need to "become" the PostgreSQL
+ superuser (on Debian, this is "postgres"), and then we will
+ run the createuser program. So, once we are logged in as root:
+<pre>
+ # su postgres
+ $ createuser -d sql-ledger
+ ...
+ $ exit
+ #
+</pre>
+ As shown above, we then typed "exit" after createuser was done,
+ to stop being the "postgres" user. The "-d" switch (you called
+ also use "--createdb") specifies that this user can create
+ databases.
+<li>We need to adjust the configuration of the HTTP server Apache
+ next. Older Apache installations (srm.conf, access.conf and
+ httpd.conf) need changes in srm.conf and httpd.conf. Newer
+ installations just need to edit /etc/apache/httpd.conf. First,
+ we need to instruct the server that files that end in ".pl"
+ are to be treated as "cgi-script"s (srm.conf if separate).<pre>
+ AddHandler cgi-script .pl</pre>
+ Second, we need to map our SQL-Ledger installation to be easy
+ for users to find it (in srm.conf if separate).<pre>
+ Alias /sql-ledger/ /usr/local/www/sql-ledger/</pre>
+ The "/" at the end of sql-ledger in both strings is important!
+ Next, we need to allow the server to execute files from those
+ directories, include things and follow links. This information
+ is in httpd.conf (old or new installations).<pre>
+ &lt;Directory /usr/local/www/sql-ledger&gt;
+ Options ExecCGI Includes FollowSymLinks
+ &lt;/Directory&gt;</pre>
+ If we decided to put SQL-Ledger somewhere other than
+ /usr/local/www/sql-ledger, we would use different paths above.
+<li>All the files in the "users" and "templates" subdirectories
+ of /usr/local/www/sql-ledger need to be owned by "www-data".<pre>
+ # cd /usr/local/www/sql-ledger
+ # chown www-data:www-data users templates users/members</pre>
+ You may get an "error" about users/members not existing. It
+ is safe to ignore this error.
+<li>Restart the apache server.<pre>
+ /etc/init.d/apache restart</pre>
+<li>From a browser, visit the URL<pre>
+ http://localhost/sql-ledger/admin.pl</pre>
+<li>Login as the PostgreSQL user responsible for the SQL-Ledger
+ database you set up. Create a database and create
+ at least one user. (It's not a good idea to access your
+ SQL-Ledger data as the "owner" of the data on a regular basis.)
+<li>Visit<pre>
+ http://localhost/sql-ledger/login.pl</pre>
+ and login as the user you created</pre>
+
+</ul>
+
+
+<p><li><h4>login.pl has compilation error</h4>
+
+This could be because of a missing configuration file in the users directory
+
+<p>check the permission for the users directory. The directory must be
+set writeable for the webserver. If your webserver runs under nobody.nogroup
+set it to
+<pre>
+drwxrwx--x 2 johndoe nogroup 1024 May 26 16:49 users
+
+or
+
+drwx--x--x 2 nobody nogroup 1024 May 26 16:49 users
+</pre>
+
+
+<p><li><h4>script not executing, shows in browser instead</h4>
+
+Add
+
+<pre>
+ AddHandler cgi-script .pl
+</pre>
+
+in your httpd.conf file.
+
+
+<p><li><h4>unknown terminal!</h4>
+the frontend script couldn't figure out which browser you are using
+<p>include the terminal variable on the URL
+<pre>
+ http://localhost/sql-ledger/login.pl?terminal=lynx</pre>
+<p>Valid terminal variables are lynx and mozilla
+
+
+<p><li><h4>permission denied at filesystem level</h4>
+
+Check if your web server has write permission to write to the following
+files and directories:
+<pre>
+ users/
+ templates/
+ users/members
+
+ # chown nobody:nogroup users templates users/members
+</pre>
+
+
+<p><li><h4>permission denied to access tables</h4>
+The user you entered in the "Database section" must be a valid
+database user who has the rights to access the tables.
+
+<p>If the tables are owned by 'john' and you enter 'mary' as the dba
+you might run into this problem if mary doesn't have the rights to
+access tables owned by john.
+
+
+<p><li><h4>html and graphics files don't show up on screen</h4>
+
+Enable Includes and FollowSymlinks Options in your httpd.conf file
+<pre> &lt;Directory /usr/local/sql-ledger&gt;
+ Options ExecCGI Includes FollowSymlinks
+ &lt;/Directory&gt;
+</pre>
+
+
+<p><li><h4>Can I use mySQL</h4>
+
+No. mySQL lacks certain features required by SQL-Ledger.
+
+
+<p><li><h4>switch display to a foreign language</h4>
+
+Load your preferences and select the language.
+<br>Language selection is in accordance to
+<a href=http://www.unece.org/cefact/locode/service/main.htm>
+ISO 3166-1</a> standards.
+
+
+<p><li><h4>Text shows in English when I use a foreign language</h4>
+
+This is because the corresponding hash entry is missing.
+Add the missing text in the locale/cc/all or locale/cc/missing
+file and run 'perl locales.pl' to rebuild the individual files.
+
+<br>cc refers to the country code.
+
+
+<p><li><h4>switch to a foreign language for the login and admin screen</h4>
+
+Edit sql-ledger.conf and enter the code for the variable
+$language. If your language specific files are in 'locales/cc', enter 'cc'
+
+
+</ul>
+
+<p>
+<hr>
+<a name=security>
+<h1>SQL-Ledger security</h1>
+</a>
+
+<ul>
+<li>The security features built into SQL-Ledger provide encrypted passwords
+and access control which makes it fairly safe out of the box to run even in
+front of a firewall.
+Some precautions which are out of our control must be taken though.
+It matters where you install SL and how you configure your web and SQL server.
+
+<pre>
+ Typical setups:
+
+ /usr/local/vh/www <- DocumentRoot for virtual host
+ /usr/local/vh/sql-ledger <- Alias for sql-ledger
+ /usr/local/vh/users <- users directory out of reach
+
+<hr width=60% align=left>
+ /usr/local/vh/www <- DocumentRoot for virtual host
+ /usr/local/vh/www/sql-ledger <- Alias for sql-ledger
+ /usr/local/vh/www/sql-ledger/users <- users configuration files and tmp space
+
+ &lt;Directory /usr/local/vh/www/sql-ledger/users&gt; <- disable webserver access
+ Order Deny,Allow for users directory
+ Deny from All
+ &lt;/Directory&gt;
+
+</pre>
+
+The location for the users directory can be specified in sql-ledger.conf
+
+<p><li>Set permission for the users and templates directory to 711
+(most restrictive)
+
+<p><li>If you do not want anyone to change the templates with the built-in
+editor set the files in templates/directory/ to read only or disable
+the menu item to edit the templates.
+
+<p><li>For PostgreSQL you can set who has access to the server in the file
+pg_hba.conf
+<br>Authentication crypt does not work because not all SQL servers
+accept encrypted passwords.
+
+<p><li>in addition you can secure the tables from unauthorized access by
+setting up a different database user and GRANT rights. For instance,
+users without DELETE rights will still be able to use the program, change
+customers or vendors but will not be able to delete transactions.
+To lock all the tables GRANT SELECT rights only.
+
+<p><li>Other security options include a secure shell, your webserver's
+authentication system, SSL, encrypted tunnels, ...
+
+</ul>
+
+</BODY>
+</HTML>
+
diff --git a/sql-ledger/favicon.ico b/sql-ledger/favicon.ico
new file mode 100644
index 0000000..43578f4
--- /dev/null
+++ b/sql-ledger/favicon.ico
Binary files differ
diff --git a/sql-ledger/locale/br/COPYING b/sql-ledger/locale/br/COPYING
new file mode 100644
index 0000000..133af7d
--- /dev/null
+++ b/sql-ledger/locale/br/COPYING
@@ -0,0 +1,24 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2002
+#
+# Brazilian texts:
+#
+# Author: Andre Felipe Machado <andremachado@techforce.com.br>
+# Miguel Koren O'Brien de Lacy <miguelk@konsultex.com.br>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/br/LANGUAGE b/sql-ledger/locale/br/LANGUAGE
new file mode 100644
index 0000000..d45d52d
--- /dev/null
+++ b/sql-ledger/locale/br/LANGUAGE
@@ -0,0 +1 @@
+Brazilian Portuguese
diff --git a/sql-ledger/locale/br/admin b/sql-ledger/locale/br/admin
new file mode 100644
index 0000000..c5cd2e1
--- /dev/null
+++ b/sql-ledger/locale/br/admin
@@ -0,0 +1,122 @@
+$self{texts} = {
+ 'Access Control' => 'Controle de Acesso',
+ 'Accounting' => 'Contabilidade',
+ 'Add User' => 'Adicionar Usuário',
+ 'Address' => 'Endereço',
+ 'Administration' => 'Administração',
+ 'Administrator' => 'Administrador',
+ 'All Datasets up to date!' => 'Todos grupos de dados atualizados!',
+ 'Change Admin Password' => 'Trocar senha de administração',
+ 'Change Password' => 'Trocar senha',
+ 'Character Set' => 'Conjunto de caracteres',
+ 'Click on login name to edit!' => 'Clique no nome de acesso para editar',
+ 'Company' => 'Companhia',
+ 'Connect to' => 'Conectar a',
+ 'Continue' => 'Continuar',
+ 'Create Chart of Accounts' => 'Criar Carta de Contas',
+ 'Create Dataset' => 'Criar conjunto de dados',
+ 'DBI not installed!' => 'Driver de Interface de Banco de dados NÃO INSTALADO!',
+ 'Database' => 'Banco de Dados',
+ 'Database Administration' => 'Administração da Base de Dados',
+ 'Database Driver not checked!' => 'Driver do banco de dados não selecionado!',
+ 'Database User missing!' => 'Usuário da base de dados faltando!',
+ 'Dataset' => 'Conjunto de dados',
+ 'Dataset missing!' => 'Conjunto de dados faltando!',
+ 'Dataset updated!' => 'Conjunto de dados atualizado',
+ 'Date Format' => 'Formato de Data',
+ 'Delete' => 'Apagar',
+ 'Delete Dataset' => 'Apagar conjunto de dados',
+ 'Directory' => 'Diretório',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Limite de dropdown',
+ 'E-mail' => 'E-Mail',
+ 'Edit User' => 'Editar Usuário',
+ 'Existing Datasets' => 'Conjunto de dados existentes',
+ 'Fax' => 'Fax',
+ 'Host' => 'Servidor',
+ 'Hostname missing!' => 'Nome do servidor faltando!',
+ 'Incorrect Password!' => 'Senha incorreta!',
+ 'Language' => 'Idioma',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deixe os campos de servidor e porta vazios a menos que você queira fazer uma conexão remota',
+ 'Login' => 'Acessar/login',
+ 'Name' => 'Nome',
+ 'New Templates' => 'Novos Modelos',
+ 'No Database Drivers available!' => 'Nenhum driver de banco de dados disponível!',
+ 'No Dataset selected!' => 'Nenhum conjunto de dados selecionado!',
+ 'Nothing to delete!' => 'Nada para apagar!',
+ 'Number Format' => 'Formato de números',
+ 'Oracle Database Administration' => 'Administração da Base de Dados Oracle',
+ 'Password' => 'Senha',
+ 'Password changed!' => 'Senha trocada!',
+ 'Pg Database Administration' => 'Administração da Base de Dados PostgreSQL',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Porta',
+ 'Port missing!' => 'Porta faltando!',
+ 'Printer' => 'Impressora',
+ 'Save' => 'Salvar',
+ 'Select a Dataset to delete and press "Continue"' => 'Selecione um conjunto de dados para APAGAR e pressione Continue',
+ 'Setup Templates' => 'Modelos de Configuração',
+ 'Ship via' => 'Transportar via',
+ 'Signature' => 'Assinatura',
+ 'Stylesheet' => 'Folha de estilos',
+ 'Templates' => 'Modelos',
+ 'The following Datasets are not in use and can be deleted' => 'Os seguintes conjuntos de dados NÃO estão em uso e PODEM ser apagados',
+ 'The following Datasets need to be updated' => 'Os seguintes grupos de dados precisam ser atualizados',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta é uma verificação preliminar por fontes existentes. Nada será criado ou apagado neste estágio!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para adicionar um usuário a um grupo edite um nome, troque o nome de acesso/login e salve. Um novo usuário com as mesmas variáveis será então salvo sob o novo nome de acesso/login.',
+ 'Update Dataset' => 'Atualizar grupo de dados',
+ 'Use Templates' => 'Use Modelos',
+ 'User' => 'Usuário',
+ 'User deleted!' => 'Usuário apagado!',
+ 'User saved!' => 'Usuário salvo',
+ 'Version' => 'Versão',
+ 'You must enter a host and port for local and remote connections!' => 'Você precisa entrar um servidor e uma porta para conexões locais e remotas!',
+ 'does not exist' => 'Não existe',
+ 'is already a member!' => 'já é um membro!',
+ 'localhost' => 'localhost /servidor local',
+ 'successfully created!' => 'Criado com sucesso!',
+ 'successfully deleted!' => 'Apagado com sucesso!',
+ 'website' => 'website',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'adicionar_usuário' => 'add_user',
+ 'trocar_senha_de_administração' => 'change_admin_password',
+ 'trocar_senha' => 'change_password',
+ 'continuar' => 'continue',
+ 'criar_conjunto_de_dados' => 'create_dataset',
+ 'apagar' => 'delete',
+ 'apagar_conjunto_de_dados' => 'delete_dataset',
+ 'acessar/login' => 'login',
+ 'administração_da_base_de_dados_oracle' => 'oracle_database_administration',
+ 'administração_da_base_de_dados_postgresql' => 'pg_database_administration',
+ 'salvar' => 'save',
+ 'atualizar_grupo_de_dados' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/br/all b/sql-ledger/locale/br/all
new file mode 100644
index 0000000..b656204
--- /dev/null
+++ b/sql-ledger/locale/br/all
@@ -0,0 +1,487 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Contas a Pagar',
+ 'AP Aging' => 'Contas a Pagar Vencidas',
+ 'AP Transaction' => 'Transação - Contas a Pagar',
+ 'AP Transactions' => 'Transações - Contas a Pagar',
+ 'AR' => 'Contas a Receber',
+ 'AR Aging' => 'Contas a Receber Vencidas',
+ 'AR Transaction' => 'Transação - Contas a Receber',
+ 'AR Transactions' => 'Transações - Contas a Receber',
+ 'About' => 'Sobre',
+ 'Access Control' => 'Controle de Acesso',
+ 'Account' => 'Conta',
+ 'Account Number' => 'Número da Conta',
+ 'Account Number missing!' => 'Número da Conta não encontrado!',
+ 'Account Type' => 'Tipo de Conta',
+ 'Account Type missing!' => 'Tipo de Conta não encontrado!',
+ 'Account deleted!' => 'Conta apagada!',
+ 'Account saved!' => 'Conta salva!',
+ 'Accounting' => 'Contabilidade',
+ 'Accounting Menu' => 'Menu de Contabilidade',
+ 'Accounts' => 'Contas',
+ 'Active' => 'Ativa',
+ 'Add' => 'Adicionar',
+ 'Add Account' => 'Adicionar Conta',
+ 'Add Accounts Payables Transaction' => 'Adicionar Transação de contas pagáveis',
+ 'Add Accounts Receivables Transaction' => 'Adicionar Transação de contas recebíveis',
+ 'Add Assembly' => 'Adicionar Conjunto',
+ 'Add Customer' => 'Adicionar Cliente',
+ 'Add GIFI' => 'Adicionar CFOP',
+ 'Add General Ledger Transaction' => 'Adicionar Transação Livro Razão',
+ 'Add Part' => 'Adicionar Parte',
+ 'Add Project' => 'Adicionar projeto',
+ 'Add Purchase Invoice' => 'Adicionar Fatura de Compra',
+ 'Add Purchase Order' => 'Adicionar Pedido de Compra',
+ 'Add Sales Invoice' => 'Adicionar Fatura de Venda',
+ 'Add Sales Order' => 'Adicionar Pedido de Venda',
+ 'Add Service' => 'Adicionar Serviço',
+ 'Add Transaction' => 'Adicionar Transação',
+ 'Add User' => 'Adicionar Usuário',
+ 'Add Vendor' => 'Adicionar Distribuidor',
+ 'Address' => 'Endereço',
+ 'Administration' => 'Administração',
+ 'Administrator' => 'Administrador',
+ 'All' => 'Todas',
+ 'All Datasets up to date!' => 'Todos grupos de dados atualizados!',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Total Devido',
+ 'Amount does not equal applied!' => 'Total não é igual ao aplicado!',
+ 'Amount missing!' => 'Total faltando!',
+ 'Applied' => 'Aplicado',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => 'Tem certeza que quer APAGAR a Fatura Número',
+ 'Are you sure you want to delete Order Number' => 'Tem certeza que quer APAGAR tal número de Pedido?',
+ 'Are you sure you want to delete Transaction' => 'Tem certeza que quer APAGAR a Transação',
+ 'Assemblies' => 'Conjuntos',
+ 'Assemblies restocked!' => 'Conjuntos re estocados',
+ 'Assembly Number missing!' => 'Número de conjunto faltando!',
+ 'Asset' => 'Ativo',
+ 'Attachment' => 'Anexo',
+ 'Audit Control' => 'Controle de Auditoria',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'Lista de Material',
+ 'Backup' => 'Cópia de reserva',
+ 'Backup sent to' => 'Cópia reserva enviada para',
+ 'Balance' => 'Balanço',
+ 'Balance Sheet' => 'Folha de Balanço',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Caixa/bandeja',
+ 'Books are open' => 'Livros estão abertos',
+ 'Bought' => 'Comprado',
+ 'Business Number' => 'Número de negócio',
+ 'C' => 'F',
+ 'COGS' => 'Custo de Vendas',
+ 'Cannot delete account!' => 'Não pode apagar conta!',
+ 'Cannot delete customer!' => 'Não pode apagar cliente!',
+ 'Cannot delete default account!' => 'Não pode apagar conta padrão!',
+ 'Cannot delete invoice!' => 'Não pode apagar fatura!',
+ 'Cannot delete item already invoiced!' => 'Não posso apagar item já faturado!',
+ 'Cannot delete item on order!' => 'Não pode apagar item no pedido',
+ 'Cannot delete item which is part of an assembly!' => 'Não posso apagar item que é parte de um conjunto',
+ 'Cannot delete item!' => 'Não pode apagar item!',
+ 'Cannot delete order!' => 'Não pode apagar pedido!',
+ 'Cannot delete transaction!' => 'Não pode apagar transação!',
+ 'Cannot delete vendor!' => 'Não pode apagar fornecedor!',
+ 'Cannot have a value in both Debit and Credit!' => 'Não pode ter um valor em ambos Débito e Crédito!',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => 'Não pode lançar fatura em período fechado!',
+ 'Cannot post invoice!' => 'Não pode lançar fatura!',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cannot post payment!' => 'Não pode lançar pagamento!',
+ 'Cannot post transaction for a closed period!' => 'Não pode lançar transação para um período já encerrado!',
+ 'Cannot post transaction!' => 'Não pode lançar transação',
+ 'Cannot process payment for a closed period!' => 'Não pode processar pagamento para um pedíodo já encerrado!',
+ 'Cannot save account!' => 'Não pode salvar conta!',
+ 'Cannot save order!' => 'Não pode salvar pedido!',
+ 'Cannot save preferences!' => 'Não pode salvar preferências!',
+ 'Cannot stock assemblies!' => 'Não pode estocar conjuntos!',
+ 'Cash' => 'Caixa',
+ 'Cash based' => 'Baseado no Caixa',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => 'Trocar senha de administração',
+ 'Change Password' => 'Trocar senha',
+ 'Character Set' => 'Conjunto de caracteres',
+ 'Chart of Accounts' => 'Código de Contas',
+ 'Check' => 'Cheque',
+ 'Check printed!' => 'Cheque impresso',
+ 'Check printing failed!' => 'Impressão de cheque falhou!',
+ 'Cleared Balance' => 'Balanço limpo',
+ 'Click on login name to edit!' => 'Clique no nome de acesso para editar',
+ 'Close Books up to' => 'Encerrar livros até',
+ 'Closed' => 'Fechado',
+ 'Company' => 'Companhia',
+ 'Compare to' => 'Comparar a',
+ 'Confirm!' => 'Confirmar!',
+ 'Connect to' => 'Conectar a',
+ 'Contact' => 'Contato',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Copy to COA' => 'Copiar para Plano de Contas',
+ 'Create Chart of Accounts' => 'Criar Carta de Contas',
+ 'Create Dataset' => 'Criar conjunto de dados',
+ 'Credit' => 'Crédito',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Curr' => 'Moeda',
+ 'Currency' => 'Moeda',
+ 'Current' => '',
+ 'Customer' => 'Cliente',
+ 'Customer deleted!' => 'Cliente apagado!',
+ 'Customer missing!' => 'Cliente faltando!',
+ 'Customer not on file!' => 'Cliente não está no arquivo!',
+ 'Customer saved!' => 'Cliente salvo',
+ 'Customers' => 'Clientes',
+ 'DBI not installed!' => 'Driver de Interface de Banco de dados NÃO INSTALADO!',
+ 'Database' => 'Banco de Dados',
+ 'Database Administration' => 'Administração da Base de Dados',
+ 'Database Driver not checked!' => 'Driver do banco de dados não selecionado!',
+ 'Database Host' => 'Servidor de Base de Dados',
+ 'Database User missing!' => 'Usuário da base de dados faltando!',
+ 'Dataset' => 'Conjunto de dados',
+ 'Dataset missing!' => 'Conjunto de dados faltando!',
+ 'Dataset updated!' => 'Conjunto de dados atualizado',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data de Vencimento',
+ 'Date Format' => 'Formato de Data',
+ 'Date Paid' => 'Data de pagamento',
+ 'Date missing!' => 'Data faltando!',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito e crédito fora de balanço!',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Decimalplaces' => 'Casas decimais',
+ 'Delete' => 'Apagar',
+ 'Delete Account' => 'Apagar Conta',
+ 'Delete Dataset' => 'Apagar conjunto de dados',
+ 'Delivery Date' => 'Data de entrega',
+ 'Deposit' => 'Depósito',
+ 'Description' => 'Descrição',
+ 'Difference' => 'Diferença',
+ 'Directory' => 'Diretório',
+ 'Discount' => 'Desconto',
+ 'Done' => 'Feito',
+ 'Drawing' => 'Desenho',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Limite de dropdown',
+ 'Due' => 'Saldo',
+ 'Due Date' => 'Data de Vencimento',
+ 'Due Date missing!' => 'Data de Vencimento faltando!',
+ 'E-mail' => 'E-Mail',
+ 'E-mail Statement to' => 'Declaração enviada por email para',
+ 'E-mail address missing!' => 'Endereço de E-mail faltando!',
+ 'Edit' => 'Editar',
+ 'Edit Account' => 'Editar Conta',
+ 'Edit Accounts Payables Transaction' => 'Editar Transação - Contas a Pagar',
+ 'Edit Accounts Receivables Transaction' => 'Editar Transação - Contas a Receber',
+ 'Edit Assembly' => 'Editar Conjunto',
+ 'Edit GIFI' => 'Editar CFOP',
+ 'Edit General Ledger Transaction' => 'Editar Transação Livro Razão',
+ 'Edit Part' => 'Editar Parte',
+ 'Edit Preferences for' => 'Editar Preferências para',
+ 'Edit Project' => 'Editar Projeto',
+ 'Edit Purchase Invoice' => 'Editar Fatura de Compra',
+ 'Edit Purchase Order' => 'Editar Pedido de Compra',
+ 'Edit Sales Invoice' => 'Editar Fatura de Venda',
+ 'Edit Sales Order' => 'Editar Pedido de Venda',
+ 'Edit Service' => 'Editar Serviço',
+ 'Edit Template' => 'Editar Modelo',
+ 'Edit User' => 'Editar Usuário',
+ 'Employee' => 'Empregado',
+ 'Enforce transaction reversal for all dates' => 'Forçar execução de reversão de transação para todas as datas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Entre com até 3 letras separadas por dois pontos (i.e CAD:USD:EUR) para sua moeda local e estrangeira',
+ 'Equity' => 'Capital',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de câmbio',
+ 'Exchangerate Difference' => 'Diferença da Taxa de Câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Existing Datasets' => 'Conjunto de dados existentes',
+ 'Expense' => 'Despesa',
+ 'Expense Account' => 'Conta de Despesas',
+ 'Expense/Asset' => 'Despesa/Ativo',
+ 'Extended' => 'Extendida',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'Foreign Exchange Gain' => 'Ganho com câmbio estrangeiro',
+ 'Foreign Exchange Loss' => 'Perda com câmbio estrangeiro',
+ 'From' => 'De',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'GIFI deleted!' => 'CFOP apagado!',
+ 'GIFI missing!' => 'CFOP faltando!',
+ 'GIFI saved!' => 'CFOP salvo!',
+ 'GL Transaction' => 'Transação do Livro Razão',
+ 'General Ledger' => 'Livro Razão',
+ 'Goods & Services' => 'Produtos e Serviços',
+ 'HTML Templates' => 'Modelos HTML',
+ 'Heading' => 'Cabeçalho',
+ 'Host' => 'Servidor',
+ 'Hostname missing!' => 'Nome do servidor faltando!',
+ 'ID' => 'ID',
+ 'Image' => 'Imagem',
+ 'In-line' => 'em linha',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Include in drop-down menus' => 'Incluir nos menus drop-down (tipo cortina)',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluir esta conta nos formulários de cliente/fornecedor para marcar cliente/fornecedor como sujeito a impostos.',
+ 'Income' => 'Receita',
+ 'Income Account' => 'Conta de Receitas',
+ 'Income Statement' => 'Estado de Receitas',
+ 'Incorrect Dataset version!' => 'Versão incorreta de grupos de dados!',
+ 'Incorrect Password!' => 'Senha incorreta!',
+ 'Individual Items' => 'Ítens individuais',
+ 'Inventory' => 'Estoque',
+ 'Inventory Account' => 'Conta de Estoque',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Quantidade em estoque TEM de ser zero ANTES que você possa tornar este conjunto obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Quantidade em estoque TEM de ser zero ANTES que você possa tornar esta parte/peça obsoleta!',
+ 'Inventory quantity must be zero!' => 'Quantidade em estoque TEM de ser zero!',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Data de Fatura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Fatura',
+ 'Invoice Number missing!' => 'Número de Fatura não encontrado!',
+ 'Invoice deleted!' => 'Fatura apagada!',
+ 'Invoice posted!' => 'Fatura lançada!',
+ 'Invoices' => 'Faturas',
+ 'Is this a summary account to record' => 'Esta é uma conta sumária a registrar?',
+ 'Item deleted!' => 'Item apagado!',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'LaTeX Templates' => 'Modelos LaTeX',
+ 'Language' => 'Idioma',
+ 'Last Cost' => 'Último Custo',
+ 'Last Invoice Number' => 'Último Número de Fatura',
+ 'Last Numbers & Default Accounts' => 'Últimos números e Contas Padrão',
+ 'Last Purchase Order Number' => 'Último Número de Pedido de Compra',
+ 'Last Sales Order Number' => 'Último número de pedido de vendas',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deixe os campos de servidor e porta vazios a menos que você queira fazer uma conexão remota',
+ 'Liability' => 'Passivo',
+ 'Licensed to' => 'Licenciado a',
+ 'Line Total' => 'Total da linha',
+ 'Link' => 'Ligar',
+ 'Link Accounts' => 'Ligar Contas',
+ 'List Accounts' => 'Listar Contas',
+ 'List GIFI' => 'Listar CFOP',
+ 'List Price' => 'Preço de lista',
+ 'List Transactions' => 'Listar Transações',
+ 'Login' => 'Acessar/login',
+ 'Logout' => 'Logout (sair)',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Microfiche' => 'Microficha',
+ 'Model' => 'Modelo',
+ 'N/A' => 'N/D',
+ 'Name' => 'Nome',
+ 'Name missing!' => 'Nome faltando!',
+ 'New Templates' => 'Novos Modelos',
+ 'No' => 'Não',
+ 'No Database Drivers available!' => 'Nenhum driver de banco de dados disponível!',
+ 'No Dataset selected!' => 'Nenhum conjunto de dados selecionado!',
+ 'No email address for' => 'Sem endereço de email para',
+ 'No.' => '',
+ 'Notes' => 'Notas',
+ 'Nothing applied!' => 'Nada foi aplicado!',
+ 'Nothing selected!' => 'Nada foi selecionado!',
+ 'Nothing to delete!' => 'Nada para apagar!',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato de números',
+ 'Number missing in Row' => 'Número faltando na linha',
+ 'O' => 'A',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'On Hand' => 'Em Mãos',
+ 'On Order' => 'Em pedido',
+ 'Open' => 'Abrir',
+ 'Oracle Database Administration' => 'Administração da Base de Dados Oracle',
+ 'Order' => 'Pedido',
+ 'Order Date' => 'Data de Pedido',
+ 'Order Date missing!' => 'Data de Pedido Faltando',
+ 'Order Entry' => 'Entrada de Pedido',
+ 'Order Number' => 'Pedido Número',
+ 'Order Number missing!' => 'Número de pedido faltando!',
+ 'Order deleted!' => 'Pedido apagado!',
+ 'Order saved!' => 'Pedido salvo!',
+ 'Ordered' => 'Pedido feito',
+ 'Orphaned' => 'Ficaram órfãs',
+ 'Out of balance!' => 'Fora de balanço!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empacotamento',
+ 'Packing List Date missing!' => 'Data da lista de empacotamento faltando!',
+ 'Packing List Number missing!' => 'Número da lista de empacotamento faltando!',
+ 'Paid' => 'Total Efetuado',
+ 'Paid in full' => '',
+ 'Part' => 'Parte',
+ 'Part Number missing!' => 'Número da parte não encontrado!',
+ 'Parts' => 'Partes',
+ 'Parts Inventory' => 'Estoque de Partes',
+ 'Password' => 'Senha',
+ 'Password changed!' => 'Senha trocada!',
+ 'Payables' => 'A Pagar',
+ 'Payment' => 'Pagamento',
+ 'Payment date missing!' => 'Data de pagamento faltando!',
+ 'Payment posted!' => 'Pagamento Lançado',
+ 'Payments' => 'Pagamentos',
+ 'Pg Database Administration' => 'Administração da Base de Dados PostgreSQL',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Porta',
+ 'Port missing!' => 'Porta faltando!',
+ 'Post' => 'Lançar',
+ 'Post as new' => 'Lançar como novo',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Preferências',
+ 'Preferences saved!' => 'Preferências Salvas!',
+ 'Price' => 'Preço',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projeto',
+ 'Project Number missing!' => 'Número do Projeto faltando!',
+ 'Project deleted!' => 'Projeto apagado!',
+ 'Project not on file!' => 'Projeto não está no arquivo!',
+ 'Project saved!' => 'Projeto salvo!',
+ 'Projects' => 'Projetos',
+ 'Purchase Invoice' => 'Fatura de compra',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Purchase Orders' => 'Ordens de Compra',
+ 'Qty' => 'Qtde',
+ 'ROP' => 'Nível mínimo de estoque',
+ 'Rate' => 'Taxa',
+ 'Recd' => 'Recebidos',
+ 'Receipt' => 'Recibo',
+ 'Receipts' => 'Recibos',
+ 'Receivables' => 'A Receber',
+ 'Reconciliation' => 'Reconciliação',
+ 'Record in' => 'Registrar em',
+ 'Reference' => 'Referência',
+ 'Reference missing!' => 'Referência faltando!',
+ 'Remaining' => 'Restante',
+ 'Report for' => 'Relatório para',
+ 'Reports' => 'Relatórios',
+ 'Required by' => 'Requerido por',
+ 'Retained Earnings' => 'Lucros Retidos',
+ 'Sales' => 'Vendas',
+ 'Sales Invoice' => 'Fatura de Venda',
+ 'Sales Order' => 'Pedido de Venda',
+ 'Sales Orders' => 'Pedidos de Venda',
+ 'Save' => 'Salvar',
+ 'Save as new' => 'Salvar como novo',
+ 'Save to File' => 'Salvar para Arquivo',
+ 'Screen' => 'Tela',
+ 'Select a Dataset to delete and press "Continue"' => 'Selecione um conjunto de dados para APAGAR e pressione Continue',
+ 'Select all' => 'Selecionar todos',
+ 'Select from one of the items below' => 'Selecione um dos ítens abaixo',
+ 'Select from one of the names below' => 'Selecione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Selecione um dos projetos abaixo',
+ 'Select postscript or PDF!' => 'Selecionar Postscript ou PDF',
+ 'Sell Price' => 'Preço de Venda',
+ 'Send by E-Mail' => 'Enviar por E-mail',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Service Items' => 'Ítens de Serviço',
+ 'Service Number missing!' => 'Número do serviço não encontrado!',
+ 'Services' => 'Serviços',
+ 'Setup Templates' => 'Modelos de Configuração',
+ 'Ship' => 'Transportar',
+ 'Ship to' => 'Transportar para',
+ 'Ship via' => 'Transportar via',
+ 'Short' => 'Curto',
+ 'Signature' => 'Assinatura',
+ 'Sold' => 'Vendido',
+ 'Source' => 'Fonte',
+ 'Standard' => 'Padrão',
+ 'Statement' => 'Declaração',
+ 'Statement Balance' => 'Declaração de Balanço',
+ 'Statement sent to' => 'Declaração enviada para',
+ 'Statements sent to printer!' => 'Declaração enviada para impressora!',
+ 'Stock Assembly' => 'Conjunto normal de estoque',
+ 'Stylesheet' => 'Folha de estilos',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'System' => 'Sistema',
+ 'Tax' => 'Imposto',
+ 'Tax Accounts' => 'Contas de Impostos',
+ 'Tax Included' => 'Impostos incluídos',
+ 'Tax collected' => 'Imposto recolhido',
+ 'Tax paid' => 'Imposto pago',
+ 'Taxable' => 'Sujeito a impostos',
+ 'Template saved!' => 'Modelo salvo!',
+ 'Templates' => 'Modelos',
+ 'Terms: Net' => 'Crédito Líquido',
+ 'The following Datasets are not in use and can be deleted' => 'Os seguintes conjuntos de dados NÃO estão em uso e PODEM ser apagados',
+ 'The following Datasets need to be updated' => 'Os seguintes grupos de dados precisam ser atualizados',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta é uma verificação preliminar por fontes existentes. Nada será criado ou apagado neste estágio!',
+ 'To' => 'Até',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para adicionar um usuário a um grupo edite um nome, troque o nome de acesso/login e salve. Um novo usuário com as mesmas variáveis será então salvo sob o novo nome de acesso/login.',
+ 'Top Level' => 'Nível superior',
+ 'Total' => 'Total',
+ 'Transaction Date missing!' => 'Data de transação faltando!',
+ 'Transaction deleted!' => 'Transação apagada!',
+ 'Transaction posted!' => 'Transação lançada',
+ 'Transaction reversal enforced for all dates' => 'Reversão de transação forçada para todas as datas.',
+ 'Transaction reversal enforced up to' => 'Reversão de transação forçada até ',
+ 'Transactions' => 'Tansações',
+ 'Transactions exist, cannot delete customer!' => 'Existem transações, não pode apagar o cliente!',
+ 'Transactions exist, cannot delete vendor!' => 'Existem transações, não pode apagar fornecedor!',
+ 'Transactions exist; cannot delete account!' => 'Existem transações, não pode apagar conta!',
+ 'Trial Balance' => 'Balanço Preliminar',
+ 'Unit' => 'Unidade',
+ 'Unit of measure' => 'Unidade de medida',
+ 'Update' => 'Atualizar',
+ 'Update Dataset' => 'Atualizar grupo de dados',
+ 'Updated' => 'Atualizado',
+ 'Use Templates' => 'Use Modelos',
+ 'User' => 'Usuário',
+ 'User deleted!' => 'Usuário apagado!',
+ 'User saved!' => 'Usuário salvo',
+ 'Vendor' => 'Distribuidor',
+ 'Vendor deleted!' => 'Distribuidor apagado!',
+ 'Vendor missing!' => 'Distribuidor faltando!',
+ 'Vendor not on file!' => 'Distribuidor não está no arquivo!',
+ 'Vendor saved!' => 'Distribuidor salvo!',
+ 'Vendors' => 'Distribuidores',
+ 'Version' => 'Versão',
+ 'Weight' => 'Peso',
+ 'Weight Unit' => 'Unidade de Peso',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'Year End' => 'Fim de ano',
+ 'Yes' => 'Sim',
+ 'You are logged out!' => 'Você saiu do sistema!',
+ 'You did not enter a name!' => 'Você não entrou com um nome',
+ 'You must enter a host and port for local and remote connections!' => 'Você precisa entrar um servidor e uma porta para conexões locais e remotas!',
+ 'as at' => 'como em',
+ 'collected on sales' => 'recolhido sobre vendas',
+ 'days' => 'Dias',
+ 'does not exist' => 'Não existe',
+ 'ea' => 'cada',
+ 'emailed to' => 'enviado por email para',
+ 'for Period' => 'pelo período',
+ 'hr' => 'h',
+ 'is already a member!' => 'já é um membro!',
+ 'is not a member!' => 'não é um membro!',
+ 'localhost' => 'localhost /servidor local',
+ 'paid on purchases' => 'pago em aquisições',
+ 'sent to printer' => 'enviado para impressora',
+ 'successfully created!' => 'Criado com sucesso!',
+ 'successfully deleted!' => 'Apagado com sucesso!',
+ 'to' => 'para',
+ 'website' => 'website',
+};
+
+1;
diff --git a/sql-ledger/locale/br/am b/sql-ledger/locale/br/am
new file mode 100644
index 0000000..eafe19d
--- /dev/null
+++ b/sql-ledger/locale/br/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Contas a Pagar',
+ 'AR' => 'Contas a Receber',
+ 'Account' => 'Conta',
+ 'Account Number' => 'Número da Conta',
+ 'Account Number missing!' => 'Número da Conta não encontrado!',
+ 'Account Type' => 'Tipo de Conta',
+ 'Account Type missing!' => 'Tipo de Conta não encontrado!',
+ 'Account deleted!' => 'Conta apagada!',
+ 'Account saved!' => 'Conta salva!',
+ 'Add Account' => 'Adicionar Conta',
+ 'Add GIFI' => 'Adicionar CFOP',
+ 'Address' => 'Endereço',
+ 'Asset' => 'Ativo',
+ 'Audit Control' => 'Controle de Auditoria',
+ 'Backup sent to' => 'Cópia reserva enviada para',
+ 'Books are open' => 'Livros estão abertos',
+ 'Business Number' => 'Número de negócio',
+ 'COGS' => 'Custo de Vendas',
+ 'Cannot delete account!' => 'Não pode apagar conta!',
+ 'Cannot delete default account!' => 'Não pode apagar conta padrão!',
+ 'Cannot save account!' => 'Não pode salvar conta!',
+ 'Cannot save preferences!' => 'Não pode salvar preferências!',
+ 'Character Set' => 'Conjunto de caracteres',
+ 'Chart of Accounts' => 'Código de Contas',
+ 'Close Books up to' => 'Encerrar livros até',
+ 'Company' => 'Companhia',
+ 'Continue' => 'Continuar',
+ 'Copy to COA' => 'Copiar para Plano de Contas',
+ 'Credit' => 'Crédito',
+ 'Date Format' => 'Formato de Data',
+ 'Debit' => 'Débito',
+ 'Delete' => 'Apagar',
+ 'Delete Account' => 'Apagar Conta',
+ 'Description' => 'Descrição',
+ 'Dropdown Limit' => 'Limite de dropdown',
+ 'E-mail' => 'E-Mail',
+ 'Edit' => 'Editar',
+ 'Edit Account' => 'Editar Conta',
+ 'Edit GIFI' => 'Editar CFOP',
+ 'Edit Preferences for' => 'Editar Preferências para',
+ 'Edit Template' => 'Editar Modelo',
+ 'Enforce transaction reversal for all dates' => 'Forçar execução de reversão de transação para todas as datas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Entre com até 3 letras separadas por dois pontos (i.e CAD:USD:EUR) para sua moeda local e estrangeira',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Despesa',
+ 'Expense Account' => 'Conta de Despesas',
+ 'Expense/Asset' => 'Despesa/Ativo',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Ganho com câmbio estrangeiro',
+ 'Foreign Exchange Loss' => 'Perda com câmbio estrangeiro',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'GIFI deleted!' => 'CFOP apagado!',
+ 'GIFI missing!' => 'CFOP faltando!',
+ 'GIFI saved!' => 'CFOP salvo!',
+ 'Heading' => 'Cabeçalho',
+ 'Include in drop-down menus' => 'Incluir nos menus drop-down (tipo cortina)',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluir esta conta nos formulários de cliente/fornecedor para marcar cliente/fornecedor como sujeito a impostos.',
+ 'Income' => 'Receita',
+ 'Income Account' => 'Conta de Receitas',
+ 'Inventory' => 'Estoque',
+ 'Inventory Account' => 'Conta de Estoque',
+ 'Is this a summary account to record' => 'Esta é uma conta sumária a registrar?',
+ 'Language' => 'Idioma',
+ 'Last Invoice Number' => 'Último Número de Fatura',
+ 'Last Numbers & Default Accounts' => 'Últimos números e Contas Padrão',
+ 'Last Purchase Order Number' => 'Último Número de Pedido de Compra',
+ 'Last Sales Order Number' => 'Último número de pedido de vendas',
+ 'Liability' => 'Passivo',
+ 'Link' => 'Ligar',
+ 'Name' => 'Nome',
+ 'No' => 'Não',
+ 'No email address for' => 'Sem endereço de email para',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato de números',
+ 'Parts Inventory' => 'Estoque de Partes',
+ 'Password' => 'Senha',
+ 'Payables' => 'A Pagar',
+ 'Payment' => 'Pagamento',
+ 'Phone' => 'Tel.',
+ 'Preferences saved!' => 'Preferências Salvas!',
+ 'Rate' => 'Taxa',
+ 'Receivables' => 'A Receber',
+ 'Sales' => 'Vendas',
+ 'Save' => 'Salvar',
+ 'Service Items' => 'Ítens de Serviço',
+ 'Ship via' => 'Transportar via',
+ 'Signature' => 'Assinatura',
+ 'Stylesheet' => 'Folha de estilos',
+ 'Tax' => 'Imposto',
+ 'Tax Accounts' => 'Contas de Impostos',
+ 'Template saved!' => 'Modelo salvo!',
+ 'Transaction reversal enforced for all dates' => 'Reversão de transação forçada para todas as datas.',
+ 'Transaction reversal enforced up to' => 'Reversão de transação forçada até ',
+ 'Transactions exist; cannot delete account!' => 'Existem transações, não pode apagar conta!',
+ 'Weight Unit' => 'Unidade de Peso',
+ 'Year End' => 'Fim de ano',
+ 'Yes' => 'Sim',
+ 'does not exist' => 'Não existe',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'adicionar_conta' => 'add_account',
+ 'continuar' => 'continue',
+ 'copiar_para_plano_de_contas' => 'copy_to_coa',
+ 'apagar' => 'delete',
+ 'editar' => 'edit',
+ 'editar_conta' => 'edit_account',
+ 'salvar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/br/ap b/sql-ledger/locale/br/ap
new file mode 100644
index 0000000..dce6c51
--- /dev/null
+++ b/sql-ledger/locale/br/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Transação - Contas a Pagar',
+ 'AP Transactions' => 'Transações - Contas a Pagar',
+ 'Account' => 'Conta',
+ 'Add Accounts Payables Transaction' => 'Adicionar Transação de contas pagáveis',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Total Devido',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => 'Tem certeza que quer APAGAR a Transação',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Não pode apagar transação!',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cannot post transaction for a closed period!' => 'Não pode lançar transação para um período já encerrado!',
+ 'Cannot post transaction!' => 'Não pode lançar transação',
+ 'Closed' => 'Fechado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moeda',
+ 'Customer not on file!' => 'Cliente não está no arquivo!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data de pagamento',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Apagar',
+ 'Description' => 'Descrição',
+ 'Due Date' => 'Data de Vencimento',
+ 'Due Date missing!' => 'Data de Vencimento faltando!',
+ 'Edit Accounts Payables Transaction' => 'Editar Transação - Contas a Pagar',
+ 'Employee' => 'Empregado',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Data de Fatura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Fatura',
+ 'Invoice Number missing!' => 'Número de Fatura não encontrado!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Open' => 'Abrir',
+ 'Order' => 'Pedido',
+ 'Order Number' => 'Pedido Número',
+ 'Paid' => 'Total Efetuado',
+ 'Payment date missing!' => 'Data de pagamento faltando!',
+ 'Payments' => 'Pagamentos',
+ 'Post' => 'Lançar',
+ 'Post as new' => 'Lançar como novo',
+ 'Project' => 'Projeto',
+ 'Project not on file!' => 'Projeto não está no arquivo!',
+ 'Purchase Invoice' => 'Fatura de compra',
+ 'Select from one of the names below' => 'Selecione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Selecione um dos projetos abaixo',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Source' => 'Fonte',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'Tax Included' => 'Impostos incluídos',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transação apagada!',
+ 'Transaction posted!' => 'Transação lançada',
+ 'Update' => 'Atualizar',
+ 'Vendor' => 'Distribuidor',
+ 'Vendor missing!' => 'Distribuidor faltando!',
+ 'Vendor not on file!' => 'Distribuidor não está no arquivo!',
+ 'Yes' => 'Sim',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transação___contas_a_pagar' => 'ap_transaction',
+ 'adicionar_transação_de_contas_pagáveis' => 'add_accounts_payables_transaction',
+ 'continuar' => 'continue',
+ 'apagar' => 'delete',
+ 'editar_transação___contas_a_pagar' => 'edit_accounts_payables_transaction',
+ 'lançar' => 'post',
+ 'lançar_como_novo' => 'post_as_new',
+ 'fatura_de_compra' => 'purchase_invoice',
+ 'atualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/br/ar b/sql-ledger/locale/br/ar
new file mode 100644
index 0000000..95efd92
--- /dev/null
+++ b/sql-ledger/locale/br/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Transação - Contas a Receber',
+ 'AR Transactions' => 'Transações - Contas a Receber',
+ 'Account' => 'Conta',
+ 'Add Accounts Receivables Transaction' => 'Adicionar Transação de contas recebíveis',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Total Devido',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => 'Tem certeza que quer APAGAR a Transação',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Não pode apagar transação!',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cannot post transaction for a closed period!' => 'Não pode lançar transação para um período já encerrado!',
+ 'Cannot post transaction!' => 'Não pode lançar transação',
+ 'Closed' => 'Fechado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Currency' => 'Moeda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Cliente faltando!',
+ 'Customer not on file!' => 'Cliente não está no arquivo!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data de pagamento',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Apagar',
+ 'Description' => 'Descrição',
+ 'Due Date' => 'Data de Vencimento',
+ 'Due Date missing!' => 'Data de Vencimento faltando!',
+ 'Edit Accounts Receivables Transaction' => 'Editar Transação - Contas a Receber',
+ 'Employee' => 'Empregado',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Data de Fatura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Fatura',
+ 'Invoice Number missing!' => 'Número de Fatura não encontrado!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Open' => 'Abrir',
+ 'Order' => 'Pedido',
+ 'Order Number' => 'Pedido Número',
+ 'Paid' => 'Total Efetuado',
+ 'Payment date missing!' => 'Data de pagamento faltando!',
+ 'Payments' => 'Pagamentos',
+ 'Post' => 'Lançar',
+ 'Post as new' => 'Lançar como novo',
+ 'Project' => 'Projeto',
+ 'Project not on file!' => 'Projeto não está no arquivo!',
+ 'Remaining' => 'Restante',
+ 'Sales Invoice' => 'Fatura de Venda',
+ 'Select from one of the names below' => 'Selecione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Selecione um dos projetos abaixo',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Source' => 'Fonte',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'Tax Included' => 'Impostos incluídos',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transação apagada!',
+ 'Transaction posted!' => 'Transação lançada',
+ 'Update' => 'Atualizar',
+ 'Vendor not on file!' => 'Distribuidor não está no arquivo!',
+ 'Yes' => 'Sim',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transação___contas_a_receber' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'apagar' => 'delete',
+ 'lançar' => 'post',
+ 'lançar_como_novo' => 'post_as_new',
+ 'fatura_de_venda' => 'sales_invoice',
+ 'atualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/br/arap b/sql-ledger/locale/br/arap
new file mode 100644
index 0000000..4565db6
--- /dev/null
+++ b/sql-ledger/locale/br/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Endereço',
+ 'Continue' => 'Continuar',
+ 'Customer not on file!' => 'Cliente não está no arquivo!',
+ 'Description' => 'Descrição',
+ 'Number' => 'Número',
+ 'Project not on file!' => 'Projeto não está no arquivo!',
+ 'Select from one of the names below' => 'Selecione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Selecione um dos projetos abaixo',
+ 'Vendor not on file!' => 'Distribuidor não está no arquivo!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/br/ca b/sql-ledger/locale/br/ca
new file mode 100644
index 0000000..1f7cbc4
--- /dev/null
+++ b/sql-ledger/locale/br/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Balanço',
+ 'Chart of Accounts' => 'Código de Contas',
+ 'Credit' => 'Crédito',
+ 'Date' => 'Data',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Description' => 'Descrição',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'List Transactions' => 'Listar Transações',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Reference' => 'Referência',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Subtotal' => 'Sub-total',
+ 'To' => 'Até',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'listar_transações' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/br/cp b/sql-ledger/locale/br/cp
new file mode 100644
index 0000000..471654b
--- /dev/null
+++ b/sql-ledger/locale/br/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Amount does not equal applied!' => 'Total não é igual ao aplicado!',
+ 'Amount missing!' => 'Total faltando!',
+ 'Applied' => 'Aplicado',
+ 'Cannot post payment!' => 'Não pode lançar pagamento!',
+ 'Cannot process payment for a closed period!' => 'Não pode processar pagamento para um pedíodo já encerrado!',
+ 'Check' => 'Cheque',
+ 'Check printed!' => 'Cheque impresso',
+ 'Check printing failed!' => 'Impressão de cheque falhou!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moeda',
+ 'Customer' => 'Cliente',
+ 'Customer not on file!' => 'Cliente não está no arquivo!',
+ 'Date' => 'Data',
+ 'Date missing!' => 'Data faltando!',
+ 'Description' => 'Descrição',
+ 'Due' => 'Saldo',
+ 'Exchangerate' => 'Taxa de câmbio',
+ 'From' => 'De',
+ 'Invoice' => 'Fatura',
+ 'Invoices' => 'Faturas',
+ 'Nothing applied!' => 'Nada foi aplicado!',
+ 'Number' => 'Número',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'Pagamento',
+ 'Payment posted!' => 'Pagamento Lançado',
+ 'Post' => 'Lançar',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Project not on file!' => 'Projeto não está no arquivo!',
+ 'Receipt' => 'Recibo',
+ 'Reference' => 'Referência',
+ 'Screen' => 'Tela',
+ 'Select from one of the names below' => 'Selecione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Selecione um dos projetos abaixo',
+ 'To' => 'Até',
+ 'Update' => 'Atualizar',
+ 'Vendor' => 'Distribuidor',
+ 'Vendor not on file!' => 'Distribuidor não está no arquivo!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+ 'lançar' => 'post',
+ 'imprimir' => 'print',
+ 'atualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/br/ct b/sql-ledger/locale/br/ct
new file mode 100644
index 0000000..bfc96e5
--- /dev/null
+++ b/sql-ledger/locale/br/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Adicionar',
+ 'Address' => 'Endereço',
+ 'All' => 'Todas',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Não pode apagar cliente!',
+ 'Cannot delete vendor!' => 'Não pode apagar fornecedor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contato',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Customer deleted!' => 'Cliente apagado!',
+ 'Customer saved!' => 'Cliente salvo',
+ 'Customers' => 'Clientes',
+ 'Delete' => 'Apagar',
+ 'Discount' => 'Desconto',
+ 'E-mail' => 'E-Mail',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Invoice' => 'Fatura',
+ 'Name' => 'Nome',
+ 'Name missing!' => 'Nome faltando!',
+ 'Notes' => 'Notas',
+ 'Number' => 'Número',
+ 'Order' => 'Pedido',
+ 'Orphaned' => 'Ficaram órfãs',
+ 'Phone' => 'Tel.',
+ 'Save' => 'Salvar',
+ 'Ship to' => 'Transportar para',
+ 'Tax Included' => 'Impostos incluídos',
+ 'Taxable' => 'Sujeito a impostos',
+ 'Terms: Net' => 'Crédito Líquido',
+ 'Transactions exist, cannot delete customer!' => 'Existem transações, não pode apagar o cliente!',
+ 'Transactions exist, cannot delete vendor!' => 'Existem transações, não pode apagar fornecedor!',
+ 'Vendor deleted!' => 'Distribuidor apagado!',
+ 'Vendor saved!' => 'Distribuidor salvo!',
+ 'Vendors' => 'Distribuidores',
+ 'days' => 'Dias',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'adicionar' => 'add',
+ 'continuar' => 'continue',
+ 'apagar' => 'delete',
+ 'fatura' => 'invoice',
+ 'pedido' => 'order',
+ 'salvar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/br/gl b/sql-ledger/locale/br/gl
new file mode 100644
index 0000000..928761c
--- /dev/null
+++ b/sql-ledger/locale/br/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Transação - Contas a Pagar',
+ 'AR Transaction' => 'Transação - Contas a Receber',
+ 'Account' => 'Conta',
+ 'Add General Ledger Transaction' => 'Adicionar Transação Livro Razão',
+ 'Address' => 'Endereço',
+ 'All' => 'Todas',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => 'Tem certeza que quer APAGAR a Transação',
+ 'Asset' => 'Ativo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Balanço',
+ 'Cannot delete transaction!' => 'Não pode apagar transação!',
+ 'Cannot have a value in both Debit and Credit!' => 'Não pode ter um valor em ambos Débito e Crédito!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'Não pode lançar transação para um período já encerrado!',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit' => 'Crédito',
+ 'Customer not on file!' => 'Cliente não está no arquivo!',
+ 'Date' => 'Data',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito e crédito fora de balanço!',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Apagar',
+ 'Description' => 'Descrição',
+ 'Edit General Ledger Transaction' => 'Editar Transação Livro Razão',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Despesa',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'GL Transaction' => 'Transação do Livro Razão',
+ 'General Ledger' => 'Livro Razão',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Income' => 'Receita',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Liability' => 'Passivo',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Post' => 'Lançar',
+ 'Post as new' => 'Lançar como novo',
+ 'Project' => 'Projeto',
+ 'Project not on file!' => 'Projeto não está no arquivo!',
+ 'Purchase Invoice' => 'Fatura de compra',
+ 'Reference' => 'Referência',
+ 'Reference missing!' => 'Referência faltando!',
+ 'Reports' => 'Relatórios',
+ 'Sales Invoice' => 'Fatura de Venda',
+ 'Select from one of the names below' => 'Selecione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Selecione um dos projetos abaixo',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Source' => 'Fonte',
+ 'Subtotal' => 'Sub-total',
+ 'To' => 'Até',
+ 'Transaction Date missing!' => 'Data de transação faltando!',
+ 'Transaction deleted!' => 'Transação apagada!',
+ 'Transaction posted!' => 'Transação lançada',
+ 'Update' => 'Atualizar',
+ 'Vendor not on file!' => 'Distribuidor não está no arquivo!',
+ 'Yes' => 'Sim',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transação___contas_a_pagar' => 'ap_transaction',
+ 'transação___contas_a_receber' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'apagar' => 'delete',
+ 'transação_do_livro_razão' => 'gl_transaction',
+ 'lançar' => 'post',
+ 'lançar_como_novo' => 'post_as_new',
+ 'fatura_de_compra' => 'purchase_invoice',
+ 'fatura_de_venda' => 'sales_invoice',
+ 'atualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/br/ic b/sql-ledger/locale/br/ic
new file mode 100644
index 0000000..c28c265
--- /dev/null
+++ b/sql-ledger/locale/br/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Ativa',
+ 'Add' => 'Adicionar',
+ 'Add Assembly' => 'Adicionar Conjunto',
+ 'Add Part' => 'Adicionar Parte',
+ 'Add Purchase Order' => 'Adicionar Pedido de Compra',
+ 'Add Sales Order' => 'Adicionar Pedido de Venda',
+ 'Add Service' => 'Adicionar Serviço',
+ 'Address' => 'Endereço',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Assemblies' => 'Conjuntos',
+ 'Assemblies restocked!' => 'Conjuntos re estocados',
+ 'Assembly Number missing!' => 'Número de conjunto faltando!',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'Lista de Material',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Caixa/bandeja',
+ 'Bought' => 'Comprado',
+ 'COGS' => 'Custo de Vendas',
+ 'Cannot delete item already invoiced!' => 'Não posso apagar item já faturado!',
+ 'Cannot delete item on order!' => 'Não pode apagar item no pedido',
+ 'Cannot delete item which is part of an assembly!' => 'Não posso apagar item que é parte de um conjunto',
+ 'Cannot delete item!' => 'Não pode apagar item!',
+ 'Cannot stock assemblies!' => 'Não pode estocar conjuntos!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contato',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Apagar',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'Drawing' => 'Desenho',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Endereço de E-mail faltando!',
+ 'Edit Assembly' => 'Editar Conjunto',
+ 'Edit Part' => 'Editar Parte',
+ 'Edit Service' => 'Editar Serviço',
+ 'Expense' => 'Despesa',
+ 'Extended' => 'Extendida',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'Image' => 'Imagem',
+ 'In-line' => 'em linha',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Income' => 'Receita',
+ 'Individual Items' => 'Ítens individuais',
+ 'Inventory' => 'Estoque',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Quantidade em estoque TEM de ser zero ANTES que você possa tornar este conjunto obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Quantidade em estoque TEM de ser zero ANTES que você possa tornar esta parte/peça obsoleta!',
+ 'Inventory quantity must be zero!' => 'Quantidade em estoque TEM de ser zero!',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Fatura',
+ 'Invoice Number missing!' => 'Número de Fatura não encontrado!',
+ 'Item deleted!' => 'Item apagado!',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Last Cost' => 'Último Custo',
+ 'Line Total' => 'Total da linha',
+ 'Link Accounts' => 'Ligar Contas',
+ 'List Price' => 'Preço de lista',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Microfiche' => 'Microficha',
+ 'Model' => 'Modelo',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Número faltando na linha',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'On Hand' => 'Em Mãos',
+ 'On Order' => 'Em pedido',
+ 'Order' => 'Pedido',
+ 'Order Date missing!' => 'Data de Pedido Faltando',
+ 'Order Number' => 'Pedido Número',
+ 'Order Number missing!' => 'Número de pedido faltando!',
+ 'Ordered' => 'Pedido feito',
+ 'Orphaned' => 'Ficaram órfãs',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empacotamento',
+ 'Packing List Date missing!' => 'Data da lista de empacotamento faltando!',
+ 'Packing List Number missing!' => 'Número da lista de empacotamento faltando!',
+ 'Part' => 'Parte',
+ 'Part Number missing!' => 'Número da parte não encontrado!',
+ 'Parts' => 'Partes',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preço',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projeto',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Qty' => 'Qtde',
+ 'ROP' => 'Nível mínimo de estoque',
+ 'Recd' => 'Recebidos',
+ 'Required by' => 'Requerido por',
+ 'Sales' => 'Vendas',
+ 'Sales Order' => 'Pedido de Venda',
+ 'Save' => 'Salvar',
+ 'Screen' => 'Tela',
+ 'Select from one of the items below' => 'Selecione um dos ítens abaixo',
+ 'Select postscript or PDF!' => 'Selecionar Postscript ou PDF',
+ 'Sell Price' => 'Preço de Venda',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Service Number missing!' => 'Número do serviço não encontrado!',
+ 'Services' => 'Serviços',
+ 'Ship' => 'Transportar',
+ 'Ship to' => 'Transportar para',
+ 'Short' => 'Curto',
+ 'Sold' => 'Vendido',
+ 'Stock Assembly' => 'Conjunto normal de estoque',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'To' => 'Até',
+ 'Top Level' => 'Nível superior',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidade',
+ 'Unit of measure' => 'Unidade de medida',
+ 'Update' => 'Atualizar',
+ 'Updated' => 'Atualizado',
+ 'Weight' => 'Peso',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'ea' => 'cada',
+ 'emailed to' => 'enviado por email para',
+ 'hr' => 'h',
+ 'sent to printer' => 'enviado para impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'adicionar' => 'add',
+ 'adicionar_conjunto' => 'add_assembly',
+ 'adicionar_parte' => 'add_part',
+ 'adicionar_serviço' => 'add_service',
+ 'continuar' => 'continue',
+ 'apagar' => 'delete',
+ 'editar_conjunto' => 'edit_assembly',
+ 'editar_parte' => 'edit_part',
+ 'editar_serviço' => 'edit_service',
+ 'salvar' => 'save',
+ 'atualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/br/io b/sql-ledger/locale/br/io
new file mode 100644
index 0000000..8d07ecf
--- /dev/null
+++ b/sql-ledger/locale/br/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Adicionar Pedido de Compra',
+ 'Add Sales Order' => 'Adicionar Pedido de Venda',
+ 'Address' => 'Endereço',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Caixa/bandeja',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contato',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Endereço de E-mail faltando!',
+ 'Extended' => 'Extendida',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'In-line' => 'em linha',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number missing!' => 'Número de Fatura não encontrado!',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Número faltando na linha',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Order' => 'Pedido',
+ 'Order Date missing!' => 'Data de Pedido Faltando',
+ 'Order Number missing!' => 'Número de pedido faltando!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empacotamento',
+ 'Packing List Date missing!' => 'Data da lista de empacotamento faltando!',
+ 'Packing List Number missing!' => 'Número da lista de empacotamento faltando!',
+ 'Part' => 'Parte',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preço',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projeto',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Qty' => 'Qtde',
+ 'Recd' => 'Recebidos',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Pedido de Venda',
+ 'Screen' => 'Tela',
+ 'Select from one of the items below' => 'Selecione um dos ítens abaixo',
+ 'Select postscript or PDF!' => 'Selecionar Postscript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Ship' => 'Transportar',
+ 'Ship to' => 'Transportar para',
+ 'Subject' => 'Assunto',
+ 'To' => 'Até',
+ 'Unit' => 'Unidade',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'emailed to' => 'enviado por email para',
+ 'sent to printer' => 'enviado para impressora',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/br/ir b/sql-ledger/locale/br/ir
new file mode 100644
index 0000000..67bc4d4
--- /dev/null
+++ b/sql-ledger/locale/br/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Add Purchase Invoice' => 'Adicionar Fatura de Compra',
+ 'Add Purchase Order' => 'Adicionar Pedido de Compra',
+ 'Add Sales Order' => 'Adicionar Pedido de Venda',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => 'Tem certeza que quer APAGAR a Fatura Número',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Caixa/bandeja',
+ 'Cannot delete invoice!' => 'Não pode apagar fatura!',
+ 'Cannot post invoice for a closed period!' => 'Não pode lançar fatura em período fechado!',
+ 'Cannot post invoice!' => 'Não pode lançar fatura!',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contato',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Currency' => 'Moeda',
+ 'Customer not on file!' => 'Cliente não está no arquivo!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data de Vencimento',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Apagar',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Endereço de E-mail faltando!',
+ 'Edit Purchase Invoice' => 'Editar Fatura de Compra',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Extended' => 'Extendida',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'In-line' => 'em linha',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Data de Fatura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Fatura',
+ 'Invoice Number missing!' => 'Número de Fatura não encontrado!',
+ 'Invoice deleted!' => 'Fatura apagada!',
+ 'Invoice posted!' => 'Fatura lançada!',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Número faltando na linha',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Order' => 'Pedido',
+ 'Order Date missing!' => 'Data de Pedido Faltando',
+ 'Order Number' => 'Pedido Número',
+ 'Order Number missing!' => 'Número de pedido faltando!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empacotamento',
+ 'Packing List Date missing!' => 'Data da lista de empacotamento faltando!',
+ 'Packing List Number missing!' => 'Número da lista de empacotamento faltando!',
+ 'Part' => 'Parte',
+ 'Payment date missing!' => 'Data de pagamento faltando!',
+ 'Payments' => 'Pagamentos',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Lançar',
+ 'Post as new' => 'Lançar como novo',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preço',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projeto',
+ 'Project not on file!' => 'Projeto não está no arquivo!',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Qty' => 'Qtde',
+ 'Recd' => 'Recebidos',
+ 'Record in' => 'Registrar em',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Pedido de Venda',
+ 'Screen' => 'Tela',
+ 'Select from one of the items below' => 'Selecione um dos ítens abaixo',
+ 'Select from one of the names below' => 'Selecione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Selecione um dos projetos abaixo',
+ 'Select postscript or PDF!' => 'Selecionar Postscript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Ship' => 'Transportar',
+ 'Ship to' => 'Transportar para',
+ 'Source' => 'Fonte',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax Included' => 'Impostos incluídos',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidade',
+ 'Update' => 'Atualizar',
+ 'Vendor' => 'Distribuidor',
+ 'Vendor missing!' => 'Distribuidor faltando!',
+ 'Vendor not on file!' => 'Distribuidor não está no arquivo!',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'Yes' => 'Sim',
+ 'ea' => 'cada',
+ 'emailed to' => 'enviado por email para',
+ 'sent to printer' => 'enviado para impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'apagar' => 'delete',
+ 'pedido' => 'order',
+ 'lançar' => 'post',
+ 'lançar_como_novo' => 'post_as_new',
+ 'atualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/br/is b/sql-ledger/locale/br/is
new file mode 100644
index 0000000..7d11365
--- /dev/null
+++ b/sql-ledger/locale/br/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Add Purchase Order' => 'Adicionar Pedido de Compra',
+ 'Add Sales Invoice' => 'Adicionar Fatura de Venda',
+ 'Add Sales Order' => 'Adicionar Pedido de Venda',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => 'Tem certeza que quer APAGAR a Fatura Número',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Caixa/bandeja',
+ 'Cannot delete invoice!' => 'Não pode apagar fatura!',
+ 'Cannot post invoice for a closed period!' => 'Não pode lançar fatura em período fechado!',
+ 'Cannot post invoice!' => 'Não pode lançar fatura!',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contato',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Currency' => 'Moeda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Cliente faltando!',
+ 'Customer not on file!' => 'Cliente não está no arquivo!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data de Vencimento',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Apagar',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Endereço de E-mail faltando!',
+ 'Edit Sales Invoice' => 'Editar Fatura de Venda',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Extended' => 'Extendida',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'In-line' => 'em linha',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Data de Fatura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Fatura',
+ 'Invoice Number missing!' => 'Número de Fatura não encontrado!',
+ 'Invoice deleted!' => 'Fatura apagada!',
+ 'Invoice posted!' => 'Fatura lançada!',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Número faltando na linha',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Order' => 'Pedido',
+ 'Order Date missing!' => 'Data de Pedido Faltando',
+ 'Order Number' => 'Pedido Número',
+ 'Order Number missing!' => 'Número de pedido faltando!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empacotamento',
+ 'Packing List Date missing!' => 'Data da lista de empacotamento faltando!',
+ 'Packing List Number missing!' => 'Número da lista de empacotamento faltando!',
+ 'Part' => 'Parte',
+ 'Payment date missing!' => 'Data de pagamento faltando!',
+ 'Payments' => 'Pagamentos',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Lançar',
+ 'Post as new' => 'Lançar como novo',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preço',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projeto',
+ 'Project not on file!' => 'Projeto não está no arquivo!',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Qty' => 'Qtde',
+ 'Recd' => 'Recebidos',
+ 'Record in' => 'Registrar em',
+ 'Remaining' => 'Restante',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Pedido de Venda',
+ 'Screen' => 'Tela',
+ 'Select from one of the items below' => 'Selecione um dos ítens abaixo',
+ 'Select from one of the names below' => 'Selecione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Selecione um dos projetos abaixo',
+ 'Select postscript or PDF!' => 'Selecionar Postscript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Ship' => 'Transportar',
+ 'Ship to' => 'Transportar para',
+ 'Ship via' => 'Transportar via',
+ 'Source' => 'Fonte',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax Included' => 'Impostos incluídos',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidade',
+ 'Update' => 'Atualizar',
+ 'Vendor not on file!' => 'Distribuidor não está no arquivo!',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'Yes' => 'Sim',
+ 'ea' => 'cada',
+ 'emailed to' => 'enviado por email para',
+ 'sent to printer' => 'enviado para impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'apagar' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'pedido' => 'order',
+ 'lançar' => 'post',
+ 'lançar_como_novo' => 'post_as_new',
+ 'imprimir' => 'print',
+ 'transportar_para' => 'ship_to',
+ 'atualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/br/login b/sql-ledger/locale/br/login
new file mode 100644
index 0000000..ff7494c
--- /dev/null
+++ b/sql-ledger/locale/br/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'Sobre',
+ 'Accounting' => 'Contabilidade',
+ 'Database Host' => 'Servidor de Base de Dados',
+ 'Dataset' => 'Conjunto de dados',
+ 'Incorrect Dataset version!' => 'Versão incorreta de grupos de dados!',
+ 'Incorrect Password!' => 'Senha incorreta!',
+ 'Licensed to' => 'Licenciado a',
+ 'Login' => 'Acessar/login',
+ 'Name' => 'Nome',
+ 'Password' => 'Senha',
+ 'User' => 'Usuário',
+ 'Version' => 'Versão',
+ 'You are logged out!' => 'Você saiu do sistema!',
+ 'You did not enter a name!' => 'Você não entrou com um nome',
+ 'is not a member!' => 'não é um membro!',
+ 'localhost' => 'localhost /servidor local',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'acessar/login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/br/menu b/sql-ledger/locale/br/menu
new file mode 100644
index 0000000..1ad51b6
--- /dev/null
+++ b/sql-ledger/locale/br/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'Contas a Pagar',
+ 'AP Aging' => 'Contas a Pagar Vencidas',
+ 'AR' => 'Contas a Receber',
+ 'AR Aging' => 'Contas a Receber Vencidas',
+ 'Accounting Menu' => 'Menu de Contabilidade',
+ 'Add Account' => 'Adicionar Conta',
+ 'Add Assembly' => 'Adicionar Conjunto',
+ 'Add Customer' => 'Adicionar Cliente',
+ 'Add GIFI' => 'Adicionar CFOP',
+ 'Add Part' => 'Adicionar Parte',
+ 'Add Project' => 'Adicionar projeto',
+ 'Add Service' => 'Adicionar Serviço',
+ 'Add Transaction' => 'Adicionar Transação',
+ 'Add Vendor' => 'Adicionar Distribuidor',
+ 'Assemblies' => 'Conjuntos',
+ 'Audit Control' => 'Controle de Auditoria',
+ 'Backup' => 'Cópia de reserva',
+ 'Balance Sheet' => 'Folha de Balanço',
+ 'Cash' => 'Caixa',
+ 'Chart of Accounts' => 'Código de Contas',
+ 'Check' => 'Cheque',
+ 'Customers' => 'Clientes',
+ 'General Ledger' => 'Livro Razão',
+ 'Goods & Services' => 'Produtos e Serviços',
+ 'HTML Templates' => 'Modelos HTML',
+ 'Income Statement' => 'Estado de Receitas',
+ 'Invoice' => 'Fatura',
+ 'LaTeX Templates' => 'Modelos LaTeX',
+ 'List Accounts' => 'Listar Contas',
+ 'List GIFI' => 'Listar CFOP',
+ 'Logout' => 'Logout (sair)',
+ 'Order Entry' => 'Entrada de Pedido',
+ 'Packing List' => 'Lista de Empacotamento',
+ 'Parts' => 'Partes',
+ 'Payment' => 'Pagamento',
+ 'Payments' => 'Pagamentos',
+ 'Preferences' => 'Preferências',
+ 'Projects' => 'Projetos',
+ 'Purchase Invoice' => 'Fatura de compra',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Purchase Orders' => 'Ordens de Compra',
+ 'Receipt' => 'Recibo',
+ 'Receipts' => 'Recibos',
+ 'Reconciliation' => 'Reconciliação',
+ 'Reports' => 'Relatórios',
+ 'Sales Invoice' => 'Fatura de Venda',
+ 'Sales Order' => 'Pedido de Venda',
+ 'Sales Orders' => 'Pedidos de Venda',
+ 'Save to File' => 'Salvar para Arquivo',
+ 'Send by E-Mail' => 'Enviar por E-mail',
+ 'Services' => 'Serviços',
+ 'Statement' => 'Declaração',
+ 'Stock Assembly' => 'Conjunto normal de estoque',
+ 'Stylesheet' => 'Folha de estilos',
+ 'System' => 'Sistema',
+ 'Tax collected' => 'Imposto recolhido',
+ 'Tax paid' => 'Imposto pago',
+ 'Transactions' => 'Tansações',
+ 'Trial Balance' => 'Balanço Preliminar',
+ 'Vendors' => 'Distribuidores',
+ 'Version' => 'Versão',
+ 'localhost' => 'localhost /servidor local',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/br/oe b/sql-ledger/locale/br/oe
new file mode 100644
index 0000000..d984270
--- /dev/null
+++ b/sql-ledger/locale/br/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Adicionar',
+ 'Add Purchase Invoice' => 'Adicionar Fatura de Compra',
+ 'Add Purchase Order' => 'Adicionar Pedido de Compra',
+ 'Add Sales Invoice' => 'Adicionar Fatura de Venda',
+ 'Add Sales Order' => 'Adicionar Pedido de Venda',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Order Number' => 'Tem certeza que quer APAGAR tal número de Pedido?',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Caixa/bandeja',
+ 'C' => 'F',
+ 'Cannot delete order!' => 'Não pode apagar pedido!',
+ 'Cannot save order!' => 'Não pode salvar pedido!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Fechado',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contato',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Curr' => 'Moeda',
+ 'Currency' => 'Moeda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Cliente faltando!',
+ 'Customer not on file!' => 'Cliente não está no arquivo!',
+ 'Date' => 'Data',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Apagar',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Endereço de E-mail faltando!',
+ 'Edit Purchase Order' => 'Editar Pedido de Compra',
+ 'Edit Sales Order' => 'Editar Pedido de Venda',
+ 'Exchangerate' => 'Taxa de câmbio',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Extended' => 'Extendida',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'In-line' => 'em linha',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number missing!' => 'Número de Fatura não encontrado!',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Número faltando na linha',
+ 'O' => 'A',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Open' => 'Abrir',
+ 'Order' => 'Pedido',
+ 'Order Date' => 'Data de Pedido',
+ 'Order Date missing!' => 'Data de Pedido Faltando',
+ 'Order Number' => 'Pedido Número',
+ 'Order Number missing!' => 'Número de pedido faltando!',
+ 'Order deleted!' => 'Pedido apagado!',
+ 'Order saved!' => 'Pedido salvo!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empacotamento',
+ 'Packing List Date missing!' => 'Data da lista de empacotamento faltando!',
+ 'Packing List Number missing!' => 'Número da lista de empacotamento faltando!',
+ 'Part' => 'Parte',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preço',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projeto',
+ 'Project not on file!' => 'Projeto não está no arquivo!',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Purchase Orders' => 'Ordens de Compra',
+ 'Qty' => 'Qtde',
+ 'Recd' => 'Recebidos',
+ 'Remaining' => 'Restante',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Pedido de Venda',
+ 'Sales Orders' => 'Pedidos de Venda',
+ 'Save' => 'Salvar',
+ 'Save as new' => 'Salvar como novo',
+ 'Screen' => 'Tela',
+ 'Select from one of the items below' => 'Selecione um dos ítens abaixo',
+ 'Select from one of the names below' => 'Selecione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Selecione um dos projetos abaixo',
+ 'Select postscript or PDF!' => 'Selecionar Postscript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Ship' => 'Transportar',
+ 'Ship to' => 'Transportar para',
+ 'Ship via' => 'Transportar via',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'Tax Included' => 'Impostos incluídos',
+ 'Terms: Net' => 'Crédito Líquido',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidade',
+ 'Update' => 'Atualizar',
+ 'Vendor' => 'Distribuidor',
+ 'Vendor missing!' => 'Distribuidor faltando!',
+ 'Vendor not on file!' => 'Distribuidor não está no arquivo!',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'Yes' => 'Sim',
+ 'days' => 'Dias',
+ 'ea' => 'cada',
+ 'emailed to' => 'enviado por email para',
+ 'sent to printer' => 'enviado para impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'adicionar' => 'add',
+ 'continuar' => 'continue',
+ 'apagar' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'fatura' => 'invoice',
+ 'imprimir' => 'print',
+ 'salvar' => 'save',
+ 'salvar_como_novo' => 'save_as_new',
+ 'transportar_para' => 'ship_to',
+ 'atualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/br/pe b/sql-ledger/locale/br/pe
new file mode 100644
index 0000000..1441b36
--- /dev/null
+++ b/sql-ledger/locale/br/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Adicionar',
+ 'Add Project' => 'Adicionar projeto',
+ 'All' => 'Todas',
+ 'Continue' => 'Continuar',
+ 'Delete' => 'Apagar',
+ 'Description' => 'Descrição',
+ 'Edit Project' => 'Editar Projeto',
+ 'Number' => 'Número',
+ 'Orphaned' => 'Ficaram órfãs',
+ 'Project' => 'Projeto',
+ 'Project Number missing!' => 'Número do Projeto faltando!',
+ 'Project deleted!' => 'Projeto apagado!',
+ 'Project saved!' => 'Projeto salvo!',
+ 'Projects' => 'Projetos',
+ 'Save' => 'Salvar',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'adicionar' => 'add',
+ 'continuar' => 'continue',
+ 'apagar' => 'delete',
+ 'salvar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/br/rc b/sql-ledger/locale/br/rc
new file mode 100644
index 0000000..7fd872b
--- /dev/null
+++ b/sql-ledger/locale/br/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Balance' => 'Balanço',
+ 'Cleared Balance' => 'Balanço limpo',
+ 'Continue' => 'Continuar',
+ 'Date' => 'Data',
+ 'Deposit' => 'Depósito',
+ 'Description' => 'Descrição',
+ 'Difference' => 'Diferença',
+ 'Done' => 'Feito',
+ 'Exchangerate Difference' => 'Diferença da Taxa de Câmbio',
+ 'From' => 'De',
+ 'Out of balance!' => 'Fora de balanço!',
+ 'Payment' => 'Pagamento',
+ 'Reconciliation' => 'Reconciliação',
+ 'Select all' => 'Selecionar todos',
+ 'Source' => 'Fonte',
+ 'Statement Balance' => 'Declaração de Balanço',
+ 'To' => 'Até',
+ 'Update' => 'Atualizar',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continuar' => 'continue',
+ 'feito' => 'done',
+ 'selecionar_todos' => 'select_all',
+ 'atualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/br/rp b/sql-ledger/locale/br/rp
new file mode 100644
index 0000000..f441153
--- /dev/null
+++ b/sql-ledger/locale/br/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Contas a Pagar Vencidas',
+ 'AR Aging' => 'Contas a Receber Vencidas',
+ 'Account' => 'Conta',
+ 'Accounts' => 'Contas',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance Sheet' => 'Folha de Balanço',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Baseado no Caixa',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Comparar a',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Credit' => 'Crédito',
+ 'Current' => 'Current',
+ 'Customer' => 'Cliente',
+ 'Date' => 'Data',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Decimalplaces' => 'Casas decimais',
+ 'Description' => 'Descrição',
+ 'Due' => 'Saldo',
+ 'E-mail' => 'E-Mail',
+ 'E-mail Statement to' => 'Declaração enviada por email para',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'Heading' => 'Cabeçalho',
+ 'ID' => 'ID',
+ 'In-line' => 'em linha',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Income Statement' => 'Estado de Receitas',
+ 'Invoice' => 'Fatura',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'N/A' => 'N/D',
+ 'Nothing selected!' => 'Nada foi selecionado!',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Pagamentos',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Receipts' => 'Recibos',
+ 'Report for' => 'Relatório para',
+ 'Retained Earnings' => 'Lucros Retidos',
+ 'Screen' => 'Tela',
+ 'Select all' => 'Selecionar todos',
+ 'Select postscript or PDF!' => 'Selecionar Postscript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Source' => 'Fonte',
+ 'Standard' => 'Padrão',
+ 'Statement' => 'Declaração',
+ 'Statement sent to' => 'Declaração enviada para',
+ 'Statements sent to printer!' => 'Declaração enviada para impressora!',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'Tax collected' => 'Imposto recolhido',
+ 'Tax paid' => 'Imposto pago',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Balanço Preliminar',
+ 'Vendor' => 'Distribuidor',
+ 'as at' => 'como em',
+ 'collected on sales' => 'recolhido sobre vendas',
+ 'for Period' => 'pelo período',
+ 'paid on purchases' => 'pago em aquisições',
+ 'to' => 'para',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continuar' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'imprimir' => 'print',
+ 'selecionar_todos' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/COPYING b/sql-ledger/locale/cn/COPYING
new file mode 100644
index 0000000..784c015
--- /dev/null
+++ b/sql-ledger/locale/cn/COPYING
@@ -0,0 +1,24 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Simplified Chinese texts:
+#
+# Author: Chien Hsin Chang <werther@elixus.org>
+# Autrijus Tang <autrijus@autrijus.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/cn/LANGUAGE b/sql-ledger/locale/cn/LANGUAGE
new file mode 100644
index 0000000..42c3708
--- /dev/null
+++ b/sql-ledger/locale/cn/LANGUAGE
@@ -0,0 +1 @@
+Simplified Chinese
diff --git a/sql-ledger/locale/cn/admin b/sql-ledger/locale/cn/admin
new file mode 100644
index 0000000..c867787
--- /dev/null
+++ b/sql-ledger/locale/cn/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => '?¨ÏÞ¿ØÖ?',
+ 'Accounting' => '»á¼Æ',
+ 'Add User' => 'ÐÂÔöʹÓÃÕß',
+ 'Address' => 'µØÖ·',
+ 'Administration' => 'ϵͳ¹ÜÀí',
+ 'Administrator' => 'ϵͳ¹ÜÀíÔ±',
+ 'All Datasets up to date!' => 'ËùÓÐ×ÊÁϽÔÒѸüÐÂ!',
+ 'Change Admin Password' => '¸ü¸Ä¹ÜÀíÔ±ÃÜÂë',
+ 'Change Password' => '¸ü¸ÄÃÜÂë',
+ 'Character Set' => '×ÖÔª¼¯',
+ 'Click on login name to edit!' => 'Çë°´µÇ?ëÃ?³ÆÒÔ½øÐÐÐÞ¸Ä!',
+ 'Company' => '¹«Ë¾Ãû³Æ',
+ 'Connect to' => 'Á¬½áµ½',
+ 'Continue' => '¼ÌÐø',
+ 'Create Chart of Accounts' => '½¨Á¢ÕÊ»§Í¼±í',
+ 'Create Dataset' => '½¨Á¢×ÊÁϼ¯',
+ 'DBI not installed!' => 'δ°²×° DBI Ä£×é!',
+ 'Database' => '×ÊÁÏ¿â',
+ 'Database Administration' => '×ÊÁÏ¿â¹ÜÀí',
+ 'Database Driver not checked!' => 'δѡ¶¨×ÊÁÏ¿â??¶¯³Ìʽ!',
+ 'Database User missing!' => 'δָÃ÷×ÊÁÏ¿âʹÓÃÕß!',
+ 'Dataset' => '×ÊÁϼ¯',
+ 'Dataset missing!' => 'δָÃ÷×ÊÁϼ¯!',
+ 'Dataset updated!' => '²¹³ä×îÐÂ×ÊÁϼ¯!',
+ 'Date Format' => 'ÈÕÆÚ¸ñʽ',
+ 'Delete' => 'ɾ³ý',
+ 'Delete Dataset' => 'ɾ³ý×ÊÁϼ¯',
+ 'Directory' => 'Ŀ¼',
+ 'Driver' => '??¶¯³Ìʽ',
+ 'Dropdown Limit' => 'ÏÞÖÆ×ÊÁÏÏÔʾ¹¦ÄÜ',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'Edit User' => '±à¼­Ê¹ÓÃÕß',
+ 'Existing Datasets' => '¼ÈÓеÄ×ÊÁϼ¯',
+ 'Fax' => '´«Õæ',
+ 'Host' => 'Ö÷»ú',
+ 'Hostname missing!' => 'δָÃ÷Ö÷»úÃû³Æ!',
+ 'Incorrect Password!' => 'ÃÜÂë´íÎó!',
+ 'Language' => 'Óïϵ',
+ 'Leave host and port field empty unless you want to make a remote connection.' => '³ý·ÇÄúÏëÒª½øÐÐÔ¶¶ËÁ¬Ïß, ·ñÔòÇ뽫Ö÷»ú¼°²ººÅÁô°×.',
+ 'Login' => 'µÇ??',
+ 'Multibyte Encoding' => 'Multibyte Encoding',
+ 'Name' => 'Ãû³Æ',
+ 'New Templates' => 'ÐÂÔöÄ£°æ',
+ 'No Database Drivers available!' => 'ûÓпÉÓõÄ??¶¯³Ìʽ!',
+ 'No Dataset selected!' => 'δѡ¶¨×ÊÁϼ¯!',
+ 'Nothing to delete!' => 'ûÓпÉɾ³ýµÄÏîÄ¿',
+ 'Number Format' => 'Êý×Ö¸ñʽ',
+ 'Oracle Database Administration' => 'Oracle ×ÊÁÏ¿â¹ÜÀí',
+ 'Password' => 'ÃÜÂë',
+ 'Password changed!' => 'ÃÜÂëÒѾ­¸ü¸Ä',
+ 'Pg Database Administration' => 'Pg ×ÊÁÏ¿â¹ÜÀí',
+ 'Phone' => 'µç»°ºÅÂë',
+ 'Port' => '²ººÅ',
+ 'Port missing!' => 'δָÃ÷²ººÅ!',
+ 'Printer' => 'Ó¡±í»ú',
+ 'Save' => '´¢´æ',
+ 'Select a Dataset to delete and press "Continue"' => 'ÇëÑ¡ÔñÓûɾ³ýµÄ×ÊÁϼ¯, ÔÙ°´ "¼ÌÐø"',
+ 'Setup Templates' => 'É趨ģ°æ',
+ 'Ship via' => 'º½ÔË·½·¨',
+ 'Signature' => 'Ç©Ãû',
+ 'Stylesheet' => 'Ñùʽ±í',
+ 'Templates' => 'Ä£°æ',
+ 'The following Datasets are not in use and can be deleted' => 'ÏÂÁÐ×ÊÁϼ¯²¢Î´Ê¹ÓÃ, ¿ÉÒÔɾ³ý',
+ 'The following Datasets need to be updated' => 'ÏÂÁÐ×ÊÁϼ¯ÐèÒª¸üÐÂ',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'ÕâÊǶԼȴæ×ÊÁÏÀ´Ô´µÄ³õ²½¼ì²é. Ôڴ˽׶Î, ²»»áɾ³ý»òÐÂÔö?κÎ×ÊÁ?!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => '?ôÒªÐÂÔöȺ×éÄÚµÄʹÓÃÕ?, Çë±à¼­Ãû³Æ, ¸ü¸ÄµÇ?ëÃ?, ?»ºó´¢´?. ÕâÑùÒ»À´, ÐÂʹÓÃÕ߻ᱣÁôÏàͬµÄ±äÊý, ²¢ÒÔеĵÇ?ëÃ?´æ??.',
+ 'Update Dataset' => '¸üÐÂ×ÊÁϼ¯',
+ 'Use Templates' => 'ʹÓÃÄ£°æ',
+ 'User' => 'ʹÓÃÕß',
+ 'User deleted!' => 'ʹÓÃÕßÒÔ±»É¾³ý!',
+ 'User saved!' => 'ʹÓÃÕßÒÔ±»´¢´æ!',
+ 'Version' => '°æ±¾',
+ 'You must enter a host and port for local and remote connections!' => 'Äú±ØÐè¼ü?ëÖ÷»?¼°²ººÅ, ÒÔ½øÐб¾»ú»òÔ¶¶ËÁ¬Ïß!',
+ 'does not exist' => '²»´æÔÚ',
+ 'is already a member!' => 'ÒѾ­ÊdzÉÔ±ÁË!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'locked!',
+ 'successfully created!' => '³É¹¦½¨Á¢!',
+ 'successfully deleted!' => '³É¹¦É¾³ý!',
+ 'website' => 'ÍøÕ¾',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'ÐÂÔöʹÓÃÕß' => 'add_user',
+ '¸ü¸Ä¹ÜÀíÔ±ÃÜÂë' => 'change_admin_password',
+ '¸ü¸ÄÃÜÂë' => 'change_password',
+ '¼ÌÐø' => 'continue',
+ '½¨Á¢×ÊÁϼ¯' => 'create_dataset',
+ 'ɾ³ý' => 'delete',
+ 'ɾ³ý×ÊÁϼ¯' => 'delete_dataset',
+ 'µÇ??' => 'login',
+ 'oracle_×ÊÁÏ¿â¹ÜÀí' => 'oracle_database_administration',
+ 'pg_×ÊÁÏ¿â¹ÜÀí' => 'pg_database_administration',
+ '´¢´æ' => 'save',
+ '¸üÐÂ×ÊÁϼ¯' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/all b/sql-ledger/locale/cn/all
new file mode 100644
index 0000000..6b01f15
--- /dev/null
+++ b/sql-ledger/locale/cn/all
@@ -0,0 +1,495 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Ó¦¸¶ÕÊ¿î',
+ 'AP Aging' => 'Ó¦¸¶ÕÊÁä·ÖÎö',
+ 'AP Transaction' => 'Ó¦¸¶ÕÊÄ¿',
+ 'AP Transactions' => 'Ó¦¸¶ÕÊÄ¿',
+ 'AR' => 'Ó¦ÊÕÕÊ¿î',
+ 'AR Aging' => 'Ó¦ÊÕÕÊÁä·ÖÎö',
+ 'AR Transaction' => 'Ó¦ÊÕÕÊÄ¿',
+ 'AR Transactions' => 'Ó¦ÊÕÕÊÄ¿',
+ 'About' => '¹Øì¶',
+ 'Access Control' => '?¨ÏÞ¿ØÖ?',
+ 'Account' => '¿ÆÄ¿',
+ 'Account Number' => '¿ÆÄ¿±àºÅ',
+ 'Account Number missing!' => '©Ìî¿ÆÄ¿±àºÅ!',
+ 'Account Type' => '¿ÆÄ¿Àà±ð',
+ 'Account Type missing!' => '©Ìî¿ÆÄ¿Àà±ð!',
+ 'Account deleted!' => '¿ÆÄ¿ÒÔ±»É¾³ý!',
+ 'Account saved!' => '¿ÆÄ¿ÒÔ±»´¢´æ!',
+ 'Accounting' => '»á¼Æ',
+ 'Accounting Menu' => '»á¼ÆÑ¡µ¥',
+ 'Accounts' => 'ÕÊ»§',
+ 'Active' => '»îÔ¾',
+ 'Add' => 'ÐÂÔö',
+ 'Add Account' => 'ÐÂÔö¿ÆÄ¿',
+ 'Add Accounts Payables Transaction' => 'ÐÂÔöÓ¦¸¶ÕÊÄ¿',
+ 'Add Accounts Receivables Transaction' => 'ÐÂÔöÓ¦ÊÕÕÊÄ¿',
+ 'Add Assembly' => 'ÐÂÔöÉÌÆ·',
+ 'Add Customer' => 'ÐÂÔö¿Í»§',
+ 'Add GIFI' => 'ÐÂÔö GIFI',
+ 'Add General Ledger Transaction' => 'ÐÂÔö×ÜÕÊ',
+ 'Add Part' => 'ÐÂÔöÔ­ÁÏ',
+ 'Add Project' => 'ÐÂÔö¹¤³Ì',
+ 'Add Purchase Invoice' => 'ÐÂÔö²É¹º·¢Æ±',
+ 'Add Purchase Order' => 'ÐÂÔö²É¹ºµ¥',
+ 'Add Sales Invoice' => 'ÐÂÔöÏú»õ·¢Æ±',
+ 'Add Sales Order' => 'ÐÂÔöÏú»õµ¥',
+ 'Add Service' => 'ÐÂÔö·þÎñ',
+ 'Add Transaction' => 'ÐÂÔöÕÊÄ¿',
+ 'Add User' => 'ÐÂÔöʹÓÃÕß',
+ 'Add Vendor' => 'ÐÂÔö³§ÉÌ',
+ 'Address' => 'µØÖ·',
+ 'Administration' => 'ϵͳ¹ÜÀí',
+ 'Administrator' => 'ϵͳ¹ÜÀíÔ±',
+ 'All' => 'È«²¿',
+ 'All Datasets up to date!' => 'ËùÓÐ×ÊÁϽÔÒѸüÐÂ!',
+ 'Amount' => '×ܼÆ',
+ 'Amount Due' => 'µ½ÆÚµÄ×ܼÆ',
+ 'Amount does not equal applied!' => '×ܶÏàµÈ!',
+ 'Amount missing!' => 'δָÃ÷×ܶî!',
+ 'Applied' => 'Ö§¸¶',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Are you sure you want to delete Invoice Number' => 'ÄúÈ·¶¨ÒªÉ¾³ý·¢Æ±±àºÅ',
+ 'Are you sure you want to delete Order Number' => 'ÄúÊÇ·ñ?·¶¨ÒªÉ¾³?¶©µ¥',
+ 'Are you sure you want to delete Transaction' => 'ÄúÈ·¶¨ÒªÉ¾³ýÕÊÄ¿',
+ 'Assemblies' => 'ÉÌÆ·',
+ 'Assemblies restocked!' => '×°ÅäÖØнø»õ!',
+ 'Assembly Number missing!' => '²éÎÞ´ËÉÌÆ·!',
+ 'Asset' => '×ʲú',
+ 'Attachment' => '¸½µµ',
+ 'Audit Control' => '»üºË¿ØÖÆ',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'BOM' => '²ÄÁÏÕʵ¥',
+ 'Backup' => '±¸·Ý',
+ 'Backup sent to' => '±¸·Ý¼ÄË͵½',
+ 'Balance' => '²î¶î',
+ 'Balance Sheet' => '×ʲú¸ºÕ®±í',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ïä',
+ 'Books are open' => 'Õʲ¾ÒÑ¿ªÆô',
+ 'Bought' => 'ÒѹºÂò',
+ 'Business Number' => 'ͳһ±àºÅ',
+ 'C' => 'C',
+ 'COGS' => '»õÏú³É±¾',
+ 'Cannot delete account!' => 'ÎÞ·¨É¾³ý¿ÆÄ¿!',
+ 'Cannot delete customer!' => '²»ÄÜɾ³ý¿Í»§!',
+ 'Cannot delete default account!' => 'ÎÞ·¨É¾³ýÔ¤ÉèÕʺÅ',
+ 'Cannot delete invoice!' => 'ÎÞ·¨É¾³ý·¢Æ±!',
+ 'Cannot delete item already invoiced!' => 'ÎÞ·¨É¾³ý±¾Ïî',
+ 'Cannot delete item on order!' => 'ÎÞ·¨É¾³ýµ¥ÉϵÄÏîÄ¿!',
+ 'Cannot delete item which is part of an assembly!' => 'ÎÞ·¨É¾³ýÓÃì¶ÉÌÆ·ÖеÄÔ­ÁÏ',
+ 'Cannot delete item!' => 'ÎÞ·¨É¾³ýÏîÄ¿!',
+ 'Cannot delete order!' => 'ÎÞ·¨É¾³ý¶©µ¥!',
+ 'Cannot delete transaction!' => 'ÎÞ·¨É¾³ýÕÊÄ¿!',
+ 'Cannot delete vendor!' => '²»ÄÜɾ³ý³§ÉÌ!',
+ 'Cannot have a value in both Debit and Credit!' => '²»µÃͬʱÌîÈëÊýֵ춽跽Óë´û·½À¸Î»',
+ 'Cannot post a transaction without a value!' => 'ÎÞ·¨È·ÈÏû¼Û¸ñÕÊÄ¿!',
+ 'Cannot post invoice for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚÈ·ÈÏ·¢Æ±?ë½»Ò!',
+ 'Cannot post invoice!' => 'ÎÞ·¨È·ÈÏ·¢Æ±!',
+ 'Cannot post payment for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚ¼Ó?ë½»Ò?!',
+ 'Cannot post payment!' => 'ÎÞ·¨´¦Àí¸¶¿î!',
+ 'Cannot post transaction for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚ¼Ó?ë½»Ò?!',
+ 'Cannot post transaction!' => 'ÎÞ·¨È·ÈÏÕÊÄ¿!',
+ 'Cannot process payment for a closed period!' => 'ÒѹرյÄʱ¶ÎÄÚ´¦Àí¸¶¿î!',
+ 'Cannot save account!' => 'ÎÞ·¨´¢´æ¿ÆÄ¿!',
+ 'Cannot save order!' => 'ÎÞ·¨´¢´æÇåµ¥!',
+ 'Cannot save preferences!' => 'ÎÞ·¨´¢´æÉ趨!',
+ 'Cannot stock assemblies!' => 'ÎÞ·¨É¾³ý×°ÅäÉÌÆ·!',
+ 'Cash' => 'ÏÖ½ð',
+ 'Cash based' => 'ÏÖ½ð½»Ò×',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => '¸ü¸Ä¹ÜÀíÔ±ÃÜÂë',
+ 'Change Password' => '¸ü¸ÄÃÜÂë',
+ 'Character Set' => '×ÖÔª¼¯',
+ 'Chart of Accounts' => '»á¼Æ¿ÆÄ¿±í',
+ 'Check' => '֧Ʊ',
+ 'Check printed!' => 'ӡˢ֧Ʊ!',
+ 'Check printing failed!' => 'ÎÞ·¨Ó¡Ë¢Ö§Æ±!',
+ 'Cleared Balance' => 'Ö§¸¶²î¶î×ÜÊý',
+ 'Click on login name to edit!' => 'Çë°´µÇ?ëÃ?³ÆÒÔ½øÐÐÐÞ¸Ä!',
+ 'Close Books up to' => '¹Ø±Õµ½´ËΪֹµÄÕʲ¾',
+ 'Closed' => 'ÒѹرÕ',
+ 'Company' => '¹«Ë¾Ãû³Æ',
+ 'Compare to' => '¶ÔÕÕ',
+ 'Confirm!' => 'ÈëÕʳɹ¦!',
+ 'Connect to' => 'Á¬½áµ½',
+ 'Contact' => 'Á¬ÂçÈË',
+ 'Continue' => '¼ÌÐø',
+ 'Copies' => '¿½±´',
+ 'Copy to COA' => '¸´ÖƵ½ COA',
+ 'Create Chart of Accounts' => '½¨Á¢ÕÊ»§Í¼±í',
+ 'Create Dataset' => '½¨Á¢×ÊÁϼ¯',
+ 'Credit' => '´û·½',
+ 'Credit Limit' => 'ÐÅÓöî¶È',
+ 'Curr' => 'Ä¿Ç°',
+ 'Currency' => '±Ò±ð',
+ 'Current' => 'ÏÖÔÚ',
+ 'Customer' => '¿Í»§',
+ 'Customer deleted!' => '¿Í»§¼Ç¼ɾ³ý!',
+ 'Customer missing!' => 'δָÃ÷¿Í»§!',
+ 'Customer not on file!' => '¿Í»§¼Ç¼ûÔÚµµ°¸!',
+ 'Customer saved!' => '¿Í»§¼Ç¼±£´æ!',
+ 'Customers' => '¿Í»§',
+ 'DBI not installed!' => 'δ°²×° DBI Ä£×é!',
+ 'Database' => '×ÊÁÏ¿â',
+ 'Database Administration' => '×ÊÁÏ¿â¹ÜÀí',
+ 'Database Driver not checked!' => 'δѡ¶¨×ÊÁÏ¿â??¶¯³Ìʽ!',
+ 'Database Host' => '×ÊÁÏ¿âÖ÷»ú',
+ 'Database User missing!' => 'δָÃ÷×ÊÁÏ¿âʹÓÃÕß!',
+ 'Dataset' => '×ÊÁϼ¯',
+ 'Dataset missing!' => 'δָÃ÷×ÊÁϼ¯!',
+ 'Dataset updated!' => '²¹³ä×îÐÂ×ÊÁϼ¯!',
+ 'Date' => 'ÈÕÆÚ',
+ 'Date Due' => 'Ó¦¸¶ÈÕÆÚ',
+ 'Date Format' => 'ÈÕÆÚ¸ñʽ',
+ 'Date Paid' => '¸¶¿îÈÕÆÚ',
+ 'Date missing!' => 'δָÃ÷ÈÕÆÚ',
+ 'Debit' => '½è·½',
+ 'Debit and credit out of balance!' => '½è´û²»Æ½ºâ!',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Decimalplaces' => 'СÊýµÄÊýÄ¿',
+ 'Delete' => 'ɾ³ý',
+ 'Delete Account' => 'ɾ³ý¿ÆÄ¿',
+ 'Delete Dataset' => 'ɾ³ý×ÊÁϼ¯',
+ 'Delivery Date' => 'µÝËÍÈÕÆÚ',
+ 'Department' => '',
+ 'Deposit' => '´¢´æ',
+ 'Description' => '˵Ã÷',
+ 'Difference' => '²îÒì',
+ 'Directory' => 'Ŀ¼',
+ 'Discount' => 'ÕÛ¿Û',
+ 'Done' => 'Íê³É',
+ 'Drawing' => 'ͼ',
+ 'Driver' => '??¶¯³Ìʽ',
+ 'Dropdown Limit' => 'ÏÞÖÆ×ÊÁÏÏÔʾ¹¦ÄÜ',
+ 'Due' => 'µ½ÆÚ',
+ 'Due Date' => 'µ½ÆÚÈÕ',
+ 'Due Date missing!' => '©Ìîµ½ÆÚÈÕ!',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'E-mail Statement to' => 'µç×ÓÓʼþÕÊÄ¿³ÂÊöµ½',
+ 'E-mail address missing!' => '©Ìîµç×ÓÓʼþλַ!',
+ 'Edit' => '±à¼­',
+ 'Edit Account' => '±à¼­¿ÆÄ¿',
+ 'Edit Accounts Payables Transaction' => '¸ü»»Ó¦¸¶ÕÊ¿îÕÊÄ¿',
+ 'Edit Accounts Receivables Transaction' => '¸ü»»Ó¦ÊÕÕÊ¿îÕÊÄ¿',
+ 'Edit Assembly' => '±à¼­ÉÌÆ·',
+ 'Edit Customer' => '±à¼­¿Í»§',
+ 'Edit GIFI' => '±à¼­ GIFI',
+ 'Edit General Ledger Transaction' => '±à¼­×ÜÕÊ',
+ 'Edit Part' => '±à¼­Ô­ÁÏ',
+ 'Edit Preferences for' => 'É趨ʹÓÃÕß',
+ 'Edit Project' => '¸ü¸Ä¹¤³Ì',
+ 'Edit Purchase Invoice' => '±à¼­²É¹º·¢Æ±',
+ 'Edit Purchase Order' => '±à¼­²É¹ºµ¥',
+ 'Edit Sales Invoice' => '±à¼­Ïú»õ·¢Æ±',
+ 'Edit Sales Order' => '±à¼­Ïú»õµ¥',
+ 'Edit Service' => '±à¼­·þÎñ',
+ 'Edit Template' => '±à¼­Ä£°æ',
+ 'Edit User' => '±à¼­Ê¹ÓÃÕß',
+ 'Edit Vendor' => '±à¼­³§ÉÌ',
+ 'Employee' => 'Ö°Ô±',
+ 'Enforce transaction reversal for all dates' => 'Ç¿ÖÆËùÓÐ?ÕÆڵĽ»Ò׻ظ?',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Çë¼ü?ëÒÔðºÅ·Ö¸ôµÄÓ?ÎÄ×Öĸ, ÿÏî²»³¬¹ý??¸ö×Ö (?? CAD:USD:EUR), ×÷ΪÄúµÄ±¾¹ú¼°Íâ¹ú»õ±Ò',
+ 'Equity' => '¹ÉȨ',
+ 'Exch' => '»ãÂÊ',
+ 'Exchangerate' => '»ãÂÊ',
+ 'Exchangerate Difference' => '»ãÂʲîÒì',
+ 'Exchangerate for payment missing!' => 'δָÃ÷¸¶¿î»ãÂÊ!',
+ 'Exchangerate missing!' => 'δָÃ÷»ãÂÊ!',
+ 'Existing Datasets' => '¼ÈÓеÄ×ÊÁϼ¯',
+ 'Expense' => '·ÑÓÃ',
+ 'Expense Account' => '·ÑÓÿÆÄ¿',
+ 'Expense/Asset' => '·ÑÓÃ/×ʲú',
+ 'Extended' => '¼ÆËãÁÐ',
+ 'Fax' => '´«Õæ',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'Foreign Exchange Gain' => 'Íâ»ãÊÕÒæ',
+ 'Foreign Exchange Loss' => 'Íâ»ãËðʧ',
+ 'From' => '´Ó',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI ¼Ç¼ɾ³ý',
+ 'GIFI missing!' => 'δָÃ÷ GIFI!',
+ 'GIFI saved!' => 'GIFI ¼Ç¼±£´æ',
+ 'GL Transaction' => '×ÜÕÊ',
+ 'General Ledger' => '×ÜÕÊ',
+ 'Goods & Services' => '',
+ 'HTML Templates' => 'HTML ±íµ¥',
+ 'Heading' => '±íÍ·',
+ 'Host' => 'Ö÷»ú',
+ 'Hostname missing!' => 'δָÃ÷Ö÷»úÃû³Æ!',
+ 'ID' => '񅧏',
+ 'Image' => 'ͼÏó',
+ 'In-line' => 'ÐÐÄÚ',
+ 'Include in Report' => 'Ò»²¢ÏÔʾ',
+ 'Include in drop-down menus' => '°üº¬ÔÚÏÂÀ­Ê½Ñ¡µ¥ÖÐ',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Òª½«Õâ¸ö¿Í»§/³§É̼ÓÈëÓ¦¼ÓË°Çåµ¥?',
+ 'Income' => 'ÊÕÒæ',
+ 'Income Account' => 'ËðÒæ¿ÆÄ¿',
+ 'Income Statement' => 'ËðÒæ±í',
+ 'Incorrect Dataset version!' => '×ÊÁϼ¯°æ±¾´íÎó!',
+ 'Incorrect Password!' => 'ÃÜÂë´íÎó!',
+ 'Individual Items' => '×é³ÉÏîÄ¿',
+ 'Inventory' => '¿â´æ',
+ 'Inventory Account' => '´æ»õ¿ÆÄ¿',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'ÔÚÍ£ÓôËÏî×éºÏƷ֮ǰ, ´æ»õÊýÁ¿±ØÐèΪÁã!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Í£ÓôËÏîÁã¼þ֮ǰ, ´æ»õÊýÁ¿±ØÐèΪÁã!',
+ 'Inventory quantity must be zero!' => '´æ»õÊýÁ¿±ØÐèΪÁã!',
+ 'Invoice' => '·¢Æ±',
+ 'Invoice Date' => '·¢Æ±ÈÕÆÚ',
+ 'Invoice Date missing!' => '·¢Æ±ÈÕÆÚ´íÎó!',
+ 'Invoice Number' => '·¢Æ±±àºÅ',
+ 'Invoice Number missing!' => '·¢Æ±±àºÅ´íÎó!',
+ 'Invoice deleted!' => '·¢Æ±É¾³ý!',
+ 'Invoice posted!' => '·¢Æ±È·ÈÏ!',
+ 'Invoices' => '·¢Æ±',
+ 'Is this a summary account to record' => '´ËΪ×ܽá¿ÆÄ¿Âð?',
+ 'Item deleted!' => 'ÏîĿɾ³ý!',
+ 'Item not on file!' => '²éÎÞ´ËÏîÄ¿',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'LaTeX Templates' => 'LaTex Ä£°æ',
+ 'Language' => 'Óïϵ',
+ 'Last Cost' => 'ÉÏÒ»±Ê³É±¾',
+ 'Last Invoice Number' => 'ÉÏÒ»±Ê·¢Æ±±àºÅ',
+ 'Last Numbers & Default Accounts' => 'ÉÏÒ»±Ê±àºÅ¼°Ô¤Éè¿ÆÄ¿',
+ 'Last Purchase Order Number' => 'Ç°´Î²É¹ºµ¥ºÅ',
+ 'Last Sales Order Number' => 'Ç°´ÎÏú',
+ 'Leave host and port field empty unless you want to make a remote connection.' => '³ý·ÇÄúÏëÒª½øÐÐÔ¶¶ËÁ¬Ïß, ·ñÔòÇ뽫Ö÷»ú¼°²ººÅÁô°×.',
+ 'Liability' => '¸ºÕ®',
+ 'Licensed to' => 'ÊÚȨÓè',
+ 'Line Total' => '×ÜÁÐÊý',
+ 'Link' => 'Á¬½á',
+ 'Link Accounts' => 'Á¬½á¿ÆÄ¿',
+ 'List Accounts' => 'ÁгöÕʺÅ',
+ 'List GIFI' => 'Áгö GIFI',
+ 'List Price' => '',
+ 'List Transactions' => 'ÁгöÕÊÄ¿',
+ 'Login' => 'µÇ??',
+ 'Logout' => 'µÇ³ö',
+ 'Make' => 'ÖÆÔì',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Message' => 'ѶϢ',
+ 'Microfiche' => 'Ëõ΢½ºÆ¬',
+ 'Model' => 'ÐͺÅ',
+ 'Multibyte Encoding' => '',
+ 'N/A' => '²»ÊÊÓÃ',
+ 'Name' => 'Ãû³Æ',
+ 'Name missing!' => 'ȱÉÙÃû³Æ!',
+ 'New Templates' => 'ÐÂÔöÄ£°æ',
+ 'No' => '·ñ',
+ 'No Database Drivers available!' => 'ûÓпÉÓõÄ??¶¯³Ìʽ!',
+ 'No Dataset selected!' => 'δѡ¶¨×ÊÁϼ¯!',
+ 'No email address for' => 'δָÃ÷µç×ÓÓʼþλÖÃ',
+ 'No.' => '񅧏',
+ 'Notes' => '±¸×¢',
+ 'Nothing applied!' => 'δָÃ÷Ö§¸¶×ܶî!',
+ 'Nothing selected!' => 'δѡ¶¨×Ê!',
+ 'Nothing to delete!' => 'ûÓпÉɾ³ýµÄÏîÄ¿',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Number' => '񅧏',
+ 'Number Format' => 'Êý×Ö¸ñʽ',
+ 'Number missing in Row' => 'δָÃ÷ºÅÂë',
+ 'O' => 'O',
+ 'Obsolete' => 'Í£ÓÃ',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'On Hand' => '´æÁ¿',
+ 'On Order' => 'ÒÑϵ¥¶©¹º',
+ 'Open' => '¿ªÆô',
+ 'Oracle Database Administration' => 'Oracle ×ÊÁÏ¿â¹ÜÀí',
+ 'Order' => '¶©µ¥',
+ 'Order Date' => '쵴?ͮ?',
+ 'Order Date missing!' => 'δָÃ÷ϵ¥?ÕÆ?!',
+ 'Order Entry' => 'ϵ¥ÏîÄ¿',
+ 'Order Number' => '¶©µ¥±àºÅ',
+ 'Order Number missing!' => 'δָÃ÷¶©µ¥±àºÅ!',
+ 'Order deleted!' => 'ɾ³ý¶©µ¥!',
+ 'Order saved!' => '´¢´æ¶©µ¥!',
+ 'Ordered' => 'ÒÑ϶©¹º',
+ 'Orphaned' => 'ÎÞÖ÷',
+ 'Out of balance!' => '³öÓÚ²î¶î!',
+ 'PDF' => 'PDF',
+ 'Packing List' => '³ö»õµ¥',
+ 'Packing List Date missing!' => 'δָÃ÷°ü×°Çåµ¥?ÕÆ?!',
+ 'Packing List Number missing!' => 'δָÃ÷°ü×°Çåµ¥±àºÅ!',
+ 'Paid' => 'ÒѸ¶',
+ 'Paid in full' => 'Ö§¸¶È«²¿×ܶî',
+ 'Part' => 'Ô­ÁÏ',
+ 'Part Number missing!' => '©ÌîÔ­ÁϱàºÅ!',
+ 'Parts' => 'Ô­ÁÏ',
+ 'Parts Inventory' => '¿â´æÔ­ÁÏ',
+ 'Password' => 'ÃÜÂë',
+ 'Password changed!' => 'ÃÜÂëÒѾ­¸ü¸Ä',
+ 'Payables' => 'Ó¦¸¶¿ÆÄ¿',
+ 'Payment' => '¸¶¿î·½Ê½',
+ 'Payment date missing!' => 'δָÃ÷¸¶¿î?ÕÆ?!',
+ 'Payment posted!' => '',
+ 'Payments' => '¸¶¿î',
+ 'Pg Database Administration' => 'Pg ×ÊÁÏ¿â¹ÜÀí',
+ 'Phone' => 'µç»°ºÅÂë',
+ 'Port' => '²ººÅ',
+ 'Port missing!' => 'δָÃ÷²ººÅ!',
+ 'Post' => 'È·ÈÏ',
+ 'Post as new' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => '¸öÈËÉ趨',
+ 'Preferences saved!' => '¸öÈËÉ趨ÒÑ´¢´æ!',
+ 'Price' => '¼Û¸ñ',
+ 'Print' => 'Ó¡Ë¢',
+ 'Printer' => 'Ó¡±í»ú',
+ 'Project' => '¹¤³Ì',
+ 'Project Number' => '',
+ 'Project Number missing!' => 'δָÃ÷¹¤³ÌºÅÂë!',
+ 'Project deleted!' => '¹¤³ÌÒÔ±»É¾³ý!',
+ 'Project not on file!' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Project saved!' => '¹¤³ÌÒÔ±»´¢´æ!',
+ 'Projects' => '¹¤³Ì',
+ 'Purchase Invoice' => '²É¹º·¢Æ±',
+ 'Purchase Order' => '²É¹ºµ¥',
+ 'Purchase Orders' => '²É¹ºµ¥',
+ 'Qty' => 'ÊýÁ¿',
+ 'ROP' => 'ÔÙ¶©µã',
+ 'Rate' => 'Ë°ÂÊ',
+ 'Recd' => 'Recd',
+ 'Receipt' => 'ÊÕ¾Ý',
+ 'Receipt printed!' => '',
+ 'Receipt printing failed!' => '',
+ 'Receipts' => 'ÊÕ¾Ý',
+ 'Receivables' => 'Ó¦ÊÕ¿ÆÄ¿',
+ 'Reconciliation' => 'µ÷Í£',
+ 'Record in' => '¼Ç¼ì¶',
+ 'Reference' => '²Î¿¼ºÅÂë',
+ 'Reference missing!' => 'δָÃ÷²Î¿¼ºÅÂë!',
+ 'Remaining' => 'ÉÐâÅ',
+ 'Report for' => '±¨±íÀ´Ô´',
+ 'Reports' => '±¨±í',
+ 'Required by' => '×ÓÏîÄ¿',
+ 'Retained Earnings' => '±£ÁôÓ¯âÅ',
+ 'Sales' => 'ÒµÎñ',
+ 'Sales Invoice' => 'Ïú»õ·¢Æ±',
+ 'Sales Order' => 'Ïú»õµ¥',
+ 'Sales Orders' => 'Ïú»õµ¥',
+ 'Save' => '´¢´æ',
+ 'Save as new' => '´¢´æ',
+ 'Save to File' => '´¢´æÖÁµµ°¸',
+ 'Screen' => 'Ó©Ä»',
+ 'Select a Dataset to delete and press "Continue"' => 'ÇëÑ¡ÔñÓûɾ³ýµÄ×ÊÁϼ¯, ÔÙ°´ "¼ÌÐø"',
+ 'Select all' => 'Ñ¡ÔñÈ«²¿',
+ 'Select from one of the items below' => 'ì¶ÏÂÁÐÏîÄ¿ÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the names below' => 'ì¶ÏÂÁÐÃû×ÖÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the projects below' => 'ì¶ÏÂÁй¤³ÌÖÐÑ¡ÔñÒ»Ïî',
+ 'Select postscript or PDF!' => 'Ñ¡Ôñ postscript »ò PDF!',
+ 'Sell Price' => 'ÊÛ¼Û',
+ 'Send by E-Mail' => 'ÒÔµç×ÓÓʼþ¼ÄËÍ',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Service' => '·þÎñ',
+ 'Service Items' => '·þÎñÏîÄ¿',
+ 'Service Number missing!' => '©Ìî·þÎñ±àºÅ!',
+ 'Services' => '·þÎñ',
+ 'Setup Templates' => 'É趨ģ°æ',
+ 'Ship' => 'º½ÔË',
+ 'Ship to' => 'ÏúÊÛ´ú±í',
+ 'Ship via' => 'º½ÔË·½·¨',
+ 'Short' => '¶Ì',
+ 'Signature' => 'Ç©Ãû',
+ 'Sold' => 'ÒÑÂô³ö',
+ 'Source' => 'À´Ô´',
+ 'Standard' => '±ê×¼',
+ 'Statement' => 'ÕÊÄ¿³ÂÊö',
+ 'Statement Balance' => 'ÕÊÄ¿³ÂÊö²î¶î',
+ 'Statement sent to' => 'ÕÊÄ¿³ÂÊöË͵½',
+ 'Statements sent to printer!' => 'ÕÊÄ¿³ÂÊöË͵½Ó¡±í»ú!',
+ 'Stock Assembly' => 'Å̵ã',
+ 'Stylesheet' => 'Ñùʽ±í',
+ 'Subject' => '±êÌâ',
+ 'Subtotal' => 'С¼Æ',
+ 'System' => 'ϵͳ',
+ 'Tax' => 'Ë°½ð',
+ 'Tax Accounts' => 'Ë°½ð¿ÆÄ¿',
+ 'Tax Included' => '²»ÊÕ·þÎñ·Ñ',
+ 'Tax collected' => 'ÊÕµ½µÄË°',
+ 'Tax paid' => 'Ö§¸¶µÄË°',
+ 'Taxable' => 'Ӧ˰',
+ 'Template saved!' => 'Ä£°æÒÑ´¢´æ',
+ 'Templates' => 'Ä£°æ',
+ 'Terms: Net' => 'ƱÆÚ¾»¼Æ',
+ 'The following Datasets are not in use and can be deleted' => 'ÏÂÁÐ×ÊÁϼ¯²¢Î´Ê¹ÓÃ, ¿ÉÒÔɾ³ý',
+ 'The following Datasets need to be updated' => 'ÏÂÁÐ×ÊÁϼ¯ÐèÒª¸üÐÂ',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'ÕâÊǶԼȴæ×ÊÁÏÀ´Ô´µÄ³õ²½¼ì²é. Ôڴ˽׶Î, ²»»áɾ³ý»òÐÂÔö?κÎ×ÊÁ?!',
+ 'To' => 'ÖÁ',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => '?ôÒªÐÂÔöȺ×éÄÚµÄʹÓÃÕ?, Çë±à¼­Ãû³Æ, ¸ü¸ÄµÇ?ëÃ?, ?»ºó´¢´?. ÕâÑùÒ»À´, ÐÂʹÓÃÕ߻ᱣÁôÏàͬµÄ±äÊý, ²¢ÒÔеĵÇ?ëÃ?´æ??.',
+ 'Top Level' => '×î¸ßµÈ¼¶',
+ 'Total' => '×ܼÆ',
+ 'Transaction Date missing!' => '©ÌîÕÊÄ¿ÈÕÆÚ!',
+ 'Transaction deleted!' => 'ÕÊĿɾ³ý!',
+ 'Transaction posted!' => 'ÕÊÄ¿È·ÈÏ!',
+ 'Transaction reversal enforced for all dates' => 'Ç¿Öƻظ´ËùÓÐ?ÕÆڵĽ»Ò?',
+ 'Transaction reversal enforced up to' => 'Ç¿Öƻظ´½»Ò×Ö±µ½',
+ 'Transactions' => 'ÕÊÄ¿',
+ 'Transactions exist, cannot delete customer!' => '´Ë¿Í»§ÒÑÓÐÕÊÄ¿, ²»ÄÜɾ³ý!',
+ 'Transactions exist, cannot delete vendor!' => '´Ë³§ÉÌÒÑÓÐÕÊÄ¿, ²»ÄÜɾ³ý!',
+ 'Transactions exist; cannot delete account!' => 'ÉÐÓн»Ò×´æÔÚ; ÎÞ·¨É¾³ýÕÊ»§!',
+ 'Trial Balance' => 'ÊÔËã±í',
+ 'Unit' => 'µ¥Î»',
+ 'Unit of measure' => '¶ÈÁ¿µ¥Î»',
+ 'Update' => '¸üÐÂ',
+ 'Update Dataset' => '¸üÐÂ×ÊÁϼ¯',
+ 'Updated' => 'ÒѸüÐÂ',
+ 'Use Templates' => 'ʹÓÃÄ£°æ',
+ 'User' => 'ʹÓÃÕß',
+ 'User deleted!' => 'ʹÓÃÕßÒÔ±»É¾³ý!',
+ 'User saved!' => 'ʹÓÃÕßÒÔ±»´¢´æ!',
+ 'Vendor' => '³§ÉÌ',
+ 'Vendor deleted!' => '³§ÉÌɾ³ý!',
+ 'Vendor missing!' => 'δָÃ÷³§ÉÌ!',
+ 'Vendor not on file!' => '´Ë³§ÉÌδÔÚµµ°¸!',
+ 'Vendor saved!' => '³§É̱£´æ!',
+ 'Vendors' => '³§ÉÌ',
+ 'Version' => '°æ±¾',
+ 'Weight' => 'ÖØÁ¿',
+ 'Weight Unit' => 'ÖØÁ¿µ¥Î»',
+ 'What type of item is this?' => '´ËÏîÄ¿µÄÐÍ̬?',
+ 'Year End' => '»á¼ÆÄê¶È',
+ 'Yes' => 'ÊÇ',
+ 'You are logged out!' => 'ÄãÒԵdzö!',
+ 'You did not enter a name!' => 'Äú²¢Î´¼ü?ëÃ?³Æ!',
+ 'You must enter a host and port for local and remote connections!' => 'Äú±ØÐè¼ü?ëÖ÷»?¼°²ººÅ, ÒÔ½øÐб¾»ú»òÔ¶¶ËÁ¬Ïß!',
+ 'as at' => '¸ù¾Ý',
+ 'collected on sales' => 'ÔÚÏú»õʱ½áÇå',
+ 'days' => 'ÈÕ',
+ 'does not exist' => '²»´æÔÚ',
+ 'ea' => '',
+ 'emailed to' => 'ÒѼÄÖÁ',
+ 'for Period' => 'ÆÚ¼ä',
+ 'hr' => 'hr',
+ 'is already a member!' => 'ÒѾ­ÊdzÉÔ±ÁË!',
+ 'is not a member!' => '²¢²»ÊdzÉÔ±!',
+ 'localhost' => 'localhost',
+ 'locked!' => '',
+ 'paid on purchases' => 'ÔڲɹºÊ±½áÇå',
+ 'sent to printer' => 'ËÍÖÁÓ¡±í»ú',
+ 'successfully created!' => '³É¹¦½¨Á¢!',
+ 'successfully deleted!' => '³É¹¦É¾³ý!',
+ 'to' => 'ÖÁ',
+ 'website' => 'ÍøÕ¾',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/am b/sql-ledger/locale/cn/am
new file mode 100644
index 0000000..610d7dd
--- /dev/null
+++ b/sql-ledger/locale/cn/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Ó¦¸¶ÕÊ¿î',
+ 'AR' => 'Ó¦ÊÕÕÊ¿î',
+ 'Account' => '¿ÆÄ¿',
+ 'Account Number' => '¿ÆÄ¿±àºÅ',
+ 'Account Number missing!' => '©Ìî¿ÆÄ¿±àºÅ!',
+ 'Account Type' => '¿ÆÄ¿Àà±ð',
+ 'Account Type missing!' => '©Ìî¿ÆÄ¿Àà±ð!',
+ 'Account deleted!' => '¿ÆÄ¿ÒÔ±»É¾³ý!',
+ 'Account saved!' => '¿ÆÄ¿ÒÔ±»´¢´æ!',
+ 'Add Account' => 'ÐÂÔö¿ÆÄ¿',
+ 'Add GIFI' => 'ÐÂÔö GIFI',
+ 'Address' => 'µØÖ·',
+ 'Asset' => '×ʲú',
+ 'Audit Control' => '»üºË¿ØÖÆ',
+ 'Backup sent to' => '±¸·Ý¼ÄË͵½',
+ 'Books are open' => 'Õʲ¾ÒÑ¿ªÆô',
+ 'Business Number' => 'ͳһ±àºÅ',
+ 'COGS' => '»õÏú³É±¾',
+ 'Cannot delete account!' => 'ÎÞ·¨É¾³ý¿ÆÄ¿!',
+ 'Cannot delete default account!' => 'ÎÞ·¨É¾³ýÔ¤ÉèÕʺÅ',
+ 'Cannot save account!' => 'ÎÞ·¨´¢´æ¿ÆÄ¿!',
+ 'Cannot save preferences!' => 'ÎÞ·¨´¢´æÉ趨!',
+ 'Character Set' => '×ÖÔª¼¯',
+ 'Chart of Accounts' => '»á¼Æ¿ÆÄ¿±í',
+ 'Close Books up to' => '¹Ø±Õµ½´ËΪֹµÄÕʲ¾',
+ 'Company' => '¹«Ë¾Ãû³Æ',
+ 'Continue' => '¼ÌÐø',
+ 'Copy to COA' => '¸´ÖƵ½ COA',
+ 'Credit' => '´û·½',
+ 'Date Format' => 'ÈÕÆÚ¸ñʽ',
+ 'Debit' => '½è·½',
+ 'Delete' => 'ɾ³ý',
+ 'Delete Account' => 'ɾ³ý¿ÆÄ¿',
+ 'Description' => '˵Ã÷',
+ 'Dropdown Limit' => 'ÏÞÖÆ×ÊÁÏÏÔʾ¹¦ÄÜ',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'Edit' => '±à¼­',
+ 'Edit Account' => '±à¼­¿ÆÄ¿',
+ 'Edit GIFI' => '±à¼­ GIFI',
+ 'Edit Preferences for' => 'É趨ʹÓÃÕß',
+ 'Edit Template' => '±à¼­Ä£°æ',
+ 'Enforce transaction reversal for all dates' => 'Ç¿ÖÆËùÓÐ?ÕÆڵĽ»Ò׻ظ?',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Çë¼ü?ëÒÔðºÅ·Ö¸ôµÄÓ?ÎÄ×Öĸ, ÿÏî²»³¬¹ý??¸ö×Ö (?? CAD:USD:EUR), ×÷ΪÄúµÄ±¾¹ú¼°Íâ¹ú»õ±Ò',
+ 'Equity' => '¹ÉȨ',
+ 'Expense' => '·ÑÓÃ',
+ 'Expense Account' => '·ÑÓÿÆÄ¿',
+ 'Expense/Asset' => '·ÑÓÃ/×ʲú',
+ 'Fax' => '´«Õæ',
+ 'Foreign Exchange Gain' => 'Íâ»ãÊÕÒæ',
+ 'Foreign Exchange Loss' => 'Íâ»ãËðʧ',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI ¼Ç¼ɾ³ý',
+ 'GIFI missing!' => 'δָÃ÷ GIFI!',
+ 'GIFI saved!' => 'GIFI ¼Ç¼±£´æ',
+ 'Heading' => '±íÍ·',
+ 'Include in drop-down menus' => '°üº¬ÔÚÏÂÀ­Ê½Ñ¡µ¥ÖÐ',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Òª½«Õâ¸ö¿Í»§/³§É̼ÓÈëÓ¦¼ÓË°Çåµ¥?',
+ 'Income' => 'ÊÕÒæ',
+ 'Income Account' => 'ËðÒæ¿ÆÄ¿',
+ 'Inventory' => '¿â´æ',
+ 'Inventory Account' => '´æ»õ¿ÆÄ¿',
+ 'Is this a summary account to record' => '´ËΪ×ܽá¿ÆÄ¿Âð?',
+ 'Language' => 'Óïϵ',
+ 'Last Invoice Number' => 'ÉÏÒ»±Ê·¢Æ±±àºÅ',
+ 'Last Numbers & Default Accounts' => 'ÉÏÒ»±Ê±àºÅ¼°Ô¤Éè¿ÆÄ¿',
+ 'Last Purchase Order Number' => 'Ç°´Î²É¹ºµ¥ºÅ',
+ 'Last Sales Order Number' => 'Ç°´ÎÏú',
+ 'Liability' => '¸ºÕ®',
+ 'Link' => 'Á¬½á',
+ 'Name' => 'Ãû³Æ',
+ 'No' => '·ñ',
+ 'No email address for' => 'δָÃ÷µç×ÓÓʼþλÖÃ',
+ 'Number' => '񅧏',
+ 'Number Format' => 'Êý×Ö¸ñʽ',
+ 'Parts Inventory' => '¿â´æÔ­ÁÏ',
+ 'Password' => 'ÃÜÂë',
+ 'Payables' => 'Ó¦¸¶¿ÆÄ¿',
+ 'Payment' => '¸¶¿î·½Ê½',
+ 'Phone' => 'µç»°ºÅÂë',
+ 'Preferences saved!' => '¸öÈËÉ趨ÒÑ´¢´æ!',
+ 'Rate' => 'Ë°ÂÊ',
+ 'Receivables' => 'Ó¦ÊÕ¿ÆÄ¿',
+ 'Sales' => 'ÒµÎñ',
+ 'Save' => '´¢´æ',
+ 'Service Items' => '·þÎñÏîÄ¿',
+ 'Ship via' => 'º½ÔË·½·¨',
+ 'Signature' => 'Ç©Ãû',
+ 'Stylesheet' => 'Ñùʽ±í',
+ 'Tax' => 'Ë°½ð',
+ 'Tax Accounts' => 'Ë°½ð¿ÆÄ¿',
+ 'Template saved!' => 'Ä£°æÒÑ´¢´æ',
+ 'Transaction reversal enforced for all dates' => 'Ç¿Öƻظ´ËùÓÐ?ÕÆڵĽ»Ò?',
+ 'Transaction reversal enforced up to' => 'Ç¿Öƻظ´½»Ò×Ö±µ½',
+ 'Transactions exist; cannot delete account!' => 'ÉÐÓн»Ò×´æÔÚ; ÎÞ·¨É¾³ýÕÊ»§!',
+ 'Weight Unit' => 'ÖØÁ¿µ¥Î»',
+ 'Year End' => '»á¼ÆÄê¶È',
+ 'Yes' => 'ÊÇ',
+ 'does not exist' => '²»´æÔÚ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'ÐÂÔö¿ÆÄ¿' => 'add_account',
+ '¼ÌÐø' => 'continue',
+ '¸´ÖƵ½_coa' => 'copy_to_coa',
+ 'ɾ³ý' => 'delete',
+ '±à¼­' => 'edit',
+ '±à¼­¿ÆÄ¿' => 'edit_account',
+ '´¢´æ' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/ap b/sql-ledger/locale/cn/ap
new file mode 100644
index 0000000..03dc72c
--- /dev/null
+++ b/sql-ledger/locale/cn/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Ó¦¸¶ÕÊÄ¿',
+ 'AP Transactions' => 'Ó¦¸¶ÕÊÄ¿',
+ 'Account' => '¿ÆÄ¿',
+ 'Add Accounts Payables Transaction' => 'ÐÂÔöÓ¦¸¶ÕÊÄ¿',
+ 'Address' => 'µØÖ·',
+ 'Amount' => '×ܼÆ',
+ 'Amount Due' => 'µ½ÆÚµÄ×ܼÆ',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Are you sure you want to delete Transaction' => 'ÄúÈ·¶¨ÒªÉ¾³ýÕÊÄ¿',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'Cannot delete transaction!' => 'ÎÞ·¨É¾³ýÕÊÄ¿!',
+ 'Cannot post payment for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚ¼Ó?ë½»Ò?!',
+ 'Cannot post transaction for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚ¼Ó?ë½»Ò?!',
+ 'Cannot post transaction!' => 'ÎÞ·¨È·ÈÏÕÊÄ¿!',
+ 'Closed' => 'ÒѹرÕ',
+ 'Confirm!' => 'ÈëÕʳɹ¦!',
+ 'Continue' => '¼ÌÐø',
+ 'Currency' => '±Ò±ð',
+ 'Customer not on file!' => '¿Í»§¼Ç¼ûÔÚµµ°¸!',
+ 'Date' => 'ÈÕÆÚ',
+ 'Date Paid' => '¸¶¿îÈÕÆÚ',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Delete' => 'ɾ³ý',
+ 'Description' => '˵Ã÷',
+ 'Due Date' => 'µ½ÆÚÈÕ',
+ 'Due Date missing!' => '©Ìîµ½ÆÚÈÕ!',
+ 'Edit Accounts Payables Transaction' => '¸ü»»Ó¦¸¶ÕÊ¿îÕÊÄ¿',
+ 'Employee' => 'Ö°Ô±',
+ 'Exch' => '»ãÂÊ',
+ 'Exchangerate' => '»ãÂÊ',
+ 'Exchangerate for payment missing!' => 'δָÃ÷¸¶¿î»ãÂÊ!',
+ 'Exchangerate missing!' => 'δָÃ÷»ãÂÊ!',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'From' => '´Ó',
+ 'ID' => '񅧏',
+ 'Include in Report' => 'Ò»²¢ÏÔʾ',
+ 'Invoice' => '·¢Æ±',
+ 'Invoice Date' => '·¢Æ±ÈÕÆÚ',
+ 'Invoice Date missing!' => '·¢Æ±ÈÕÆÚ´íÎó!',
+ 'Invoice Number' => '·¢Æ±±àºÅ',
+ 'Invoice Number missing!' => '·¢Æ±±àºÅ´íÎó!',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Notes' => '±¸×¢',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Number' => '񅧏',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'Open' => '¿ªÆô',
+ 'Order' => '¶©µ¥',
+ 'Order Number' => '¶©µ¥±àºÅ',
+ 'Paid' => 'ÒѸ¶',
+ 'Payment date missing!' => 'δָÃ÷¸¶¿î?ÕÆ?!',
+ 'Payments' => '¸¶¿î',
+ 'Post' => 'È·ÈÏ',
+ 'Post as new' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Project' => '¹¤³Ì',
+ 'Project not on file!' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Purchase Invoice' => '²É¹º·¢Æ±',
+ 'Select from one of the names below' => 'ì¶ÏÂÁÐÃû×ÖÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the projects below' => 'ì¶ÏÂÁй¤³ÌÖÐÑ¡ÔñÒ»Ïî',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Source' => 'À´Ô´',
+ 'Subtotal' => 'С¼Æ',
+ 'Tax' => 'Ë°½ð',
+ 'Tax Included' => '²»ÊÕ·þÎñ·Ñ',
+ 'Total' => '×ܼÆ',
+ 'Transaction deleted!' => 'ÕÊĿɾ³ý!',
+ 'Transaction posted!' => 'ÕÊÄ¿È·ÈÏ!',
+ 'Update' => '¸üÐÂ',
+ 'Vendor' => '³§ÉÌ',
+ 'Vendor missing!' => 'δָÃ÷³§ÉÌ!',
+ 'Vendor not on file!' => '´Ë³§ÉÌδÔÚµµ°¸!',
+ 'Yes' => 'ÊÇ',
+ 'to' => 'ÖÁ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'Ó¦¸¶ÕÊÄ¿' => 'ap_transaction',
+ 'ÐÂÔöÓ¦¸¶ÕÊÄ¿' => 'add_accounts_payables_transaction',
+ '¼ÌÐø' => 'continue',
+ 'ɾ³ý' => 'delete',
+ '¸ü»»Ó¦¸¶ÕÊ¿îÕÊÄ¿' => 'edit_accounts_payables_transaction',
+ 'È·ÈÏ' => 'post',
+ 'È·ÈϳÉΪÐÂÕÊÄ¿' => 'post_as_new',
+ '²É¹º·¢Æ±' => 'purchase_invoice',
+ '¸üÐÂ' => 'update',
+ 'ÊÇ' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/ar b/sql-ledger/locale/cn/ar
new file mode 100644
index 0000000..f6fb3ff
--- /dev/null
+++ b/sql-ledger/locale/cn/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Ó¦ÊÕÕÊÄ¿',
+ 'AR Transactions' => 'Ó¦ÊÕÕÊÄ¿',
+ 'Account' => '¿ÆÄ¿',
+ 'Add Accounts Receivables Transaction' => 'ÐÂÔöÓ¦ÊÕÕÊÄ¿',
+ 'Address' => 'µØÖ·',
+ 'Amount' => '×ܼÆ',
+ 'Amount Due' => 'µ½ÆÚµÄ×ܼÆ',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Are you sure you want to delete Transaction' => 'ÄúÈ·¶¨ÒªÉ¾³ýÕÊÄ¿',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'Cannot delete transaction!' => 'ÎÞ·¨É¾³ýÕÊÄ¿!',
+ 'Cannot post payment for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚ¼Ó?ë½»Ò?!',
+ 'Cannot post transaction for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚ¼Ó?ë½»Ò?!',
+ 'Cannot post transaction!' => 'ÎÞ·¨È·ÈÏÕÊÄ¿!',
+ 'Closed' => 'ÒѹرÕ',
+ 'Confirm!' => 'ÈëÕʳɹ¦!',
+ 'Continue' => '¼ÌÐø',
+ 'Credit Limit' => 'ÐÅÓöî¶È',
+ 'Currency' => '±Ò±ð',
+ 'Customer' => '¿Í»§',
+ 'Customer missing!' => 'δָÃ÷¿Í»§!',
+ 'Customer not on file!' => '¿Í»§¼Ç¼ûÔÚµµ°¸!',
+ 'Date' => 'ÈÕÆÚ',
+ 'Date Paid' => '¸¶¿îÈÕÆÚ',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Delete' => 'ɾ³ý',
+ 'Description' => '˵Ã÷',
+ 'Due Date' => 'µ½ÆÚÈÕ',
+ 'Due Date missing!' => '©Ìîµ½ÆÚÈÕ!',
+ 'Edit Accounts Receivables Transaction' => '¸ü»»Ó¦ÊÕÕÊ¿îÕÊÄ¿',
+ 'Employee' => 'Ö°Ô±',
+ 'Exch' => '»ãÂÊ',
+ 'Exchangerate' => '»ãÂÊ',
+ 'Exchangerate for payment missing!' => 'δָÃ÷¸¶¿î»ãÂÊ!',
+ 'Exchangerate missing!' => 'δָÃ÷»ãÂÊ!',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'From' => '´Ó',
+ 'ID' => '񅧏',
+ 'Include in Report' => 'Ò»²¢ÏÔʾ',
+ 'Invoice' => '·¢Æ±',
+ 'Invoice Date' => '·¢Æ±ÈÕÆÚ',
+ 'Invoice Date missing!' => '·¢Æ±ÈÕÆÚ´íÎó!',
+ 'Invoice Number' => '·¢Æ±±àºÅ',
+ 'Invoice Number missing!' => '·¢Æ±±àºÅ´íÎó!',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Notes' => '±¸×¢',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Number' => '񅧏',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'Open' => '¿ªÆô',
+ 'Order' => '¶©µ¥',
+ 'Order Number' => '¶©µ¥±àºÅ',
+ 'Paid' => 'ÒѸ¶',
+ 'Payment date missing!' => 'δָÃ÷¸¶¿î?ÕÆ?!',
+ 'Payments' => '¸¶¿î',
+ 'Post' => 'È·ÈÏ',
+ 'Post as new' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Project' => '¹¤³Ì',
+ 'Project not on file!' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Remaining' => 'ÉÐâÅ',
+ 'Sales Invoice' => 'Ïú»õ·¢Æ±',
+ 'Select from one of the names below' => 'ì¶ÏÂÁÐÃû×ÖÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the projects below' => 'ì¶ÏÂÁй¤³ÌÖÐÑ¡ÔñÒ»Ïî',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Source' => 'À´Ô´',
+ 'Subtotal' => 'С¼Æ',
+ 'Tax' => 'Ë°½ð',
+ 'Tax Included' => '²»ÊÕ·þÎñ·Ñ',
+ 'Total' => '×ܼÆ',
+ 'Transaction deleted!' => 'ÕÊĿɾ³ý!',
+ 'Transaction posted!' => 'ÕÊÄ¿È·ÈÏ!',
+ 'Update' => '¸üÐÂ',
+ 'Vendor not on file!' => '´Ë³§ÉÌδÔÚµµ°¸!',
+ 'Yes' => 'ÊÇ',
+ 'to' => 'ÖÁ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'Ó¦ÊÕÕÊÄ¿' => 'ar_transaction',
+ '¼ÌÐø' => 'continue',
+ 'ɾ³ý' => 'delete',
+ 'È·ÈÏ' => 'post',
+ 'È·ÈϳÉΪÐÂÕÊÄ¿' => 'post_as_new',
+ 'Ïú»õ·¢Æ±' => 'sales_invoice',
+ '¸üÐÂ' => 'update',
+ 'ÊÇ' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/arap b/sql-ledger/locale/cn/arap
new file mode 100644
index 0000000..a6a3975
--- /dev/null
+++ b/sql-ledger/locale/cn/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'µØÖ·',
+ 'Continue' => '¼ÌÐø',
+ 'Customer not on file!' => '¿Í»§¼Ç¼ûÔÚµµ°¸!',
+ 'Description' => '˵Ã÷',
+ 'Number' => '񅧏',
+ 'Project not on file!' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Select from one of the names below' => 'ì¶ÏÂÁÐÃû×ÖÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the projects below' => 'ì¶ÏÂÁй¤³ÌÖÐÑ¡ÔñÒ»Ïî',
+ 'Vendor not on file!' => '´Ë³§ÉÌδÔÚµµ°¸!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ '¼ÌÐø' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/ca b/sql-ledger/locale/cn/ca
new file mode 100644
index 0000000..91587fb
--- /dev/null
+++ b/sql-ledger/locale/cn/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => '¿ÆÄ¿',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'Balance' => '²î¶î',
+ 'Chart of Accounts' => '»á¼Æ¿ÆÄ¿±í',
+ 'Credit' => '´û·½',
+ 'Date' => 'ÈÕÆÚ',
+ 'Debit' => '½è·½',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Description' => '˵Ã÷',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'From' => '´Ó',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Ò»²¢ÏÔʾ',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'List Transactions' => 'ÁгöÕÊÄ¿',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'Reference' => '²Î¿¼ºÅÂë',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Subtotal' => 'С¼Æ',
+ 'to' => 'ÖÁ',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'ÁгöÕÊÄ¿' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/cp b/sql-ledger/locale/cn/cp
new file mode 100644
index 0000000..fb357dc
--- /dev/null
+++ b/sql-ledger/locale/cn/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => '¿ÆÄ¿',
+ 'Address' => 'µØÖ·',
+ 'Amount' => '×ܼÆ',
+ 'Amount does not equal applied!' => '×ܶÏàµÈ!',
+ 'Amount missing!' => 'δָÃ÷×ܶî!',
+ 'Applied' => 'Ö§¸¶',
+ 'Cannot post payment!' => 'ÎÞ·¨´¦Àí¸¶¿î!',
+ 'Cannot process payment for a closed period!' => 'ÒѹرյÄʱ¶ÎÄÚ´¦Àí¸¶¿î!',
+ 'Check' => '֧Ʊ',
+ 'Check printed!' => 'ӡˢ֧Ʊ!',
+ 'Check printing failed!' => 'ÎÞ·¨Ó¡Ë¢Ö§Æ±!',
+ 'Continue' => '¼ÌÐø',
+ 'Currency' => '±Ò±ð',
+ 'Customer' => '¿Í»§',
+ 'Customer not on file!' => '¿Í»§¼Ç¼ûÔÚµµ°¸!',
+ 'Date' => 'ÈÕÆÚ',
+ 'Date missing!' => 'δָÃ÷ÈÕÆÚ',
+ 'Description' => '˵Ã÷',
+ 'Due' => 'µ½ÆÚ',
+ 'Exchangerate' => '»ãÂÊ',
+ 'From' => '´Ó',
+ 'Invoice' => '·¢Æ±',
+ 'Invoices' => '·¢Æ±',
+ 'Nothing applied!' => 'δָÃ÷Ö§¸¶×ܶî!',
+ 'Number' => '񅧏',
+ 'Paid in full' => 'Ö§¸¶È«²¿×ܶî',
+ 'Payment' => '¸¶¿î·½Ê½',
+ 'Payment posted!' => 'Payment posted!',
+ 'Post' => 'È·ÈÏ',
+ 'Print' => 'Ó¡Ë¢',
+ 'Printer' => 'Ó¡±í»ú',
+ 'Project not on file!' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Receipt' => 'ÊÕ¾Ý',
+ 'Receipt printed!' => 'Receipt printed!',
+ 'Receipt printing failed!' => 'Receipt printing failed!',
+ 'Reference' => '²Î¿¼ºÅÂë',
+ 'Screen' => 'Ó©Ä»',
+ 'Select from one of the names below' => 'ì¶ÏÂÁÐÃû×ÖÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the projects below' => 'ì¶ÏÂÁй¤³ÌÖÐÑ¡ÔñÒ»Ïî',
+ 'Update' => '¸üÐÂ',
+ 'Vendor' => '³§ÉÌ',
+ 'Vendor not on file!' => '´Ë³§ÉÌδÔÚµµ°¸!',
+ 'to' => 'ÖÁ',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ '¼ÌÐø' => 'continue',
+ 'È·ÈÏ' => 'post',
+ 'Ó¡Ë¢' => 'print',
+ '¸üÐÂ' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/ct b/sql-ledger/locale/cn/ct
new file mode 100644
index 0000000..7793fea
--- /dev/null
+++ b/sql-ledger/locale/cn/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'ÐÂÔö',
+ 'Address' => 'µØÖ·',
+ 'All' => 'È«²¿',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => '²»ÄÜɾ³ý¿Í»§!',
+ 'Cannot delete vendor!' => '²»ÄÜɾ³ý³§ÉÌ!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Á¬ÂçÈË',
+ 'Continue' => '¼ÌÐø',
+ 'Credit Limit' => 'ÐÅÓöî¶È',
+ 'Customer deleted!' => '¿Í»§¼Ç¼ɾ³ý!',
+ 'Customer saved!' => '¿Í»§¼Ç¼±£´æ!',
+ 'Customers' => '¿Í»§',
+ 'Delete' => 'ɾ³ý',
+ 'Discount' => 'ÕÛ¿Û',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'Edit Customer' => '±à¼­¿Í»§',
+ 'Edit Vendor' => '±à¼­³§ÉÌ',
+ 'Fax' => '´«Õæ',
+ 'Include in Report' => 'Ò»²¢ÏÔʾ',
+ 'Invoice' => '·¢Æ±',
+ 'Name' => 'Ãû³Æ',
+ 'Name missing!' => 'ȱÉÙÃû³Æ!',
+ 'Notes' => '±¸×¢',
+ 'Number' => '񅧏',
+ 'Order' => '¶©µ¥',
+ 'Orphaned' => 'ÎÞÖ÷',
+ 'Phone' => 'µç»°ºÅÂë',
+ 'Save' => '´¢´æ',
+ 'Ship to' => 'ÏúÊÛ´ú±í',
+ 'Tax Included' => '²»ÊÕ·þÎñ·Ñ',
+ 'Taxable' => 'Ӧ˰',
+ 'Terms: Net' => 'ƱÆÚ¾»¼Æ',
+ 'Transactions exist, cannot delete customer!' => '´Ë¿Í»§ÒÑÓÐÕÊÄ¿, ²»ÄÜɾ³ý!',
+ 'Transactions exist, cannot delete vendor!' => '´Ë³§ÉÌÒÑÓÐÕÊÄ¿, ²»ÄÜɾ³ý!',
+ 'Vendor deleted!' => '³§ÉÌɾ³ý!',
+ 'Vendor saved!' => '³§É̱£´æ!',
+ 'Vendors' => '³§ÉÌ',
+ 'days' => 'ÈÕ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'ÐÂÔö' => 'add',
+ '¼ÌÐø' => 'continue',
+ 'ɾ³ý' => 'delete',
+ '·¢Æ±' => 'invoice',
+ '¶©µ¥' => 'order',
+ '´¢´æ' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/gl b/sql-ledger/locale/cn/gl
new file mode 100644
index 0000000..df81370
--- /dev/null
+++ b/sql-ledger/locale/cn/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Ó¦¸¶ÕÊÄ¿',
+ 'AR Transaction' => 'Ó¦ÊÕÕÊÄ¿',
+ 'Account' => '¿ÆÄ¿',
+ 'Add General Ledger Transaction' => 'ÐÂÔö×ÜÕÊ',
+ 'Address' => 'µØÖ·',
+ 'All' => 'È«²¿',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Are you sure you want to delete Transaction' => 'ÄúÈ·¶¨ÒªÉ¾³ýÕÊÄ¿',
+ 'Asset' => '×ʲú',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'Balance' => '²î¶î',
+ 'Cannot delete transaction!' => 'ÎÞ·¨É¾³ýÕÊÄ¿!',
+ 'Cannot have a value in both Debit and Credit!' => '²»µÃͬʱÌîÈëÊýֵ춽跽Óë´û·½À¸Î»',
+ 'Cannot post a transaction without a value!' => 'ÎÞ·¨È·ÈÏû¼Û¸ñÕÊÄ¿!',
+ 'Cannot post transaction for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚ¼Ó?ë½»Ò?!',
+ 'Confirm!' => 'ÈëÕʳɹ¦!',
+ 'Continue' => '¼ÌÐø',
+ 'Credit' => '´û·½',
+ 'Customer not on file!' => '¿Í»§¼Ç¼ûÔÚµµ°¸!',
+ 'Date' => 'ÈÕÆÚ',
+ 'Debit' => '½è·½',
+ 'Debit and credit out of balance!' => '½è´û²»Æ½ºâ!',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Delete' => 'ɾ³ý',
+ 'Description' => '˵Ã÷',
+ 'Edit General Ledger Transaction' => '±à¼­×ÜÕÊ',
+ 'Equity' => '¹ÉȨ',
+ 'Expense' => '·ÑÓÃ',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'From' => '´Ó',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => '×ÜÕÊ',
+ 'General Ledger' => '×ÜÕÊ',
+ 'ID' => '񅧏',
+ 'Include in Report' => 'Ò»²¢ÏÔʾ',
+ 'Income' => 'ÊÕÒæ',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'Liability' => '¸ºÕ®',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Notes' => '±¸×¢',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Number' => '񅧏',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'Post' => 'È·ÈÏ',
+ 'Post as new' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Project' => '¹¤³Ì',
+ 'Project not on file!' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Purchase Invoice' => '²É¹º·¢Æ±',
+ 'Reference' => '²Î¿¼ºÅÂë',
+ 'Reference missing!' => 'δָÃ÷²Î¿¼ºÅÂë!',
+ 'Reports' => '±¨±í',
+ 'Sales Invoice' => 'Ïú»õ·¢Æ±',
+ 'Select from one of the names below' => 'ì¶ÏÂÁÐÃû×ÖÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the projects below' => 'ì¶ÏÂÁй¤³ÌÖÐÑ¡ÔñÒ»Ïî',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Source' => 'À´Ô´',
+ 'Subtotal' => 'С¼Æ',
+ 'Transaction Date missing!' => '©ÌîÕÊÄ¿ÈÕÆÚ!',
+ 'Transaction deleted!' => 'ÕÊĿɾ³ý!',
+ 'Transaction posted!' => 'ÕÊÄ¿È·ÈÏ!',
+ 'Update' => '¸üÐÂ',
+ 'Vendor not on file!' => '´Ë³§ÉÌδÔÚµµ°¸!',
+ 'Yes' => 'ÊÇ',
+ 'to' => 'ÖÁ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'Ó¦¸¶ÕÊÄ¿' => 'ap_transaction',
+ 'Ó¦ÊÕÕÊÄ¿' => 'ar_transaction',
+ '¼ÌÐø' => 'continue',
+ 'ɾ³ý' => 'delete',
+ '×ÜÕÊ' => 'gl_transaction',
+ 'È·ÈÏ' => 'post',
+ 'È·ÈϳÉΪÐÂÕÊÄ¿' => 'post_as_new',
+ '²É¹º·¢Æ±' => 'purchase_invoice',
+ 'Ïú»õ·¢Æ±' => 'sales_invoice',
+ '¸üÐÂ' => 'update',
+ 'ÊÇ' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/ic b/sql-ledger/locale/cn/ic
new file mode 100644
index 0000000..e9bc870
--- /dev/null
+++ b/sql-ledger/locale/cn/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => '»îÔ¾',
+ 'Add' => 'ÐÂÔö',
+ 'Add Assembly' => 'ÐÂÔöÉÌÆ·',
+ 'Add Part' => 'ÐÂÔöÔ­ÁÏ',
+ 'Add Purchase Order' => 'ÐÂÔö²É¹ºµ¥',
+ 'Add Sales Order' => 'ÐÂÔöÏú»õµ¥',
+ 'Add Service' => 'ÐÂÔö·þÎñ',
+ 'Address' => 'µØÖ·',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Assemblies' => 'ÉÌÆ·',
+ 'Assemblies restocked!' => '×°ÅäÖØнø»õ!',
+ 'Assembly Number missing!' => '²éÎÞ´ËÉÌÆ·!',
+ 'Attachment' => '¸½µµ',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'BOM' => '²ÄÁÏÕʵ¥',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ïä',
+ 'Bought' => 'ÒѹºÂò',
+ 'COGS' => '»õÏú³É±¾',
+ 'Cannot delete item already invoiced!' => 'ÎÞ·¨É¾³ý±¾Ïî',
+ 'Cannot delete item on order!' => 'ÎÞ·¨É¾³ýµ¥ÉϵÄÏîÄ¿!',
+ 'Cannot delete item which is part of an assembly!' => 'ÎÞ·¨É¾³ýÓÃì¶ÉÌÆ·ÖеÄÔ­ÁÏ',
+ 'Cannot delete item!' => 'ÎÞ·¨É¾³ýÏîÄ¿!',
+ 'Cannot stock assemblies!' => 'ÎÞ·¨É¾³ý×°ÅäÉÌÆ·!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Á¬ÂçÈË',
+ 'Continue' => '¼ÌÐø',
+ 'Copies' => '¿½±´',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Delete' => 'ɾ³ý',
+ 'Delivery Date' => 'µÝËÍÈÕÆÚ',
+ 'Description' => '˵Ã÷',
+ 'Drawing' => 'ͼ',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'E-mail address missing!' => '©Ìîµç×ÓÓʼþλַ!',
+ 'Edit Assembly' => '±à¼­ÉÌÆ·',
+ 'Edit Part' => '±à¼­Ô­ÁÏ',
+ 'Edit Service' => '±à¼­·þÎñ',
+ 'Expense' => '·ÑÓÃ',
+ 'Extended' => '¼ÆËãÁÐ',
+ 'Fax' => '´«Õæ',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'From' => '´Ó',
+ 'Image' => 'ͼÏó',
+ 'In-line' => 'ÐÐÄÚ',
+ 'Include in Report' => 'Ò»²¢ÏÔʾ',
+ 'Income' => 'ÊÕÒæ',
+ 'Individual Items' => '×é³ÉÏîÄ¿',
+ 'Inventory' => '¿â´æ',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'ÔÚÍ£ÓôËÏî×éºÏƷ֮ǰ, ´æ»õÊýÁ¿±ØÐèΪÁã!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Í£ÓôËÏîÁã¼þ֮ǰ, ´æ»õÊýÁ¿±ØÐèΪÁã!',
+ 'Inventory quantity must be zero!' => '´æ»õÊýÁ¿±ØÐèΪÁã!',
+ 'Invoice' => '·¢Æ±',
+ 'Invoice Date missing!' => '·¢Æ±ÈÕÆÚ´íÎó!',
+ 'Invoice Number' => '·¢Æ±±àºÅ',
+ 'Invoice Number missing!' => '·¢Æ±±àºÅ´íÎó!',
+ 'Item deleted!' => 'ÏîĿɾ³ý!',
+ 'Item not on file!' => '²éÎÞ´ËÏîÄ¿',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'Last Cost' => 'ÉÏÒ»±Ê³É±¾',
+ 'Line Total' => '×ÜÁÐÊý',
+ 'Link Accounts' => 'Á¬½á¿ÆÄ¿',
+ 'List Price' => 'List Price',
+ 'Make' => 'ÖÆÔì',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Message' => 'ѶϢ',
+ 'Microfiche' => 'Ëõ΢½ºÆ¬',
+ 'Model' => 'ÐͺÅ',
+ 'Name' => 'Ãû³Æ',
+ 'No.' => '񅧏',
+ 'Notes' => '±¸×¢',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Number' => '񅧏',
+ 'Number missing in Row' => 'δָÃ÷ºÅÂë',
+ 'Obsolete' => 'Í£ÓÃ',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'On Hand' => '´æÁ¿',
+ 'On Order' => 'ÒÑϵ¥¶©¹º',
+ 'Order' => '¶©µ¥',
+ 'Order Date missing!' => 'δָÃ÷ϵ¥?ÕÆ?!',
+ 'Order Number' => '¶©µ¥±àºÅ',
+ 'Order Number missing!' => 'δָÃ÷¶©µ¥±àºÅ!',
+ 'Ordered' => 'ÒÑ϶©¹º',
+ 'Orphaned' => 'ÎÞÖ÷',
+ 'PDF' => 'PDF',
+ 'Packing List' => '³ö»õµ¥',
+ 'Packing List Date missing!' => 'δָÃ÷°ü×°Çåµ¥?ÕÆ?!',
+ 'Packing List Number missing!' => 'δָÃ÷°ü×°Çåµ¥±àºÅ!',
+ 'Part' => 'Ô­ÁÏ',
+ 'Part Number missing!' => '©ÌîÔ­ÁϱàºÅ!',
+ 'Parts' => 'Ô­ÁÏ',
+ 'Phone' => 'µç»°ºÅÂë',
+ 'Postscript' => 'Postscript',
+ 'Price' => '¼Û¸ñ',
+ 'Printer' => 'Ó¡±í»ú',
+ 'Project' => '¹¤³Ì',
+ 'Purchase Order' => '²É¹ºµ¥',
+ 'Qty' => 'ÊýÁ¿',
+ 'ROP' => 'ÔÙ¶©µã',
+ 'Recd' => 'Recd',
+ 'Required by' => '×ÓÏîÄ¿',
+ 'Sales' => 'ÒµÎñ',
+ 'Sales Order' => 'Ïú»õµ¥',
+ 'Save' => '´¢´æ',
+ 'Screen' => 'Ó©Ä»',
+ 'Select from one of the items below' => 'ì¶ÏÂÁÐÏîÄ¿ÖÐÑ¡ÔñÒ»Ïî',
+ 'Select postscript or PDF!' => 'Ñ¡Ôñ postscript »ò PDF!',
+ 'Sell Price' => 'ÊÛ¼Û',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Service' => '·þÎñ',
+ 'Service Number missing!' => '©Ìî·þÎñ±àºÅ!',
+ 'Services' => '·þÎñ',
+ 'Ship' => 'º½ÔË',
+ 'Ship to' => 'ÏúÊÛ´ú±í',
+ 'Short' => '¶Ì',
+ 'Sold' => 'ÒÑÂô³ö',
+ 'Stock Assembly' => 'Å̵ã',
+ 'Subject' => '±êÌâ',
+ 'Subtotal' => 'С¼Æ',
+ 'Tax' => 'Ë°½ð',
+ 'To' => 'ÖÁ',
+ 'Top Level' => '×î¸ßµÈ¼¶',
+ 'Total' => '×ܼÆ',
+ 'Unit' => 'µ¥Î»',
+ 'Unit of measure' => '¶ÈÁ¿µ¥Î»',
+ 'Update' => '¸üÐÂ',
+ 'Updated' => 'ÒѸüÐÂ',
+ 'Weight' => 'ÖØÁ¿',
+ 'What type of item is this?' => '´ËÏîÄ¿µÄÐÍ̬?',
+ 'ea' => 'ea',
+ 'emailed to' => 'ÒѼÄÖÁ',
+ 'hr' => 'hr',
+ 'sent to printer' => 'ËÍÖÁÓ¡±í»ú',
+ 'to' => 'ÖÁ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'ÐÂÔö' => 'add',
+ 'ÐÂÔöÉÌÆ·' => 'add_assembly',
+ 'ÐÂÔöÔ­ÁÏ' => 'add_part',
+ 'ÐÂÔö·þÎñ' => 'add_service',
+ '¼ÌÐø' => 'continue',
+ 'ɾ³ý' => 'delete',
+ '±à¼­ÉÌÆ·' => 'edit_assembly',
+ '±à¼­Ô­ÁÏ' => 'edit_part',
+ '±à¼­·þÎñ' => 'edit_service',
+ '´¢´æ' => 'save',
+ '¸üÐÂ' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/io b/sql-ledger/locale/cn/io
new file mode 100644
index 0000000..fb68738
--- /dev/null
+++ b/sql-ledger/locale/cn/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'ÐÂÔö²É¹ºµ¥',
+ 'Add Sales Order' => 'ÐÂÔöÏú»õµ¥',
+ 'Address' => 'µØÖ·',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Attachment' => '¸½µµ',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ïä',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Á¬ÂçÈË',
+ 'Continue' => '¼ÌÐø',
+ 'Copies' => '¿½±´',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Delivery Date' => 'µÝËÍÈÕÆÚ',
+ 'Description' => '˵Ã÷',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'E-mail address missing!' => '©Ìîµç×ÓÓʼþλַ!',
+ 'Extended' => '¼ÆËãÁÐ',
+ 'Fax' => '´«Õæ',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'In-line' => 'ÐÐÄÚ',
+ 'Invoice' => '·¢Æ±',
+ 'Invoice Date missing!' => '·¢Æ±ÈÕÆÚ´íÎó!',
+ 'Invoice Number missing!' => '·¢Æ±±àºÅ´íÎó!',
+ 'Item not on file!' => '²éÎÞ´ËÏîÄ¿',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Message' => 'ѶϢ',
+ 'Name' => 'Ãû³Æ',
+ 'No.' => '񅧏',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Number' => '񅧏',
+ 'Number missing in Row' => 'δָÃ÷ºÅÂë',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'Order' => '¶©µ¥',
+ 'Order Date missing!' => 'δָÃ÷ϵ¥?ÕÆ?!',
+ 'Order Number missing!' => 'δָÃ÷¶©µ¥±àºÅ!',
+ 'PDF' => 'PDF',
+ 'Packing List' => '³ö»õµ¥',
+ 'Packing List Date missing!' => 'δָÃ÷°ü×°Çåµ¥?ÕÆ?!',
+ 'Packing List Number missing!' => 'δָÃ÷°ü×°Çåµ¥±àºÅ!',
+ 'Part' => 'Ô­ÁÏ',
+ 'Phone' => 'µç»°ºÅÂë',
+ 'Postscript' => 'Postscript',
+ 'Price' => '¼Û¸ñ',
+ 'Printer' => 'Ó¡±í»ú',
+ 'Project' => '¹¤³Ì',
+ 'Purchase Order' => '²É¹ºµ¥',
+ 'Qty' => 'ÊýÁ¿',
+ 'Recd' => 'Recd',
+ 'Required by' => '×ÓÏîÄ¿',
+ 'Sales Order' => 'Ïú»õµ¥',
+ 'Screen' => 'Ó©Ä»',
+ 'Select from one of the items below' => 'ì¶ÏÂÁÐÏîÄ¿ÖÐÑ¡ÔñÒ»Ïî',
+ 'Select postscript or PDF!' => 'Ñ¡Ôñ postscript »ò PDF!',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Service' => '·þÎñ',
+ 'Ship' => 'º½ÔË',
+ 'Ship to' => 'ÏúÊÛ´ú±í',
+ 'Subject' => '±êÌâ',
+ 'To' => 'ÖÁ',
+ 'Unit' => 'µ¥Î»',
+ 'What type of item is this?' => '´ËÏîÄ¿µÄÐÍ̬?',
+ 'emailed to' => 'ÒѼÄÖÁ',
+ 'sent to printer' => 'ËÍÖÁÓ¡±í»ú',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ '¼ÌÐø' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/ir b/sql-ledger/locale/cn/ir
new file mode 100644
index 0000000..321d812
--- /dev/null
+++ b/sql-ledger/locale/cn/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => '¿ÆÄ¿',
+ 'Add Purchase Invoice' => 'ÐÂÔö²É¹º·¢Æ±',
+ 'Add Purchase Order' => 'ÐÂÔö²É¹ºµ¥',
+ 'Add Sales Order' => 'ÐÂÔöÏú»õµ¥',
+ 'Address' => 'µØÖ·',
+ 'Amount' => '×ܼÆ',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Are you sure you want to delete Invoice Number' => 'ÄúÈ·¶¨ÒªÉ¾³ý·¢Æ±±àºÅ',
+ 'Attachment' => '¸½µµ',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ïä',
+ 'Cannot delete invoice!' => 'ÎÞ·¨É¾³ý·¢Æ±!',
+ 'Cannot post invoice for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚÈ·ÈÏ·¢Æ±?ë½»Ò!',
+ 'Cannot post invoice!' => 'ÎÞ·¨È·ÈÏ·¢Æ±!',
+ 'Cannot post payment for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚ¼Ó?ë½»Ò?!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'ÈëÕʳɹ¦!',
+ 'Contact' => 'Á¬ÂçÈË',
+ 'Continue' => '¼ÌÐø',
+ 'Copies' => '¿½±´',
+ 'Currency' => '±Ò±ð',
+ 'Customer not on file!' => '¿Í»§¼Ç¼ûÔÚµµ°¸!',
+ 'Date' => 'ÈÕÆÚ',
+ 'Date Due' => 'Ó¦¸¶ÈÕÆÚ',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Delete' => 'ɾ³ý',
+ 'Delivery Date' => 'µÝËÍÈÕÆÚ',
+ 'Description' => '˵Ã÷',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'E-mail address missing!' => '©Ìîµç×ÓÓʼþλַ!',
+ 'Edit Purchase Invoice' => '±à¼­²É¹º·¢Æ±',
+ 'Exch' => '»ãÂÊ',
+ 'Exchangerate' => '»ãÂÊ',
+ 'Exchangerate for payment missing!' => 'δָÃ÷¸¶¿î»ãÂÊ!',
+ 'Exchangerate missing!' => 'δָÃ÷»ãÂÊ!',
+ 'Extended' => '¼ÆËãÁÐ',
+ 'Fax' => '´«Õæ',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'In-line' => 'ÐÐÄÚ',
+ 'Invoice' => '·¢Æ±',
+ 'Invoice Date' => '·¢Æ±ÈÕÆÚ',
+ 'Invoice Date missing!' => '·¢Æ±ÈÕÆÚ´íÎó!',
+ 'Invoice Number' => '·¢Æ±±àºÅ',
+ 'Invoice Number missing!' => '·¢Æ±±àºÅ´íÎó!',
+ 'Invoice deleted!' => '·¢Æ±É¾³ý!',
+ 'Invoice posted!' => '·¢Æ±È·ÈÏ!',
+ 'Item not on file!' => '²éÎÞ´ËÏîÄ¿',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Message' => 'ѶϢ',
+ 'Name' => 'Ãû³Æ',
+ 'No.' => '񅧏',
+ 'Notes' => '±¸×¢',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Number' => '񅧏',
+ 'Number missing in Row' => 'δָÃ÷ºÅÂë',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'Order' => '¶©µ¥',
+ 'Order Date missing!' => 'δָÃ÷ϵ¥?ÕÆ?!',
+ 'Order Number' => '¶©µ¥±àºÅ',
+ 'Order Number missing!' => 'δָÃ÷¶©µ¥±àºÅ!',
+ 'PDF' => 'PDF',
+ 'Packing List' => '³ö»õµ¥',
+ 'Packing List Date missing!' => 'δָÃ÷°ü×°Çåµ¥?ÕÆ?!',
+ 'Packing List Number missing!' => 'δָÃ÷°ü×°Çåµ¥±àºÅ!',
+ 'Part' => 'Ô­ÁÏ',
+ 'Payment date missing!' => 'δָÃ÷¸¶¿î?ÕÆ?!',
+ 'Payments' => '¸¶¿î',
+ 'Phone' => 'µç»°ºÅÂë',
+ 'Post' => 'È·ÈÏ',
+ 'Post as new' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Postscript' => 'Postscript',
+ 'Price' => '¼Û¸ñ',
+ 'Printer' => 'Ó¡±í»ú',
+ 'Project' => '¹¤³Ì',
+ 'Project not on file!' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Purchase Order' => '²É¹ºµ¥',
+ 'Qty' => 'ÊýÁ¿',
+ 'Recd' => 'Recd',
+ 'Record in' => '¼Ç¼ì¶',
+ 'Required by' => '×ÓÏîÄ¿',
+ 'Sales Order' => 'Ïú»õµ¥',
+ 'Screen' => 'Ó©Ä»',
+ 'Select from one of the items below' => 'ì¶ÏÂÁÐÏîÄ¿ÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the names below' => 'ì¶ÏÂÁÐÃû×ÖÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the projects below' => 'ì¶ÏÂÁй¤³ÌÖÐÑ¡ÔñÒ»Ïî',
+ 'Select postscript or PDF!' => 'Ñ¡Ôñ postscript »ò PDF!',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Service' => '·þÎñ',
+ 'Ship' => 'º½ÔË',
+ 'Ship to' => 'ÏúÊÛ´ú±í',
+ 'Source' => 'À´Ô´',
+ 'Subject' => '±êÌâ',
+ 'Subtotal' => 'С¼Æ',
+ 'Tax Included' => '²»ÊÕ·þÎñ·Ñ',
+ 'To' => 'ÖÁ',
+ 'Total' => '×ܼÆ',
+ 'Unit' => 'µ¥Î»',
+ 'Update' => '¸üÐÂ',
+ 'Vendor' => '³§ÉÌ',
+ 'Vendor missing!' => 'δָÃ÷³§ÉÌ!',
+ 'Vendor not on file!' => '´Ë³§ÉÌδÔÚµµ°¸!',
+ 'What type of item is this?' => '´ËÏîÄ¿µÄÐÍ̬?',
+ 'Yes' => 'ÊÇ',
+ 'ea' => 'ea',
+ 'emailed to' => 'ÒѼÄÖÁ',
+ 'sent to printer' => 'ËÍÖÁÓ¡±í»ú',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ '¼ÌÐø' => 'continue',
+ 'ɾ³ý' => 'delete',
+ '¶©µ¥' => 'order',
+ 'È·ÈÏ' => 'post',
+ 'È·ÈϳÉΪÐÂÕÊÄ¿' => 'post_as_new',
+ '¸üÐÂ' => 'update',
+ 'ÊÇ' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/is b/sql-ledger/locale/cn/is
new file mode 100644
index 0000000..d55c467
--- /dev/null
+++ b/sql-ledger/locale/cn/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => '¿ÆÄ¿',
+ 'Add Purchase Order' => 'ÐÂÔö²É¹ºµ¥',
+ 'Add Sales Invoice' => 'ÐÂÔöÏú»õ·¢Æ±',
+ 'Add Sales Order' => 'ÐÂÔöÏú»õµ¥',
+ 'Address' => 'µØÖ·',
+ 'Amount' => '×ܼÆ',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Are you sure you want to delete Invoice Number' => 'ÄúÈ·¶¨ÒªÉ¾³ý·¢Æ±±àºÅ',
+ 'Attachment' => '¸½µµ',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ïä',
+ 'Cannot delete invoice!' => 'ÎÞ·¨É¾³ý·¢Æ±!',
+ 'Cannot post invoice for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚÈ·ÈÏ·¢Æ±?ë½»Ò!',
+ 'Cannot post invoice!' => 'ÎÞ·¨È·ÈÏ·¢Æ±!',
+ 'Cannot post payment for a closed period!' => 'ÎÞ·¨ÔÚÒѹرյÄʱ¶ÎÄÚ¼Ó?ë½»Ò?!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'ÈëÕʳɹ¦!',
+ 'Contact' => 'Á¬ÂçÈË',
+ 'Continue' => '¼ÌÐø',
+ 'Copies' => '¿½±´',
+ 'Credit Limit' => 'ÐÅÓöî¶È',
+ 'Currency' => '±Ò±ð',
+ 'Customer' => '¿Í»§',
+ 'Customer missing!' => 'δָÃ÷¿Í»§!',
+ 'Customer not on file!' => '¿Í»§¼Ç¼ûÔÚµµ°¸!',
+ 'Date' => 'ÈÕÆÚ',
+ 'Date Due' => 'Ó¦¸¶ÈÕÆÚ',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Delete' => 'ɾ³ý',
+ 'Delivery Date' => 'µÝËÍÈÕÆÚ',
+ 'Description' => '˵Ã÷',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'E-mail address missing!' => '©Ìîµç×ÓÓʼþλַ!',
+ 'Edit Sales Invoice' => '±à¼­Ïú»õ·¢Æ±',
+ 'Exch' => '»ãÂÊ',
+ 'Exchangerate' => '»ãÂÊ',
+ 'Exchangerate for payment missing!' => 'δָÃ÷¸¶¿î»ãÂÊ!',
+ 'Exchangerate missing!' => 'δָÃ÷»ãÂÊ!',
+ 'Extended' => '¼ÆËãÁÐ',
+ 'Fax' => '´«Õæ',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'In-line' => 'ÐÐÄÚ',
+ 'Invoice' => '·¢Æ±',
+ 'Invoice Date' => '·¢Æ±ÈÕÆÚ',
+ 'Invoice Date missing!' => '·¢Æ±ÈÕÆÚ´íÎó!',
+ 'Invoice Number' => '·¢Æ±±àºÅ',
+ 'Invoice Number missing!' => '·¢Æ±±àºÅ´íÎó!',
+ 'Invoice deleted!' => '·¢Æ±É¾³ý!',
+ 'Invoice posted!' => '·¢Æ±È·ÈÏ!',
+ 'Item not on file!' => '²éÎÞ´ËÏîÄ¿',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Message' => 'ѶϢ',
+ 'Name' => 'Ãû³Æ',
+ 'No.' => '񅧏',
+ 'Notes' => '±¸×¢',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Number' => '񅧏',
+ 'Number missing in Row' => 'δָÃ÷ºÅÂë',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'Order' => '¶©µ¥',
+ 'Order Date missing!' => 'δָÃ÷ϵ¥?ÕÆ?!',
+ 'Order Number' => '¶©µ¥±àºÅ',
+ 'Order Number missing!' => 'δָÃ÷¶©µ¥±àºÅ!',
+ 'PDF' => 'PDF',
+ 'Packing List' => '³ö»õµ¥',
+ 'Packing List Date missing!' => 'δָÃ÷°ü×°Çåµ¥?ÕÆ?!',
+ 'Packing List Number missing!' => 'δָÃ÷°ü×°Çåµ¥±àºÅ!',
+ 'Part' => 'Ô­ÁÏ',
+ 'Payment date missing!' => 'δָÃ÷¸¶¿î?ÕÆ?!',
+ 'Payments' => '¸¶¿î',
+ 'Phone' => 'µç»°ºÅÂë',
+ 'Post' => 'È·ÈÏ',
+ 'Post as new' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Postscript' => 'Postscript',
+ 'Price' => '¼Û¸ñ',
+ 'Print' => 'Ó¡Ë¢',
+ 'Printer' => 'Ó¡±í»ú',
+ 'Project' => '¹¤³Ì',
+ 'Project not on file!' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Purchase Order' => '²É¹ºµ¥',
+ 'Qty' => 'ÊýÁ¿',
+ 'Recd' => 'Recd',
+ 'Record in' => '¼Ç¼ì¶',
+ 'Remaining' => 'ÉÐâÅ',
+ 'Required by' => '×ÓÏîÄ¿',
+ 'Sales Order' => 'Ïú»õµ¥',
+ 'Screen' => 'Ó©Ä»',
+ 'Select from one of the items below' => 'ì¶ÏÂÁÐÏîÄ¿ÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the names below' => 'ì¶ÏÂÁÐÃû×ÖÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the projects below' => 'ì¶ÏÂÁй¤³ÌÖÐÑ¡ÔñÒ»Ïî',
+ 'Select postscript or PDF!' => 'Ñ¡Ôñ postscript »ò PDF!',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Service' => '·þÎñ',
+ 'Ship' => 'º½ÔË',
+ 'Ship to' => 'ÏúÊÛ´ú±í',
+ 'Ship via' => 'º½ÔË·½·¨',
+ 'Source' => 'À´Ô´',
+ 'Subject' => '±êÌâ',
+ 'Subtotal' => 'С¼Æ',
+ 'Tax Included' => '²»ÊÕ·þÎñ·Ñ',
+ 'To' => 'ÖÁ',
+ 'Total' => '×ܼÆ',
+ 'Unit' => 'µ¥Î»',
+ 'Update' => '¸üÐÂ',
+ 'Vendor not on file!' => '´Ë³§ÉÌδÔÚµµ°¸!',
+ 'What type of item is this?' => '´ËÏîÄ¿µÄÐÍ̬?',
+ 'Yes' => 'ÊÇ',
+ 'ea' => 'ea',
+ 'emailed to' => 'ÒѼÄÖÁ',
+ 'sent to printer' => 'ËÍÖÁÓ¡±í»ú',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ '¼ÌÐø' => 'continue',
+ 'ɾ³ý' => 'delete',
+ 'µç×ÓÓʼþ' => 'e_mail',
+ '¶©µ¥' => 'order',
+ 'È·ÈÏ' => 'post',
+ 'È·ÈϳÉΪÐÂÕÊÄ¿' => 'post_as_new',
+ 'Ó¡Ë¢' => 'print',
+ 'ÏúÊÛ´ú±í' => 'ship_to',
+ '¸üÐÂ' => 'update',
+ 'ÊÇ' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/login b/sql-ledger/locale/cn/login
new file mode 100644
index 0000000..e22cfe3
--- /dev/null
+++ b/sql-ledger/locale/cn/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => '¹Øì¶',
+ 'Database Host' => '×ÊÁÏ¿âÖ÷»ú',
+ 'Dataset' => '×ÊÁϼ¯',
+ 'Incorrect Dataset version!' => '×ÊÁϼ¯°æ±¾´íÎó!',
+ 'Incorrect Password!' => 'ÃÜÂë´íÎó!',
+ 'Licensed to' => 'ÊÚȨÓè',
+ 'Login' => 'µÇ??',
+ 'Name' => 'Ãû³Æ',
+ 'Password' => 'ÃÜÂë',
+ 'User' => 'ʹÓÃÕß',
+ 'Version' => '°æ±¾',
+ 'You are logged out!' => 'ÄãÒԵdzö!',
+ 'You did not enter a name!' => 'Äú²¢Î´¼ü?ëÃ?³Æ!',
+ 'is not a member!' => '²¢²»ÊdzÉÔ±!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'µÇ??' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/menu b/sql-ledger/locale/cn/menu
new file mode 100644
index 0000000..c1d4657
--- /dev/null
+++ b/sql-ledger/locale/cn/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Ó¦¸¶ÕÊ¿î',
+ 'AP Aging' => 'Ó¦¸¶ÕÊÁä·ÖÎö',
+ 'AR' => 'Ó¦ÊÕÕÊ¿î',
+ 'AR Aging' => 'Ó¦ÊÕÕÊÁä·ÖÎö',
+ 'Accounting Menu' => '»á¼ÆÑ¡µ¥',
+ 'Add Account' => 'ÐÂÔö¿ÆÄ¿',
+ 'Add Assembly' => 'ÐÂÔöÉÌÆ·',
+ 'Add Customer' => 'ÐÂÔö¿Í»§',
+ 'Add GIFI' => 'ÐÂÔö GIFI',
+ 'Add Part' => 'ÐÂÔöÔ­ÁÏ',
+ 'Add Project' => 'ÐÂÔö¹¤³Ì',
+ 'Add Service' => 'ÐÂÔö·þÎñ',
+ 'Add Transaction' => 'ÐÂÔöÕÊÄ¿',
+ 'Add Vendor' => 'ÐÂÔö³§ÉÌ',
+ 'Assemblies' => 'ÉÌÆ·',
+ 'Audit Control' => '»üºË¿ØÖÆ',
+ 'Backup' => '±¸·Ý',
+ 'Balance Sheet' => '×ʲú¸ºÕ®±í',
+ 'Cash' => 'ÏÖ½ð',
+ 'Chart of Accounts' => '»á¼Æ¿ÆÄ¿±í',
+ 'Check' => '֧Ʊ',
+ 'Customers' => '¿Í»§',
+ 'General Ledger' => '×ÜÕÊ',
+ 'Goods & Services' => 'Goods & Services',
+ 'HTML Templates' => 'HTML ±íµ¥',
+ 'Income Statement' => 'ËðÒæ±í',
+ 'Invoice' => '·¢Æ±',
+ 'LaTeX Templates' => 'LaTex Ä£°æ',
+ 'List Accounts' => 'ÁгöÕʺÅ',
+ 'List GIFI' => 'Áгö GIFI',
+ 'Logout' => 'µÇ³ö',
+ 'Order Entry' => 'ϵ¥ÏîÄ¿',
+ 'Packing List' => '³ö»õµ¥',
+ 'Parts' => 'Ô­ÁÏ',
+ 'Payment' => '¸¶¿î·½Ê½',
+ 'Payments' => '¸¶¿î',
+ 'Preferences' => '¸öÈËÉ趨',
+ 'Projects' => '¹¤³Ì',
+ 'Purchase Invoice' => '²É¹º·¢Æ±',
+ 'Purchase Order' => '²É¹ºµ¥',
+ 'Purchase Orders' => '²É¹ºµ¥',
+ 'Receipt' => 'ÊÕ¾Ý',
+ 'Receipts' => 'ÊÕ¾Ý',
+ 'Reconciliation' => 'µ÷Í£',
+ 'Reports' => '±¨±í',
+ 'Sales Invoice' => 'Ïú»õ·¢Æ±',
+ 'Sales Order' => 'Ïú»õµ¥',
+ 'Sales Orders' => 'Ïú»õµ¥',
+ 'Save to File' => '´¢´æÖÁµµ°¸',
+ 'Send by E-Mail' => 'ÒÔµç×ÓÓʼþ¼ÄËÍ',
+ 'Services' => '·þÎñ',
+ 'Statement' => 'ÕÊÄ¿³ÂÊö',
+ 'Stock Assembly' => 'Å̵ã',
+ 'Stylesheet' => 'Ñùʽ±í',
+ 'System' => 'ϵͳ',
+ 'Tax collected' => 'ÊÕµ½µÄË°',
+ 'Tax paid' => 'Ö§¸¶µÄË°',
+ 'Transactions' => 'ÕÊÄ¿',
+ 'Trial Balance' => 'ÊÔËã±í',
+ 'Vendors' => '³§ÉÌ',
+ 'Version' => '°æ±¾',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/oe b/sql-ledger/locale/cn/oe
new file mode 100644
index 0000000..5054b9b
--- /dev/null
+++ b/sql-ledger/locale/cn/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'ÐÂÔö',
+ 'Add Purchase Invoice' => 'ÐÂÔö²É¹º·¢Æ±',
+ 'Add Purchase Order' => 'ÐÂÔö²É¹ºµ¥',
+ 'Add Sales Invoice' => 'ÐÂÔöÏú»õ·¢Æ±',
+ 'Add Sales Order' => 'ÐÂÔöÏú»õµ¥',
+ 'Address' => 'µØÖ·',
+ 'Amount' => '×ܼÆ',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Are you sure you want to delete Order Number' => 'ÄúÊÇ·ñ?·¶¨ÒªÉ¾³?¶©µ¥',
+ 'Attachment' => '¸½µµ',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ïä',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'ÎÞ·¨É¾³ý¶©µ¥!',
+ 'Cannot save order!' => 'ÎÞ·¨´¢´æÇåµ¥!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'ÒѹرÕ',
+ 'Confirm!' => 'ÈëÕʳɹ¦!',
+ 'Contact' => 'Á¬ÂçÈË',
+ 'Continue' => '¼ÌÐø',
+ 'Copies' => '¿½±´',
+ 'Credit Limit' => 'ÐÅÓöî¶È',
+ 'Curr' => 'Ä¿Ç°',
+ 'Currency' => '±Ò±ð',
+ 'Customer' => '¿Í»§',
+ 'Customer missing!' => 'δָÃ÷¿Í»§!',
+ 'Customer not on file!' => '¿Í»§¼Ç¼ûÔÚµµ°¸!',
+ 'Date' => 'ÈÕÆÚ',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Delete' => 'ɾ³ý',
+ 'Delivery Date' => 'µÝËÍÈÕÆÚ',
+ 'Description' => '˵Ã÷',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'E-mail address missing!' => '©Ìîµç×ÓÓʼþλַ!',
+ 'Edit Purchase Order' => '±à¼­²É¹ºµ¥',
+ 'Edit Sales Order' => '±à¼­Ïú»õµ¥',
+ 'Exchangerate' => '»ãÂÊ',
+ 'Exchangerate missing!' => 'δָÃ÷»ãÂÊ!',
+ 'Extended' => '¼ÆËãÁÐ',
+ 'Fax' => '´«Õæ',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'From' => '´Ó',
+ 'ID' => '񅧏',
+ 'In-line' => 'ÐÐÄÚ',
+ 'Include in Report' => 'Ò»²¢ÏÔʾ',
+ 'Invoice' => '·¢Æ±',
+ 'Invoice Date missing!' => '·¢Æ±ÈÕÆÚ´íÎó!',
+ 'Invoice Number missing!' => '·¢Æ±±àºÅ´íÎó!',
+ 'Item not on file!' => '²éÎÞ´ËÏîÄ¿',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Message' => 'ѶϢ',
+ 'Name' => 'Ãû³Æ',
+ 'No.' => '񅧏',
+ 'Notes' => '±¸×¢',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Number' => '񅧏',
+ 'Number missing in Row' => 'δָÃ÷ºÅÂë',
+ 'O' => 'O',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'Open' => '¿ªÆô',
+ 'Order' => '¶©µ¥',
+ 'Order Date' => '쵴?ͮ?',
+ 'Order Date missing!' => 'δָÃ÷ϵ¥?ÕÆ?!',
+ 'Order Number' => '¶©µ¥±àºÅ',
+ 'Order Number missing!' => 'δָÃ÷¶©µ¥±àºÅ!',
+ 'Order deleted!' => 'ɾ³ý¶©µ¥!',
+ 'Order saved!' => '´¢´æ¶©µ¥!',
+ 'PDF' => 'PDF',
+ 'Packing List' => '³ö»õµ¥',
+ 'Packing List Date missing!' => 'δָÃ÷°ü×°Çåµ¥?ÕÆ?!',
+ 'Packing List Number missing!' => 'δָÃ÷°ü×°Çåµ¥±àºÅ!',
+ 'Part' => 'Ô­ÁÏ',
+ 'Phone' => 'µç»°ºÅÂë',
+ 'Postscript' => 'Postscript',
+ 'Price' => '¼Û¸ñ',
+ 'Print' => 'Ó¡Ë¢',
+ 'Printer' => 'Ó¡±í»ú',
+ 'Project' => '¹¤³Ì',
+ 'Project not on file!' => 'È·ÈϳÉΪÐÂÕÊÄ¿',
+ 'Purchase Order' => '²É¹ºµ¥',
+ 'Purchase Orders' => '²É¹ºµ¥',
+ 'Qty' => 'ÊýÁ¿',
+ 'Recd' => 'Recd',
+ 'Remaining' => 'ÉÐâÅ',
+ 'Required by' => '×ÓÏîÄ¿',
+ 'Sales Order' => 'Ïú»õµ¥',
+ 'Sales Orders' => 'Ïú»õµ¥',
+ 'Save' => '´¢´æ',
+ 'Save as new' => '´¢´æ',
+ 'Screen' => 'Ó©Ä»',
+ 'Select from one of the items below' => 'ì¶ÏÂÁÐÏîÄ¿ÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the names below' => 'ì¶ÏÂÁÐÃû×ÖÖÐÑ¡ÔñÒ»Ïî',
+ 'Select from one of the projects below' => 'ì¶ÏÂÁй¤³ÌÖÐÑ¡ÔñÒ»Ïî',
+ 'Select postscript or PDF!' => 'Ñ¡Ôñ postscript »ò PDF!',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Service' => '·þÎñ',
+ 'Ship' => 'º½ÔË',
+ 'Ship to' => 'ÏúÊÛ´ú±í',
+ 'Ship via' => 'º½ÔË·½·¨',
+ 'Subject' => '±êÌâ',
+ 'Subtotal' => 'С¼Æ',
+ 'Tax' => 'Ë°½ð',
+ 'Tax Included' => '²»ÊÕ·þÎñ·Ñ',
+ 'Terms: Net' => 'ƱÆÚ¾»¼Æ',
+ 'To' => 'ÖÁ',
+ 'Total' => '×ܼÆ',
+ 'Unit' => 'µ¥Î»',
+ 'Update' => '¸üÐÂ',
+ 'Vendor' => '³§ÉÌ',
+ 'Vendor missing!' => 'δָÃ÷³§ÉÌ!',
+ 'Vendor not on file!' => '´Ë³§ÉÌδÔÚµµ°¸!',
+ 'What type of item is this?' => '´ËÏîÄ¿µÄÐÍ̬?',
+ 'Yes' => 'ÊÇ',
+ 'days' => 'ÈÕ',
+ 'ea' => 'ea',
+ 'emailed to' => 'ÒѼÄÖÁ',
+ 'sent to printer' => 'ËÍÖÁÓ¡±í»ú',
+ 'to' => 'ÖÁ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'ÐÂÔö' => 'add',
+ '¼ÌÐø' => 'continue',
+ 'ɾ³ý' => 'delete',
+ 'µç×ÓÓʼþ' => 'e_mail',
+ '·¢Æ±' => 'invoice',
+ 'Ó¡Ë¢' => 'print',
+ '´¢´æ' => 'save',
+ '´¢´æ' => 'save_as_new',
+ 'ÏúÊÛ´ú±í' => 'ship_to',
+ '¸üÐÂ' => 'update',
+ 'ÊÇ' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/pe b/sql-ledger/locale/cn/pe
new file mode 100644
index 0000000..35372d3
--- /dev/null
+++ b/sql-ledger/locale/cn/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'ÐÂÔö',
+ 'Add Project' => 'ÐÂÔö¹¤³Ì',
+ 'All' => 'È«²¿',
+ 'Continue' => '¼ÌÐø',
+ 'Delete' => 'ɾ³ý',
+ 'Description' => '˵Ã÷',
+ 'Edit Project' => '¸ü¸Ä¹¤³Ì',
+ 'Number' => '񅧏',
+ 'Orphaned' => 'ÎÞÖ÷',
+ 'Project' => '¹¤³Ì',
+ 'Project Number missing!' => 'δָÃ÷¹¤³ÌºÅÂë!',
+ 'Project deleted!' => '¹¤³ÌÒÔ±»É¾³ý!',
+ 'Project saved!' => '¹¤³ÌÒÔ±»´¢´æ!',
+ 'Projects' => '¹¤³Ì',
+ 'Save' => '´¢´æ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'ÐÂÔö' => 'add',
+ '¼ÌÐø' => 'continue',
+ 'ɾ³ý' => 'delete',
+ '´¢´æ' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/rc b/sql-ledger/locale/cn/rc
new file mode 100644
index 0000000..31f35f2
--- /dev/null
+++ b/sql-ledger/locale/cn/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => '¿ÆÄ¿',
+ 'Balance' => '²î¶î',
+ 'Cleared Balance' => 'Ö§¸¶²î¶î×ÜÊý',
+ 'Continue' => '¼ÌÐø',
+ 'Date' => 'ÈÕÆÚ',
+ 'Deposit' => '´¢´æ',
+ 'Description' => '˵Ã÷',
+ 'Difference' => '²îÒì',
+ 'Done' => 'Íê³É',
+ 'Exchangerate Difference' => '»ãÂʲîÒì',
+ 'From' => '´Ó',
+ 'Out of balance!' => '³öÓÚ²î¶î!',
+ 'Payment' => '¸¶¿î·½Ê½',
+ 'Reconciliation' => 'µ÷Í£',
+ 'Select all' => 'Ñ¡ÔñÈ«²¿',
+ 'Source' => 'À´Ô´',
+ 'Statement Balance' => 'ÕÊÄ¿³ÂÊö²î¶î',
+ 'Update' => '¸üÐÂ',
+ 'to' => 'ÖÁ',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ '¼ÌÐø' => 'continue',
+ 'Íê³É' => 'done',
+ 'Ñ¡ÔñÈ«²¿' => 'select_all',
+ '¸üÐÂ' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/cn/rp b/sql-ledger/locale/cn/rp
new file mode 100644
index 0000000..6d80cf8
--- /dev/null
+++ b/sql-ledger/locale/cn/rp
@@ -0,0 +1,120 @@
+$self{texts} = {
+ 'AP Aging' => 'Ó¦¸¶ÕÊÁä·ÖÎö',
+ 'AR Aging' => 'Ó¦ÊÕÕÊÁä·ÖÎö',
+ 'Account' => '¿ÆÄ¿',
+ 'Accounts' => 'ÕÊ»§',
+ 'Amount' => '×ܼÆ',
+ 'Apr' => 'ËÄÔÂ',
+ 'April' => 'ËÄÔÂ',
+ 'Attachment' => '¸½µµ',
+ 'Aug' => '°ËÔÂ',
+ 'August' => '°ËÔÂ',
+ 'Balance' => '²î¶î',
+ 'Balance Sheet' => '×ʲú¸ºÕ®±í',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'ÏÖ½ð½»Ò×',
+ 'Cc' => 'Cc',
+ 'Compare to' => '¶ÔÕÕ',
+ 'Continue' => '¼ÌÐø',
+ 'Copies' => '¿½±´',
+ 'Credit' => '´û·½',
+ 'Current' => 'ÏÖÔÚ',
+ 'Customer' => '¿Í»§',
+ 'Date' => 'ÈÕÆÚ',
+ 'Debit' => '½è·½',
+ 'Dec' => 'Ê®¶þÔÂ',
+ 'December' => 'Ê®¶þÔÂ',
+ 'Decimalplaces' => 'СÊýµÄÊýÄ¿',
+ 'Department' => 'Department',
+ 'Description' => '˵Ã÷',
+ 'Due' => 'µ½ÆÚ',
+ 'E-mail' => 'µç×ÓÓʼþ',
+ 'E-mail Statement to' => 'µç×ÓÓʼþÕÊÄ¿³ÂÊöµ½',
+ 'Feb' => '¶þÔÂ',
+ 'February' => '¶þÔÂ',
+ 'From' => '´Ó',
+ 'GIFI' => 'GIFI',
+ 'Heading' => '±íÍ·',
+ 'ID' => '񅧏',
+ 'In-line' => 'ÐÐÄÚ',
+ 'Include in Report' => 'Ò»²¢ÏÔʾ',
+ 'Income Statement' => 'ËðÒæ±í',
+ 'Invoice' => '·¢Æ±',
+ 'Jan' => 'Ò»ÔÂ',
+ 'January' => 'Ò»ÔÂ',
+ 'Jul' => 'ÆßÔÂ',
+ 'July' => 'ÆßÔÂ',
+ 'Jun' => 'ÁùÔÂ',
+ 'June' => 'ÁùÔÂ',
+ 'Mar' => 'ÈýÔÂ',
+ 'March' => 'ÈýÔÂ',
+ 'May' => 'ÎåÔÂ',
+ 'May ' => 'ÎåÔÂ',
+ 'Message' => 'ѶϢ',
+ 'N/A' => '²»ÊÊÓÃ',
+ 'Nothing selected!' => 'δѡ¶¨×Ê!',
+ 'Nov' => 'ʮһÔÂ',
+ 'November' => 'ʮһÔÂ',
+ 'Oct' => 'Ê®ÔÂ',
+ 'October' => 'Ê®ÔÂ',
+ 'PDF' => 'PDF',
+ 'Payments' => '¸¶¿î',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Ó¡Ë¢',
+ 'Printer' => 'Ó¡±í»ú',
+ 'Project Number' => 'Project Number',
+ 'Receipts' => 'ÊÕ¾Ý',
+ 'Report for' => '±¨±íÀ´Ô´',
+ 'Retained Earnings' => '±£ÁôÓ¯âÅ',
+ 'Screen' => 'Ó©Ä»',
+ 'Select all' => 'Ñ¡ÔñÈ«²¿',
+ 'Select postscript or PDF!' => 'Ñ¡Ôñ postscript »ò PDF!',
+ 'Sep' => '¾ÅÔÂ',
+ 'September' => '¾ÅÔÂ',
+ 'Source' => 'À´Ô´',
+ 'Standard' => '±ê×¼',
+ 'Statement' => 'ÕÊÄ¿³ÂÊö',
+ 'Statement sent to' => 'ÕÊÄ¿³ÂÊöË͵½',
+ 'Statements sent to printer!' => 'ÕÊÄ¿³ÂÊöË͵½Ó¡±í»ú!',
+ 'Subject' => '±êÌâ',
+ 'Subtotal' => 'С¼Æ',
+ 'Tax' => 'Ë°½ð',
+ 'Tax collected' => 'ÊÕµ½µÄË°',
+ 'Tax paid' => 'Ö§¸¶µÄË°',
+ 'Total' => '×ܼÆ',
+ 'Trial Balance' => 'ÊÔËã±í',
+ 'Vendor' => '³§ÉÌ',
+ 'as at' => '¸ù¾Ý',
+ 'collected on sales' => 'ÔÚÏú»õʱ½áÇå',
+ 'for Period' => 'ÆÚ¼ä',
+ 'paid on purchases' => 'ÔڲɹºÊ±½áÇå',
+ 'to' => 'ÖÁ',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ '¼ÌÐø' => 'continue',
+ 'µç×ÓÓʼþ' => 'e_mail',
+ 'Ó¡Ë¢' => 'print',
+ 'Ñ¡ÔñÈ«²¿' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/COPYING b/sql-ledger/locale/ct/COPYING
new file mode 100644
index 0000000..fbb7b61
--- /dev/null
+++ b/sql-ledger/locale/ct/COPYING
@@ -0,0 +1,21 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (C) 2002
+#
+# Catalan Translation:
+#
+# Author: Jaume Teixi <teixi@rocacorbit.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+######################################################################
diff --git a/sql-ledger/locale/ct/LANGUAGE b/sql-ledger/locale/ct/LANGUAGE
new file mode 100644
index 0000000..f37af43
--- /dev/null
+++ b/sql-ledger/locale/ct/LANGUAGE
@@ -0,0 +1 @@
+Catalan
diff --git a/sql-ledger/locale/ct/admin b/sql-ledger/locale/ct/admin
new file mode 100644
index 0000000..a394d28
--- /dev/null
+++ b/sql-ledger/locale/ct/admin
@@ -0,0 +1,122 @@
+$self{texts} = {
+ 'Access Control' => 'Control d\'Accés',
+ 'Accounting' => 'Comptabilitat',
+ 'Add User' => 'Afegir Usuari',
+ 'Address' => 'Adreça',
+ 'Administration' => 'Administració',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => 'Totes les Base de Dades Actualitzades!',
+ 'Change Admin Password' => 'Canviar la contrasenya de l\'administrador',
+ 'Change Password' => 'Canviar contrasenya',
+ 'Character Set' => 'Canviar Tipus Caràcters',
+ 'Click on login name to edit!' => 'Clicar en el nom d\'accés per editar',
+ 'Company' => 'Empresa',
+ 'Connect to' => 'Connectar a',
+ 'Continue' => 'Continuar',
+ 'Create Chart of Accounts' => 'Crear la Taula de Comptes',
+ 'Create Dataset' => 'Crear el Conjunt de Dades',
+ 'DBI not installed!' => 'DBI no instal.lat',
+ 'Database' => 'Base de Dades',
+ 'Database Administration' => 'Administrar Base de Dades',
+ 'Database Driver not checked!' => 'Mòdul de la Base de Dades no comprovat!',
+ 'Database User missing!' => 'Falta el usuari de la Base de Dades!',
+ 'Dataset' => 'Conjunt de Dades',
+ 'Dataset missing!' => 'Falta el Conjunt de Dades',
+ 'Dataset updated!' => 'Dataset updated!',
+ 'Date Format' => 'Format Data',
+ 'Delete' => 'Esborrar',
+ 'Delete Dataset' => 'Esborrar Conjunt de Dades',
+ 'Directory' => 'Directori',
+ 'Driver' => 'Mòdul',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'Email',
+ 'Edit User' => 'Editar Usuari',
+ 'Existing Datasets' => 'Conjunt de Dades Existents',
+ 'Fax' => 'Fax',
+ 'Host' => 'Servidor',
+ 'Hostname missing!' => 'Falta el Nom del Servidor!',
+ 'Incorrect Password!' => 'Contrasenya no Vàlida!',
+ 'Language' => 'Idioma',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deixar en blanc el servidor i el port excepte per fer una connexió remota',
+ 'Login' => 'Entrar',
+ 'Name' => 'Nom',
+ 'New Templates' => 'Noves Plantilles',
+ 'No Database Drivers available!' => 'Cap Mòdul de Base de Dades disponible!',
+ 'No Dataset selected!' => 'No hi ha cap Conjunt de Dades seleccionat!',
+ 'Nothing to delete!' => 'No hi ha res per esborrar!',
+ 'Number Format' => 'Format Número',
+ 'Oracle Database Administration' => 'Administració Base de Dades Oracle',
+ 'Password' => 'Contrasenya',
+ 'Password changed!' => 'Password changed!',
+ 'Pg Database Administration' => 'Administració Base de Dades PostgreSQL',
+ 'Phone' => 'Tel',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Falta Port!',
+ 'Printer' => 'Impressora',
+ 'Save' => 'Guardar',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccionar Conjunt de Dades a esborrar i prèmer "Continuar"',
+ 'Setup Templates' => 'Configurar Plantilles',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Signatura',
+ 'Stylesheet' => 'Fulla Estils',
+ 'Templates' => 'Plantilles',
+ 'The following Datasets are not in use and can be deleted' => 'Els següents conjunt de dades no s\'usen i poden esborrar-se',
+ 'The following Datasets need to be updated' => 'Cal actualitzar els següents conjunt de dades',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Comprovació preliminar de les fonts existents. No es crearà ni s\'esborrra res en aquest punt!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Per afegir un usuari a un grup, editar el nom, canviar el nom d\'accés i guardar. Un nou usuari amb les mateixes variables es guardarà amb el nou nom d\«accés',
+ 'Update Dataset' => 'Actualitzar Conjut de Dades',
+ 'Use Templates' => 'Emprar Plantilles',
+ 'User' => 'Usuari',
+ 'User deleted!' => 'User deleted!',
+ 'User saved!' => 'User saved!',
+ 'Version' => 'Versió',
+ 'You must enter a host and port for local and remote connections!' => 'Heu d\'entrar el servidor i el port per les connexions locals i remotes!',
+ 'does not exist' => 'no existeix',
+ 'is already a member!' => 'ja és membre!',
+ 'localhost' => 'màquina local',
+ 'successfully created!' => 'creat correctament!',
+ 'successfully deleted!' => 'esborrat correctament!',
+ 'website' => 'web',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'afegir_usuari' => 'add_user',
+ 'canviar_la_contrasenya_de_l\'administrador' => 'change_admin_password',
+ 'canviar_contrasenya' => 'change_password',
+ 'continuar' => 'continue',
+ 'crear_el_conjunt_de_dades' => 'create_dataset',
+ 'esborrar' => 'delete',
+ 'esborrar_conjunt_de_dades' => 'delete_dataset',
+ 'entrar' => 'login',
+ 'administració_base_de_dades_oracle' => 'oracle_database_administration',
+ 'administració_base_de_dades_postgresql' => 'pg_database_administration',
+ 'guardar' => 'save',
+ 'actualitzar_conjut_de_dades' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/all b/sql-ledger/locale/ct/all
new file mode 100644
index 0000000..c2c9327
--- /dev/null
+++ b/sql-ledger/locale/ct/all
@@ -0,0 +1,487 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Despeses',
+ 'AP Aging' => 'Diari de Despeses',
+ 'AP Transaction' => '',
+ 'AP Transactions' => 'Transaccions de Despeses',
+ 'AR' => 'Ingressos',
+ 'AR Aging' => 'Diari d\'Ingressos',
+ 'AR Transaction' => '',
+ 'AR Transactions' => 'Transaccions d\'Ingressos',
+ 'About' => 'Referent',
+ 'Access Control' => 'Control d\'Accés',
+ 'Account' => 'Compta',
+ 'Account Number' => 'Num. Compta',
+ 'Account Number missing!' => 'Falta el Num. Compta!',
+ 'Account Type' => 'Tipus de Compta',
+ 'Account Type missing!' => 'Falta el Tipus de Compta!',
+ 'Account deleted!' => '',
+ 'Account saved!' => '',
+ 'Accounting' => 'Comptabilitat',
+ 'Accounting Menu' => 'Menú Comptable',
+ 'Accounts' => '',
+ 'Active' => '',
+ 'Add' => 'Afegir',
+ 'Add Account' => 'Afegir Compta',
+ 'Add Accounts Payables Transaction' => '',
+ 'Add Accounts Receivables Transaction' => '',
+ 'Add Assembly' => 'Afegir Compost',
+ 'Add Customer' => 'Afegir Client',
+ 'Add GIFI' => '',
+ 'Add General Ledger Transaction' => 'Afegir Transacció Llibre Major',
+ 'Add Part' => 'Afegir Article',
+ 'Add Project' => '',
+ 'Add Purchase Invoice' => '',
+ 'Add Purchase Order' => 'Afegir Ordre Compra',
+ 'Add Sales Invoice' => '',
+ 'Add Sales Order' => 'Afegir Pressupost',
+ 'Add Service' => 'Afegir Servei',
+ 'Add Transaction' => 'Afegir Transacció',
+ 'Add User' => 'Afegir Usuari',
+ 'Add Vendor' => 'Afegir Proveïdor',
+ 'Address' => 'Adreça',
+ 'Administration' => 'Administració',
+ 'Administrator' => '',
+ 'All' => 'Tots',
+ 'All Datasets up to date!' => 'Totes les Base de Dades Actualitzades!',
+ 'Amount' => 'Total',
+ 'Amount Due' => '',
+ 'Amount does not equal applied!' => '',
+ 'Amount missing!' => '',
+ 'Applied' => '',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => 'Segur que voleu esborrar la Fra. Num.',
+ 'Are you sure you want to delete Order Number' => 'Segur que voleu esborrar l\'Ordre',
+ 'Are you sure you want to delete Transaction' => 'Segur que voleu esborrar la Transacció',
+ 'Assemblies' => 'Compostos',
+ 'Assemblies restocked!' => '',
+ 'Assembly Number missing!' => 'Falta el Num. del Compost',
+ 'Asset' => 'Activat',
+ 'Attachment' => 'Adjunt',
+ 'Audit Control' => 'Control Auditoria',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'BOM' => '',
+ 'Backup' => 'Còpia de Seguretat',
+ 'Backup sent to' => 'Còpia de Seguretat enviada a',
+ 'Balance' => '',
+ 'Balance Sheet' => 'Fulla de Balanç',
+ 'Bcc' => '',
+ 'Bin' => 'Bin',
+ 'Books are open' => 'Els Llibres estan Oberts',
+ 'Bought' => 'Comprat',
+ 'Business Number' => 'Núm. Negoci',
+ 'C' => '',
+ 'COGS' => 'Cost de Preu',
+ 'Cannot delete account!' => '',
+ 'Cannot delete customer!' => '',
+ 'Cannot delete default account!' => 'No es pot esborrar la compta per defecte!',
+ 'Cannot delete invoice!' => '',
+ 'Cannot delete item already invoiced!' => 'No es pot esborrar un element facturat!',
+ 'Cannot delete item on order!' => 'No es pot esborrar un element pressupostat!',
+ 'Cannot delete item which is part of an assembly!' => 'No es pot eliminar un element que és part d\'un compost',
+ 'Cannot delete item!' => '',
+ 'Cannot delete order!' => '',
+ 'Cannot delete transaction!' => '',
+ 'Cannot delete vendor!' => '',
+ 'Cannot have a value in both Debit and Credit!' => 'No es pot tenir un valor simultàniament a Dèbit i a Crèdit',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => '',
+ 'Cannot post invoice!' => '',
+ 'Cannot post payment for a closed period!' => '',
+ 'Cannot post payment!' => '',
+ 'Cannot post transaction for a closed period!' => 'No es pot registrar una transacció per un període tancat',
+ 'Cannot post transaction!' => '',
+ 'Cannot process payment for a closed period!' => '',
+ 'Cannot save account!' => '',
+ 'Cannot save order!' => '',
+ 'Cannot save preferences!' => '',
+ 'Cannot stock assemblies!' => '',
+ 'Cash' => '',
+ 'Cash based' => '',
+ 'Cc' => '',
+ 'Change Admin Password' => 'Canviar la contrasenya de l\'administrador',
+ 'Change Password' => 'Canviar contrasenya',
+ 'Character Set' => 'Canviar Tipus Caràcters',
+ 'Chart of Accounts' => 'Taula de Comptes',
+ 'Check' => '',
+ 'Check printed!' => '',
+ 'Check printing failed!' => '',
+ 'Cleared Balance' => '',
+ 'Click on login name to edit!' => 'Clicar en el nom d\'accés per editar',
+ 'Close Books up to' => 'Tancar els llibres fins',
+ 'Closed' => 'Tancat',
+ 'Company' => 'Empresa',
+ 'Compare to' => 'Comparar amb',
+ 'Confirm!' => 'Confirmar!',
+ 'Connect to' => 'Connectar a',
+ 'Contact' => 'Contacte',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Còpies',
+ 'Copy to COA' => '',
+ 'Create Chart of Accounts' => 'Crear la Taula de Comptes',
+ 'Create Dataset' => 'Crear el Conjunt de Dades',
+ 'Credit' => 'Crèdit',
+ 'Credit Limit' => 'Límit de Crèdit',
+ 'Curr' => '',
+ 'Currency' => 'Moneda',
+ 'Current' => '',
+ 'Customer' => 'Client',
+ 'Customer deleted!' => '',
+ 'Customer missing!' => '',
+ 'Customer not on file!' => '',
+ 'Customer saved!' => '',
+ 'Customers' => '',
+ 'DBI not installed!' => 'DBI no instal.lat',
+ 'Database' => 'Base de Dades',
+ 'Database Administration' => 'Administrar Base de Dades',
+ 'Database Driver not checked!' => 'Mòdul de la Base de Dades no comprovat!',
+ 'Database Host' => 'Servidor Base de Dades',
+ 'Database User missing!' => 'Falta el usuari de la Base de Dades!',
+ 'Dataset' => 'Conjunt de Dades',
+ 'Dataset missing!' => 'Falta el Conjunt de Dades',
+ 'Dataset updated!' => '',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data Venciment',
+ 'Date Format' => 'Format Data',
+ 'Date Paid' => 'Data Pagament',
+ 'Date missing!' => '',
+ 'Debit' => 'Dèbit',
+ 'Debit and credit out of balance!' => 'Dèbit i Crèdit fora de balanç!',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Decimalplaces' => '',
+ 'Delete' => 'Esborrar',
+ 'Delete Account' => 'Esborrar Compta',
+ 'Delete Dataset' => 'Esborrar Conjunt de Dades',
+ 'Delivery Date' => '',
+ 'Deposit' => '',
+ 'Description' => 'Descripció',
+ 'Difference' => '',
+ 'Directory' => 'Directori',
+ 'Discount' => 'Descompte',
+ 'Done' => '',
+ 'Drawing' => '',
+ 'Driver' => 'Mòdul',
+ 'Dropdown Limit' => '',
+ 'Due' => 'Venciment',
+ 'Due Date' => 'Data Venciment',
+ 'Due Date missing!' => 'Falta la Data Venciment!',
+ 'E-mail' => 'Email',
+ 'E-mail Statement to' => '',
+ 'E-mail address missing!' => 'Falta Email!',
+ 'Edit' => '',
+ 'Edit Account' => 'Editar Compta',
+ 'Edit Accounts Payables Transaction' => '',
+ 'Edit Accounts Receivables Transaction' => '',
+ 'Edit Assembly' => 'Editar Compost',
+ 'Edit GIFI' => '',
+ 'Edit General Ledger Transaction' => 'Editar Transacció del LLibre Major',
+ 'Edit Part' => 'Editar Article',
+ 'Edit Preferences for' => 'Editar Preferències per',
+ 'Edit Project' => '',
+ 'Edit Purchase Invoice' => '',
+ 'Edit Purchase Order' => 'Editar Ordre Compra',
+ 'Edit Sales Invoice' => '',
+ 'Edit Sales Order' => 'Editar Pressupost',
+ 'Edit Service' => 'Editar Servei',
+ 'Edit Template' => 'Editar Plantilla',
+ 'Edit User' => 'Editar Usuari',
+ 'Employee' => '',
+ 'Enforce transaction reversal for all dates' => 'Forçar l\'anul.lació de transaccions per totes les dates',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Entrar fins a 3 caràcters separats per dos punts (p.e. EUR:USD:CAD) per les monedes nacionals i estrangeres',
+ 'Equity' => 'Balanç',
+ 'Exch' => 'Canvi',
+ 'Exchangerate' => 'Taxa de Canvi',
+ 'Exchangerate Difference' => '',
+ 'Exchangerate for payment missing!' => '',
+ 'Exchangerate missing!' => '',
+ 'Existing Datasets' => 'Conjunt de Dades Existents',
+ 'Expense' => 'Despeses',
+ 'Expense Account' => 'Compta Despeses',
+ 'Expense/Asset' => 'Despesa/Activa',
+ 'Extended' => '',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'Foreign Exchange Gain' => 'Guany en Bescanvi Moneda',
+ 'Foreign Exchange Loss' => 'Pèrdua en Bescanvi Moneda',
+ 'From' => 'De',
+ 'GIFI' => '',
+ 'GIFI deleted!' => '',
+ 'GIFI missing!' => '',
+ 'GIFI saved!' => '',
+ 'GL Transaction' => '',
+ 'General Ledger' => 'Llibre Major',
+ 'Goods & Services' => 'Bèns i Serveis',
+ 'HTML Templates' => 'Plantilles HTML',
+ 'Heading' => 'Capçalera',
+ 'Host' => 'Servidor',
+ 'Hostname missing!' => 'Falta el Nom del Servidor!',
+ 'ID' => 'ID',
+ 'Image' => '',
+ 'In-line' => 'Afegit',
+ 'Include in Report' => 'Incloure en l\'Informe',
+ 'Include in drop-down menus' => 'Incloure en Menús Desplegables',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incloure aquesta compta en els formularis client/proveïdor per marcar els impostos aplicables client/proveïdor?',
+ 'Income' => 'Ingressos',
+ 'Income Account' => 'Compta Ingressos',
+ 'Income Statement' => 'Balanç Situació',
+ 'Incorrect Dataset version!' => 'Versió Incorrecta del Conjunt de Dades!',
+ 'Incorrect Password!' => 'Contrasenya no Vàlida!',
+ 'Individual Items' => 'Elements Individuals',
+ 'Inventory' => 'Inventari',
+ 'Inventory Account' => 'Compta Inventari',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La quantitat en l\'inventari ha de ser zero abans de marcar-lo com obsolet',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La quantitat en l\'inventari ha de ser zero abans de marcar-lo com obsolet',
+ 'Inventory quantity must be zero!' => 'La quantitat en l\'inventari ha de ser zero',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data Fra.',
+ 'Invoice Date missing!' => 'Falta Data Fra.!',
+ 'Invoice Number' => 'Núm Fra.',
+ 'Invoice Number missing!' => 'Falta Núm Fra.!',
+ 'Invoice deleted!' => '',
+ 'Invoice posted!' => '',
+ 'Invoices' => '',
+ 'Is this a summary account to record' => 'És una compta resum a registrar?',
+ 'Item deleted!' => '',
+ 'Item not on file!' => 'No es troba cap arxiu amb aquest element!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'LaTeX Templates' => 'Plantilles LaTeX',
+ 'Language' => 'Idioma',
+ 'Last Cost' => 'Darrer Cost',
+ 'Last Invoice Number' => 'Darrer Núm Fra.',
+ 'Last Numbers & Default Accounts' => 'Darrers Núms & Comptes per Defecte',
+ 'Last Purchase Order Number' => 'Darrera Ordre de Compra',
+ 'Last Sales Order Number' => '',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deixar en blanc el servidor i el port excepte per fer una connexió remota',
+ 'Liability' => 'Passiu',
+ 'Licensed to' => 'Adaptat per',
+ 'Line Total' => 'Total Línia',
+ 'Link' => 'Enllaç',
+ 'Link Accounts' => 'Enllaçar Comptes',
+ 'List Accounts' => 'Llistar Comptes',
+ 'List GIFI' => '',
+ 'List Price' => 'Llistar Preu',
+ 'List Transactions' => 'Llistar Transaccions',
+ 'Login' => 'Entrar',
+ 'Logout' => 'Desconnectar',
+ 'Make' => 'Fer',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Message' => '',
+ 'Microfiche' => '',
+ 'Model' => 'Model',
+ 'N/A' => '',
+ 'Name' => 'Nom',
+ 'Name missing!' => '',
+ 'New Templates' => 'Noves Plantilles',
+ 'No' => 'No',
+ 'No Database Drivers available!' => 'Cap Mòdul de Base de Dades disponible!',
+ 'No Dataset selected!' => 'No hi ha cap Conjunt de Dades seleccionat!',
+ 'No email address for' => 'Falta adreça email de',
+ 'No.' => '',
+ 'Notes' => 'Notes',
+ 'Nothing applied!' => '',
+ 'Nothing selected!' => '',
+ 'Nothing to delete!' => 'No hi ha res per esborrar!',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Número',
+ 'Number Format' => 'Format Número',
+ 'Number missing in Row' => 'Falta en número en la fila',
+ 'O' => '',
+ 'Obsolete' => 'Obsolet',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'On Hand' => 'Disponible',
+ 'On Order' => '',
+ 'Open' => 'Obert',
+ 'Oracle Database Administration' => 'Administració Base de Dades Oracle',
+ 'Order' => 'Ordre',
+ 'Order Date' => 'Data Ordre',
+ 'Order Date missing!' => 'Falta Data Ordre!',
+ 'Order Entry' => 'Pressupostos i Comandes',
+ 'Order Number' => 'Número Ordre',
+ 'Order Number missing!' => 'Falta Número Ordre!',
+ 'Order deleted!' => '',
+ 'Order saved!' => '',
+ 'Ordered' => '',
+ 'Orphaned' => 'Orfe',
+ 'Out of balance!' => '',
+ 'PDF' => '',
+ 'Packing List' => 'Albarà',
+ 'Packing List Date missing!' => 'Falta Data Albarà!',
+ 'Packing List Number missing!' => 'Falta Número Albarà!',
+ 'Paid' => 'Pagat',
+ 'Paid in full' => '',
+ 'Part' => 'Article',
+ 'Part Number missing!' => 'Falta Número Article!',
+ 'Parts' => 'Articles',
+ 'Parts Inventory' => 'Inventari Articles',
+ 'Password' => 'Contrasenya',
+ 'Password changed!' => '',
+ 'Payables' => 'Pagables',
+ 'Payment' => 'Pagament',
+ 'Payment date missing!' => 'Falta Data Pagament!',
+ 'Payment posted!' => '',
+ 'Payments' => 'Pagaments',
+ 'Pg Database Administration' => 'Administració Base de Dades PostgreSQL',
+ 'Phone' => 'Tel',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Falta Port!',
+ 'Post' => '',
+ 'Post as new' => '',
+ 'Postscript' => '',
+ 'Preferences' => 'Preferències',
+ 'Preferences saved!' => 'Preferències Guardades!',
+ 'Price' => 'Preu',
+ 'Print' => '',
+ 'Printer' => 'Impressora',
+ 'Project' => '',
+ 'Project Number missing!' => '',
+ 'Project deleted!' => '',
+ 'Project not on file!' => '',
+ 'Project saved!' => '',
+ 'Projects' => '',
+ 'Purchase Invoice' => '',
+ 'Purchase Order' => 'Ordre de Compra',
+ 'Purchase Orders' => 'Ordres de Compra',
+ 'Qty' => 'Quantitat',
+ 'ROP' => 'ROP',
+ 'Rate' => 'Tarifa',
+ 'Recd' => '',
+ 'Receipt' => '',
+ 'Receipts' => '',
+ 'Receivables' => 'Cobraments',
+ 'Reconciliation' => '',
+ 'Record in' => 'Registar en',
+ 'Reference' => '',
+ 'Reference missing!' => '',
+ 'Remaining' => 'Remanent',
+ 'Report for' => 'Registrar per',
+ 'Reports' => 'Informes',
+ 'Required by' => 'Soliciat per',
+ 'Retained Earnings' => 'Guanys Retinguts',
+ 'Sales' => 'Vendes',
+ 'Sales Invoice' => '',
+ 'Sales Order' => 'Pressupost',
+ 'Sales Orders' => 'Pressupostos',
+ 'Save' => 'Guardar',
+ 'Save as new' => '',
+ 'Save to File' => 'Guardar a Fitxer',
+ 'Screen' => 'Pantalla',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccionar Conjunt de Dades a esborrar i prèmer "Continuar"',
+ 'Select all' => '',
+ 'Select from one of the items below' => 'Seleccionar d\'un dels elements de sota',
+ 'Select from one of the names below' => '',
+ 'Select from one of the projects below' => '',
+ 'Select postscript or PDF!' => '',
+ 'Sell Price' => 'Preu Venta',
+ 'Send by E-Mail' => 'Enviar per Email',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Service' => 'Servei',
+ 'Service Items' => 'Elements Servei',
+ 'Service Number missing!' => 'Falta Nombre Servei!',
+ 'Services' => 'Serveis',
+ 'Setup Templates' => 'Configurar Plantilles',
+ 'Ship' => '',
+ 'Ship to' => '',
+ 'Ship via' => '',
+ 'Short' => 'Curt',
+ 'Signature' => 'Signatura',
+ 'Sold' => 'Venut',
+ 'Source' => 'Font',
+ 'Standard' => '',
+ 'Statement' => '',
+ 'Statement Balance' => '',
+ 'Statement sent to' => '',
+ 'Statements sent to printer!' => '',
+ 'Stock Assembly' => 'Inventari Compost',
+ 'Stylesheet' => 'Fulla Estils',
+ 'Subject' => '',
+ 'Subtotal' => 'Subtotal',
+ 'System' => 'Sistema',
+ 'Tax' => 'Impost',
+ 'Tax Accounts' => 'Comptes Impostos',
+ 'Tax Included' => 'Impostos Inclosos',
+ 'Tax collected' => '',
+ 'Tax paid' => '',
+ 'Taxable' => 'Imponible',
+ 'Template saved!' => '',
+ 'Templates' => 'Plantilles',
+ 'Terms: Net' => 'Terms:Net',
+ 'The following Datasets are not in use and can be deleted' => 'Els següents conjunt de dades no s\'usen i poden esborrar-se',
+ 'The following Datasets need to be updated' => 'Cal actualitzar els següents conjunt de dades',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Comprovació preliminar de les fonts existents. No es crearà ni s\'esborrra res en aquest punt!',
+ 'To' => 'Fins',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Per afegir un usuari a un grup, editar el nom, canviar el nom d\'accés i guardar. Un nou usuari amb les mateixes variables es guardarà amb el nou nom d\«accés',
+ 'Top Level' => '',
+ 'Total' => 'Total',
+ 'Transaction Date missing!' => 'Falta Data Transacció!',
+ 'Transaction deleted!' => '',
+ 'Transaction posted!' => '',
+ 'Transaction reversal enforced for all dates' => 'Anul.lació transaccions forçada per totes les dates',
+ 'Transaction reversal enforced up to' => 'Anul.lació transaccions forçada a',
+ 'Transactions' => 'Transaccions',
+ 'Transactions exist, cannot delete customer!' => 'Hi han transaccions, no esborrar el client!',
+ 'Transactions exist, cannot delete vendor!' => 'Hi han transaccions, no esborrar el proveïdor',
+ 'Transactions exist; cannot delete account!' => 'Hi han transaccions, no esborrar compta',
+ 'Trial Balance' => 'Balanç de Comprovació',
+ 'Unit' => 'Unitat',
+ 'Unit of measure' => 'Unitat de Mesura',
+ 'Update' => '',
+ 'Update Dataset' => 'Actualitzar Conjut de Dades',
+ 'Updated' => '',
+ 'Use Templates' => 'Emprar Plantilles',
+ 'User' => 'Usuari',
+ 'User deleted!' => '',
+ 'User saved!' => '',
+ 'Vendor' => 'Proveïdor',
+ 'Vendor deleted!' => '',
+ 'Vendor missing!' => '',
+ 'Vendor not on file!' => '',
+ 'Vendor saved!' => '',
+ 'Vendors' => '',
+ 'Version' => 'Versió',
+ 'Weight' => 'Pes',
+ 'Weight Unit' => 'Unitat Pes',
+ 'What type of item is this?' => 'Quin tipus d\'element és?',
+ 'Year End' => 'Fí Any',
+ 'Yes' => 'Sí',
+ 'You are logged out!' => '',
+ 'You did not enter a name!' => 'No heu entrat cap nom!',
+ 'You must enter a host and port for local and remote connections!' => 'Heu d\'entrar el servidor i el port per les connexions locals i remotes!',
+ 'as at' => '',
+ 'collected on sales' => 'recollit en vendes',
+ 'days' => 'dies',
+ 'does not exist' => 'no existeix',
+ 'ea' => 'unit.',
+ 'emailed to' => 'emailejat a',
+ 'for Period' => 'pel període',
+ 'hr' => 'hr',
+ 'is already a member!' => 'ja és membre!',
+ 'is not a member!' => 'no és membre!',
+ 'localhost' => 'màquina local',
+ 'paid on purchases' => 'pagat al comprat',
+ 'sent to printer' => 'enviat a impressora',
+ 'successfully created!' => 'creat correctament!',
+ 'successfully deleted!' => 'esborrat correctament!',
+ 'to' => '',
+ 'website' => 'web',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/am b/sql-ledger/locale/ct/am
new file mode 100644
index 0000000..6dc7a2c
--- /dev/null
+++ b/sql-ledger/locale/ct/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Despeses',
+ 'AR' => 'Ingressos',
+ 'Account' => 'Compta',
+ 'Account Number' => 'Num. Compta',
+ 'Account Number missing!' => 'Falta el Num. Compta!',
+ 'Account Type' => 'Tipus de Compta',
+ 'Account Type missing!' => 'Falta el Tipus de Compta!',
+ 'Account deleted!' => 'Account deleted!',
+ 'Account saved!' => 'Account saved!',
+ 'Add Account' => 'Afegir Compta',
+ 'Add GIFI' => 'Add GIFI',
+ 'Address' => 'Adreça',
+ 'Asset' => 'Activat',
+ 'Audit Control' => 'Control Auditoria',
+ 'Backup sent to' => 'Còpia de Seguretat enviada a',
+ 'Books are open' => 'Els Llibres estan Oberts',
+ 'Business Number' => 'Núm. Negoci',
+ 'COGS' => 'Cost de Preu',
+ 'Cannot delete account!' => 'Cannot delete account!',
+ 'Cannot delete default account!' => 'No es pot esborrar la compta per defecte!',
+ 'Cannot save account!' => 'Cannot save account!',
+ 'Cannot save preferences!' => 'Cannot save preferences!',
+ 'Character Set' => 'Canviar Tipus Caràcters',
+ 'Chart of Accounts' => 'Taula de Comptes',
+ 'Close Books up to' => 'Tancar els llibres fins',
+ 'Company' => 'Empresa',
+ 'Continue' => 'Continuar',
+ 'Copy to COA' => 'Copy to COA',
+ 'Credit' => 'Crèdit',
+ 'Date Format' => 'Format Data',
+ 'Debit' => 'Dèbit',
+ 'Delete' => 'Esborrar',
+ 'Delete Account' => 'Esborrar Compta',
+ 'Description' => 'Descripció',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'Email',
+ 'Edit' => 'Edit',
+ 'Edit Account' => 'Editar Compta',
+ 'Edit GIFI' => 'Edit GIFI',
+ 'Edit Preferences for' => 'Editar Preferències per',
+ 'Edit Template' => 'Editar Plantilla',
+ 'Enforce transaction reversal for all dates' => 'Forçar l\'anul.lació de transaccions per totes les dates',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Entrar fins a 3 caràcters separats per dos punts (p.e. EUR:USD:CAD) per les monedes nacionals i estrangeres',
+ 'Equity' => 'Balanç',
+ 'Expense' => 'Despeses',
+ 'Expense Account' => 'Compta Despeses',
+ 'Expense/Asset' => 'Despesa/Activa',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Guany en Bescanvi Moneda',
+ 'Foreign Exchange Loss' => 'Pèrdua en Bescanvi Moneda',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI deleted!',
+ 'GIFI missing!' => 'GIFI missing!',
+ 'GIFI saved!' => 'GIFI saved!',
+ 'Heading' => 'Capçalera',
+ 'Include in drop-down menus' => 'Incloure en Menús Desplegables',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incloure aquesta compta en els formularis client/proveïdor per marcar els impostos aplicables client/proveïdor?',
+ 'Income' => 'Ingressos',
+ 'Income Account' => 'Compta Ingressos',
+ 'Inventory' => 'Inventari',
+ 'Inventory Account' => 'Compta Inventari',
+ 'Is this a summary account to record' => 'És una compta resum a registrar?',
+ 'Language' => 'Idioma',
+ 'Last Invoice Number' => 'Darrer Núm Fra.',
+ 'Last Numbers & Default Accounts' => 'Darrers Núms & Comptes per Defecte',
+ 'Last Purchase Order Number' => 'Darrera Ordre de Compra',
+ 'Last Sales Order Number' => 'Last Sales Order Number',
+ 'Liability' => 'Passiu',
+ 'Link' => 'Enllaç',
+ 'Name' => 'Nom',
+ 'No' => 'No',
+ 'No email address for' => 'Falta adreça email de',
+ 'Number' => 'Número',
+ 'Number Format' => 'Format Número',
+ 'Parts Inventory' => 'Inventari Articles',
+ 'Password' => 'Contrasenya',
+ 'Payables' => 'Pagables',
+ 'Payment' => 'Pagament',
+ 'Phone' => 'Tel',
+ 'Preferences saved!' => 'Preferències Guardades!',
+ 'Rate' => 'Tarifa',
+ 'Receivables' => 'Cobraments',
+ 'Sales' => 'Vendes',
+ 'Save' => 'Guardar',
+ 'Service Items' => 'Elements Servei',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Signatura',
+ 'Stylesheet' => 'Fulla Estils',
+ 'Tax' => 'Impost',
+ 'Tax Accounts' => 'Comptes Impostos',
+ 'Template saved!' => 'Template saved!',
+ 'Transaction reversal enforced for all dates' => 'Anul.lació transaccions forçada per totes les dates',
+ 'Transaction reversal enforced up to' => 'Anul.lació transaccions forçada a',
+ 'Transactions exist; cannot delete account!' => 'Hi han transaccions, no esborrar compta',
+ 'Weight Unit' => 'Unitat Pes',
+ 'Year End' => 'Fí Any',
+ 'Yes' => 'Sí',
+ 'does not exist' => 'no existeix',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'afegir_compta' => 'add_account',
+ 'continuar' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'esborrar' => 'delete',
+ 'edit' => 'edit',
+ 'editar_compta' => 'edit_account',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/ap b/sql-ledger/locale/ct/ap
new file mode 100644
index 0000000..7520fd0
--- /dev/null
+++ b/sql-ledger/locale/ct/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AP Transactions' => 'Transaccions de Despeses',
+ 'Account' => 'Compta',
+ 'Add Accounts Payables Transaction' => 'Add Accounts Payables Transaction',
+ 'Address' => 'Adreça',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => 'Segur que voleu esborrar la Transacció',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'No es pot registrar una transacció per un període tancat',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Tancat',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moneda',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data Pagament',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Delete' => 'Esborrar',
+ 'Description' => 'Descripció',
+ 'Due Date' => 'Data Venciment',
+ 'Due Date missing!' => 'Falta la Data Venciment!',
+ 'Edit Accounts Payables Transaction' => 'Edit Accounts Payables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Canvi',
+ 'Exchangerate' => 'Taxa de Canvi',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incloure en l\'Informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data Fra.',
+ 'Invoice Date missing!' => 'Falta Data Fra.!',
+ 'Invoice Number' => 'Núm Fra.',
+ 'Invoice Number missing!' => 'Falta Núm Fra.!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Obert',
+ 'Order' => 'Ordre',
+ 'Order Number' => 'Número Ordre',
+ 'Paid' => 'Pagat',
+ 'Payment date missing!' => 'Falta Data Pagament!',
+ 'Payments' => 'Pagaments',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Source' => 'Font',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impost',
+ 'Tax Included' => 'Impostos Inclosos',
+ 'To' => 'Fins',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveïdor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Sí',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'add_accounts_payables_transaction' => 'add_accounts_payables_transaction',
+ 'continuar' => 'continue',
+ 'esborrar' => 'delete',
+ 'edit_accounts_payables_transaction' => 'edit_accounts_payables_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'update' => 'update',
+ 'sí' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/ar b/sql-ledger/locale/ct/ar
new file mode 100644
index 0000000..90a111d
--- /dev/null
+++ b/sql-ledger/locale/ct/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'AR Transaction',
+ 'AR Transactions' => 'Transaccions d\'Ingressos',
+ 'Account' => 'Compta',
+ 'Add Accounts Receivables Transaction' => 'Add Accounts Receivables Transaction',
+ 'Address' => 'Adreça',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => 'Segur que voleu esborrar la Transacció',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'No es pot registrar una transacció per un període tancat',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Tancat',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Límit de Crèdit',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Client',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data Pagament',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Delete' => 'Esborrar',
+ 'Description' => 'Descripció',
+ 'Due Date' => 'Data Venciment',
+ 'Due Date missing!' => 'Falta la Data Venciment!',
+ 'Edit Accounts Receivables Transaction' => 'Edit Accounts Receivables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Canvi',
+ 'Exchangerate' => 'Taxa de Canvi',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incloure en l\'Informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data Fra.',
+ 'Invoice Date missing!' => 'Falta Data Fra.!',
+ 'Invoice Number' => 'Núm Fra.',
+ 'Invoice Number missing!' => 'Falta Núm Fra.!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Obert',
+ 'Order' => 'Ordre',
+ 'Order Number' => 'Número Ordre',
+ 'Paid' => 'Pagat',
+ 'Payment date missing!' => 'Falta Data Pagament!',
+ 'Payments' => 'Pagaments',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Remaining' => 'Remanent',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Source' => 'Font',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impost',
+ 'Tax Included' => 'Impostos Inclosos',
+ 'To' => 'Fins',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Sí',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ar_transaction' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'esborrar' => 'delete',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'sí' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/arap b/sql-ledger/locale/ct/arap
new file mode 100644
index 0000000..688a019
--- /dev/null
+++ b/sql-ledger/locale/ct/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adreça',
+ 'Continue' => 'Continuar',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Description' => 'Descripció',
+ 'Number' => 'Número',
+ 'Project not on file!' => 'Project not on file!',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/ca b/sql-ledger/locale/ct/ca
new file mode 100644
index 0000000..89a4023
--- /dev/null
+++ b/sql-ledger/locale/ct/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Compta',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'Taula de Comptes',
+ 'Credit' => 'Crèdit',
+ 'Date' => 'Data',
+ 'Debit' => 'Dèbit',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Description' => 'Descripció',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'From' => 'De',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Incloure en l\'Informe',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'List Transactions' => 'Llistar Transaccions',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Reference' => 'Reference',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Fins',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'llistar_transaccions' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/cp b/sql-ledger/locale/ct/cp
new file mode 100644
index 0000000..4bb685f
--- /dev/null
+++ b/sql-ledger/locale/ct/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Compta',
+ 'Address' => 'Adreça',
+ 'Amount' => 'Total',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Amount missing!',
+ 'Applied' => 'Applied',
+ 'Cannot post payment!' => 'Cannot post payment!',
+ 'Cannot process payment for a closed period!' => 'Cannot process payment for a closed period!',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check printed!',
+ 'Check printing failed!' => 'Check printing failed!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Client',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Data',
+ 'Date missing!' => 'Date missing!',
+ 'Description' => 'Descripció',
+ 'Due' => 'Venciment',
+ 'Exchangerate' => 'Taxa de Canvi',
+ 'From' => 'De',
+ 'Invoice' => 'Factura',
+ 'Invoices' => 'Invoices',
+ 'Nothing applied!' => 'Nothing applied!',
+ 'Number' => 'Número',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'Pagament',
+ 'Payment posted!' => 'Payment posted!',
+ 'Post' => 'Post',
+ 'Print' => 'Print',
+ 'Printer' => 'Impressora',
+ 'Project not on file!' => 'Project not on file!',
+ 'Receipt' => 'Receipt',
+ 'Reference' => 'Reference',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'To' => 'Fins',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveïdor',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/ct b/sql-ledger/locale/ct/ct
new file mode 100644
index 0000000..d88db2a
--- /dev/null
+++ b/sql-ledger/locale/ct/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Afegir',
+ 'Address' => 'Adreça',
+ 'All' => 'Tots',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Cannot delete customer!',
+ 'Cannot delete vendor!' => 'Cannot delete vendor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacte',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Límit de Crèdit',
+ 'Customer deleted!' => 'Customer deleted!',
+ 'Customer saved!' => 'Customer saved!',
+ 'Customers' => 'Customers',
+ 'Delete' => 'Esborrar',
+ 'Discount' => 'Descompte',
+ 'E-mail' => 'Email',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Incloure en l\'Informe',
+ 'Invoice' => 'Factura',
+ 'Name' => 'Nom',
+ 'Name missing!' => 'Name missing!',
+ 'Notes' => 'Notes',
+ 'Number' => 'Número',
+ 'Order' => 'Ordre',
+ 'Orphaned' => 'Orfe',
+ 'Phone' => 'Tel',
+ 'Save' => 'Guardar',
+ 'Ship to' => 'Ship to',
+ 'Tax Included' => 'Impostos Inclosos',
+ 'Taxable' => 'Imponible',
+ 'Terms: Net' => 'Terms:Net',
+ 'Transactions exist, cannot delete customer!' => 'Hi han transaccions, no esborrar el client!',
+ 'Transactions exist, cannot delete vendor!' => 'Hi han transaccions, no esborrar el proveïdor',
+ 'Vendor deleted!' => 'Vendor deleted!',
+ 'Vendor saved!' => 'Vendor saved!',
+ 'Vendors' => 'Vendors',
+ 'days' => 'dies',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'afegir' => 'add',
+ 'continuar' => 'continue',
+ 'esborrar' => 'delete',
+ 'factura' => 'invoice',
+ 'ordre' => 'order',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/gl b/sql-ledger/locale/ct/gl
new file mode 100644
index 0000000..7e25978
--- /dev/null
+++ b/sql-ledger/locale/ct/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AR Transaction' => 'AR Transaction',
+ 'Account' => 'Compta',
+ 'Add General Ledger Transaction' => 'Afegir Transacció Llibre Major',
+ 'Address' => 'Adreça',
+ 'All' => 'Tots',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => 'Segur que voleu esborrar la Transacció',
+ 'Asset' => 'Activat',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot have a value in both Debit and Credit!' => 'No es pot tenir un valor simultàniament a Dèbit i a Crèdit',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'No es pot registrar una transacció per un període tancat',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit' => 'Crèdit',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Data',
+ 'Debit' => 'Dèbit',
+ 'Debit and credit out of balance!' => 'Dèbit i Crèdit fora de balanç!',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Delete' => 'Esborrar',
+ 'Description' => 'Descripció',
+ 'Edit General Ledger Transaction' => 'Editar Transacció del LLibre Major',
+ 'Equity' => 'Balanç',
+ 'Expense' => 'Despeses',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'From' => 'De',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'GL Transaction',
+ 'General Ledger' => 'Llibre Major',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incloure en l\'Informe',
+ 'Income' => 'Ingressos',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'Liability' => 'Passiu',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference missing!',
+ 'Reports' => 'Informes',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Source' => 'Font',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Fins',
+ 'Transaction Date missing!' => 'Falta Data Transacció!',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Sí',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'esborrar' => 'delete',
+ 'gl_transaction' => 'gl_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'sí' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/ic b/sql-ledger/locale/ct/ic
new file mode 100644
index 0000000..66c84d7
--- /dev/null
+++ b/sql-ledger/locale/ct/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Active',
+ 'Add' => 'Afegir',
+ 'Add Assembly' => 'Afegir Compost',
+ 'Add Part' => 'Afegir Article',
+ 'Add Purchase Order' => 'Afegir Ordre Compra',
+ 'Add Sales Order' => 'Afegir Pressupost',
+ 'Add Service' => 'Afegir Servei',
+ 'Address' => 'Adreça',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Assemblies' => 'Compostos',
+ 'Assemblies restocked!' => 'Assemblies restocked!',
+ 'Assembly Number missing!' => 'Falta el Num. del Compost',
+ 'Attachment' => 'Adjunt',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Bought' => 'Comprat',
+ 'COGS' => 'Cost de Preu',
+ 'Cannot delete item already invoiced!' => 'No es pot esborrar un element facturat!',
+ 'Cannot delete item on order!' => 'No es pot esborrar un element pressupostat!',
+ 'Cannot delete item which is part of an assembly!' => 'No es pot eliminar un element que és part d\'un compost',
+ 'Cannot delete item!' => 'Cannot delete item!',
+ 'Cannot stock assemblies!' => 'Cannot stock assemblies!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacte',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Còpies',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Delete' => 'Esborrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripció',
+ 'Drawing' => 'Drawing',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Falta Email!',
+ 'Edit Assembly' => 'Editar Compost',
+ 'Edit Part' => 'Editar Article',
+ 'Edit Service' => 'Editar Servei',
+ 'Expense' => 'Despeses',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'From' => 'De',
+ 'Image' => 'Image',
+ 'In-line' => 'Afegit',
+ 'Include in Report' => 'Incloure en l\'Informe',
+ 'Income' => 'Ingressos',
+ 'Individual Items' => 'Elements Individuals',
+ 'Inventory' => 'Inventari',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La quantitat en l\'inventari ha de ser zero abans de marcar-lo com obsolet',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La quantitat en l\'inventari ha de ser zero abans de marcar-lo com obsolet',
+ 'Inventory quantity must be zero!' => 'La quantitat en l\'inventari ha de ser zero',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta Data Fra.!',
+ 'Invoice Number' => 'Núm Fra.',
+ 'Invoice Number missing!' => 'Falta Núm Fra.!',
+ 'Item deleted!' => 'Item deleted!',
+ 'Item not on file!' => 'No es troba cap arxiu amb aquest element!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'Last Cost' => 'Darrer Cost',
+ 'Line Total' => 'Total Línia',
+ 'Link Accounts' => 'Enllaçar Comptes',
+ 'List Price' => 'Llistar Preu',
+ 'Make' => 'Fer',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Message' => 'Message',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Model',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta en número en la fila',
+ 'Obsolete' => 'Obsolet',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'On Hand' => 'Disponible',
+ 'On Order' => 'On Order',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Falta Data Ordre!',
+ 'Order Number' => 'Número Ordre',
+ 'Order Number missing!' => 'Falta Número Ordre!',
+ 'Ordered' => 'Ordered',
+ 'Orphaned' => 'Orfe',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarà',
+ 'Packing List Date missing!' => 'Falta Data Albarà!',
+ 'Packing List Number missing!' => 'Falta Número Albarà!',
+ 'Part' => 'Article',
+ 'Part Number missing!' => 'Falta Número Article!',
+ 'Parts' => 'Articles',
+ 'Phone' => 'Tel',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preu',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Ordre de Compra',
+ 'Qty' => 'Quantitat',
+ 'ROP' => 'ROP',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Soliciat per',
+ 'Sales' => 'Vendes',
+ 'Sales Order' => 'Pressupost',
+ 'Save' => 'Guardar',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccionar d\'un dels elements de sota',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sell Price' => 'Preu Venta',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Service' => 'Servei',
+ 'Service Number missing!' => 'Falta Nombre Servei!',
+ 'Services' => 'Serveis',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Short' => 'Curt',
+ 'Sold' => 'Venut',
+ 'Stock Assembly' => 'Inventari Compost',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impost',
+ 'To' => 'Fins',
+ 'Top Level' => 'Top Level',
+ 'Total' => 'Total',
+ 'Unit' => 'Unitat',
+ 'Unit of measure' => 'Unitat de Mesura',
+ 'Update' => 'Update',
+ 'Updated' => 'Updated',
+ 'Weight' => 'Pes',
+ 'What type of item is this?' => 'Quin tipus d\'element és?',
+ 'ea' => 'unit.',
+ 'emailed to' => 'emailejat a',
+ 'hr' => 'hr',
+ 'sent to printer' => 'enviat a impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'afegir' => 'add',
+ 'afegir_compost' => 'add_assembly',
+ 'afegir_article' => 'add_part',
+ 'afegir_servei' => 'add_service',
+ 'continuar' => 'continue',
+ 'esborrar' => 'delete',
+ 'editar_compost' => 'edit_assembly',
+ 'editar_article' => 'edit_part',
+ 'editar_servei' => 'edit_service',
+ 'guardar' => 'save',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/io b/sql-ledger/locale/ct/io
new file mode 100644
index 0000000..b48c79b
--- /dev/null
+++ b/sql-ledger/locale/ct/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Afegir Ordre Compra',
+ 'Add Sales Order' => 'Afegir Pressupost',
+ 'Address' => 'Adreça',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Adjunt',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacte',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Còpies',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripció',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Falta Email!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'In-line' => 'Afegit',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta Data Fra.!',
+ 'Invoice Number missing!' => 'Falta Núm Fra.!',
+ 'Item not on file!' => 'No es troba cap arxiu amb aquest element!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Message' => 'Message',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta en número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Falta Data Ordre!',
+ 'Order Number missing!' => 'Falta Número Ordre!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarà',
+ 'Packing List Date missing!' => 'Falta Data Albarà!',
+ 'Packing List Number missing!' => 'Falta Número Albarà!',
+ 'Part' => 'Article',
+ 'Phone' => 'Tel',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preu',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Ordre de Compra',
+ 'Qty' => 'Quantitat',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Soliciat per',
+ 'Sales Order' => 'Pressupost',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccionar d\'un dels elements de sota',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Service' => 'Servei',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Subject' => 'Subject',
+ 'To' => 'Fins',
+ 'Unit' => 'Unitat',
+ 'What type of item is this?' => 'Quin tipus d\'element és?',
+ 'emailed to' => 'emailejat a',
+ 'sent to printer' => 'enviat a impressora',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/ir b/sql-ledger/locale/ct/ir
new file mode 100644
index 0000000..c6a42bc
--- /dev/null
+++ b/sql-ledger/locale/ct/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Compta',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Afegir Ordre Compra',
+ 'Add Sales Order' => 'Afegir Pressupost',
+ 'Address' => 'Adreça',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => 'Segur que voleu esborrar la Fra. Num.',
+ 'Attachment' => 'Adjunt',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacte',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Còpies',
+ 'Currency' => 'Moneda',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data Venciment',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Delete' => 'Esborrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripció',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Falta Email!',
+ 'Edit Purchase Invoice' => 'Edit Purchase Invoice',
+ 'Exch' => 'Canvi',
+ 'Exchangerate' => 'Taxa de Canvi',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'In-line' => 'Afegit',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data Fra.',
+ 'Invoice Date missing!' => 'Falta Data Fra.!',
+ 'Invoice Number' => 'Núm Fra.',
+ 'Invoice Number missing!' => 'Falta Núm Fra.!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'No es troba cap arxiu amb aquest element!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Message' => 'Message',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta en número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Falta Data Ordre!',
+ 'Order Number' => 'Número Ordre',
+ 'Order Number missing!' => 'Falta Número Ordre!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarà',
+ 'Packing List Date missing!' => 'Falta Data Albarà!',
+ 'Packing List Number missing!' => 'Falta Número Albarà!',
+ 'Part' => 'Article',
+ 'Payment date missing!' => 'Falta Data Pagament!',
+ 'Payments' => 'Pagaments',
+ 'Phone' => 'Tel',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preu',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Ordre de Compra',
+ 'Qty' => 'Quantitat',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Registar en',
+ 'Required by' => 'Soliciat per',
+ 'Sales Order' => 'Pressupost',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccionar d\'un dels elements de sota',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Service' => 'Servei',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Source' => 'Font',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impostos Inclosos',
+ 'To' => 'Fins',
+ 'Total' => 'Total',
+ 'Unit' => 'Unitat',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveïdor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'Quin tipus d\'element és?',
+ 'Yes' => 'Sí',
+ 'ea' => 'unit.',
+ 'emailed to' => 'emailejat a',
+ 'sent to printer' => 'enviat a impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'esborrar' => 'delete',
+ 'ordre' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'update' => 'update',
+ 'sí' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/is b/sql-ledger/locale/ct/is
new file mode 100644
index 0000000..7afaebb
--- /dev/null
+++ b/sql-ledger/locale/ct/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Compta',
+ 'Add Purchase Order' => 'Afegir Ordre Compra',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Afegir Pressupost',
+ 'Address' => 'Adreça',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => 'Segur que voleu esborrar la Fra. Num.',
+ 'Attachment' => 'Adjunt',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacte',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Còpies',
+ 'Credit Limit' => 'Límit de Crèdit',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Client',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data Venciment',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Delete' => 'Esborrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripció',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Falta Email!',
+ 'Edit Sales Invoice' => 'Edit Sales Invoice',
+ 'Exch' => 'Canvi',
+ 'Exchangerate' => 'Taxa de Canvi',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'In-line' => 'Afegit',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data Fra.',
+ 'Invoice Date missing!' => 'Falta Data Fra.!',
+ 'Invoice Number' => 'Núm Fra.',
+ 'Invoice Number missing!' => 'Falta Núm Fra.!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'No es troba cap arxiu amb aquest element!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Message' => 'Message',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta en número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Falta Data Ordre!',
+ 'Order Number' => 'Número Ordre',
+ 'Order Number missing!' => 'Falta Número Ordre!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarà',
+ 'Packing List Date missing!' => 'Falta Data Albarà!',
+ 'Packing List Number missing!' => 'Falta Número Albarà!',
+ 'Part' => 'Article',
+ 'Payment date missing!' => 'Falta Data Pagament!',
+ 'Payments' => 'Pagaments',
+ 'Phone' => 'Tel',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preu',
+ 'Print' => 'Print',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Ordre de Compra',
+ 'Qty' => 'Quantitat',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Registar en',
+ 'Remaining' => 'Remanent',
+ 'Required by' => 'Soliciat per',
+ 'Sales Order' => 'Pressupost',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccionar d\'un dels elements de sota',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Service' => 'Servei',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Source' => 'Font',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impostos Inclosos',
+ 'To' => 'Fins',
+ 'Total' => 'Total',
+ 'Unit' => 'Unitat',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'Quin tipus d\'element és?',
+ 'Yes' => 'Sí',
+ 'ea' => 'unit.',
+ 'emailed to' => 'emailejat a',
+ 'sent to printer' => 'enviat a impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'esborrar' => 'delete',
+ 'email' => 'e_mail',
+ 'ordre' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'sí' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/login b/sql-ledger/locale/ct/login
new file mode 100644
index 0000000..09baae0
--- /dev/null
+++ b/sql-ledger/locale/ct/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'Referent',
+ 'Accounting' => 'Comptabilitat',
+ 'Database Host' => 'Servidor Base de Dades',
+ 'Dataset' => 'Conjunt de Dades',
+ 'Incorrect Dataset version!' => 'Versió Incorrecta del Conjunt de Dades!',
+ 'Incorrect Password!' => 'Contrasenya no Vàlida!',
+ 'Licensed to' => 'Adaptat per',
+ 'Login' => 'Entrar',
+ 'Name' => 'Nom',
+ 'Password' => 'Contrasenya',
+ 'User' => 'Usuari',
+ 'Version' => 'Versió',
+ 'You are logged out!' => 'You are logged out!',
+ 'You did not enter a name!' => 'No heu entrat cap nom!',
+ 'is not a member!' => 'no és membre!',
+ 'localhost' => 'màquina local',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'entrar' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/menu b/sql-ledger/locale/ct/menu
new file mode 100644
index 0000000..4defaf1
--- /dev/null
+++ b/sql-ledger/locale/ct/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'Despeses',
+ 'AP Aging' => 'Diari de Despeses',
+ 'AR' => 'Ingressos',
+ 'AR Aging' => 'Diari d\'Ingressos',
+ 'Accounting Menu' => 'Menú Comptable',
+ 'Add Account' => 'Afegir Compta',
+ 'Add Assembly' => 'Afegir Compost',
+ 'Add Customer' => 'Afegir Client',
+ 'Add GIFI' => 'Add GIFI',
+ 'Add Part' => 'Afegir Article',
+ 'Add Project' => 'Add Project',
+ 'Add Service' => 'Afegir Servei',
+ 'Add Transaction' => 'Afegir Transacció',
+ 'Add Vendor' => 'Afegir Proveïdor',
+ 'Assemblies' => 'Compostos',
+ 'Audit Control' => 'Control Auditoria',
+ 'Backup' => 'Còpia de Seguretat',
+ 'Balance Sheet' => 'Fulla de Balanç',
+ 'Cash' => 'Cash',
+ 'Chart of Accounts' => 'Taula de Comptes',
+ 'Check' => 'Check',
+ 'Customers' => 'Customers',
+ 'General Ledger' => 'Llibre Major',
+ 'Goods & Services' => 'Bèns i Serveis',
+ 'HTML Templates' => 'Plantilles HTML',
+ 'Income Statement' => 'Balanç Situació',
+ 'Invoice' => 'Factura',
+ 'LaTeX Templates' => 'Plantilles LaTeX',
+ 'List Accounts' => 'Llistar Comptes',
+ 'List GIFI' => 'List GIFI',
+ 'Logout' => 'Desconnectar',
+ 'Order Entry' => 'Pressupostos i Comandes',
+ 'Packing List' => 'Albarà',
+ 'Parts' => 'Articles',
+ 'Payment' => 'Pagament',
+ 'Payments' => 'Pagaments',
+ 'Preferences' => 'Preferències',
+ 'Projects' => 'Projects',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Purchase Order' => 'Ordre de Compra',
+ 'Purchase Orders' => 'Ordres de Compra',
+ 'Receipt' => 'Receipt',
+ 'Receipts' => 'Receipts',
+ 'Reconciliation' => 'Reconciliation',
+ 'Reports' => 'Informes',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Sales Order' => 'Pressupost',
+ 'Sales Orders' => 'Pressupostos',
+ 'Save to File' => 'Guardar a Fitxer',
+ 'Send by E-Mail' => 'Enviar per Email',
+ 'Services' => 'Serveis',
+ 'Statement' => 'Statement',
+ 'Stock Assembly' => 'Inventari Compost',
+ 'Stylesheet' => 'Fulla Estils',
+ 'System' => 'Sistema',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'Transactions' => 'Transaccions',
+ 'Trial Balance' => 'Balanç de Comprovació',
+ 'Vendors' => 'Vendors',
+ 'Version' => 'Versió',
+ 'localhost' => 'màquina local',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/oe b/sql-ledger/locale/ct/oe
new file mode 100644
index 0000000..951fd1b
--- /dev/null
+++ b/sql-ledger/locale/ct/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Afegir',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Afegir Ordre Compra',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Afegir Pressupost',
+ 'Address' => 'Adreça',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Order Number' => 'Segur que voleu esborrar l\'Ordre',
+ 'Attachment' => 'Adjunt',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Cannot delete order!',
+ 'Cannot save order!' => 'Cannot save order!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Tancat',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacte',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Còpies',
+ 'Credit Limit' => 'Límit de Crèdit',
+ 'Curr' => 'Curr',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Client',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Data',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Delete' => 'Esborrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripció',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Falta Email!',
+ 'Edit Purchase Order' => 'Editar Ordre Compra',
+ 'Edit Sales Order' => 'Editar Pressupost',
+ 'Exchangerate' => 'Taxa de Canvi',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'In-line' => 'Afegit',
+ 'Include in Report' => 'Incloure en l\'Informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta Data Fra.!',
+ 'Invoice Number missing!' => 'Falta Núm Fra.!',
+ 'Item not on file!' => 'No es troba cap arxiu amb aquest element!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Message' => 'Message',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta en número en la fila',
+ 'O' => 'O',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Obert',
+ 'Order' => 'Ordre',
+ 'Order Date' => 'Data Ordre',
+ 'Order Date missing!' => 'Falta Data Ordre!',
+ 'Order Number' => 'Número Ordre',
+ 'Order Number missing!' => 'Falta Número Ordre!',
+ 'Order deleted!' => 'Order deleted!',
+ 'Order saved!' => 'Order saved!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarà',
+ 'Packing List Date missing!' => 'Falta Data Albarà!',
+ 'Packing List Number missing!' => 'Falta Número Albarà!',
+ 'Part' => 'Article',
+ 'Phone' => 'Tel',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preu',
+ 'Print' => 'Print',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Ordre de Compra',
+ 'Purchase Orders' => 'Ordres de Compra',
+ 'Qty' => 'Quantitat',
+ 'Recd' => 'Recd',
+ 'Remaining' => 'Remanent',
+ 'Required by' => 'Soliciat per',
+ 'Sales Order' => 'Pressupost',
+ 'Sales Orders' => 'Pressupostos',
+ 'Save' => 'Guardar',
+ 'Save as new' => 'Save as new',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccionar d\'un dels elements de sota',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Service' => 'Servei',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impost',
+ 'Tax Included' => 'Impostos Inclosos',
+ 'Terms: Net' => 'Terms:Net',
+ 'To' => 'Fins',
+ 'Total' => 'Total',
+ 'Unit' => 'Unitat',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveïdor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'Quin tipus d\'element és?',
+ 'Yes' => 'Sí',
+ 'days' => 'dies',
+ 'ea' => 'unit.',
+ 'emailed to' => 'emailejat a',
+ 'sent to printer' => 'enviat a impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'afegir' => 'add',
+ 'continuar' => 'continue',
+ 'esborrar' => 'delete',
+ 'email' => 'e_mail',
+ 'factura' => 'invoice',
+ 'print' => 'print',
+ 'guardar' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'sí' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/pe b/sql-ledger/locale/ct/pe
new file mode 100644
index 0000000..01856d5
--- /dev/null
+++ b/sql-ledger/locale/ct/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Afegir',
+ 'Add Project' => 'Add Project',
+ 'All' => 'Tots',
+ 'Continue' => 'Continuar',
+ 'Delete' => 'Esborrar',
+ 'Description' => 'Descripció',
+ 'Edit Project' => 'Edit Project',
+ 'Number' => 'Número',
+ 'Orphaned' => 'Orfe',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Project Number missing!',
+ 'Project deleted!' => 'Project deleted!',
+ 'Project saved!' => 'Project saved!',
+ 'Projects' => 'Projects',
+ 'Save' => 'Guardar',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'afegir' => 'add',
+ 'continuar' => 'continue',
+ 'esborrar' => 'delete',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/rc b/sql-ledger/locale/ct/rc
new file mode 100644
index 0000000..8b6112c
--- /dev/null
+++ b/sql-ledger/locale/ct/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Compta',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'Continuar',
+ 'Date' => 'Data',
+ 'Deposit' => 'Deposit',
+ 'Description' => 'Descripció',
+ 'Difference' => 'Difference',
+ 'Done' => 'Done',
+ 'Exchangerate Difference' => 'Exchangerate Difference',
+ 'From' => 'De',
+ 'Out of balance!' => 'Out of balance!',
+ 'Payment' => 'Pagament',
+ 'Reconciliation' => 'Reconciliation',
+ 'Select all' => 'Select all',
+ 'Source' => 'Font',
+ 'Statement Balance' => 'Statement Balance',
+ 'To' => 'Fins',
+ 'Update' => 'Update',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continuar' => 'continue',
+ 'done' => 'done',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ct/rp b/sql-ledger/locale/ct/rp
new file mode 100644
index 0000000..75eff42
--- /dev/null
+++ b/sql-ledger/locale/ct/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Diari de Despeses',
+ 'AR Aging' => 'Diari d\'Ingressos',
+ 'Account' => 'Compta',
+ 'Accounts' => 'Accounts',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Adjunt',
+ 'Aug' => 'Ago',
+ 'August' => 'Agost',
+ 'Balance Sheet' => 'Fulla de Balanç',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Comparar amb',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Còpies',
+ 'Credit' => 'Crèdit',
+ 'Current' => 'Current',
+ 'Customer' => 'Client',
+ 'Date' => 'Data',
+ 'Debit' => 'Dèbit',
+ 'Dec' => 'Des',
+ 'December' => 'Desembre',
+ 'Decimalplaces' => 'Decimalplaces',
+ 'Description' => 'Descripció',
+ 'Due' => 'Venciment',
+ 'E-mail' => 'Email',
+ 'E-mail Statement to' => 'E-mail Statement to',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrer',
+ 'From' => 'De',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Capçalera',
+ 'ID' => 'ID',
+ 'In-line' => 'Afegit',
+ 'Include in Report' => 'Incloure en l\'Informe',
+ 'Income Statement' => 'Balanç Situació',
+ 'Invoice' => 'Factura',
+ 'Jan' => 'Gen',
+ 'January' => 'Gener',
+ 'Jul' => 'Jul',
+ 'July' => 'Juliol',
+ 'Jun' => 'Jun',
+ 'June' => 'Juny',
+ 'Mar' => 'Mar',
+ 'March' => 'Març',
+ 'May' => 'Mai',
+ 'May ' => 'Maig',
+ 'Message' => 'Message',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Nothing selected!',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Pagaments',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Print',
+ 'Printer' => 'Impressora',
+ 'Receipts' => 'Receipts',
+ 'Report for' => 'Registrar per',
+ 'Retained Earnings' => 'Guanys Retinguts',
+ 'Screen' => 'Pantalla',
+ 'Select all' => 'Select all',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Setembre',
+ 'Source' => 'Font',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Statement',
+ 'Statement sent to' => 'Statement sent to',
+ 'Statements sent to printer!' => 'Statements sent to printer!',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impost',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'To' => 'Fins',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Balanç de Comprovació',
+ 'Vendor' => 'Proveïdor',
+ 'as at' => 'as at',
+ 'collected on sales' => 'recollit en vendes',
+ 'for Period' => 'pel període',
+ 'paid on purchases' => 'pagat al comprat',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continuar' => 'continue',
+ 'email' => 'e_mail',
+ 'print' => 'print',
+ 'select_all' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/COPYING b/sql-ledger/locale/cz/COPYING
new file mode 100644
index 0000000..64c58a2
--- /dev/null
+++ b/sql-ledger/locale/cz/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Czech texts:
+#
+# Author: Tomas Fencl <tomas.fencl@centrum.cz>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/cz/LANGUAGE b/sql-ledger/locale/cz/LANGUAGE
new file mode 100644
index 0000000..618b7f5
--- /dev/null
+++ b/sql-ledger/locale/cz/LANGUAGE
@@ -0,0 +1 @@
+Czech
diff --git a/sql-ledger/locale/cz/admin b/sql-ledger/locale/cz/admin
new file mode 100644
index 0000000..4a238b5
--- /dev/null
+++ b/sql-ledger/locale/cz/admin
@@ -0,0 +1,122 @@
+$self{texts} = {
+ 'Access Control' => 'Pøístupová práva',
+ 'Accounting' => 'Úèetnictví',
+ 'Add User' => 'Nový u¾ivatel',
+ 'Address' => 'Adresa',
+ 'Administration' => 'Administrace',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => 'V¹echna data jsou aktualizována',
+ 'Change Admin Password' => 'Zmìnit heslo administrátora',
+ 'Change Password' => 'Zmìnit heslo',
+ 'Character Set' => 'Znaková sada',
+ 'Click on login name to edit!' => 'Pro úpravy kliknìte na jméno u¾ivatele',
+ 'Company' => 'Firma',
+ 'Connect to' => 'Pøipojit k serveru',
+ 'Continue' => 'Pokraèování',
+ 'Create Chart of Accounts' => 'Vytvoøit úètový rozvrh',
+ 'Create Dataset' => 'Vytvoøit dataset',
+ 'DBI not installed!' => 'DBI není nainstalováno',
+ 'Database' => 'Databáze',
+ 'Database Administration' => 'Správa databáze',
+ 'Database Driver not checked!' => 'Nepodaøilo se zkontrolovat ovladaè databáze',
+ 'Database User missing!' => 'Chybí jméno pro pøihlá¹ení k databázi!',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Není zadán dataset',
+ 'Dataset updated!' => 'Dataset updated!',
+ 'Date Format' => 'Formát data',
+ 'Delete' => 'Vymazat',
+ 'Delete Dataset' => 'Zru¹it dataset',
+ 'Directory' => 'Adresáø',
+ 'Driver' => 'Øidiè',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'E-mail',
+ 'Edit User' => 'Upravit u¾ivatele',
+ 'Existing Datasets' => 'Datasety',
+ 'Fax' => 'Fax',
+ 'Host' => 'Server',
+ 'Hostname missing!' => 'Chybí jméno serveru!',
+ 'Incorrect Password!' => 'Nesprávné heslo!',
+ 'Language' => 'Jazyk',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Pro lokální databázi, nezadávejte adresu serveru a port.',
+ 'Login' => 'U¾ivatelské jméno',
+ 'Name' => 'Jméno',
+ 'New Templates' => 'Nové ¹ablony',
+ 'No Database Drivers available!' => 'Není instalován ¾ádný ovladaè databáze!',
+ 'No Dataset selected!' => 'Není zvolen ¾ádný dataset!',
+ 'Nothing to delete!' => 'Nejsou polo¾ky k vymazání!',
+ 'Number Format' => 'Èíselný formát',
+ 'Oracle Database Administration' => 'Oracle Správa databáze',
+ 'Password' => 'Heslo',
+ 'Password changed!' => 'Password changed!',
+ 'Pg Database Administration' => 'Pg Správa databáze',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Chybí èíslo portu!',
+ 'Printer' => 'Tiskárna',
+ 'Save' => 'Ulo¾it',
+ 'Select a Dataset to delete and press "Continue"' => 'Zvolte dataset, který chcete vymazat a stisknìte "Pokraèovat"',
+ 'Setup Templates' => 'Nastavení ¹ablon',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Podpis',
+ 'Stylesheet' => 'Stylesheet',
+ 'Templates' => '©ablony',
+ 'The following Datasets are not in use and can be deleted' => 'Uvedené datasety nejsou vyu¾ívány a mohou být vymazány',
+ 'The following Datasets need to be updated' => 'Následující data musí být aktualizována',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Toto je pøedbì¾ná kontrola existence zdrojových dokumentù. V této fázi nebude databáze aktualizována.',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Pro pøidání u¾ivatele do skupiny otevøete existujícího u¾ivatele a ulo¾te jej s jiným u¾ivatelským jménem. Nový u¾ivatel bude vytvoøen s toto¾ným nastavením v¹ech promìnných.',
+ 'Update Dataset' => 'Aktualizovat data',
+ 'Use Templates' => 'Vyu¾ít ¹ablony',
+ 'User' => 'U¾ivatel',
+ 'User deleted!' => 'User deleted!',
+ 'User saved!' => 'User saved!',
+ 'Version' => 'Verze',
+ 'You must enter a host and port for local and remote connections!' => 'Pro lokální i vzdálené pøipojení je nutné zadat adresu serveru a port!',
+ 'does not exist' => 'neexistuje',
+ 'is already a member!' => 'ji¾ existuje!',
+ 'localhost' => 'lokální server',
+ 'successfully created!' => 'úspì¹nì vytvoøen!',
+ 'successfully deleted!' => 'úspì¹nì smazán!',
+ 'website' => 'www adresa',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'nový_u¾ivatel' => 'add_user',
+ 'zmìnit_heslo_administrátora' => 'change_admin_password',
+ 'zmìnit_heslo' => 'change_password',
+ 'pokraèování' => 'continue',
+ 'vytvoøit_dataset' => 'create_dataset',
+ 'vymazat' => 'delete',
+ 'zru¹it_dataset' => 'delete_dataset',
+ 'u¾ivatelské_jméno' => 'login',
+ 'oracle_správa_databáze' => 'oracle_database_administration',
+ 'pg_správa_databáze' => 'pg_database_administration',
+ 'ulo¾it' => 'save',
+ 'aktualizovat_data' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/all b/sql-ledger/locale/cz/all
new file mode 100644
index 0000000..71704c1
--- /dev/null
+++ b/sql-ledger/locale/cz/all
@@ -0,0 +1,487 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Závazky',
+ 'AP Aging' => 'Analýza splatnosti',
+ 'AP Transaction' => '',
+ 'AP Transactions' => 'Faktury pøijaté',
+ 'AR' => 'Pohledávky',
+ 'AR Aging' => 'Analýza splatnosti',
+ 'AR Transaction' => '',
+ 'AR Transactions' => 'Faktury vydané',
+ 'About' => 'O programu',
+ 'Access Control' => 'Pøístupová práva',
+ 'Account' => 'Úèet',
+ 'Account Number' => 'Èíslo úètu',
+ 'Account Number missing!' => 'Chybí èíslo úètu!',
+ 'Account Type' => 'Typ úètu',
+ 'Account Type missing!' => 'Chybí typ úètu!',
+ 'Account deleted!' => '',
+ 'Account saved!' => '',
+ 'Accounting' => 'Úèetnictví',
+ 'Accounting Menu' => 'Menu úèetnictví',
+ 'Accounts' => 'Úèty',
+ 'Active' => '',
+ 'Add' => 'Pøidat',
+ 'Add Account' => 'Zalo¾it úèet',
+ 'Add Accounts Payables Transaction' => '',
+ 'Add Accounts Receivables Transaction' => '',
+ 'Add Assembly' => 'Nový výrobek',
+ 'Add Customer' => 'Nový zákazník',
+ 'Add GIFI' => 'Doplnit úètovací øetìzec',
+ 'Add General Ledger Transaction' => 'Nový zápis do hlavní knihy',
+ 'Add Part' => 'Pøíjem zbo¾í',
+ 'Add Project' => '',
+ 'Add Purchase Invoice' => '',
+ 'Add Purchase Order' => 'Nová objednávka (nákup)',
+ 'Add Sales Invoice' => '',
+ 'Add Sales Order' => 'Nová objednávka (pøíjem)',
+ 'Add Service' => 'Nový druh slu¾by',
+ 'Add Transaction' => 'Nová transakce',
+ 'Add User' => 'Nový u¾ivatel',
+ 'Add Vendor' => 'Nový dodavatel',
+ 'Address' => 'Adresa',
+ 'Administration' => 'Administrace',
+ 'Administrator' => '',
+ 'All' => 'V¹e',
+ 'All Datasets up to date!' => 'V¹echna data jsou aktualizována',
+ 'Amount' => 'Èástka',
+ 'Amount Due' => '',
+ 'Amount does not equal applied!' => '',
+ 'Amount missing!' => '',
+ 'Applied' => '',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Are you sure you want to delete Invoice Number' => 'Opravdu chcete vymazat fakturu èíslo',
+ 'Are you sure you want to delete Order Number' => 'Opravdu chcete vymazat objednávku èíslo',
+ 'Are you sure you want to delete Transaction' => 'Opravdu chcete vymazat transakci?',
+ 'Assemblies' => 'Výrobky',
+ 'Assemblies restocked!' => '',
+ 'Assembly Number missing!' => 'Chybí èíslo výrobku',
+ 'Asset' => 'Aktiva',
+ 'Attachment' => 'Pøílohy',
+ 'Audit Control' => 'Kontrola pøístupù',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'BOM' => '',
+ 'Backup' => 'Záloha',
+ 'Backup sent to' => 'Záloha odeslána na adresu',
+ 'Balance' => '',
+ 'Balance Sheet' => 'Rozvaha',
+ 'Bcc' => '',
+ 'Bin' => 'Paleta',
+ 'Books are open' => '¡Uèetní knihy jsou otevøeny',
+ 'Bought' => 'Nakoupeno',
+ 'Business Number' => 'IÈO',
+ 'C' => '',
+ 'COGS' => 'Náklady na prodané zbo¾í',
+ 'Cannot delete account!' => '',
+ 'Cannot delete customer!' => '',
+ 'Cannot delete default account!' => 'Úèet je nastaven jako defaultní, nelze jej proto vymamazat!',
+ 'Cannot delete invoice!' => '',
+ 'Cannot delete item already invoiced!' => 'Ji¾ fakturované polo¾ky nelze vymazat!',
+ 'Cannot delete item on order!' => 'Polo¾ku objednávky nelze vymazat!',
+ 'Cannot delete item which is part of an assembly!' => 'Nelze vymazat polo¾ku, která je souèástí výrobku!',
+ 'Cannot delete item!' => '',
+ 'Cannot delete order!' => '',
+ 'Cannot delete transaction!' => '',
+ 'Cannot delete vendor!' => '',
+ 'Cannot have a value in both Debit and Credit!' => 'Nelze úètovat souèasnì Má dáti i Dal!',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => '',
+ 'Cannot post invoice!' => '',
+ 'Cannot post payment for a closed period!' => '',
+ 'Cannot post payment!' => '',
+ 'Cannot post transaction for a closed period!' => 'Do uzavøeného období nelze úètovat!',
+ 'Cannot post transaction!' => '',
+ 'Cannot process payment for a closed period!' => '',
+ 'Cannot save account!' => '',
+ 'Cannot save order!' => '',
+ 'Cannot save preferences!' => '',
+ 'Cannot stock assemblies!' => '',
+ 'Cash' => '',
+ 'Cash based' => '',
+ 'Cc' => '',
+ 'Change Admin Password' => 'Zmìnit heslo administrátora',
+ 'Change Password' => 'Zmìnit heslo',
+ 'Character Set' => 'Znaková sada',
+ 'Chart of Accounts' => 'Úètový rozvrh',
+ 'Check' => '',
+ 'Check printed!' => '',
+ 'Check printing failed!' => '',
+ 'Cleared Balance' => '',
+ 'Click on login name to edit!' => 'Pro úpravy kliknìte na jméno u¾ivatele',
+ 'Close Books up to' => 'Uzavøít úèetní knihy do',
+ 'Closed' => 'Zaplaceno',
+ 'Company' => 'Firma',
+ 'Compare to' => 'Porovnáno k',
+ 'Confirm!' => 'Podtvrïte!',
+ 'Connect to' => 'Pøipojit k serveru',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Pokraèování',
+ 'Copies' => 'Kopie',
+ 'Copy to COA' => 'Zkopírovat do úètového rozvrhu',
+ 'Create Chart of Accounts' => 'Vytvoøit úètový rozvrh',
+ 'Create Dataset' => 'Vytvoøit dataset',
+ 'Credit' => 'Dal',
+ 'Credit Limit' => 'Úvìrový limit',
+ 'Curr' => 'Mìna',
+ 'Currency' => 'Mìna',
+ 'Current' => '',
+ 'Customer' => 'Odbìratel',
+ 'Customer deleted!' => '',
+ 'Customer missing!' => '',
+ 'Customer not on file!' => '',
+ 'Customer saved!' => '',
+ 'Customers' => '',
+ 'DBI not installed!' => 'DBI není nainstalováno',
+ 'Database' => 'Databáze',
+ 'Database Administration' => 'Správa databáze',
+ 'Database Driver not checked!' => 'Nepodaøilo se zkontrolovat ovladaè databáze',
+ 'Database Host' => 'Databázový server',
+ 'Database User missing!' => 'Chybí jméno pro pøihlá¹ení k databázi!',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Není zadán dataset',
+ 'Dataset updated!' => '',
+ 'Date' => 'Datum',
+ 'Date Due' => 'Datum splatnosti',
+ 'Date Format' => 'Formát data',
+ 'Date Paid' => 'Zaplaceno',
+ 'Date missing!' => '',
+ 'Debit' => 'Má dáti',
+ 'Debit and credit out of balance!' => 'Má dáti a Dal se nerovnají.',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Decimalplaces' => '',
+ 'Delete' => 'Vymazat',
+ 'Delete Account' => 'Vymazat úèet',
+ 'Delete Dataset' => 'Zru¹it dataset',
+ 'Delivery Date' => '',
+ 'Deposit' => '',
+ 'Description' => 'Popis',
+ 'Difference' => '',
+ 'Directory' => 'Adresáø',
+ 'Discount' => 'Sleva',
+ 'Done' => '',
+ 'Drawing' => '',
+ 'Driver' => 'Øidiè',
+ 'Dropdown Limit' => '',
+ 'Due' => 'Splatno',
+ 'Due Date' => 'Datum splatnosti',
+ 'Due Date missing!' => 'Chybí datum splatnosti!',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => '',
+ 'E-mail address missing!' => 'Chybí E-mailová adresa!',
+ 'Edit' => '',
+ 'Edit Account' => 'Upravit úèet',
+ 'Edit Accounts Payables Transaction' => '',
+ 'Edit Accounts Receivables Transaction' => '',
+ 'Edit Assembly' => 'Upravit výrobek',
+ 'Edit GIFI' => 'Upravit úètovací øetìzec',
+ 'Edit General Ledger Transaction' => 'Opravit záznam v hlavní knize',
+ 'Edit Part' => 'Upravit zbo¾í',
+ 'Edit Preferences for' => 'Nastavení pro',
+ 'Edit Project' => '',
+ 'Edit Purchase Invoice' => '',
+ 'Edit Purchase Order' => 'Upravit vystavenou objednávku',
+ 'Edit Sales Invoice' => '',
+ 'Edit Sales Order' => 'Upravit pøijatou objednávku',
+ 'Edit Service' => 'Upravit slu¾bu',
+ 'Edit Template' => 'Upravit ¹ablonu',
+ 'Edit User' => 'Upravit u¾ivatele',
+ 'Employee' => '',
+ 'Enforce transaction reversal for all dates' => 'Zakázat editaci v¹ech úèetních polo¾ek',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Vlo¾te zkratky mìn (max. 3 znaky) oddìlené dvojteèkou pro domácí i cizí mìny (napø. CZK:USD:EUR)',
+ 'Equity' => 'Vlastní jmìní',
+ 'Exch' => 'Kurz',
+ 'Exchangerate' => 'Mìnový kurz',
+ 'Exchangerate Difference' => '',
+ 'Exchangerate for payment missing!' => '',
+ 'Exchangerate missing!' => '',
+ 'Existing Datasets' => 'Datasety',
+ 'Expense' => 'Náklady',
+ 'Expense Account' => 'Nákladový úèet',
+ 'Expense/Asset' => 'Náklad',
+ 'Extended' => '',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'Foreign Exchange Gain' => 'Kurzový zisk',
+ 'Foreign Exchange Loss' => 'Kurzová ztráta',
+ 'From' => 'z',
+ 'GIFI' => 'Úètovací øetìzec',
+ 'GIFI deleted!' => '',
+ 'GIFI missing!' => 'Chybí úètovací øetìzec!',
+ 'GIFI saved!' => '',
+ 'GL Transaction' => '',
+ 'General Ledger' => 'Hlavní kniha',
+ 'Goods & Services' => 'Zbo¾í a slu¾by',
+ 'HTML Templates' => 'HTML ¹ablony',
+ 'Heading' => 'Nadpis',
+ 'Host' => 'Server',
+ 'Hostname missing!' => 'Chybí jméno serveru!',
+ 'ID' => 'ID',
+ 'Image' => '',
+ 'In-line' => 'Vlo¾ené',
+ 'Include in Report' => 'Zahrnovat v sestavì',
+ 'Include in drop-down menus' => 'Ukazovat v drop-down menu',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Zahrnovat tento úèet ve formuláøích odbìratelù/dodavatelù, aby bylo mo¾né oznaèit je za zdanitelné?',
+ 'Income' => 'Výnosy',
+ 'Income Account' => 'Výnosový úèet',
+ 'Income Statement' => 'Výsledovka',
+ 'Incorrect Dataset version!' => '©patná verze dat!',
+ 'Incorrect Password!' => 'Nesprávné heslo!',
+ 'Individual Items' => 'Komponenty výrobku',
+ 'Inventory' => 'Zásoby',
+ 'Inventory Account' => 'Úèet zásob',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Pøed vyøazením výrobu, musí být stav na skladì nulový!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Pøed vyøazením zbo¾í musí být mno¾ství na skladì nulové',
+ 'Inventory quantity must be zero!' => 'Stav skladu musí být nulový!',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Datum vystavení',
+ 'Invoice Date missing!' => 'Chybí datum vystavení!',
+ 'Invoice Number' => 'Èíslo faktury',
+ 'Invoice Number missing!' => 'Chybí èíslo faktury!',
+ 'Invoice deleted!' => '',
+ 'Invoice posted!' => '',
+ 'Invoices' => '',
+ 'Is this a summary account to record' => 'Øídící úèet pro',
+ 'Item deleted!' => '',
+ 'Item not on file!' => 'Tato polo¾ka není v databázi!',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'LaTeX Templates' => 'LaTeX ¹ablony',
+ 'Language' => 'Jazyk',
+ 'Last Cost' => 'Poslední cena',
+ 'Last Invoice Number' => 'Èíslo poslední faktury',
+ 'Last Numbers & Default Accounts' => 'Poslední èísla a standardní èísla úètù',
+ 'Last Purchase Order Number' => 'Èíslo poslední objednávky',
+ 'Last Sales Order Number' => 'Èíslo poslední objednávky',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Pro lokální databázi, nezadávejte adresu serveru a port.',
+ 'Liability' => 'Závazek',
+ 'Licensed to' => 'Licencováno pro',
+ 'Line Total' => 'Øádek celkem',
+ 'Link' => 'Vazby',
+ 'Link Accounts' => 'Vazby mezi úèty',
+ 'List Accounts' => 'Seznam úètù',
+ 'List GIFI' => 'Vypsat úètovací øetìzce',
+ 'List Price' => 'Výrobní cena',
+ 'List Transactions' => 'Vypsat transakce',
+ 'Login' => 'U¾ivatelské jméno',
+ 'Logout' => 'Odhlásit',
+ 'Make' => 'Výrobce',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Message' => 'Zpráva',
+ 'Microfiche' => '',
+ 'Model' => 'Model',
+ 'N/A' => '---',
+ 'Name' => 'Jméno',
+ 'Name missing!' => '',
+ 'New Templates' => 'Nové ¹ablony',
+ 'No' => 'Ne',
+ 'No Database Drivers available!' => 'Není instalován ¾ádný ovladaè databáze!',
+ 'No Dataset selected!' => 'Není zvolen ¾ádný dataset!',
+ 'No email address for' => 'Chybí emailová adresy pro',
+ 'No.' => '',
+ 'Notes' => 'Poznámky',
+ 'Nothing applied!' => '',
+ 'Nothing selected!' => '',
+ 'Nothing to delete!' => 'Nejsou polo¾ky k vymazání!',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Number' => 'Èíslo',
+ 'Number Format' => 'Èíselný formát',
+ 'Number missing in Row' => 'Chybìjící èíslo na øádku',
+ 'O' => '',
+ 'Obsolete' => 'Vyøazené',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'On Hand' => 'K dispozici',
+ 'On Order' => '',
+ 'Open' => 'Otevøené',
+ 'Oracle Database Administration' => 'Oracle Správa databáze',
+ 'Order' => 'Objednávka',
+ 'Order Date' => 'Datum objednávky',
+ 'Order Date missing!' => 'Chybí datum objednávky!',
+ 'Order Entry' => 'Zadání objednávky',
+ 'Order Number' => 'Objednávka èíslo',
+ 'Order Number missing!' => 'Chybí èíslo objednávky!',
+ 'Order deleted!' => '',
+ 'Order saved!' => '',
+ 'Ordered' => '',
+ 'Orphaned' => 'Neprodejné',
+ 'Out of balance!' => '',
+ 'PDF' => '',
+ 'Packing List' => 'Dodací list',
+ 'Packing List Date missing!' => 'Chybí datum dodacího listu',
+ 'Packing List Number missing!' => 'Chybí èíslo dodacího listu',
+ 'Paid' => 'Zaplaceno',
+ 'Paid in full' => '',
+ 'Part' => 'Zbo¾í',
+ 'Part Number missing!' => 'Chybí èíslo zbo¾í!',
+ 'Parts' => 'Díly',
+ 'Parts Inventory' => 'Zbo¾í',
+ 'Password' => 'Heslo',
+ 'Password changed!' => '',
+ 'Payables' => 'Závazky',
+ 'Payment' => 'Platba',
+ 'Payment date missing!' => 'Chybí datum platby!',
+ 'Payment posted!' => '',
+ 'Payments' => 'Platby',
+ 'Pg Database Administration' => 'Pg Správa databáze',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Chybí èíslo portu!',
+ 'Post' => '',
+ 'Post as new' => '',
+ 'Postscript' => '',
+ 'Preferences' => 'Nastavení',
+ 'Preferences saved!' => 'Nastavení bylo ulo¾eno!',
+ 'Price' => 'Cena',
+ 'Print' => '',
+ 'Printer' => 'Tiskárna',
+ 'Project' => '',
+ 'Project Number missing!' => '',
+ 'Project deleted!' => '',
+ 'Project not on file!' => '',
+ 'Project saved!' => '',
+ 'Projects' => '',
+ 'Purchase Invoice' => '',
+ 'Purchase Order' => 'Vystavená objednávka',
+ 'Purchase Orders' => 'Vystavené objednávky',
+ 'Qty' => 'Mno¾ství',
+ 'ROP' => 'ROP',
+ 'Rate' => 'Sazba',
+ 'Recd' => '',
+ 'Receipt' => '',
+ 'Receipts' => '',
+ 'Receivables' => 'Pohledávky',
+ 'Reconciliation' => '',
+ 'Record in' => 'Zaúètovat do',
+ 'Reference' => '',
+ 'Reference missing!' => '',
+ 'Remaining' => 'Zbývá',
+ 'Report for' => 'Výkaz za',
+ 'Reports' => 'Sestavy',
+ 'Required by' => 'Po¾adováno do',
+ 'Retained Earnings' => 'Nerozdìlený zisk',
+ 'Sales' => 'Pøíjmy z prodeje',
+ 'Sales Invoice' => '',
+ 'Sales Order' => 'Pøijatá objednávka',
+ 'Sales Orders' => 'Pøijaté objednávky',
+ 'Save' => 'Ulo¾it',
+ 'Save as new' => '',
+ 'Save to File' => 'Ulo¾it do souboru',
+ 'Screen' => 'Na obrazovku',
+ 'Select a Dataset to delete and press "Continue"' => 'Zvolte dataset, který chcete vymazat a stisknìte "Pokraèovat"',
+ 'Select all' => '',
+ 'Select from one of the items below' => 'Zvolte z ní¾e uvedených polo¾ek',
+ 'Select from one of the names below' => '',
+ 'Select from one of the projects below' => '',
+ 'Select postscript or PDF!' => '',
+ 'Sell Price' => 'Prodejní cena',
+ 'Send by E-Mail' => 'Poslat e-mailem',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Service' => 'Slu¾ba',
+ 'Service Items' => 'Polo¾ky slu¾eb',
+ 'Service Number missing!' => 'Chybí èíslo slu¾by!',
+ 'Services' => 'Slu¾by',
+ 'Setup Templates' => 'Nastavení ¹ablon',
+ 'Ship' => '',
+ 'Ship to' => '',
+ 'Ship via' => '',
+ 'Short' => 'Krátký výpis',
+ 'Signature' => 'Podpis',
+ 'Sold' => 'Prodané',
+ 'Source' => 'Zdroj',
+ 'Standard' => 'Standardní',
+ 'Statement' => '',
+ 'Statement Balance' => '',
+ 'Statement sent to' => '',
+ 'Statements sent to printer!' => '',
+ 'Stock Assembly' => 'Výrobky',
+ 'Stylesheet' => 'Stylesheet',
+ 'Subject' => 'Pøedmìt',
+ 'Subtotal' => 'Mezisouèet',
+ 'System' => 'Systém',
+ 'Tax' => 'Daò',
+ 'Tax Accounts' => 'Daòové úèty',
+ 'Tax Included' => 'Cena vèetnì danì',
+ 'Tax collected' => '',
+ 'Tax paid' => '',
+ 'Taxable' => 'Zdanitelné',
+ 'Template saved!' => '',
+ 'Templates' => '©ablony',
+ 'Terms: Net' => 'Netto',
+ 'The following Datasets are not in use and can be deleted' => 'Uvedené datasety nejsou vyu¾ívány a mohou být vymazány',
+ 'The following Datasets need to be updated' => 'Následující data musí být aktualizována',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Toto je pøedbì¾ná kontrola existence zdrojových dokumentù. V této fázi nebude databáze aktualizována.',
+ 'To' => 'do',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Pro pøidání u¾ivatele do skupiny otevøete existujícího u¾ivatele a ulo¾te jej s jiným u¾ivatelským jménem. Nový u¾ivatel bude vytvoøen s toto¾ným nastavením v¹ech promìnných.',
+ 'Top Level' => '',
+ 'Total' => 'Celkem',
+ 'Transaction Date missing!' => 'Chybí datum!',
+ 'Transaction deleted!' => '',
+ 'Transaction posted!' => '',
+ 'Transaction reversal enforced for all dates' => 'Editace v¹ech polo¾ek zakázána (je nutné provést storno a nové zadání)',
+ 'Transaction reversal enforced up to' => 'Editace polo¾ek zakázána do',
+ 'Transactions' => 'Polo¾ky',
+ 'Transactions exist, cannot delete customer!' => 'Odbìratele nelze vymazat, proto¾e k nìmu existují transakce!',
+ 'Transactions exist, cannot delete vendor!' => 'Dodavatele nelze vymazat, proto¾e k nìmu existují transakce!',
+ 'Transactions exist; cannot delete account!' => 'Úèet nelze vymazat, proto¾e na nìm je úètováno!',
+ 'Trial Balance' => 'Obratová pøedvaha',
+ 'Unit' => 'Jednotka',
+ 'Unit of measure' => 'Mìrná jednotka',
+ 'Update' => '',
+ 'Update Dataset' => 'Aktualizovat data',
+ 'Updated' => '',
+ 'Use Templates' => 'Vyu¾ít ¹ablony',
+ 'User' => 'U¾ivatel',
+ 'User deleted!' => '',
+ 'User saved!' => '',
+ 'Vendor' => 'Dodavatel',
+ 'Vendor deleted!' => '',
+ 'Vendor missing!' => '',
+ 'Vendor not on file!' => '',
+ 'Vendor saved!' => '',
+ 'Vendors' => '',
+ 'Version' => 'Verze',
+ 'Weight' => 'Váha',
+ 'Weight Unit' => 'Jednotka váhy',
+ 'What type of item is this?' => 'O jaký typ polo¾ky se jedná?',
+ 'Year End' => 'Konec roku',
+ 'Yes' => 'Ano',
+ 'You are logged out!' => '',
+ 'You did not enter a name!' => 'Nezadal jste jméno!',
+ 'You must enter a host and port for local and remote connections!' => 'Pro lokální i vzdálené pøipojení je nutné zadat adresu serveru a port!',
+ 'as at' => '',
+ 'collected on sales' => 'vybráno na výstupu',
+ 'days' => 'dní',
+ 'does not exist' => 'neexistuje',
+ 'ea' => 'm.j.',
+ 'emailed to' => 'odesláno na adresu',
+ 'for Period' => 'za období',
+ 'hr' => 'hod',
+ 'is already a member!' => 'ji¾ existuje!',
+ 'is not a member!' => 'není platným u¾ivatelem',
+ 'localhost' => 'lokální server',
+ 'paid on purchases' => 'zaplaceno na vstupu',
+ 'sent to printer' => 'vyti¹tìno',
+ 'successfully created!' => 'úspì¹nì vytvoøen!',
+ 'successfully deleted!' => 'úspì¹nì smazán!',
+ 'to' => '',
+ 'website' => 'www adresa',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/am b/sql-ledger/locale/cz/am
new file mode 100644
index 0000000..caee54c
--- /dev/null
+++ b/sql-ledger/locale/cz/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Závazky',
+ 'AR' => 'Pohledávky',
+ 'Account' => 'Úèet',
+ 'Account Number' => 'Èíslo úètu',
+ 'Account Number missing!' => 'Chybí èíslo úètu!',
+ 'Account Type' => 'Typ úètu',
+ 'Account Type missing!' => 'Chybí typ úètu!',
+ 'Account deleted!' => 'Account deleted!',
+ 'Account saved!' => 'Account saved!',
+ 'Add Account' => 'Zalo¾it úèet',
+ 'Add GIFI' => 'Doplnit úètovací øetìzec',
+ 'Address' => 'Adresa',
+ 'Asset' => 'Aktiva',
+ 'Audit Control' => 'Kontrola pøístupù',
+ 'Backup sent to' => 'Záloha odeslána na adresu',
+ 'Books are open' => '¡Uèetní knihy jsou otevøeny',
+ 'Business Number' => 'IÈO',
+ 'COGS' => 'Náklady na prodané zbo¾í',
+ 'Cannot delete account!' => 'Cannot delete account!',
+ 'Cannot delete default account!' => 'Úèet je nastaven jako defaultní, nelze jej proto vymamazat!',
+ 'Cannot save account!' => 'Cannot save account!',
+ 'Cannot save preferences!' => 'Cannot save preferences!',
+ 'Character Set' => 'Znaková sada',
+ 'Chart of Accounts' => 'Úètový rozvrh',
+ 'Close Books up to' => 'Uzavøít úèetní knihy do',
+ 'Company' => 'Firma',
+ 'Continue' => 'Pokraèování',
+ 'Copy to COA' => 'Zkopírovat do úètového rozvrhu',
+ 'Credit' => 'Dal',
+ 'Date Format' => 'Formát data',
+ 'Debit' => 'Má dáti',
+ 'Delete' => 'Vymazat',
+ 'Delete Account' => 'Vymazat úèet',
+ 'Description' => 'Popis',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'E-mail',
+ 'Edit' => 'Edit',
+ 'Edit Account' => 'Upravit úèet',
+ 'Edit GIFI' => 'Upravit úètovací øetìzec',
+ 'Edit Preferences for' => 'Nastavení pro',
+ 'Edit Template' => 'Upravit ¹ablonu',
+ 'Enforce transaction reversal for all dates' => 'Zakázat editaci v¹ech úèetních polo¾ek',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Vlo¾te zkratky mìn (max. 3 znaky) oddìlené dvojteèkou pro domácí i cizí mìny (napø. CZK:USD:EUR)',
+ 'Equity' => 'Vlastní jmìní',
+ 'Expense' => 'Náklady',
+ 'Expense Account' => 'Nákladový úèet',
+ 'Expense/Asset' => 'Náklad',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Kurzový zisk',
+ 'Foreign Exchange Loss' => 'Kurzová ztráta',
+ 'GIFI' => 'Úètovací øetìzec',
+ 'GIFI deleted!' => 'GIFI deleted!',
+ 'GIFI missing!' => 'Chybí úètovací øetìzec!',
+ 'GIFI saved!' => 'GIFI saved!',
+ 'Heading' => 'Nadpis',
+ 'Include in drop-down menus' => 'Ukazovat v drop-down menu',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Zahrnovat tento úèet ve formuláøích odbìratelù/dodavatelù, aby bylo mo¾né oznaèit je za zdanitelné?',
+ 'Income' => 'Výnosy',
+ 'Income Account' => 'Výnosový úèet',
+ 'Inventory' => 'Zásoby',
+ 'Inventory Account' => 'Úèet zásob',
+ 'Is this a summary account to record' => 'Øídící úèet pro',
+ 'Language' => 'Jazyk',
+ 'Last Invoice Number' => 'Èíslo poslední faktury',
+ 'Last Numbers & Default Accounts' => 'Poslední èísla a standardní èísla úètù',
+ 'Last Purchase Order Number' => 'Èíslo poslední objednávky',
+ 'Last Sales Order Number' => 'Èíslo poslední objednávky',
+ 'Liability' => 'Závazek',
+ 'Link' => 'Vazby',
+ 'Name' => 'Jméno',
+ 'No' => 'Ne',
+ 'No email address for' => 'Chybí emailová adresy pro',
+ 'Number' => 'Èíslo',
+ 'Number Format' => 'Èíselný formát',
+ 'Parts Inventory' => 'Zbo¾í',
+ 'Password' => 'Heslo',
+ 'Payables' => 'Závazky',
+ 'Payment' => 'Platba',
+ 'Phone' => 'Telefon',
+ 'Preferences saved!' => 'Nastavení bylo ulo¾eno!',
+ 'Rate' => 'Sazba',
+ 'Receivables' => 'Pohledávky',
+ 'Sales' => 'Pøíjmy z prodeje',
+ 'Save' => 'Ulo¾it',
+ 'Service Items' => 'Polo¾ky slu¾eb',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Podpis',
+ 'Stylesheet' => 'Stylesheet',
+ 'Tax' => 'Daò',
+ 'Tax Accounts' => 'Daòové úèty',
+ 'Template saved!' => 'Template saved!',
+ 'Transaction reversal enforced for all dates' => 'Editace v¹ech polo¾ek zakázána (je nutné provést storno a nové zadání)',
+ 'Transaction reversal enforced up to' => 'Editace polo¾ek zakázána do',
+ 'Transactions exist; cannot delete account!' => 'Úèet nelze vymazat, proto¾e na nìm je úètováno!',
+ 'Weight Unit' => 'Jednotka váhy',
+ 'Year End' => 'Konec roku',
+ 'Yes' => 'Ano',
+ 'does not exist' => 'neexistuje',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'zalo¾it_úèet' => 'add_account',
+ 'pokraèování' => 'continue',
+ 'zkopírovat_do_úètového_rozvrhu' => 'copy_to_coa',
+ 'vymazat' => 'delete',
+ 'edit' => 'edit',
+ 'upravit_úèet' => 'edit_account',
+ 'ulo¾it' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/ap b/sql-ledger/locale/cz/ap
new file mode 100644
index 0000000..609bcbb
--- /dev/null
+++ b/sql-ledger/locale/cz/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AP Transactions' => 'Faktury pøijaté',
+ 'Account' => 'Úèet',
+ 'Add Accounts Payables Transaction' => 'Add Accounts Payables Transaction',
+ 'Address' => 'Adresa',
+ 'Amount' => 'Èástka',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Are you sure you want to delete Transaction' => 'Opravdu chcete vymazat transakci?',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'Do uzavøeného období nelze úètovat!',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Zaplaceno',
+ 'Confirm!' => 'Podtvrïte!',
+ 'Continue' => 'Pokraèování',
+ 'Currency' => 'Mìna',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Datum',
+ 'Date Paid' => 'Zaplaceno',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Delete' => 'Vymazat',
+ 'Description' => 'Popis',
+ 'Due Date' => 'Datum splatnosti',
+ 'Due Date missing!' => 'Chybí datum splatnosti!',
+ 'Edit Accounts Payables Transaction' => 'Edit Accounts Payables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Kurz',
+ 'Exchangerate' => 'Mìnový kurz',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'From' => 'z',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Zahrnovat v sestavì',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Datum vystavení',
+ 'Invoice Date missing!' => 'Chybí datum vystavení!',
+ 'Invoice Number' => 'Èíslo faktury',
+ 'Invoice Number missing!' => 'Chybí èíslo faktury!',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Notes' => 'Poznámky',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Number' => 'Èíslo',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'Open' => 'Otevøené',
+ 'Order' => 'Objednávka',
+ 'Order Number' => 'Objednávka èíslo',
+ 'Paid' => 'Zaplaceno',
+ 'Payment date missing!' => 'Chybí datum platby!',
+ 'Payments' => 'Platby',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Source' => 'Zdroj',
+ 'Subtotal' => 'Mezisouèet',
+ 'Tax' => 'Daò',
+ 'Tax Included' => 'Cena vèetnì danì',
+ 'To' => 'do',
+ 'Total' => 'Celkem',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor' => 'Dodavatel',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Ano',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'add_accounts_payables_transaction' => 'add_accounts_payables_transaction',
+ 'pokraèování' => 'continue',
+ 'vymazat' => 'delete',
+ 'edit_accounts_payables_transaction' => 'edit_accounts_payables_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'update' => 'update',
+ 'ano' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/ar b/sql-ledger/locale/cz/ar
new file mode 100644
index 0000000..512634f
--- /dev/null
+++ b/sql-ledger/locale/cz/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'AR Transaction',
+ 'AR Transactions' => 'Faktury vydané',
+ 'Account' => 'Úèet',
+ 'Add Accounts Receivables Transaction' => 'Add Accounts Receivables Transaction',
+ 'Address' => 'Adresa',
+ 'Amount' => 'Èástka',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Are you sure you want to delete Transaction' => 'Opravdu chcete vymazat transakci?',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'Do uzavøeného období nelze úètovat!',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Zaplaceno',
+ 'Confirm!' => 'Podtvrïte!',
+ 'Continue' => 'Pokraèování',
+ 'Credit Limit' => 'Úvìrový limit',
+ 'Currency' => 'Mìna',
+ 'Customer' => 'Odbìratel',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Datum',
+ 'Date Paid' => 'Zaplaceno',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Delete' => 'Vymazat',
+ 'Description' => 'Popis',
+ 'Due Date' => 'Datum splatnosti',
+ 'Due Date missing!' => 'Chybí datum splatnosti!',
+ 'Edit Accounts Receivables Transaction' => 'Edit Accounts Receivables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Kurz',
+ 'Exchangerate' => 'Mìnový kurz',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'From' => 'z',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Zahrnovat v sestavì',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Datum vystavení',
+ 'Invoice Date missing!' => 'Chybí datum vystavení!',
+ 'Invoice Number' => 'Èíslo faktury',
+ 'Invoice Number missing!' => 'Chybí èíslo faktury!',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Notes' => 'Poznámky',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Number' => 'Èíslo',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'Open' => 'Otevøené',
+ 'Order' => 'Objednávka',
+ 'Order Number' => 'Objednávka èíslo',
+ 'Paid' => 'Zaplaceno',
+ 'Payment date missing!' => 'Chybí datum platby!',
+ 'Payments' => 'Platby',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Remaining' => 'Zbývá',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Source' => 'Zdroj',
+ 'Subtotal' => 'Mezisouèet',
+ 'Tax' => 'Daò',
+ 'Tax Included' => 'Cena vèetnì danì',
+ 'To' => 'do',
+ 'Total' => 'Celkem',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Ano',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ar_transaction' => 'ar_transaction',
+ 'pokraèování' => 'continue',
+ 'vymazat' => 'delete',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'ano' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/arap b/sql-ledger/locale/cz/arap
new file mode 100644
index 0000000..3db4284
--- /dev/null
+++ b/sql-ledger/locale/cz/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adresa',
+ 'Continue' => 'Pokraèování',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Description' => 'Popis',
+ 'Number' => 'Èíslo',
+ 'Project not on file!' => 'Project not on file!',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'pokraèování' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/ca b/sql-ledger/locale/cz/ca
new file mode 100644
index 0000000..cd48d2f
--- /dev/null
+++ b/sql-ledger/locale/cz/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Úèet',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'Úètový rozvrh',
+ 'Credit' => 'Dal',
+ 'Date' => 'Datum',
+ 'Debit' => 'Má dáti',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Description' => 'Popis',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'From' => 'z',
+ 'GIFI' => 'Úètovací øetìzec',
+ 'Include in Report' => 'Zahrnovat v sestavì',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'List Transactions' => 'Vypsat transakce',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'Reference' => 'Reference',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Subtotal' => 'Mezisouèet',
+ 'To' => 'do',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'vypsat_transakce' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/cp b/sql-ledger/locale/cz/cp
new file mode 100644
index 0000000..f85ed50
--- /dev/null
+++ b/sql-ledger/locale/cz/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Úèet',
+ 'Address' => 'Adresa',
+ 'Amount' => 'Èástka',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Amount missing!',
+ 'Applied' => 'Applied',
+ 'Cannot post payment!' => 'Cannot post payment!',
+ 'Cannot process payment for a closed period!' => 'Cannot process payment for a closed period!',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check printed!',
+ 'Check printing failed!' => 'Check printing failed!',
+ 'Continue' => 'Pokraèování',
+ 'Currency' => 'Mìna',
+ 'Customer' => 'Odbìratel',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Datum',
+ 'Date missing!' => 'Date missing!',
+ 'Description' => 'Popis',
+ 'Due' => 'Splatno',
+ 'Exchangerate' => 'Mìnový kurz',
+ 'From' => 'z',
+ 'Invoice' => 'Faktura',
+ 'Invoices' => 'Invoices',
+ 'Nothing applied!' => 'Nothing applied!',
+ 'Number' => 'Èíslo',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'Platba',
+ 'Payment posted!' => 'Payment posted!',
+ 'Post' => 'Post',
+ 'Print' => 'Print',
+ 'Printer' => 'Tiskárna',
+ 'Project not on file!' => 'Project not on file!',
+ 'Receipt' => 'Receipt',
+ 'Reference' => 'Reference',
+ 'Screen' => 'Na obrazovku',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'To' => 'do',
+ 'Update' => 'Update',
+ 'Vendor' => 'Dodavatel',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'pokraèování' => 'continue',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/ct b/sql-ledger/locale/cz/ct
new file mode 100644
index 0000000..7c2863d
--- /dev/null
+++ b/sql-ledger/locale/cz/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Pøidat',
+ 'Address' => 'Adresa',
+ 'All' => 'V¹e',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Cannot delete customer!',
+ 'Cannot delete vendor!' => 'Cannot delete vendor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Pokraèování',
+ 'Credit Limit' => 'Úvìrový limit',
+ 'Customer deleted!' => 'Customer deleted!',
+ 'Customer saved!' => 'Customer saved!',
+ 'Customers' => 'Customers',
+ 'Delete' => 'Vymazat',
+ 'Discount' => 'Sleva',
+ 'E-mail' => 'E-mail',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Zahrnovat v sestavì',
+ 'Invoice' => 'Faktura',
+ 'Name' => 'Jméno',
+ 'Name missing!' => 'Name missing!',
+ 'Notes' => 'Poznámky',
+ 'Number' => 'Èíslo',
+ 'Order' => 'Objednávka',
+ 'Orphaned' => 'Neprodejné',
+ 'Phone' => 'Telefon',
+ 'Save' => 'Ulo¾it',
+ 'Ship to' => 'Ship to',
+ 'Tax Included' => 'Cena vèetnì danì',
+ 'Taxable' => 'Zdanitelné',
+ 'Terms: Net' => 'Netto',
+ 'Transactions exist, cannot delete customer!' => 'Odbìratele nelze vymazat, proto¾e k nìmu existují transakce!',
+ 'Transactions exist, cannot delete vendor!' => 'Dodavatele nelze vymazat, proto¾e k nìmu existují transakce!',
+ 'Vendor deleted!' => 'Vendor deleted!',
+ 'Vendor saved!' => 'Vendor saved!',
+ 'Vendors' => 'Vendors',
+ 'days' => 'dní',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'pøidat' => 'add',
+ 'pokraèování' => 'continue',
+ 'vymazat' => 'delete',
+ 'faktura' => 'invoice',
+ 'objednávka' => 'order',
+ 'ulo¾it' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/gl b/sql-ledger/locale/cz/gl
new file mode 100644
index 0000000..1928de8
--- /dev/null
+++ b/sql-ledger/locale/cz/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AR Transaction' => 'AR Transaction',
+ 'Account' => 'Úèet',
+ 'Add General Ledger Transaction' => 'Nový zápis do hlavní knihy',
+ 'Address' => 'Adresa',
+ 'All' => 'V¹e',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Are you sure you want to delete Transaction' => 'Opravdu chcete vymazat transakci?',
+ 'Asset' => 'Aktiva',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot have a value in both Debit and Credit!' => 'Nelze úètovat souèasnì Má dáti i Dal!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'Do uzavøeného období nelze úètovat!',
+ 'Confirm!' => 'Podtvrïte!',
+ 'Continue' => 'Pokraèování',
+ 'Credit' => 'Dal',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Datum',
+ 'Debit' => 'Má dáti',
+ 'Debit and credit out of balance!' => 'Má dáti a Dal se nerovnají.',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Delete' => 'Vymazat',
+ 'Description' => 'Popis',
+ 'Edit General Ledger Transaction' => 'Opravit záznam v hlavní knize',
+ 'Equity' => 'Vlastní jmìní',
+ 'Expense' => 'Náklady',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'From' => 'z',
+ 'GIFI' => 'Úètovací øetìzec',
+ 'GL Transaction' => 'GL Transaction',
+ 'General Ledger' => 'Hlavní kniha',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Zahrnovat v sestavì',
+ 'Income' => 'Výnosy',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'Liability' => 'Závazek',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Notes' => 'Poznámky',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Number' => 'Èíslo',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference missing!',
+ 'Reports' => 'Sestavy',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Source' => 'Zdroj',
+ 'Subtotal' => 'Mezisouèet',
+ 'To' => 'do',
+ 'Transaction Date missing!' => 'Chybí datum!',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Ano',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'pokraèování' => 'continue',
+ 'vymazat' => 'delete',
+ 'gl_transaction' => 'gl_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'ano' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/ic b/sql-ledger/locale/cz/ic
new file mode 100644
index 0000000..effb534
--- /dev/null
+++ b/sql-ledger/locale/cz/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Active',
+ 'Add' => 'Pøidat',
+ 'Add Assembly' => 'Nový výrobek',
+ 'Add Part' => 'Pøíjem zbo¾í',
+ 'Add Purchase Order' => 'Nová objednávka (nákup)',
+ 'Add Sales Order' => 'Nová objednávka (pøíjem)',
+ 'Add Service' => 'Nový druh slu¾by',
+ 'Address' => 'Adresa',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Assemblies' => 'Výrobky',
+ 'Assemblies restocked!' => 'Assemblies restocked!',
+ 'Assembly Number missing!' => 'Chybí èíslo výrobku',
+ 'Attachment' => 'Pøílohy',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Paleta',
+ 'Bought' => 'Nakoupeno',
+ 'COGS' => 'Náklady na prodané zbo¾í',
+ 'Cannot delete item already invoiced!' => 'Ji¾ fakturované polo¾ky nelze vymazat!',
+ 'Cannot delete item on order!' => 'Polo¾ku objednávky nelze vymazat!',
+ 'Cannot delete item which is part of an assembly!' => 'Nelze vymazat polo¾ku, která je souèástí výrobku!',
+ 'Cannot delete item!' => 'Cannot delete item!',
+ 'Cannot stock assemblies!' => 'Cannot stock assemblies!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Pokraèování',
+ 'Copies' => 'Kopie',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Delete' => 'Vymazat',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Popis',
+ 'Drawing' => 'Drawing',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Chybí E-mailová adresa!',
+ 'Edit Assembly' => 'Upravit výrobek',
+ 'Edit Part' => 'Upravit zbo¾í',
+ 'Edit Service' => 'Upravit slu¾bu',
+ 'Expense' => 'Náklady',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'From' => 'z',
+ 'Image' => 'Image',
+ 'In-line' => 'Vlo¾ené',
+ 'Include in Report' => 'Zahrnovat v sestavì',
+ 'Income' => 'Výnosy',
+ 'Individual Items' => 'Komponenty výrobku',
+ 'Inventory' => 'Zásoby',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Pøed vyøazením výrobu, musí být stav na skladì nulový!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Pøed vyøazením zbo¾í musí být mno¾ství na skladì nulové',
+ 'Inventory quantity must be zero!' => 'Stav skladu musí být nulový!',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Chybí datum vystavení!',
+ 'Invoice Number' => 'Èíslo faktury',
+ 'Invoice Number missing!' => 'Chybí èíslo faktury!',
+ 'Item deleted!' => 'Item deleted!',
+ 'Item not on file!' => 'Tato polo¾ka není v databázi!',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'Last Cost' => 'Poslední cena',
+ 'Line Total' => 'Øádek celkem',
+ 'Link Accounts' => 'Vazby mezi úèty',
+ 'List Price' => 'Výrobní cena',
+ 'Make' => 'Výrobce',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Message' => 'Zpráva',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Model',
+ 'Name' => 'Jméno',
+ 'No.' => 'No.',
+ 'Notes' => 'Poznámky',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Number' => 'Èíslo',
+ 'Number missing in Row' => 'Chybìjící èíslo na øádku',
+ 'Obsolete' => 'Vyøazené',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'On Hand' => 'K dispozici',
+ 'On Order' => 'On Order',
+ 'Order' => 'Objednávka',
+ 'Order Date missing!' => 'Chybí datum objednávky!',
+ 'Order Number' => 'Objednávka èíslo',
+ 'Order Number missing!' => 'Chybí èíslo objednávky!',
+ 'Ordered' => 'Ordered',
+ 'Orphaned' => 'Neprodejné',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Dodací list',
+ 'Packing List Date missing!' => 'Chybí datum dodacího listu',
+ 'Packing List Number missing!' => 'Chybí èíslo dodacího listu',
+ 'Part' => 'Zbo¾í',
+ 'Part Number missing!' => 'Chybí èíslo zbo¾í!',
+ 'Parts' => 'Díly',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena',
+ 'Printer' => 'Tiskárna',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Vystavená objednávka',
+ 'Qty' => 'Mno¾ství',
+ 'ROP' => 'ROP',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Po¾adováno do',
+ 'Sales' => 'Pøíjmy z prodeje',
+ 'Sales Order' => 'Pøijatá objednávka',
+ 'Save' => 'Ulo¾it',
+ 'Screen' => 'Na obrazovku',
+ 'Select from one of the items below' => 'Zvolte z ní¾e uvedených polo¾ek',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sell Price' => 'Prodejní cena',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Service' => 'Slu¾ba',
+ 'Service Number missing!' => 'Chybí èíslo slu¾by!',
+ 'Services' => 'Slu¾by',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Short' => 'Krátký výpis',
+ 'Sold' => 'Prodané',
+ 'Stock Assembly' => 'Výrobky',
+ 'Subject' => 'Pøedmìt',
+ 'Subtotal' => 'Mezisouèet',
+ 'Tax' => 'Daò',
+ 'To' => 'do',
+ 'Top Level' => 'Top Level',
+ 'Total' => 'Celkem',
+ 'Unit' => 'Jednotka',
+ 'Unit of measure' => 'Mìrná jednotka',
+ 'Update' => 'Update',
+ 'Updated' => 'Updated',
+ 'Weight' => 'Váha',
+ 'What type of item is this?' => 'O jaký typ polo¾ky se jedná?',
+ 'ea' => 'm.j.',
+ 'emailed to' => 'odesláno na adresu',
+ 'hr' => 'hod',
+ 'sent to printer' => 'vyti¹tìno',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'pøidat' => 'add',
+ 'nový_výrobek' => 'add_assembly',
+ 'pøíjem_zbo¾í' => 'add_part',
+ 'nový_druh_slu¾by' => 'add_service',
+ 'pokraèování' => 'continue',
+ 'vymazat' => 'delete',
+ 'upravit_výrobek' => 'edit_assembly',
+ 'upravit_zbo¾í' => 'edit_part',
+ 'upravit_slu¾bu' => 'edit_service',
+ 'ulo¾it' => 'save',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/io b/sql-ledger/locale/cz/io
new file mode 100644
index 0000000..9fa6c63
--- /dev/null
+++ b/sql-ledger/locale/cz/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Nová objednávka (nákup)',
+ 'Add Sales Order' => 'Nová objednávka (pøíjem)',
+ 'Address' => 'Adresa',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Attachment' => 'Pøílohy',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Paleta',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Pokraèování',
+ 'Copies' => 'Kopie',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Popis',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Chybí E-mailová adresa!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'In-line' => 'Vlo¾ené',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Chybí datum vystavení!',
+ 'Invoice Number missing!' => 'Chybí èíslo faktury!',
+ 'Item not on file!' => 'Tato polo¾ka není v databázi!',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Message' => 'Zpráva',
+ 'Name' => 'Jméno',
+ 'No.' => 'No.',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Number' => 'Èíslo',
+ 'Number missing in Row' => 'Chybìjící èíslo na øádku',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'Order' => 'Objednávka',
+ 'Order Date missing!' => 'Chybí datum objednávky!',
+ 'Order Number missing!' => 'Chybí èíslo objednávky!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Dodací list',
+ 'Packing List Date missing!' => 'Chybí datum dodacího listu',
+ 'Packing List Number missing!' => 'Chybí èíslo dodacího listu',
+ 'Part' => 'Zbo¾í',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena',
+ 'Printer' => 'Tiskárna',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Vystavená objednávka',
+ 'Qty' => 'Mno¾ství',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Po¾adováno do',
+ 'Sales Order' => 'Pøijatá objednávka',
+ 'Screen' => 'Na obrazovku',
+ 'Select from one of the items below' => 'Zvolte z ní¾e uvedených polo¾ek',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Service' => 'Slu¾ba',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Subject' => 'Pøedmìt',
+ 'To' => 'do',
+ 'Unit' => 'Jednotka',
+ 'What type of item is this?' => 'O jaký typ polo¾ky se jedná?',
+ 'emailed to' => 'odesláno na adresu',
+ 'sent to printer' => 'vyti¹tìno',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'pokraèování' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/ir b/sql-ledger/locale/cz/ir
new file mode 100644
index 0000000..5e36073
--- /dev/null
+++ b/sql-ledger/locale/cz/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Úèet',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Nová objednávka (nákup)',
+ 'Add Sales Order' => 'Nová objednávka (pøíjem)',
+ 'Address' => 'Adresa',
+ 'Amount' => 'Èástka',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Are you sure you want to delete Invoice Number' => 'Opravdu chcete vymazat fakturu èíslo',
+ 'Attachment' => 'Pøílohy',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Paleta',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Podtvrïte!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Pokraèování',
+ 'Copies' => 'Kopie',
+ 'Currency' => 'Mìna',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Datum',
+ 'Date Due' => 'Datum splatnosti',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Delete' => 'Vymazat',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Popis',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Chybí E-mailová adresa!',
+ 'Edit Purchase Invoice' => 'Edit Purchase Invoice',
+ 'Exch' => 'Kurz',
+ 'Exchangerate' => 'Mìnový kurz',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'In-line' => 'Vlo¾ené',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Datum vystavení',
+ 'Invoice Date missing!' => 'Chybí datum vystavení!',
+ 'Invoice Number' => 'Èíslo faktury',
+ 'Invoice Number missing!' => 'Chybí èíslo faktury!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'Tato polo¾ka není v databázi!',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Message' => 'Zpráva',
+ 'Name' => 'Jméno',
+ 'No.' => 'No.',
+ 'Notes' => 'Poznámky',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Number' => 'Èíslo',
+ 'Number missing in Row' => 'Chybìjící èíslo na øádku',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'Order' => 'Objednávka',
+ 'Order Date missing!' => 'Chybí datum objednávky!',
+ 'Order Number' => 'Objednávka èíslo',
+ 'Order Number missing!' => 'Chybí èíslo objednávky!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Dodací list',
+ 'Packing List Date missing!' => 'Chybí datum dodacího listu',
+ 'Packing List Number missing!' => 'Chybí èíslo dodacího listu',
+ 'Part' => 'Zbo¾í',
+ 'Payment date missing!' => 'Chybí datum platby!',
+ 'Payments' => 'Platby',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena',
+ 'Printer' => 'Tiskárna',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Vystavená objednávka',
+ 'Qty' => 'Mno¾ství',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Zaúètovat do',
+ 'Required by' => 'Po¾adováno do',
+ 'Sales Order' => 'Pøijatá objednávka',
+ 'Screen' => 'Na obrazovku',
+ 'Select from one of the items below' => 'Zvolte z ní¾e uvedených polo¾ek',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Service' => 'Slu¾ba',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Source' => 'Zdroj',
+ 'Subject' => 'Pøedmìt',
+ 'Subtotal' => 'Mezisouèet',
+ 'Tax Included' => 'Cena vèetnì danì',
+ 'To' => 'do',
+ 'Total' => 'Celkem',
+ 'Unit' => 'Jednotka',
+ 'Update' => 'Update',
+ 'Vendor' => 'Dodavatel',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'O jaký typ polo¾ky se jedná?',
+ 'Yes' => 'Ano',
+ 'ea' => 'm.j.',
+ 'emailed to' => 'odesláno na adresu',
+ 'sent to printer' => 'vyti¹tìno',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'pokraèování' => 'continue',
+ 'vymazat' => 'delete',
+ 'objednávka' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'update' => 'update',
+ 'ano' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/is b/sql-ledger/locale/cz/is
new file mode 100644
index 0000000..845b381
--- /dev/null
+++ b/sql-ledger/locale/cz/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Úèet',
+ 'Add Purchase Order' => 'Nová objednávka (nákup)',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Nová objednávka (pøíjem)',
+ 'Address' => 'Adresa',
+ 'Amount' => 'Èástka',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Are you sure you want to delete Invoice Number' => 'Opravdu chcete vymazat fakturu èíslo',
+ 'Attachment' => 'Pøílohy',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Paleta',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Podtvrïte!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Pokraèování',
+ 'Copies' => 'Kopie',
+ 'Credit Limit' => 'Úvìrový limit',
+ 'Currency' => 'Mìna',
+ 'Customer' => 'Odbìratel',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Datum',
+ 'Date Due' => 'Datum splatnosti',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Delete' => 'Vymazat',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Popis',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Chybí E-mailová adresa!',
+ 'Edit Sales Invoice' => 'Edit Sales Invoice',
+ 'Exch' => 'Kurz',
+ 'Exchangerate' => 'Mìnový kurz',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'In-line' => 'Vlo¾ené',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Datum vystavení',
+ 'Invoice Date missing!' => 'Chybí datum vystavení!',
+ 'Invoice Number' => 'Èíslo faktury',
+ 'Invoice Number missing!' => 'Chybí èíslo faktury!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'Tato polo¾ka není v databázi!',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Message' => 'Zpráva',
+ 'Name' => 'Jméno',
+ 'No.' => 'No.',
+ 'Notes' => 'Poznámky',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Number' => 'Èíslo',
+ 'Number missing in Row' => 'Chybìjící èíslo na øádku',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'Order' => 'Objednávka',
+ 'Order Date missing!' => 'Chybí datum objednávky!',
+ 'Order Number' => 'Objednávka èíslo',
+ 'Order Number missing!' => 'Chybí èíslo objednávky!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Dodací list',
+ 'Packing List Date missing!' => 'Chybí datum dodacího listu',
+ 'Packing List Number missing!' => 'Chybí èíslo dodacího listu',
+ 'Part' => 'Zbo¾í',
+ 'Payment date missing!' => 'Chybí datum platby!',
+ 'Payments' => 'Platby',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena',
+ 'Print' => 'Print',
+ 'Printer' => 'Tiskárna',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Vystavená objednávka',
+ 'Qty' => 'Mno¾ství',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Zaúètovat do',
+ 'Remaining' => 'Zbývá',
+ 'Required by' => 'Po¾adováno do',
+ 'Sales Order' => 'Pøijatá objednávka',
+ 'Screen' => 'Na obrazovku',
+ 'Select from one of the items below' => 'Zvolte z ní¾e uvedených polo¾ek',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Service' => 'Slu¾ba',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Source' => 'Zdroj',
+ 'Subject' => 'Pøedmìt',
+ 'Subtotal' => 'Mezisouèet',
+ 'Tax Included' => 'Cena vèetnì danì',
+ 'To' => 'do',
+ 'Total' => 'Celkem',
+ 'Unit' => 'Jednotka',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'O jaký typ polo¾ky se jedná?',
+ 'Yes' => 'Ano',
+ 'ea' => 'm.j.',
+ 'emailed to' => 'odesláno na adresu',
+ 'sent to printer' => 'vyti¹tìno',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'pokraèování' => 'continue',
+ 'vymazat' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'objednávka' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'ano' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/login b/sql-ledger/locale/cz/login
new file mode 100644
index 0000000..c0d9264
--- /dev/null
+++ b/sql-ledger/locale/cz/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'O programu',
+ 'Accounting' => 'Úèetnictví',
+ 'Database Host' => 'Databázový server',
+ 'Dataset' => 'Dataset',
+ 'Incorrect Dataset version!' => '©patná verze dat!',
+ 'Incorrect Password!' => 'Nesprávné heslo!',
+ 'Licensed to' => 'Licencováno pro',
+ 'Login' => 'U¾ivatelské jméno',
+ 'Name' => 'Jméno',
+ 'Password' => 'Heslo',
+ 'User' => 'U¾ivatel',
+ 'Version' => 'Verze',
+ 'You are logged out!' => 'You are logged out!',
+ 'You did not enter a name!' => 'Nezadal jste jméno!',
+ 'is not a member!' => 'není platným u¾ivatelem',
+ 'localhost' => 'lokální server',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'u¾ivatelské_jméno' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/menu b/sql-ledger/locale/cz/menu
new file mode 100644
index 0000000..bb77601
--- /dev/null
+++ b/sql-ledger/locale/cz/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'Závazky',
+ 'AP Aging' => 'Analýza splatnosti',
+ 'AR' => 'Pohledávky',
+ 'AR Aging' => 'Analýza splatnosti',
+ 'Accounting Menu' => 'Menu úèetnictví',
+ 'Add Account' => 'Zalo¾it úèet',
+ 'Add Assembly' => 'Nový výrobek',
+ 'Add Customer' => 'Nový zákazník',
+ 'Add GIFI' => 'Doplnit úètovací øetìzec',
+ 'Add Part' => 'Pøíjem zbo¾í',
+ 'Add Project' => 'Add Project',
+ 'Add Service' => 'Nový druh slu¾by',
+ 'Add Transaction' => 'Nová transakce',
+ 'Add Vendor' => 'Nový dodavatel',
+ 'Assemblies' => 'Výrobky',
+ 'Audit Control' => 'Kontrola pøístupù',
+ 'Backup' => 'Záloha',
+ 'Balance Sheet' => 'Rozvaha',
+ 'Cash' => 'Cash',
+ 'Chart of Accounts' => 'Úètový rozvrh',
+ 'Check' => 'Check',
+ 'Customers' => 'Customers',
+ 'General Ledger' => 'Hlavní kniha',
+ 'Goods & Services' => 'Zbo¾í a slu¾by',
+ 'HTML Templates' => 'HTML ¹ablony',
+ 'Income Statement' => 'Výsledovka',
+ 'Invoice' => 'Faktura',
+ 'LaTeX Templates' => 'LaTeX ¹ablony',
+ 'List Accounts' => 'Seznam úètù',
+ 'List GIFI' => 'Vypsat úètovací øetìzce',
+ 'Logout' => 'Odhlásit',
+ 'Order Entry' => 'Zadání objednávky',
+ 'Packing List' => 'Dodací list',
+ 'Parts' => 'Díly',
+ 'Payment' => 'Platba',
+ 'Payments' => 'Platby',
+ 'Preferences' => 'Nastavení',
+ 'Projects' => 'Projects',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Purchase Order' => 'Vystavená objednávka',
+ 'Purchase Orders' => 'Vystavené objednávky',
+ 'Receipt' => 'Receipt',
+ 'Receipts' => 'Receipts',
+ 'Reconciliation' => 'Reconciliation',
+ 'Reports' => 'Sestavy',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Sales Order' => 'Pøijatá objednávka',
+ 'Sales Orders' => 'Pøijaté objednávky',
+ 'Save to File' => 'Ulo¾it do souboru',
+ 'Send by E-Mail' => 'Poslat e-mailem',
+ 'Services' => 'Slu¾by',
+ 'Statement' => 'Statement',
+ 'Stock Assembly' => 'Výrobky',
+ 'Stylesheet' => 'Stylesheet',
+ 'System' => 'Systém',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'Transactions' => 'Polo¾ky',
+ 'Trial Balance' => 'Obratová pøedvaha',
+ 'Vendors' => 'Vendors',
+ 'Version' => 'Verze',
+ 'localhost' => 'lokální server',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/oe b/sql-ledger/locale/cz/oe
new file mode 100644
index 0000000..609a9f1
--- /dev/null
+++ b/sql-ledger/locale/cz/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Pøidat',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Nová objednávka (nákup)',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Nová objednávka (pøíjem)',
+ 'Address' => 'Adresa',
+ 'Amount' => 'Èástka',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Are you sure you want to delete Order Number' => 'Opravdu chcete vymazat objednávku èíslo',
+ 'Attachment' => 'Pøílohy',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Paleta',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Cannot delete order!',
+ 'Cannot save order!' => 'Cannot save order!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Zaplaceno',
+ 'Confirm!' => 'Podtvrïte!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Pokraèování',
+ 'Copies' => 'Kopie',
+ 'Credit Limit' => 'Úvìrový limit',
+ 'Curr' => 'Mìna',
+ 'Currency' => 'Mìna',
+ 'Customer' => 'Odbìratel',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Datum',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Delete' => 'Vymazat',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Popis',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Chybí E-mailová adresa!',
+ 'Edit Purchase Order' => 'Upravit vystavenou objednávku',
+ 'Edit Sales Order' => 'Upravit pøijatou objednávku',
+ 'Exchangerate' => 'Mìnový kurz',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'From' => 'z',
+ 'ID' => 'ID',
+ 'In-line' => 'Vlo¾ené',
+ 'Include in Report' => 'Zahrnovat v sestavì',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Chybí datum vystavení!',
+ 'Invoice Number missing!' => 'Chybí èíslo faktury!',
+ 'Item not on file!' => 'Tato polo¾ka není v databázi!',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Message' => 'Zpráva',
+ 'Name' => 'Jméno',
+ 'No.' => 'No.',
+ 'Notes' => 'Poznámky',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Number' => 'Èíslo',
+ 'Number missing in Row' => 'Chybìjící èíslo na øádku',
+ 'O' => 'O',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'Open' => 'Otevøené',
+ 'Order' => 'Objednávka',
+ 'Order Date' => 'Datum objednávky',
+ 'Order Date missing!' => 'Chybí datum objednávky!',
+ 'Order Number' => 'Objednávka èíslo',
+ 'Order Number missing!' => 'Chybí èíslo objednávky!',
+ 'Order deleted!' => 'Order deleted!',
+ 'Order saved!' => 'Order saved!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Dodací list',
+ 'Packing List Date missing!' => 'Chybí datum dodacího listu',
+ 'Packing List Number missing!' => 'Chybí èíslo dodacího listu',
+ 'Part' => 'Zbo¾í',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena',
+ 'Print' => 'Print',
+ 'Printer' => 'Tiskárna',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Vystavená objednávka',
+ 'Purchase Orders' => 'Vystavené objednávky',
+ 'Qty' => 'Mno¾ství',
+ 'Recd' => 'Recd',
+ 'Remaining' => 'Zbývá',
+ 'Required by' => 'Po¾adováno do',
+ 'Sales Order' => 'Pøijatá objednávka',
+ 'Sales Orders' => 'Pøijaté objednávky',
+ 'Save' => 'Ulo¾it',
+ 'Save as new' => 'Save as new',
+ 'Screen' => 'Na obrazovku',
+ 'Select from one of the items below' => 'Zvolte z ní¾e uvedených polo¾ek',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Service' => 'Slu¾ba',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Subject' => 'Pøedmìt',
+ 'Subtotal' => 'Mezisouèet',
+ 'Tax' => 'Daò',
+ 'Tax Included' => 'Cena vèetnì danì',
+ 'Terms: Net' => 'Netto',
+ 'To' => 'do',
+ 'Total' => 'Celkem',
+ 'Unit' => 'Jednotka',
+ 'Update' => 'Update',
+ 'Vendor' => 'Dodavatel',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'O jaký typ polo¾ky se jedná?',
+ 'Yes' => 'Ano',
+ 'days' => 'dní',
+ 'ea' => 'm.j.',
+ 'emailed to' => 'odesláno na adresu',
+ 'sent to printer' => 'vyti¹tìno',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'pøidat' => 'add',
+ 'pokraèování' => 'continue',
+ 'vymazat' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'faktura' => 'invoice',
+ 'print' => 'print',
+ 'ulo¾it' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'ano' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/pe b/sql-ledger/locale/cz/pe
new file mode 100644
index 0000000..de5aad3
--- /dev/null
+++ b/sql-ledger/locale/cz/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Pøidat',
+ 'Add Project' => 'Add Project',
+ 'All' => 'V¹e',
+ 'Continue' => 'Pokraèování',
+ 'Delete' => 'Vymazat',
+ 'Description' => 'Popis',
+ 'Edit Project' => 'Edit Project',
+ 'Number' => 'Èíslo',
+ 'Orphaned' => 'Neprodejné',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Project Number missing!',
+ 'Project deleted!' => 'Project deleted!',
+ 'Project saved!' => 'Project saved!',
+ 'Projects' => 'Projects',
+ 'Save' => 'Ulo¾it',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'pøidat' => 'add',
+ 'pokraèování' => 'continue',
+ 'vymazat' => 'delete',
+ 'ulo¾it' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/rc b/sql-ledger/locale/cz/rc
new file mode 100644
index 0000000..38999ec
--- /dev/null
+++ b/sql-ledger/locale/cz/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Úèet',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'Pokraèování',
+ 'Date' => 'Datum',
+ 'Deposit' => 'Deposit',
+ 'Description' => 'Popis',
+ 'Difference' => 'Difference',
+ 'Done' => 'Done',
+ 'Exchangerate Difference' => 'Exchangerate Difference',
+ 'From' => 'z',
+ 'Out of balance!' => 'Out of balance!',
+ 'Payment' => 'Platba',
+ 'Reconciliation' => 'Reconciliation',
+ 'Select all' => 'Select all',
+ 'Source' => 'Zdroj',
+ 'Statement Balance' => 'Statement Balance',
+ 'To' => 'do',
+ 'Update' => 'Update',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'pokraèování' => 'continue',
+ 'done' => 'done',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/cz/rp b/sql-ledger/locale/cz/rp
new file mode 100644
index 0000000..0896ce4
--- /dev/null
+++ b/sql-ledger/locale/cz/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Analýza splatnosti',
+ 'AR Aging' => 'Analýza splatnosti',
+ 'Account' => 'Úèet',
+ 'Accounts' => 'Úèty',
+ 'Amount' => 'Èástka',
+ 'Apr' => 'Dub',
+ 'April' => 'Duben',
+ 'Attachment' => 'Pøílohy',
+ 'Aug' => 'Srp',
+ 'August' => 'Srpen',
+ 'Balance Sheet' => 'Rozvaha',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Porovnáno k',
+ 'Continue' => 'Pokraèování',
+ 'Copies' => 'Kopie',
+ 'Credit' => 'Dal',
+ 'Current' => 'Current',
+ 'Customer' => 'Odbìratel',
+ 'Date' => 'Datum',
+ 'Debit' => 'Má dáti',
+ 'Dec' => 'Pro',
+ 'December' => 'Prosinec',
+ 'Decimalplaces' => 'Decimalplaces',
+ 'Description' => 'Popis',
+ 'Due' => 'Splatno',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'E-mail Statement to',
+ 'Feb' => 'Úno',
+ 'February' => 'Únor',
+ 'From' => 'z',
+ 'GIFI' => 'Úètovací øetìzec',
+ 'Heading' => 'Nadpis',
+ 'ID' => 'ID',
+ 'In-line' => 'Vlo¾ené',
+ 'Include in Report' => 'Zahrnovat v sestavì',
+ 'Income Statement' => 'Výsledovka',
+ 'Invoice' => 'Faktura',
+ 'Jan' => 'Led',
+ 'January' => 'Leden',
+ 'Jul' => 'Èec',
+ 'July' => 'Èervenec',
+ 'Jun' => 'Èer',
+ 'June' => 'Èerven',
+ 'Mar' => 'Bøe',
+ 'March' => 'Bøezen',
+ 'May' => 'Kvìten',
+ 'May ' => 'Kvì',
+ 'Message' => 'Zpráva',
+ 'N/A' => '---',
+ 'Nothing selected!' => 'Nothing selected!',
+ 'Nov' => 'Lis',
+ 'November' => 'Listopad',
+ 'Oct' => 'Øíj',
+ 'October' => 'Øíjen',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Platby',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Print',
+ 'Printer' => 'Tiskárna',
+ 'Receipts' => 'Receipts',
+ 'Report for' => 'Výkaz za',
+ 'Retained Earnings' => 'Nerozdìlený zisk',
+ 'Screen' => 'Na obrazovku',
+ 'Select all' => 'Select all',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Záø',
+ 'September' => 'Záøí',
+ 'Source' => 'Zdroj',
+ 'Standard' => 'Standardní',
+ 'Statement' => 'Statement',
+ 'Statement sent to' => 'Statement sent to',
+ 'Statements sent to printer!' => 'Statements sent to printer!',
+ 'Subject' => 'Pøedmìt',
+ 'Subtotal' => 'Mezisouèet',
+ 'Tax' => 'Daò',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'To' => 'do',
+ 'Total' => 'Celkem',
+ 'Trial Balance' => 'Obratová pøedvaha',
+ 'Vendor' => 'Dodavatel',
+ 'as at' => 'as at',
+ 'collected on sales' => 'vybráno na výstupu',
+ 'for Period' => 'za období',
+ 'paid on purchases' => 'zaplaceno na vstupu',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'pokraèování' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'print' => 'print',
+ 'select_all' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/de/COPYING b/sql-ledger/locale/de/COPYING
new file mode 100644
index 0000000..b12eb1b
--- /dev/null
+++ b/sql-ledger/locale/de/COPYING
@@ -0,0 +1,22 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (C) 2002
+#
+# German texts:
+#
+# Author: Thomas Bayen <tbayen@bayen.de>
+# Gunter Ohrner <G.Ohrner@post.rwth-aachen.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+######################################################################
diff --git a/sql-ledger/locale/de/LANGUAGE b/sql-ledger/locale/de/LANGUAGE
new file mode 100644
index 0000000..fc0b977
--- /dev/null
+++ b/sql-ledger/locale/de/LANGUAGE
@@ -0,0 +1 @@
+German
diff --git a/sql-ledger/locale/de/Num2text b/sql-ledger/locale/de/Num2text
new file mode 100644
index 0000000..be84a3c
--- /dev/null
+++ b/sql-ledger/locale/de/Num2text
@@ -0,0 +1,185 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# this is a variation of the Lingua package
+# written for check and receipt printing
+# it returns a properly formatted text string
+# for a number up to 10**12
+
+sub init {
+ my $self = shift;
+
+ %{ $self->{numbername} } =
+ (0 => 'Null',
+ 1 => 'ein',
+ 2 => 'zwei',
+ 3 => 'drei',
+ 4 => 'vier',
+ 5 => 'fünf',
+ 6 => 'sechs',
+ 7 => 'sieben',
+ 8 => 'acht',
+ 9 => 'neun',
+ 10 => 'zehn',
+ 11 => 'elf',
+ 12 => 'zwölf',
+ 13 => 'dreizehn',
+ 14 => 'vierzehn',
+ 15 => 'fünfzehn',
+ 16 => 'sechzehn',
+ 17 => 'siebzehn',
+ 18 => 'achtzehn',
+ 19 => 'neunzehn',
+ 20 => 'zwanzig',
+ 30 => 'dreissig',
+ 40 => 'vierzig',
+ 50 => 'fünfzig',
+ 60 => 'sechzig',
+ 70 => 'siebzig',
+ 80 => 'achtzig',
+ 90 => 'neunzig',
+ 10**2 => 'hundert',
+ 10**3 => 'tausend',
+ 10**6 => 'million',
+ 10**9 => 'milliarde',
+ 10**12 => 'billion'
+ );
+
+}
+
+
+sub num2text {
+ my ($self, $amount) = @_;
+
+ return $self->{numbername}{0} unless $amount;
+
+ my @textnumber = ();
+
+ # split amount into chunks of 3
+ my @num = reverse split //, $amount;
+ my @numblock = ();
+ my ($i, $appendn);
+ my @a = ();
+
+ while (@num) {
+ @a = ();
+ for (1 .. 3) {
+ push @a, shift @num;
+ }
+ push @numblock, join / /, reverse @a;
+ }
+
+ my $belowhundred = !$#numblock;
+
+ while (@numblock) {
+
+ $i = $#numblock;
+ @num = split //, $numblock[$i];
+ $appendn = "";
+
+ $numblock[$i] *= 1;
+
+ if ($numblock[$i] == 0) {
+ pop @numblock;
+ next;
+ }
+
+ if ($numblock[$i] > 99) {
+ # the one from hundreds
+ push @textnumber, $self->{numbername}{$num[0]};
+
+ # add hundred designation
+ push @textnumber, $self->{numbername}{10**2};
+
+ # reduce numblock
+ $numblock[$i] -= $num[0] * 100;
+ }
+
+ $appendn = 'en' if ($i == 2);
+ $appendn = 'n' if ($i > 2);
+
+ if ($numblock[$i] > 9) {
+ # tens
+ push @textnumber, $self->format_ten($numblock[$i], $belowhundred);
+ } elsif ($numblock[$i] > 1) {
+ # ones
+ push @textnumber, $self->{numbername}{$numblock[$i]};
+ } elsif ($numblock[$i] == 1) {
+ if ($i == 0) {
+ push @textnumber, $self->{numbername}{$numblock[$i]}.'s';
+ } else {
+ if ($i >= 2) {
+ push @textnumber, $self->{numbername}{$numblock[$i]}.'e';
+ } else {
+ push @textnumber, $self->{numbername}{$numblock[$i]};
+ }
+ }
+ $appendn = "";
+ }
+
+ # add thousand, million
+ if ($i) {
+ $amount = 10**($i * 3);
+ push @textnumber, $self->{numbername}{$amount}.$appendn;
+ }
+
+ pop @numblock;
+
+ }
+
+ join '', @textnumber;
+
+}
+
+
+sub format_ten {
+ my ($self, $amount, $belowhundred) = @_;
+
+ my $textnumber = "";
+ my @num = split //, $amount;
+
+ if ($amount > 20) {
+ if ($num[1] == 0) {
+ $textnumber = $self->{numbername}{$amount};
+ } else {
+ if ($belowhundred) {
+ $amount = $num[0] * 10;
+ $textnumber = $self->{numbername}{$num[1]}.'und'.$self->{numbername}{$amount};
+ } else {
+ $amount = $num[0] * 10;
+ $textnumber = $self->{numbername}{$amount}.$self->{numbername}{$num[1]};
+ $textnumber .= 's' if ($num[1] == 1);
+ }
+ }
+ } else {
+ $textnumber = $self->{numbername}{$amount};
+ }
+
+ $textnumber;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/locale/de/admin b/sql-ledger/locale/de/admin
new file mode 100644
index 0000000..f41796d
--- /dev/null
+++ b/sql-ledger/locale/de/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Zugriffkontrolle',
+ 'Accounting' => 'Buchhaltung',
+ 'Add User' => 'Benutzer anlegen',
+ 'Address' => 'Adresse',
+ 'Administration' => 'Administration',
+ 'Administrator' => 'Verwalter',
+ 'All Datasets up to date!' => 'Alle Datenbanken sind auf aktuellem Stand.',
+ 'Change Admin Password' => 'Administratorpasswort ändern',
+ 'Change Password' => 'Passwort ändern',
+ 'Character Set' => 'Zeichensatz',
+ 'Click on login name to edit!' => 'Zum Bearbeiten den Zugriffs-Namen anklicken!',
+ 'Company' => 'Firma',
+ 'Connect to' => 'Als Vorlage verwenden',
+ 'Continue' => 'Weiter',
+ 'Create Chart of Accounts' => 'Kontenplan anlegen',
+ 'Create Dataset' => 'Datenbank anlegen',
+ 'DBI not installed!' => 'DBI ist nicht installiert!',
+ 'Database' => 'Datenbank',
+ 'Database Administration' => 'Datenbank Administration',
+ 'Database Driver not checked!' => 'Kein Datenbank-Treiber ausgewählt!',
+ 'Database User missing!' => 'Datenbank Benutzer fehlt!',
+ 'Dataset' => 'Datenbank',
+ 'Dataset missing!' => 'Datenbank fehlt!',
+ 'Dataset updated!' => 'Datenbank erneuert!',
+ 'Date Format' => 'Datumsformat',
+ 'Delete' => 'Löschen',
+ 'Delete Dataset' => 'Datenbank löschen',
+ 'Directory' => 'Verzeichnis',
+ 'Driver' => 'Treiber',
+ 'Dropdown Limit' => 'Auswahllistenbegrenzung',
+ 'E-mail' => 'eMail',
+ 'Edit User' => 'Benutzerdaten bearbeiten',
+ 'Existing Datasets' => 'Existierende Datenbanken',
+ 'Fax' => 'Fax',
+ 'Host' => 'Datenbank-Rechner',
+ 'Hostname missing!' => 'Rechnername fehlt!',
+ 'Incorrect Password!' => 'Ungültiges Passwort!',
+ 'Language' => 'Sprache',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Für lokale Verbindungen "Rechner" und "Port" freilassen.',
+ 'Login' => 'Anmelden',
+ 'Multibyte Encoding' => 'Muiltibyte Encoding',
+ 'Name' => 'Name',
+ 'New Templates' => 'Neue Vorlagen',
+ 'No Database Drivers available!' => 'Kein Datenbank-Treiber verfügbar!',
+ 'No Dataset selected!' => 'Keine Datenbank ausgewählt!',
+ 'Nothing to delete!' => 'Es konnte nichts gelöscht werden!',
+ 'Number Format' => 'Zahlenformat',
+ 'Oracle Database Administration' => 'Oracle Datenbank Administration',
+ 'Password' => 'Passwort',
+ 'Password changed!' => 'Passwort geändert!',
+ 'Pg Database Administration' => 'Pg Datenbank Administration',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Portangabe fehlt!',
+ 'Printer' => 'Drucker',
+ 'Save' => 'Speichern',
+ 'Select a Dataset to delete and press "Continue"' => 'Wählen Sie eine Datenbank und klicken Sie auf "Weiter"',
+ 'Setup Templates' => 'Vorlagen auswählen',
+ 'Ship via' => 'Transportmittel',
+ 'Signature' => 'Unterschrift',
+ 'Stylesheet' => 'Stilvorlage',
+ 'Templates' => 'Vorlagen',
+ 'The following Datasets are not in use and can be deleted' => 'Die folgenden Datenbanken sind nicht in Verwendung und können gelöscht werden',
+ 'The following Datasets need to be updated' => 'Folgende Datenbanken müssen aktualisiert werden',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'In diesem Schritt werden bestehende Datenbanken gesucht. Es werden noch keine Änderungen vorgenommen!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Um einer Gruppe einen neuen Benutzer hinzuzufügen, ändern und speichern Sie am einfachsten einen bestehenden Zugriffsnamen. Unter dem neuen Namen wird dann ein Benutzer mit denselben Einstellungen angelegt.',
+ 'Update Dataset' => 'Datenbank aktualisieren',
+ 'Use Templates' => 'Benutze Vorlagen',
+ 'User' => 'Benutzer',
+ 'User deleted!' => 'Benutzer gelöscht!',
+ 'User saved!' => 'Benutzer gespeichert!',
+ 'Version' => 'Version',
+ 'You must enter a host and port for local and remote connections!' => '"Rechner" und "Port" müssen für lokale und externe Verbindungen eingetragen werden!',
+ 'does not exist' => 'existiert nicht',
+ 'is already a member!' => 'ist bereits ein Mitglied!',
+ 'localhost' => 'lokaler Rechner',
+ 'locked!' => 'gesperrt!',
+ 'successfully created!' => 'wurde erfolgreich erstellt',
+ 'successfully deleted!' => 'wurde erfolgreich gelöscht',
+ 'website' => 'Website',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'benutzer_anlegen' => 'add_user',
+ 'administratorpasswort_ändern' => 'change_admin_password',
+ 'passwort_ändern' => 'change_password',
+ 'weiter' => 'continue',
+ 'datenbank_anlegen' => 'create_dataset',
+ 'löschen' => 'delete',
+ 'datenbank_löschen' => 'delete_dataset',
+ 'anmelden' => 'login',
+ 'oracle_datenbank_administration' => 'oracle_database_administration',
+ 'pg_datenbank_administration' => 'pg_database_administration',
+ 'speichern' => 'save',
+ 'datenbank_aktualisieren' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/de/all b/sql-ledger/locale/de/all
new file mode 100644
index 0000000..7e1d9b4
--- /dev/null
+++ b/sql-ledger/locale/de/all
@@ -0,0 +1,499 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Verbindlichkeiten',
+ 'AP Aging' => 'Offene Verbindl.',
+ 'AP Transaction' => 'Eingangsbuchung',
+ 'AP Transactions' => 'Eingangsbuchungen',
+ 'AR' => 'Forderungen',
+ 'AR Aging' => 'Offene Forderungen',
+ 'AR Transaction' => 'Ausgangsbuchung',
+ 'AR Transactions' => 'Ausgangsbuchungen',
+ 'About' => 'Über',
+ 'Access Control' => 'Zugriffkontrolle',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Kontonummer',
+ 'Account Number missing!' => 'Kontonummer fehlt!',
+ 'Account Type' => 'Kontoart',
+ 'Account Type missing!' => 'Kontoart fehlt!',
+ 'Account deleted!' => 'Konto gelöscht!',
+ 'Account saved!' => 'Konto gespeichert!',
+ 'Accounting' => 'Buchhaltung',
+ 'Accounting Menu' => 'Kontoverwaltung',
+ 'Accounts' => 'Konten',
+ 'Active' => 'Aktiv',
+ 'Add' => 'Hinzufügen',
+ 'Add Account' => 'Konto anlegen',
+ 'Add Accounts Payables Transaction' => 'Eingangsbuchung anlegen',
+ 'Add Accounts Receivables Transaction' => 'Ausgangsbuchung anlegen',
+ 'Add Assembly' => 'Erzeugnis anlegen',
+ 'Add Customer' => 'Kunde anlegen',
+ 'Add GIFI' => 'GIFI anlegen',
+ 'Add General Ledger Transaction' => 'Hinzufügen einer Buchung zum Hauptbuch',
+ 'Add Group' => 'Gruppe anlegen',
+ 'Add Part' => 'Ware anlegen',
+ 'Add Project' => 'Projekt anlegen',
+ 'Add Purchase Order' => 'Einkaufsbeleg anlegen',
+ 'Add Sales Invoice' => 'Ausgangsrechnung anlegen',
+ 'Add Sales Order' => 'Verkaufsbeleg anlegen',
+ 'Add Service' => 'Dienstleistung anlegen',
+ 'Add Transaction' => 'Buchung anlegen',
+ 'Add User' => 'Benutzer anlegen',
+ 'Add Vendor' => 'Lieferant anlegen',
+ 'Add Vendor Invoice' => 'Einkaufsrechnung anlegen',
+ 'Address' => 'Adresse',
+ 'Administration' => 'Administration',
+ 'Administrator' => 'Verwalter',
+ 'All' => 'Alle',
+ 'All Datasets up to date!' => 'Alle Datenbanken sind auf aktuellem Stand.',
+ 'Amount' => 'Betrag',
+ 'Amount Due' => 'Betrag fällig',
+ 'Amount does not equal applied!' => 'Betrag stimmt nicht überein!',
+ 'Amount missing!' => 'Betrag fehlt!',
+ 'Applied' => 'Ausgewählt',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Invoice Number' => 'Soll die Rechnung mit folgender Nummer wirklich gelöscht werden:',
+ 'Are you sure you want to delete Order Number' => 'Soll die Bestellung mit folgender Nummer wirklich gelöscht werden:',
+ 'Are you sure you want to delete Transaction' => 'Buchung wirklich löschen?',
+ 'Assemblies' => 'Erzeugnisse',
+ 'Assemblies restocked!' => 'Erzeugnisse sind im Lager!',
+ 'Assembly Number missing!' => 'Erzeugnisnummer fehlt!',
+ 'Asset' => 'Aktiva/Mittelverwendung',
+ 'Attachment' => 'als Anhang',
+ 'Audit Control' => 'Bücherkontrolle',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'BOM' => 'Stückliste',
+ 'Backup' => 'Sicherung',
+ 'Backup sent to' => 'Eine Sicherungskopie wurde gesandt an',
+ 'Balance' => 'Bilanz',
+ 'Balance Sheet' => 'Bilanz',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Stellage',
+ 'Books are open' => 'Die Bücher sind geöffnet.',
+ 'Bought' => 'Gekauft',
+ 'Business Number' => 'Firmennummer',
+ 'C' => 'G',
+ 'COGS' => 'Umsatzkosten',
+ 'Cannot delete account!' => 'Konto kann nicht gelöscht werden!',
+ 'Cannot delete customer!' => 'Kunde kann nicht gelöscht werden!',
+ 'Cannot delete default account!' => 'Das Standard-Konto kann nicht gelöscht werden!',
+ 'Cannot delete invoice!' => 'Rechnung kann nicht gelöscht werden!',
+ 'Cannot delete item!' => 'Artikel kann nicht gelöscht werden!',
+ 'Cannot delete order!' => 'Bestellung kann nicht gelöscht werden!',
+ 'Cannot delete transaction!' => 'Buchung kann nicht gelöscht werden!',
+ 'Cannot delete vendor!' => 'Lieferant kann nicht gelöscht werden!',
+ 'Cannot have a value in both Debit and Credit!' => 'Es kann nicht gleichzeitig Soll und Haben gebucht werden!',
+ 'Cannot post a transaction without a value!' => 'Eine Buchung ohne Betrag kann nicht verbucht werden!',
+ 'Cannot post invoice for a closed period!' => 'Das Rechnungsdatum fällt in einen abgeschlossen Zeitraum!',
+ 'Cannot post invoice!' => 'Rechnung kann nicht gebucht werden!',
+ 'Cannot post payment for a closed period!' => 'Es können keine Zahlungen für abgeschlossene Bücher gebucht werden!',
+ 'Cannot post payment!' => 'Zahlung kann nicht gebucht werden!',
+ 'Cannot post transaction for a closed period!' => 'Für einen bereits abgeschlossenen Zeitraum kann keine Buchung angelegt werden!',
+ 'Cannot post transaction!' => 'Rechnung kann nicht gebucht werden!',
+ 'Cannot process payment for a closed period!' => 'Es kann keine Zahlung in einem abgeschlossenen Zeitraum verbucht werden!',
+ 'Cannot save account!' => 'Konto kann nicht gespeichert werden!',
+ 'Cannot save order!' => 'Bestellung kann nicht gespeichert werden!',
+ 'Cannot save preferences!' => 'Benutzereinstellungen können nicht gespeichert werden!',
+ 'Cannot stock assemblies!' => 'Erzeugnisse können nicht ins Lager!',
+ 'Cash' => 'Kasse',
+ 'Cash based' => 'basierend auf Barzahlung',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => 'Administratorpasswort ändern',
+ 'Change Password' => 'Passwort ändern',
+ 'Character Set' => 'Zeichensatz',
+ 'Chart of Accounts' => 'Kontenübersicht',
+ 'Check' => 'Scheck',
+ 'Check printed!' => 'Scheck ist gedruckt!',
+ 'Check printing failed!' => 'Scheck drucken ist fehlgeschlagen!',
+ 'Cleared Balance' => 'Abgeschlossen',
+ 'Click on login name to edit!' => 'Zum Bearbeiten den Zugriffs-Namen anklicken!',
+ 'Close Books up to' => 'Die Bücher abschließen bis zum',
+ 'Closed' => 'Geschlossen',
+ 'Company' => 'Firma',
+ 'Compare to' => 'Gegenüberstellen zu',
+ 'Confirm!' => 'Bestätigen Sie!',
+ 'Connect to' => 'Als Vorlage verwenden',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Weiter',
+ 'Copies' => 'Kopien',
+ 'Copy to COA' => 'In Kontenplan kopieren',
+ 'Create Chart of Accounts' => 'Kontenplan anlegen',
+ 'Create Dataset' => 'Datenbank anlegen',
+ 'Credit' => 'Haben',
+ 'Credit Limit' => 'Kreditlimit',
+ 'Curr' => 'Währung',
+ 'Currency' => 'Währung',
+ 'Current' => 'Betrag',
+ 'Customer' => 'Kunde',
+ 'Customer deleted!' => 'Kunde gelöscht!',
+ 'Customer missing!' => 'Kundenname fehlt!',
+ 'Customer not on file!' => 'Kunde ist nicht in der Datenbank!',
+ 'Customer saved!' => 'Kunde gespeichert!',
+ 'Customers' => 'Kunden',
+ 'DBI not installed!' => 'DBI ist nicht installiert!',
+ 'Database' => 'Datenbank',
+ 'Database Administration' => 'Datenbank Administration',
+ 'Database Driver not checked!' => 'Kein Datenbank-Treiber ausgewählt!',
+ 'Database Host' => 'Datenbank-Rechner',
+ 'Database User missing!' => 'Datenbank Benutzer fehlt!',
+ 'Dataset' => 'Datenbank',
+ 'Dataset missing!' => 'Datenbank fehlt!',
+ 'Dataset updated!' => 'Datenbank erneuert!',
+ 'Date' => 'Datum',
+ 'Date Format' => 'Datumsformat',
+ 'Date Paid' => 'Zahlungsdatum',
+ 'Date missing!' => 'Datum fehlt!',
+ 'Debit' => 'Soll',
+ 'Debit and credit out of balance!' => 'Soll und Haben müssen gleich sein.',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Decimalplaces' => 'Dezimalstellen',
+ 'Delete' => 'Löschen',
+ 'Delete Account' => 'Konto löschen',
+ 'Delete Dataset' => 'Datenbank löschen',
+ 'Delivery Date' => 'Lieferung',
+ 'Deposit' => 'Gutschrift',
+ 'Description' => 'Beschreibung',
+ 'Difference' => 'Differenz',
+ 'Directory' => 'Verzeichnis',
+ 'Discount' => 'Rabatt',
+ 'Done' => 'Fertig',
+ 'Drawing' => 'Zeichnung',
+ 'Driver' => 'Treiber',
+ 'Dropdown Limit' => 'Auswahllistenbegrenzung',
+ 'Due' => 'Fällig',
+ 'Due Date' => 'Fälligkeitsdatum',
+ 'Due Date missing!' => 'Fälligkeitsdatum fehlt!',
+ 'E-mail' => 'eMail',
+ 'E-mail Statement to' => 'eMail Fälligkeitsabrechnung an',
+ 'E-mail address missing!' => 'eMail-Adresse fehlt!',
+ 'Edit' => 'Bearbeiten',
+ 'Edit Account' => 'Kontodaten bearbeiten',
+ 'Edit Accounts Payables Transaction' => 'Einkaufsbuchung bearbeiten',
+ 'Edit Accounts Receivables Transaction' => 'Ausgangsbuchung bearbeiten',
+ 'Edit Assembly' => 'Erzeugnis bearbeiten',
+ 'Edit Customer' => 'Kunde editieren',
+ 'Edit GIFI' => 'GIFI editieren',
+ 'Edit General Ledger Transaction' => 'Buchung im Hauptbuch bearbeiten',
+ 'Edit Group' => 'Gruppe editieren',
+ 'Edit Part' => 'Ware bearbeiten',
+ 'Edit Preferences for' => 'Benutzereinstellungen für',
+ 'Edit Project' => 'Projekt bearbeiten',
+ 'Edit Purchase Order' => 'Einkaufsbeleg bearbeiten',
+ 'Edit Sales Invoice' => 'Ausgangsrechnung bearbeiten',
+ 'Edit Sales Order' => 'Verkaufsbeleg bearbeiten',
+ 'Edit Service' => 'Dienstleistung bearbeiten',
+ 'Edit Template' => 'Vorlage bearbeiten',
+ 'Edit User' => 'Benutzerdaten bearbeiten',
+ 'Edit Vendor' => 'Lieferant editieren',
+ 'Edit Vendor Invoice' => 'Einkaufsrechnung bearbeiten',
+ 'Employee' => 'Bearbeiter',
+ 'Enforce transaction reversal for all dates' => 'Kontraeintragungen für jeden Zeitraum aktualisieren',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Durch Doppelpunkte getrennte Währungskürzel mit maximal 3 Buchstaben aufführen; Ihre eigene Landeswährung zuerst (z.B. EUR:USD:CAD)',
+ 'Equity' => 'Passiva/Eigenkapital',
+ 'Exch' => 'Wkurs.',
+ 'Exchangerate' => 'Wechselkurs',
+ 'Exchangerate Difference' => 'Wechselkursunterschied',
+ 'Exchangerate for payment missing!' => 'Es fehlt der Wechselkurs für die Bezahlung!',
+ 'Exchangerate missing!' => 'Es fehlt der Wechselkurs!',
+ 'Existing Datasets' => 'Existierende Datenbanken',
+ 'Expense' => 'Aufwand',
+ 'Expense Account' => 'Aufwandskonto',
+ 'Expense/Asset' => 'Aufwand/Anlagen',
+ 'Extended' => 'Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'Foreign Exchange Gain' => 'Wechselkurserträge',
+ 'Foreign Exchange Loss' => 'Wechselkursaufwendungen',
+ 'From' => 'Von',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI gelöscht!',
+ 'GIFI missing!' => 'GIFI fehlt!',
+ 'GIFI saved!' => 'GIFI gespeichert!',
+ 'GL Transaction' => 'Hauptbucheintragung',
+ 'General Ledger' => 'Hauptbuch',
+ 'Goods & Services' => 'Waren und Dienstleistungen',
+ 'Group' => 'Gruppe',
+ 'Group Items' => 'Waren gruppieren',
+ 'Group deleted!' => 'Gruppe gelöscht!',
+ 'Group missing!' => 'Gruppe fehlt!',
+ 'Group saved!' => 'Gruppe gespeichert!',
+ 'Groups' => 'Gruppen',
+ 'HTML Templates' => 'HTML Vorlagen',
+ 'Heading' => 'Überschrift',
+ 'Host' => 'Datenbank-Rechner',
+ 'Hostname missing!' => 'Rechnername fehlt!',
+ 'ID' => 'Nr.',
+ 'Image' => 'Grafik',
+ 'In-line' => 'im Textkörper (Inline)',
+ 'Include in Report' => 'In Bericht aufnehmen',
+ 'Include in drop-down menus' => 'In Aufklapp-Menü aufnehmen',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Soll dieses Konto auf dem Kunden- und Lieferantenformular angezeigt werden, um den Kunden/Lieferanten als steuerpflichtig zu markieren?',
+ 'Income' => 'Einkommen',
+ 'Income Account' => 'Einkommenkonto',
+ 'Income Statement' => 'G & V',
+ 'Incorrect Dataset version!' => 'Datenbankversion stimmt nicht überein!',
+ 'Incorrect Password!' => 'Ungültiges Passwort!',
+ 'Individual Items' => 'Einzelteile',
+ 'Inventory' => 'Inventar',
+ 'Inventory Account' => 'Warenbestand',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Bevor dieses Erzeugnis als ungültig markiert werden kann, muß das Inventar auf Null sein!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Bevor diese Ware als ungültig markiert werden kann, muß das Inventar Null sein!',
+ 'Invoice' => 'Rechnung',
+ 'Invoice Date' => 'Rechnungsdatum',
+ 'Invoice Date missing!' => 'Rechnungsdatum fehlt!',
+ 'Invoice Number' => 'Rechnungsnummer',
+ 'Invoice Number missing!' => 'Rechnungsnummer fehlt!',
+ 'Invoice deleted!' => 'Rechnung gelöscht!',
+ 'Invoice posted!' => 'Rechnung verbucht!',
+ 'Invoices' => 'Rechnungen',
+ 'Is this a summary account to record' => 'Summenkonto für',
+ 'Item deleted!' => 'Artikel gelöscht!',
+ 'Item not on file!' => 'Dieser Artikel ist nicht in der Datenbank!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'LaTeX Templates' => 'LaTeX Vorlagen',
+ 'Language' => 'Sprache',
+ 'Last Cost' => 'Letzte Kosten',
+ 'Last Invoice Number' => 'Letzte Rechnungsnummer',
+ 'Last Numbers & Default Accounts' => 'Laufende Zähler und Standardkonten',
+ 'Last Purchase Order Number' => 'Letzte Enkaufsbelegnummer',
+ 'Last Sales Order Number' => 'Letzte Verkaufsbelegnummer',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Für lokale Verbindungen "Rechner" und "Port" freilassen.',
+ 'Liability' => 'Passiva/Mittelherkunft',
+ 'Licensed to' => 'Lizensiert für',
+ 'Line Total' => 'Zeilensumme',
+ 'Link' => 'Verknüpfungen',
+ 'Link Accounts' => 'Konten verknüpfen',
+ 'List Accounts' => 'Kontenliste',
+ 'List GIFI' => 'GIFI aufzeigen',
+ 'List Price' => 'Listenpreis',
+ 'List Transactions' => 'Buchungsliste',
+ 'Login' => 'Anmelden',
+ 'Logout' => 'Abmelden',
+ 'Make' => 'Hersteller',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Message' => 'Nachricht',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Modell',
+ 'Multibyte Encoding' => 'Muiltibyte Encoding',
+ 'N/A' => 'N.Z.',
+ 'Name' => 'Name',
+ 'Name missing!' => 'Name fehlt!',
+ 'New Templates' => 'Neue Vorlagen',
+ 'No' => 'Nein',
+ 'No Database Drivers available!' => 'Kein Datenbank-Treiber verfügbar!',
+ 'No Dataset selected!' => 'Keine Datenbank ausgewählt!',
+ 'No email address for' => 'Keine eMail-Addresse für',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkungen',
+ 'Nothing applied!' => 'Sie haben nichts ausgewählt',
+ 'Nothing selected!' => 'Es wurde nichts ausgewählt!',
+ 'Nothing to delete!' => 'Es konnte nichts gelöscht werden!',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Zahlenformat',
+ 'Number missing in Row' => 'Nummer fehlt in Zeile',
+ 'O' => 'O',
+ 'Obsolete' => 'Ungültig',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'On Hand' => 'auf Lager',
+ 'On Order' => 'auf Bestellung',
+ 'Open' => 'Offen',
+ 'Oracle Database Administration' => 'Oracle Datenbank Administration',
+ 'Order' => 'Auftrag',
+ 'Order Date' => 'Auftragsdatum',
+ 'Order Date missing!' => 'Auftragsdatum fehlt!',
+ 'Order Entry' => 'Aufträge',
+ 'Order Number' => 'Auftragsnummer',
+ 'Order Number missing!' => 'Auftragsnummer fehlt!',
+ 'Order deleted!' => 'Auftrag gelöscht!',
+ 'Order saved!' => 'Auftrag gespeichert!',
+ 'Ordered' => 'Vom Kunde bestellt',
+ 'Orphaned' => 'nie benutzt',
+ 'Out of balance!' => 'Summen stimmen nicht überein!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Verpackungsliste',
+ 'Packing List Date missing!' => 'Datum für Verpackungsliste fehlt!',
+ 'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
+ 'Paid' => 'Bezahlt',
+ 'Paid in full' => 'Voll bezahlt',
+ 'Part' => 'Ware',
+ 'Part Number missing!' => 'Warennummer fehlt!',
+ 'Parts' => 'Waren',
+ 'Parts Inventory' => 'Warenliste',
+ 'Password' => 'Passwort',
+ 'Password changed!' => 'Passwort geändert!',
+ 'Payables' => 'Verbindlichkeiten',
+ 'Payment' => 'Zahlung',
+ 'Payment date missing!' => 'Tag der Zahlung fehlt!',
+ 'Payment posted!' => 'Zahlung gebucht!',
+ 'Payments' => 'Zahlungen',
+ 'Pg Database Administration' => 'Pg Datenbank Administration',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Portangabe fehlt!',
+ 'Post' => 'Buchen',
+ 'Post as new' => 'Neu buchen',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Benutzereinstellungen',
+ 'Preferences saved!' => 'Einstellungen gespeichert!',
+ 'Price' => 'Preis',
+ 'Print' => 'Drucken',
+ 'Printer' => 'Drucker',
+ 'Project' => 'Projekt',
+ 'Project Number' => 'Projektnummer',
+ 'Project Number missing!' => 'Projektnummer fehlt!',
+ 'Project deleted!' => 'Projekt gelöscht!',
+ 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
+ 'Project saved!' => 'Projekt gespeichert!',
+ 'Projects' => 'Projekte',
+ 'Purchase Order' => 'Einkaufsbeleg',
+ 'Purchase Orders' => 'Einkaufsbelege',
+ 'Qty' => 'Anz',
+ 'ROP' => 'UAB',
+ 'Rate' => 'Rate',
+ 'Recd' => 'Erh',
+ 'Receipt' => 'Quittung',
+ 'Receipt printed!' => 'Quittung gedruckt!',
+ 'Receipt printing failed!' => 'Quittung konnte nicht gedruckt werden!',
+ 'Receipts' => 'Quittungen',
+ 'Receivables' => 'Forderungen',
+ 'Reconciliation' => 'Abgleichung',
+ 'Record in' => 'Buchen auf',
+ 'Reference' => 'Referenz',
+ 'Reference missing!' => 'Referenz fehlt!',
+ 'Remaining' => 'Rest',
+ 'Report for' => 'Bericht für',
+ 'Reports' => 'Berichte',
+ 'Required by' => 'Erforderlich am',
+ 'Retained Earnings' => 'Verbliebenes Einkommen',
+ 'Sales' => 'Warenverkauf',
+ 'Sales Invoice' => 'Ausgangsrechnung',
+ 'Sales Order' => 'Verkaufsbeleg',
+ 'Sales Orders' => 'Verkaufsbelege',
+ 'Salesperson' => 'Verkaufsperson',
+ 'Save' => 'Speichern',
+ 'Save as new' => 'als neu speichern',
+ 'Save to File' => 'Auf Festplatte speichern',
+ 'Screen' => 'Bildschirm',
+ 'Select a Dataset to delete and press "Continue"' => 'Wählen Sie eine Datenbank und klicken Sie auf "Weiter"',
+ 'Select all' => 'Alle auswählen',
+ 'Select from one of the items below' => 'Wählen Sie einen der untenstehenden Einträge',
+ 'Select from one of the names below' => 'Wählen Sie einen der untenstehenden Namen',
+ 'Select from one of the projects below' => 'Wählen Sie eines der untenstehenden Projekte',
+ 'Select postscript or PDF!' => 'Postscript oder PDF auswählen!',
+ 'Sell Price' => 'Verkaufspreis',
+ 'Send by E-Mail' => 'Per eMail schicken',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienstleistung',
+ 'Service Items' => 'Dienstleistungen',
+ 'Service Number missing!' => 'Dienstleistungsnummer fehlt!',
+ 'Services' => 'Leistungen',
+ 'Setup Templates' => 'Vorlagen auswählen',
+ 'Ship' => 'Versand',
+ 'Ship to' => 'Verschicken an',
+ 'Ship via' => 'Transportmittel',
+ 'Short' => 'Kurz',
+ 'Signature' => 'Unterschrift',
+ 'Sold' => 'Verkauft',
+ 'Source' => 'Beleg',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Sammelrechnung',
+ 'Statement Balance' => 'Sammelrechnungsbilanz',
+ 'Statement sent to' => 'Sammelrechnung verschickt an',
+ 'Statements sent to printer!' => 'Sammelrechnungen an Drucker geschickt!',
+ 'Stock' => 'einlagern',
+ 'Stock Assembly' => 'Erzeugnis einlagern',
+ 'Stylesheet' => 'Stilvorlage',
+ 'Subject' => 'Betreff',
+ 'Subtotal' => 'Zwischensumme',
+ 'System' => 'System',
+ 'Tax' => 'Steuer',
+ 'Tax Accounts' => 'Steuerkonto',
+ 'Tax Included' => 'Steuer im Preis inbegriffen',
+ 'Tax collected' => 'vereinnahmte Steuer',
+ 'Tax paid' => 'Vorsteuer',
+ 'Taxable' => 'Steuerpflichtig',
+ 'Template saved!' => 'Schablone gespeichert!',
+ 'Templates' => 'Vorlagen',
+ 'Terms: Net' => 'Zahlungsziel',
+ 'The following Datasets are not in use and can be deleted' => 'Die folgenden Datenbanken sind nicht in Verwendung und können gelöscht werden',
+ 'The following Datasets need to be updated' => 'Folgende Datenbanken müssen aktualisiert werden',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'In diesem Schritt werden bestehende Datenbanken gesucht. Es werden noch keine Änderungen vorgenommen!',
+ 'To' => 'An',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Um einer Gruppe einen neuen Benutzer hinzuzufügen, ändern und speichern Sie am einfachsten einen bestehenden Zugriffsnamen. Unter dem neuen Namen wird dann ein Benutzer mit denselben Einstellungen angelegt.',
+ 'Top Level' => 'Hauptbeschreibung',
+ 'Total' => 'Summe',
+ 'Transaction Date missing!' => 'Buchungsdatum fehlt!',
+ 'Transaction deleted!' => 'Buchung gelöscht!',
+ 'Transaction posted!' => 'Buchung verbucht!',
+ 'Transaction reversal enforced for all dates' => 'Fehleintragungen müssen für jeden Zeitraum mit einer Kontraeintragung ausgebessert werden',
+ 'Transaction reversal enforced up to' => 'Fehleintragungen können bis zu dem angenebenen Zeitraum nur mit einer Kontraeintragung ausgebessert werden',
+ 'Transactions' => 'Buchungen',
+ 'Transactions exist, cannot delete customer!' => 'Der Kunde kann nicht gelöscht werden, da Buchungen vorhanden sind!',
+ 'Transactions exist, cannot delete vendor!' => 'Der Lieferant kann nicht gelöscht werden, da Buchungen vorhanden sind!',
+ 'Transactions exist; cannot delete account!' => 'Das Konto kann nicht gelöscht werden, da es Buchungen enthält!',
+ 'Trial Balance' => 'Vergleichsbilanz',
+ 'Unit' => 'Einh',
+ 'Unit of measure' => 'Maßeinheit',
+ 'Update' => 'Erneuern',
+ 'Update Dataset' => 'Datenbank aktualisieren',
+ 'Updated' => 'Erneuert am',
+ 'Use Templates' => 'Benutze Vorlagen',
+ 'User' => 'Benutzer',
+ 'User deleted!' => 'Benutzer gelöscht!',
+ 'User saved!' => 'Benutzer gespeichert!',
+ 'Vendor' => 'Lieferant',
+ 'Vendor Invoice' => 'Einkaufsrechnung',
+ 'Vendor deleted!' => 'Lieferant gelöscht!',
+ 'Vendor missing!' => 'Lieferant fehlt!',
+ 'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
+ 'Vendor saved!' => 'Lieferant gespeichert!',
+ 'Vendors' => 'Lieferanten',
+ 'Version' => 'Version',
+ 'Weight' => 'Gewicht',
+ 'Weight Unit' => 'Gewichtseinh.',
+ 'What type of item is this?' => 'Was ist dieser Artikel?',
+ 'Year End' => 'Jahresende',
+ 'Yes' => 'Ja',
+ 'You are logged out!' => 'Auf wiedersehen!',
+ 'You did not enter a name!' => 'Sie haben keinen Namen eingegeben!',
+ 'You must enter a host and port for local and remote connections!' => '"Rechner" und "Port" müssen für lokale und externe Verbindungen eingetragen werden!',
+ 'as at' => 'zum Stand',
+ 'collected on sales' => 'erhalten durch Verkäufe',
+ 'days' => 'Tage',
+ 'does not exist' => 'existiert nicht',
+ 'ea' => 'pro',
+ 'emailed to' => 'gemailt an',
+ 'for Period' => 'für den Zeitraum',
+ 'hr' => 'Std',
+ 'is already a member!' => 'ist bereits ein Mitglied!',
+ 'is not a member!' => 'ist kein Mitglied!',
+ 'localhost' => 'lokaler Rechner',
+ 'locked!' => 'gesperrt!',
+ 'paid on purchases' => 'gezahlt durch Einkäufe',
+ 'sent to printer' => 'an Drucker geschickt',
+ 'successfully created!' => 'wurde erfolgreich erstellt',
+ 'successfully deleted!' => 'wurde erfolgreich gelöscht',
+ 'to' => 'bis',
+ 'website' => 'Website',
+};
+
+1;
diff --git a/sql-ledger/locale/de/am b/sql-ledger/locale/de/am
new file mode 100644
index 0000000..9b93287
--- /dev/null
+++ b/sql-ledger/locale/de/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Verbindlichkeiten',
+ 'AR' => 'Forderungen',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Kontonummer',
+ 'Account Number missing!' => 'Kontonummer fehlt!',
+ 'Account Type' => 'Kontoart',
+ 'Account Type missing!' => 'Kontoart fehlt!',
+ 'Account deleted!' => 'Konto gelöscht!',
+ 'Account saved!' => 'Konto gespeichert!',
+ 'Add Account' => 'Konto anlegen',
+ 'Add GIFI' => 'GIFI anlegen',
+ 'Address' => 'Adresse',
+ 'Asset' => 'Aktiva/Mittelverwendung',
+ 'Audit Control' => 'Bücherkontrolle',
+ 'Backup sent to' => 'Eine Sicherungskopie wurde gesandt an',
+ 'Books are open' => 'Die Bücher sind geöffnet.',
+ 'Business Number' => 'Firmennummer',
+ 'COGS' => 'Umsatzkosten',
+ 'Cannot delete account!' => 'Konto kann nicht gelöscht werden!',
+ 'Cannot delete default account!' => 'Das Standard-Konto kann nicht gelöscht werden!',
+ 'Cannot save account!' => 'Konto kann nicht gespeichert werden!',
+ 'Cannot save preferences!' => 'Benutzereinstellungen können nicht gespeichert werden!',
+ 'Character Set' => 'Zeichensatz',
+ 'Chart of Accounts' => 'Kontenübersicht',
+ 'Close Books up to' => 'Die Bücher abschließen bis zum',
+ 'Company' => 'Firma',
+ 'Continue' => 'Weiter',
+ 'Copy to COA' => 'In Kontenplan kopieren',
+ 'Credit' => 'Haben',
+ 'Date Format' => 'Datumsformat',
+ 'Debit' => 'Soll',
+ 'Delete' => 'Löschen',
+ 'Delete Account' => 'Konto löschen',
+ 'Description' => 'Beschreibung',
+ 'Dropdown Limit' => 'Auswahllistenbegrenzung',
+ 'E-mail' => 'eMail',
+ 'Edit' => 'Bearbeiten',
+ 'Edit Account' => 'Kontodaten bearbeiten',
+ 'Edit GIFI' => 'GIFI editieren',
+ 'Edit Preferences for' => 'Benutzereinstellungen für',
+ 'Edit Template' => 'Vorlage bearbeiten',
+ 'Enforce transaction reversal for all dates' => 'Kontraeintragungen für jeden Zeitraum aktualisieren',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Durch Doppelpunkte getrennte Währungskürzel mit maximal 3 Buchstaben aufführen; Ihre eigene Landeswährung zuerst (z.B. EUR:USD:CAD)',
+ 'Equity' => 'Passiva/Eigenkapital',
+ 'Expense' => 'Aufwand',
+ 'Expense Account' => 'Aufwandskonto',
+ 'Expense/Asset' => 'Aufwand/Anlagen',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Wechselkurserträge',
+ 'Foreign Exchange Loss' => 'Wechselkursaufwendungen',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI gelöscht!',
+ 'GIFI missing!' => 'GIFI fehlt!',
+ 'GIFI saved!' => 'GIFI gespeichert!',
+ 'Heading' => 'Überschrift',
+ 'Include in drop-down menus' => 'In Aufklapp-Menü aufnehmen',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Soll dieses Konto auf dem Kunden- und Lieferantenformular angezeigt werden, um den Kunden/Lieferanten als steuerpflichtig zu markieren?',
+ 'Income' => 'Einkommen',
+ 'Income Account' => 'Einkommenkonto',
+ 'Inventory' => 'Inventar',
+ 'Inventory Account' => 'Warenbestand',
+ 'Is this a summary account to record' => 'Summenkonto für',
+ 'Language' => 'Sprache',
+ 'Last Invoice Number' => 'Letzte Rechnungsnummer',
+ 'Last Numbers & Default Accounts' => 'Laufende Zähler und Standardkonten',
+ 'Last Purchase Order Number' => 'Letzte Enkaufsbelegnummer',
+ 'Last Sales Order Number' => 'Letzte Verkaufsbelegnummer',
+ 'Liability' => 'Passiva/Mittelherkunft',
+ 'Link' => 'Verknüpfungen',
+ 'Name' => 'Name',
+ 'No' => 'Nein',
+ 'No email address for' => 'Keine eMail-Addresse für',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Zahlenformat',
+ 'Parts Inventory' => 'Warenliste',
+ 'Password' => 'Passwort',
+ 'Payables' => 'Verbindlichkeiten',
+ 'Payment' => 'Zahlung',
+ 'Phone' => 'Tel.',
+ 'Preferences saved!' => 'Einstellungen gespeichert!',
+ 'Rate' => 'Rate',
+ 'Receivables' => 'Forderungen',
+ 'Sales' => 'Warenverkauf',
+ 'Save' => 'Speichern',
+ 'Service Items' => 'Dienstleistungen',
+ 'Ship via' => 'Transportmittel',
+ 'Signature' => 'Unterschrift',
+ 'Stylesheet' => 'Stilvorlage',
+ 'Tax' => 'Steuer',
+ 'Tax Accounts' => 'Steuerkonto',
+ 'Template saved!' => 'Schablone gespeichert!',
+ 'Transaction reversal enforced for all dates' => 'Fehleintragungen müssen für jeden Zeitraum mit einer Kontraeintragung ausgebessert werden',
+ 'Transaction reversal enforced up to' => 'Fehleintragungen können bis zu dem angenebenen Zeitraum nur mit einer Kontraeintragung ausgebessert werden',
+ 'Transactions exist; cannot delete account!' => 'Das Konto kann nicht gelöscht werden, da es Buchungen enthält!',
+ 'Weight Unit' => 'Gewichtseinh.',
+ 'Year End' => 'Jahresende',
+ 'Yes' => 'Ja',
+ 'does not exist' => 'existiert nicht',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'konto_anlegen' => 'add_account',
+ 'weiter' => 'continue',
+ 'in_kontenplan_kopieren' => 'copy_to_coa',
+ 'löschen' => 'delete',
+ 'bearbeiten' => 'edit',
+ 'kontodaten_bearbeiten' => 'edit_account',
+ 'speichern' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/de/ap b/sql-ledger/locale/de/ap
new file mode 100644
index 0000000..59a6d47
--- /dev/null
+++ b/sql-ledger/locale/de/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Eingangsbuchung',
+ 'AP Transactions' => 'Eingangsbuchungen',
+ 'Account' => 'Konto',
+ 'Add Accounts Payables Transaction' => 'Eingangsbuchung anlegen',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Betrag',
+ 'Amount Due' => 'Betrag fällig',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Transaction' => 'Buchung wirklich löschen?',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Cannot delete transaction!' => 'Buchung kann nicht gelöscht werden!',
+ 'Cannot post payment for a closed period!' => 'Es können keine Zahlungen für abgeschlossene Bücher gebucht werden!',
+ 'Cannot post transaction for a closed period!' => 'Für einen bereits abgeschlossenen Zeitraum kann keine Buchung angelegt werden!',
+ 'Cannot post transaction!' => 'Rechnung kann nicht gebucht werden!',
+ 'Closed' => 'Geschlossen',
+ 'Confirm!' => 'Bestätigen Sie!',
+ 'Continue' => 'Weiter',
+ 'Currency' => 'Währung',
+ 'Customer not on file!' => 'Kunde ist nicht in der Datenbank!',
+ 'Date' => 'Datum',
+ 'Date Paid' => 'Zahlungsdatum',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Delete' => 'Löschen',
+ 'Description' => 'Beschreibung',
+ 'Due Date' => 'Fälligkeitsdatum',
+ 'Due Date missing!' => 'Fälligkeitsdatum fehlt!',
+ 'Edit Accounts Payables Transaction' => 'Einkaufsbuchung bearbeiten',
+ 'Employee' => 'Bearbeiter',
+ 'Exch' => 'Wkurs.',
+ 'Exchangerate' => 'Wechselkurs',
+ 'Exchangerate for payment missing!' => 'Es fehlt der Wechselkurs für die Bezahlung!',
+ 'Exchangerate missing!' => 'Es fehlt der Wechselkurs!',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'From' => 'Von',
+ 'ID' => 'Nr.',
+ 'Include in Report' => 'In Bericht aufnehmen',
+ 'Invoice' => 'Rechnung',
+ 'Invoice Date' => 'Rechnungsdatum',
+ 'Invoice Date missing!' => 'Rechnungsdatum fehlt!',
+ 'Invoice Number' => 'Rechnungsnummer',
+ 'Invoice Number missing!' => 'Rechnungsnummer fehlt!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Notes' => 'Bemerkungen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Open' => 'Offen',
+ 'Order' => 'Auftrag',
+ 'Order Number' => 'Auftragsnummer',
+ 'Paid' => 'Bezahlt',
+ 'Payment date missing!' => 'Tag der Zahlung fehlt!',
+ 'Payments' => 'Zahlungen',
+ 'Post' => 'Buchen',
+ 'Post as new' => 'Neu buchen',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
+ 'Select from one of the names below' => 'Wählen Sie einen der untenstehenden Namen',
+ 'Select from one of the projects below' => 'Wählen Sie eines der untenstehenden Projekte',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Beleg',
+ 'Subtotal' => 'Zwischensumme',
+ 'Tax' => 'Steuer',
+ 'Tax Included' => 'Steuer im Preis inbegriffen',
+ 'Total' => 'Summe',
+ 'Transaction deleted!' => 'Buchung gelöscht!',
+ 'Transaction posted!' => 'Buchung verbucht!',
+ 'Update' => 'Erneuern',
+ 'Vendor' => 'Lieferant',
+ 'Vendor Invoice' => 'Einkaufsrechnung',
+ 'Vendor missing!' => 'Lieferant fehlt!',
+ 'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
+ 'Yes' => 'Ja',
+ 'to' => 'bis',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'eingangsbuchung' => 'ap_transaction',
+ 'eingangsbuchung_anlegen' => 'add_accounts_payables_transaction',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'einkaufsbuchung_bearbeiten' => 'edit_accounts_payables_transaction',
+ 'buchen' => 'post',
+ 'neu_buchen' => 'post_as_new',
+ 'erneuern' => 'update',
+ 'einkaufsrechnung' => 'vendor_invoice',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/de/ar b/sql-ledger/locale/de/ar
new file mode 100644
index 0000000..741bc92
--- /dev/null
+++ b/sql-ledger/locale/de/ar
@@ -0,0 +1,134 @@
+$self{texts} = {
+ 'AR Transaction' => 'Ausgangsbuchung',
+ 'AR Transactions' => 'Ausgangsbuchungen',
+ 'Account' => 'Konto',
+ 'Add Accounts Receivables Transaction' => 'Ausgangsbuchung anlegen',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Betrag',
+ 'Amount Due' => 'Betrag fällig',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Transaction' => 'Buchung wirklich löschen?',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Cannot delete transaction!' => 'Buchung kann nicht gelöscht werden!',
+ 'Cannot post payment for a closed period!' => 'Es können keine Zahlungen für abgeschlossene Bücher gebucht werden!',
+ 'Cannot post transaction for a closed period!' => 'Für einen bereits abgeschlossenen Zeitraum kann keine Buchung angelegt werden!',
+ 'Cannot post transaction!' => 'Rechnung kann nicht gebucht werden!',
+ 'Closed' => 'Geschlossen',
+ 'Confirm!' => 'Bestätigen Sie!',
+ 'Continue' => 'Weiter',
+ 'Credit Limit' => 'Kreditlimit',
+ 'Currency' => 'Währung',
+ 'Customer' => 'Kunde',
+ 'Customer missing!' => 'Kundenname fehlt!',
+ 'Customer not on file!' => 'Kunde ist nicht in der Datenbank!',
+ 'Date' => 'Datum',
+ 'Date Paid' => 'Zahlungsdatum',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Delete' => 'Löschen',
+ 'Description' => 'Beschreibung',
+ 'Due Date' => 'Fälligkeitsdatum',
+ 'Due Date missing!' => 'Fälligkeitsdatum fehlt!',
+ 'Edit Accounts Receivables Transaction' => 'Ausgangsbuchung bearbeiten',
+ 'Exch' => 'Wkurs.',
+ 'Exchangerate' => 'Wechselkurs',
+ 'Exchangerate for payment missing!' => 'Es fehlt der Wechselkurs für die Bezahlung!',
+ 'Exchangerate missing!' => 'Es fehlt der Wechselkurs!',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'From' => 'Von',
+ 'ID' => 'Nr.',
+ 'Include in Report' => 'In Bericht aufnehmen',
+ 'Invoice' => 'Rechnung',
+ 'Invoice Date' => 'Rechnungsdatum',
+ 'Invoice Date missing!' => 'Rechnungsdatum fehlt!',
+ 'Invoice Number' => 'Rechnungsnummer',
+ 'Invoice Number missing!' => 'Rechnungsnummer fehlt!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Notes' => 'Bemerkungen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Open' => 'Offen',
+ 'Order' => 'Auftrag',
+ 'Order Number' => 'Auftragsnummer',
+ 'Paid' => 'Bezahlt',
+ 'Payment date missing!' => 'Tag der Zahlung fehlt!',
+ 'Payments' => 'Zahlungen',
+ 'Post' => 'Buchen',
+ 'Post as new' => 'Neu buchen',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
+ 'Remaining' => 'Rest',
+ 'Sales Invoice' => 'Ausgangsrechnung',
+ 'Salesperson' => 'Verkaufsperson',
+ 'Select from one of the names below' => 'Wählen Sie einen der untenstehenden Namen',
+ 'Select from one of the projects below' => 'Wählen Sie eines der untenstehenden Projekte',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Ship via' => 'Transportmittel',
+ 'Source' => 'Beleg',
+ 'Subtotal' => 'Zwischensumme',
+ 'Tax' => 'Steuer',
+ 'Tax Included' => 'Steuer im Preis inbegriffen',
+ 'Total' => 'Summe',
+ 'Transaction deleted!' => 'Buchung gelöscht!',
+ 'Transaction posted!' => 'Buchung verbucht!',
+ 'Update' => 'Erneuern',
+ 'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
+ 'Yes' => 'Ja',
+ 'to' => 'bis',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'ausgangsbuchung' => 'ar_transaction',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'buchen' => 'post',
+ 'neu_buchen' => 'post_as_new',
+ 'ausgangsrechnung' => 'sales_invoice',
+ 'erneuern' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/de/arap b/sql-ledger/locale/de/arap
new file mode 100644
index 0000000..7070ce1
--- /dev/null
+++ b/sql-ledger/locale/de/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adresse',
+ 'Continue' => 'Weiter',
+ 'Customer not on file!' => 'Kunde ist nicht in der Datenbank!',
+ 'Description' => 'Beschreibung',
+ 'Number' => 'Nummer',
+ 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
+ 'Select from one of the names below' => 'Wählen Sie einen der untenstehenden Namen',
+ 'Select from one of the projects below' => 'Wählen Sie eines der untenstehenden Projekte',
+ 'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'weiter' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/de/ca b/sql-ledger/locale/de/ca
new file mode 100644
index 0000000..d140801
--- /dev/null
+++ b/sql-ledger/locale/de/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Balance' => 'Bilanz',
+ 'Chart of Accounts' => 'Kontenübersicht',
+ 'Credit' => 'Haben',
+ 'Date' => 'Datum',
+ 'Debit' => 'Soll',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Description' => 'Beschreibung',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'From' => 'Von',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'In Bericht aufnehmen',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'List Transactions' => 'Buchungsliste',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Reference' => 'Referenz',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Subtotal' => 'Zwischensumme',
+ 'to' => 'bis',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'buchungsliste' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/de/cp b/sql-ledger/locale/de/cp
new file mode 100644
index 0000000..125874e
--- /dev/null
+++ b/sql-ledger/locale/de/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Betrag',
+ 'Amount does not equal applied!' => 'Betrag stimmt nicht überein!',
+ 'Amount missing!' => 'Betrag fehlt!',
+ 'Applied' => 'Ausgewählt',
+ 'Cannot post payment!' => 'Zahlung kann nicht gebucht werden!',
+ 'Cannot process payment for a closed period!' => 'Es kann keine Zahlung in einem abgeschlossenen Zeitraum verbucht werden!',
+ 'Check' => 'Scheck',
+ 'Check printed!' => 'Scheck ist gedruckt!',
+ 'Check printing failed!' => 'Scheck drucken ist fehlgeschlagen!',
+ 'Continue' => 'Weiter',
+ 'Currency' => 'Währung',
+ 'Customer' => 'Kunde',
+ 'Customer not on file!' => 'Kunde ist nicht in der Datenbank!',
+ 'Date' => 'Datum',
+ 'Date missing!' => 'Datum fehlt!',
+ 'Description' => 'Beschreibung',
+ 'Due' => 'Fällig',
+ 'Exchangerate' => 'Wechselkurs',
+ 'From' => 'Von',
+ 'Invoice' => 'Rechnung',
+ 'Invoices' => 'Rechnungen',
+ 'Nothing applied!' => 'Sie haben nichts ausgewählt',
+ 'Number' => 'Nummer',
+ 'Paid in full' => 'Voll bezahlt',
+ 'Payment' => 'Zahlung',
+ 'Payment posted!' => 'Zahlung gebucht!',
+ 'Post' => 'Buchen',
+ 'Print' => 'Drucken',
+ 'Printer' => 'Drucker',
+ 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
+ 'Receipt' => 'Quittung',
+ 'Receipt printed!' => 'Quittung gedruckt!',
+ 'Receipt printing failed!' => 'Quittung konnte nicht gedruckt werden!',
+ 'Reference' => 'Referenz',
+ 'Screen' => 'Bildschirm',
+ 'Select from one of the names below' => 'Wählen Sie einen der untenstehenden Namen',
+ 'Select from one of the projects below' => 'Wählen Sie eines der untenstehenden Projekte',
+ 'Update' => 'Erneuern',
+ 'Vendor' => 'Lieferant',
+ 'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
+ 'to' => 'bis',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'weiter' => 'continue',
+ 'buchen' => 'post',
+ 'drucken' => 'print',
+ 'erneuern' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/de/ct b/sql-ledger/locale/de/ct
new file mode 100644
index 0000000..07d2607
--- /dev/null
+++ b/sql-ledger/locale/de/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Hinzufügen',
+ 'Address' => 'Adresse',
+ 'All' => 'Alle',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Kunde kann nicht gelöscht werden!',
+ 'Cannot delete vendor!' => 'Lieferant kann nicht gelöscht werden!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Weiter',
+ 'Credit Limit' => 'Kreditlimit',
+ 'Customer deleted!' => 'Kunde gelöscht!',
+ 'Customer saved!' => 'Kunde gespeichert!',
+ 'Customers' => 'Kunden',
+ 'Delete' => 'Löschen',
+ 'Discount' => 'Rabatt',
+ 'E-mail' => 'eMail',
+ 'Edit Customer' => 'Kunde editieren',
+ 'Edit Vendor' => 'Lieferant editieren',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'In Bericht aufnehmen',
+ 'Invoice' => 'Rechnung',
+ 'Name' => 'Name',
+ 'Name missing!' => 'Name fehlt!',
+ 'Notes' => 'Bemerkungen',
+ 'Number' => 'Nummer',
+ 'Order' => 'Auftrag',
+ 'Orphaned' => 'nie benutzt',
+ 'Phone' => 'Tel.',
+ 'Save' => 'Speichern',
+ 'Ship to' => 'Verschicken an',
+ 'Tax Included' => 'Steuer im Preis inbegriffen',
+ 'Taxable' => 'Steuerpflichtig',
+ 'Terms: Net' => 'Zahlungsziel',
+ 'Transactions exist, cannot delete customer!' => 'Der Kunde kann nicht gelöscht werden, da Buchungen vorhanden sind!',
+ 'Transactions exist, cannot delete vendor!' => 'Der Lieferant kann nicht gelöscht werden, da Buchungen vorhanden sind!',
+ 'Vendor deleted!' => 'Lieferant gelöscht!',
+ 'Vendor saved!' => 'Lieferant gespeichert!',
+ 'Vendors' => 'Lieferanten',
+ 'days' => 'Tage',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'hinzufügen' => 'add',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'rechnung' => 'invoice',
+ 'auftrag' => 'order',
+ 'speichern' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/de/gl b/sql-ledger/locale/de/gl
new file mode 100644
index 0000000..7163493
--- /dev/null
+++ b/sql-ledger/locale/de/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Eingangsbuchung',
+ 'AR Transaction' => 'Ausgangsbuchung',
+ 'Account' => 'Konto',
+ 'Add General Ledger Transaction' => 'Hinzufügen einer Buchung zum Hauptbuch',
+ 'Address' => 'Adresse',
+ 'All' => 'Alle',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Transaction' => 'Buchung wirklich löschen?',
+ 'Asset' => 'Aktiva/Mittelverwendung',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Balance' => 'Bilanz',
+ 'Cannot delete transaction!' => 'Buchung kann nicht gelöscht werden!',
+ 'Cannot have a value in both Debit and Credit!' => 'Es kann nicht gleichzeitig Soll und Haben gebucht werden!',
+ 'Cannot post a transaction without a value!' => 'Eine Buchung ohne Betrag kann nicht verbucht werden!',
+ 'Cannot post transaction for a closed period!' => 'Für einen bereits abgeschlossenen Zeitraum kann keine Buchung angelegt werden!',
+ 'Confirm!' => 'Bestätigen Sie!',
+ 'Continue' => 'Weiter',
+ 'Credit' => 'Haben',
+ 'Customer not on file!' => 'Kunde ist nicht in der Datenbank!',
+ 'Date' => 'Datum',
+ 'Debit' => 'Soll',
+ 'Debit and credit out of balance!' => 'Soll und Haben müssen gleich sein.',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Delete' => 'Löschen',
+ 'Description' => 'Beschreibung',
+ 'Edit General Ledger Transaction' => 'Buchung im Hauptbuch bearbeiten',
+ 'Equity' => 'Passiva/Eigenkapital',
+ 'Expense' => 'Aufwand',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'From' => 'Von',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'Hauptbucheintragung',
+ 'General Ledger' => 'Hauptbuch',
+ 'ID' => 'Nr.',
+ 'Include in Report' => 'In Bericht aufnehmen',
+ 'Income' => 'Einkommen',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Liability' => 'Passiva/Mittelherkunft',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Notes' => 'Bemerkungen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Post' => 'Buchen',
+ 'Post as new' => 'Neu buchen',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
+ 'Reference' => 'Referenz',
+ 'Reference missing!' => 'Referenz fehlt!',
+ 'Reports' => 'Berichte',
+ 'Sales Invoice' => 'Ausgangsrechnung',
+ 'Select from one of the names below' => 'Wählen Sie einen der untenstehenden Namen',
+ 'Select from one of the projects below' => 'Wählen Sie eines der untenstehenden Projekte',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Beleg',
+ 'Subtotal' => 'Zwischensumme',
+ 'Transaction Date missing!' => 'Buchungsdatum fehlt!',
+ 'Transaction deleted!' => 'Buchung gelöscht!',
+ 'Transaction posted!' => 'Buchung verbucht!',
+ 'Update' => 'Erneuern',
+ 'Vendor Invoice' => 'Einkaufsrechnung',
+ 'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
+ 'Yes' => 'Ja',
+ 'to' => 'bis',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'eingangsbuchung' => 'ap_transaction',
+ 'ausgangsbuchung' => 'ar_transaction',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'hauptbucheintragung' => 'gl_transaction',
+ 'buchen' => 'post',
+ 'neu_buchen' => 'post_as_new',
+ 'ausgangsrechnung' => 'sales_invoice',
+ 'erneuern' => 'update',
+ 'einkaufsrechnung' => 'vendor_invoice',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/de/ic b/sql-ledger/locale/de/ic
new file mode 100644
index 0000000..6fa30d1
--- /dev/null
+++ b/sql-ledger/locale/de/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Aktiv',
+ 'Add' => 'Hinzufügen',
+ 'Add Assembly' => 'Erzeugnis anlegen',
+ 'Add Part' => 'Ware anlegen',
+ 'Add Purchase Order' => 'Einkaufsbeleg anlegen',
+ 'Add Sales Order' => 'Verkaufsbeleg anlegen',
+ 'Add Service' => 'Dienstleistung anlegen',
+ 'Address' => 'Adresse',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Assemblies' => 'Erzeugnisse',
+ 'Assemblies restocked!' => 'Erzeugnisse sind im Lager!',
+ 'Assembly Number missing!' => 'Erzeugnisnummer fehlt!',
+ 'Attachment' => 'als Anhang',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'BOM' => 'Stückliste',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Stellage',
+ 'Bought' => 'Gekauft',
+ 'COGS' => 'Umsatzkosten',
+ 'Cannot delete item!' => 'Artikel kann nicht gelöscht werden!',
+ 'Cannot stock assemblies!' => 'Erzeugnisse können nicht ins Lager!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Geschlossen',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Weiter',
+ 'Copies' => 'Kopien',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Delete' => 'Löschen',
+ 'Delivery Date' => 'Lieferung',
+ 'Description' => 'Beschreibung',
+ 'Drawing' => 'Zeichnung',
+ 'E-mail' => 'eMail',
+ 'E-mail address missing!' => 'eMail-Adresse fehlt!',
+ 'Edit Assembly' => 'Erzeugnis bearbeiten',
+ 'Edit Part' => 'Ware bearbeiten',
+ 'Edit Service' => 'Dienstleistung bearbeiten',
+ 'Expense' => 'Aufwand',
+ 'Extended' => 'Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'From' => 'Von',
+ 'Group' => 'Gruppe',
+ 'Group Items' => 'Waren gruppieren',
+ 'Image' => 'Grafik',
+ 'In-line' => 'im Textkörper (Inline)',
+ 'Include in Report' => 'In Bericht aufnehmen',
+ 'Income' => 'Einkommen',
+ 'Individual Items' => 'Einzelteile',
+ 'Inventory' => 'Inventar',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Bevor dieses Erzeugnis als ungültig markiert werden kann, muß das Inventar auf Null sein!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Bevor diese Ware als ungültig markiert werden kann, muß das Inventar Null sein!',
+ 'Invoice' => 'Rechnung',
+ 'Invoice Date missing!' => 'Rechnungsdatum fehlt!',
+ 'Invoice Number' => 'Rechnungsnummer',
+ 'Invoice Number missing!' => 'Rechnungsnummer fehlt!',
+ 'Item deleted!' => 'Artikel gelöscht!',
+ 'Item not on file!' => 'Dieser Artikel ist nicht in der Datenbank!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Last Cost' => 'Letzte Kosten',
+ 'Line Total' => 'Zeilensumme',
+ 'Link Accounts' => 'Konten verknüpfen',
+ 'List Price' => 'Listenpreis',
+ 'Make' => 'Hersteller',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Message' => 'Nachricht',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Modell',
+ 'Name' => 'Name',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkungen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer fehlt in Zeile',
+ 'Obsolete' => 'Ungültig',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'On Hand' => 'auf Lager',
+ 'On Order' => 'auf Bestellung',
+ 'Order' => 'Auftrag',
+ 'Order Date missing!' => 'Auftragsdatum fehlt!',
+ 'Order Number' => 'Auftragsnummer',
+ 'Order Number missing!' => 'Auftragsnummer fehlt!',
+ 'Ordered' => 'Vom Kunde bestellt',
+ 'Orphaned' => 'nie benutzt',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Verpackungsliste',
+ 'Packing List Date missing!' => 'Datum für Verpackungsliste fehlt!',
+ 'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
+ 'Part' => 'Ware',
+ 'Part Number missing!' => 'Warennummer fehlt!',
+ 'Parts' => 'Waren',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preis',
+ 'Printer' => 'Drucker',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Einkaufsbeleg',
+ 'Qty' => 'Anz',
+ 'ROP' => 'UAB',
+ 'Recd' => 'Erh',
+ 'Required by' => 'Erforderlich am',
+ 'Sales' => 'Warenverkauf',
+ 'Sales Order' => 'Verkaufsbeleg',
+ 'Save' => 'Speichern',
+ 'Save as new' => 'als neu speichern',
+ 'Screen' => 'Bildschirm',
+ 'Select from one of the items below' => 'Wählen Sie einen der untenstehenden Einträge',
+ 'Select postscript or PDF!' => 'Postscript oder PDF auswählen!',
+ 'Sell Price' => 'Verkaufspreis',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienstleistung',
+ 'Service Number missing!' => 'Dienstleistungsnummer fehlt!',
+ 'Services' => 'Leistungen',
+ 'Ship' => 'Versand',
+ 'Ship to' => 'Verschicken an',
+ 'Short' => 'Kurz',
+ 'Sold' => 'Verkauft',
+ 'Stock' => 'einlagern',
+ 'Stock Assembly' => 'Erzeugnis einlagern',
+ 'Subject' => 'Betreff',
+ 'Subtotal' => 'Zwischensumme',
+ 'Tax' => 'Steuer',
+ 'To' => 'An',
+ 'Top Level' => 'Hauptbeschreibung',
+ 'Total' => 'Summe',
+ 'Unit' => 'Einh',
+ 'Unit of measure' => 'Maßeinheit',
+ 'Update' => 'Erneuern',
+ 'Updated' => 'Erneuert am',
+ 'Weight' => 'Gewicht',
+ 'What type of item is this?' => 'Was ist dieser Artikel?',
+ 'ea' => 'pro',
+ 'emailed to' => 'gemailt an',
+ 'hr' => 'Std',
+ 'sent to printer' => 'an Drucker geschickt',
+ 'to' => 'bis',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'hinzufügen' => 'add',
+ 'erzeugnis_anlegen' => 'add_assembly',
+ 'ware_anlegen' => 'add_part',
+ 'dienstleistung_anlegen' => 'add_service',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'erzeugnis_bearbeiten' => 'edit_assembly',
+ 'ware_bearbeiten' => 'edit_part',
+ 'dienstleistung_bearbeiten' => 'edit_service',
+ 'speichern' => 'save',
+ 'als_neu_speichern' => 'save_as_new',
+ 'erneuern' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/de/io b/sql-ledger/locale/de/io
new file mode 100644
index 0000000..3e94eb8
--- /dev/null
+++ b/sql-ledger/locale/de/io
@@ -0,0 +1,108 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Einkaufsbeleg anlegen',
+ 'Add Sales Order' => 'Verkaufsbeleg anlegen',
+ 'Address' => 'Adresse',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Attachment' => 'als Anhang',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Stellage',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Weiter',
+ 'Copies' => 'Kopien',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Delivery Date' => 'Lieferung',
+ 'Description' => 'Beschreibung',
+ 'E-mail' => 'eMail',
+ 'E-mail address missing!' => 'eMail-Adresse fehlt!',
+ 'Extended' => 'Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'Group' => 'Gruppe',
+ 'Group Items' => 'Waren gruppieren',
+ 'In-line' => 'im Textkörper (Inline)',
+ 'Invoice' => 'Rechnung',
+ 'Invoice Date missing!' => 'Rechnungsdatum fehlt!',
+ 'Invoice Number missing!' => 'Rechnungsnummer fehlt!',
+ 'Item not on file!' => 'Dieser Artikel ist nicht in der Datenbank!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Message' => 'Nachricht',
+ 'Name' => 'Name',
+ 'No.' => 'Nr.',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer fehlt in Zeile',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Order' => 'Auftrag',
+ 'Order Date missing!' => 'Auftragsdatum fehlt!',
+ 'Order Number missing!' => 'Auftragsnummer fehlt!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Verpackungsliste',
+ 'Packing List Date missing!' => 'Datum für Verpackungsliste fehlt!',
+ 'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
+ 'Part' => 'Ware',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preis',
+ 'Printer' => 'Drucker',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Einkaufsbeleg',
+ 'Qty' => 'Anz',
+ 'Recd' => 'Erh',
+ 'Required by' => 'Erforderlich am',
+ 'Sales Order' => 'Verkaufsbeleg',
+ 'Screen' => 'Bildschirm',
+ 'Select from one of the items below' => 'Wählen Sie einen der untenstehenden Einträge',
+ 'Select postscript or PDF!' => 'Postscript oder PDF auswählen!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienstleistung',
+ 'Ship' => 'Versand',
+ 'Ship to' => 'Verschicken an',
+ 'Subject' => 'Betreff',
+ 'To' => 'An',
+ 'Unit' => 'Einh',
+ 'What type of item is this?' => 'Was ist dieser Artikel?',
+ 'emailed to' => 'gemailt an',
+ 'sent to printer' => 'an Drucker geschickt',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'weiter' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/de/ir b/sql-ledger/locale/de/ir
new file mode 100644
index 0000000..7b60e47
--- /dev/null
+++ b/sql-ledger/locale/de/ir
@@ -0,0 +1,180 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Order' => 'Einkaufsbeleg anlegen',
+ 'Add Sales Order' => 'Verkaufsbeleg anlegen',
+ 'Add Vendor Invoice' => 'Einkaufsrechnung anlegen',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Betrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Invoice Number' => 'Soll die Rechnung mit folgender Nummer wirklich gelöscht werden:',
+ 'Attachment' => 'als Anhang',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Stellage',
+ 'Cannot delete invoice!' => 'Rechnung kann nicht gelöscht werden!',
+ 'Cannot post invoice for a closed period!' => 'Das Rechnungsdatum fällt in einen abgeschlossen Zeitraum!',
+ 'Cannot post invoice!' => 'Rechnung kann nicht gebucht werden!',
+ 'Cannot post payment for a closed period!' => 'Es können keine Zahlungen für abgeschlossene Bücher gebucht werden!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Bestätigen Sie!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Weiter',
+ 'Copies' => 'Kopien',
+ 'Currency' => 'Währung',
+ 'Customer not on file!' => 'Kunde ist nicht in der Datenbank!',
+ 'Date' => 'Datum',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Delete' => 'Löschen',
+ 'Delivery Date' => 'Lieferung',
+ 'Description' => 'Beschreibung',
+ 'Due Date' => 'Fälligkeitsdatum',
+ 'E-mail' => 'eMail',
+ 'E-mail address missing!' => 'eMail-Adresse fehlt!',
+ 'Edit Vendor Invoice' => 'Einkaufsrechnung bearbeiten',
+ 'Exch' => 'Wkurs.',
+ 'Exchangerate' => 'Wechselkurs',
+ 'Exchangerate for payment missing!' => 'Es fehlt der Wechselkurs für die Bezahlung!',
+ 'Exchangerate missing!' => 'Es fehlt der Wechselkurs!',
+ 'Extended' => 'Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'Group' => 'Gruppe',
+ 'Group Items' => 'Waren gruppieren',
+ 'In-line' => 'im Textkörper (Inline)',
+ 'Invoice' => 'Rechnung',
+ 'Invoice Date' => 'Rechnungsdatum',
+ 'Invoice Date missing!' => 'Rechnungsdatum fehlt!',
+ 'Invoice Number' => 'Rechnungsnummer',
+ 'Invoice Number missing!' => 'Rechnungsnummer fehlt!',
+ 'Invoice deleted!' => 'Rechnung gelöscht!',
+ 'Invoice posted!' => 'Rechnung verbucht!',
+ 'Item not on file!' => 'Dieser Artikel ist nicht in der Datenbank!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Message' => 'Nachricht',
+ 'Name' => 'Name',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkungen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer fehlt in Zeile',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Order' => 'Auftrag',
+ 'Order Date missing!' => 'Auftragsdatum fehlt!',
+ 'Order Number' => 'Auftragsnummer',
+ 'Order Number missing!' => 'Auftragsnummer fehlt!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Verpackungsliste',
+ 'Packing List Date missing!' => 'Datum für Verpackungsliste fehlt!',
+ 'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
+ 'Part' => 'Ware',
+ 'Payment date missing!' => 'Tag der Zahlung fehlt!',
+ 'Payments' => 'Zahlungen',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Buchen',
+ 'Post as new' => 'Neu buchen',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preis',
+ 'Printer' => 'Drucker',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
+ 'Purchase Order' => 'Einkaufsbeleg',
+ 'Qty' => 'Anz',
+ 'Recd' => 'Erh',
+ 'Record in' => 'Buchen auf',
+ 'Required by' => 'Erforderlich am',
+ 'Sales Order' => 'Verkaufsbeleg',
+ 'Screen' => 'Bildschirm',
+ 'Select from one of the items below' => 'Wählen Sie einen der untenstehenden Einträge',
+ 'Select from one of the names below' => 'Wählen Sie einen der untenstehenden Namen',
+ 'Select from one of the projects below' => 'Wählen Sie eines der untenstehenden Projekte',
+ 'Select postscript or PDF!' => 'Postscript oder PDF auswählen!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienstleistung',
+ 'Ship' => 'Versand',
+ 'Ship to' => 'Verschicken an',
+ 'Source' => 'Beleg',
+ 'Subject' => 'Betreff',
+ 'Subtotal' => 'Zwischensumme',
+ 'Tax Included' => 'Steuer im Preis inbegriffen',
+ 'To' => 'An',
+ 'Total' => 'Summe',
+ 'Unit' => 'Einh',
+ 'Update' => 'Erneuern',
+ 'Vendor' => 'Lieferant',
+ 'Vendor missing!' => 'Lieferant fehlt!',
+ 'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
+ 'What type of item is this?' => 'Was ist dieser Artikel?',
+ 'Yes' => 'Ja',
+ 'ea' => 'pro',
+ 'emailed to' => 'gemailt an',
+ 'sent to printer' => 'an Drucker geschickt',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'auftrag' => 'order',
+ 'buchen' => 'post',
+ 'neu_buchen' => 'post_as_new',
+ 'erneuern' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/de/is b/sql-ledger/locale/de/is
new file mode 100644
index 0000000..f5edab6
--- /dev/null
+++ b/sql-ledger/locale/de/is
@@ -0,0 +1,187 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Order' => 'Einkaufsbeleg anlegen',
+ 'Add Sales Invoice' => 'Ausgangsrechnung anlegen',
+ 'Add Sales Order' => 'Verkaufsbeleg anlegen',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Betrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Invoice Number' => 'Soll die Rechnung mit folgender Nummer wirklich gelöscht werden:',
+ 'Attachment' => 'als Anhang',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Stellage',
+ 'Cannot delete invoice!' => 'Rechnung kann nicht gelöscht werden!',
+ 'Cannot post invoice for a closed period!' => 'Das Rechnungsdatum fällt in einen abgeschlossen Zeitraum!',
+ 'Cannot post invoice!' => 'Rechnung kann nicht gebucht werden!',
+ 'Cannot post payment for a closed period!' => 'Es können keine Zahlungen für abgeschlossene Bücher gebucht werden!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Bestätigen Sie!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Weiter',
+ 'Copies' => 'Kopien',
+ 'Credit Limit' => 'Kreditlimit',
+ 'Currency' => 'Währung',
+ 'Customer' => 'Kunde',
+ 'Customer missing!' => 'Kundenname fehlt!',
+ 'Customer not on file!' => 'Kunde ist nicht in der Datenbank!',
+ 'Date' => 'Datum',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Delete' => 'Löschen',
+ 'Delivery Date' => 'Lieferung',
+ 'Description' => 'Beschreibung',
+ 'Due Date' => 'Fälligkeitsdatum',
+ 'E-mail' => 'eMail',
+ 'E-mail address missing!' => 'eMail-Adresse fehlt!',
+ 'Edit Sales Invoice' => 'Ausgangsrechnung bearbeiten',
+ 'Exch' => 'Wkurs.',
+ 'Exchangerate' => 'Wechselkurs',
+ 'Exchangerate for payment missing!' => 'Es fehlt der Wechselkurs für die Bezahlung!',
+ 'Exchangerate missing!' => 'Es fehlt der Wechselkurs!',
+ 'Extended' => 'Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'Group' => 'Gruppe',
+ 'Group Items' => 'Waren gruppieren',
+ 'In-line' => 'im Textkörper (Inline)',
+ 'Invoice' => 'Rechnung',
+ 'Invoice Date' => 'Rechnungsdatum',
+ 'Invoice Date missing!' => 'Rechnungsdatum fehlt!',
+ 'Invoice Number' => 'Rechnungsnummer',
+ 'Invoice Number missing!' => 'Rechnungsnummer fehlt!',
+ 'Invoice deleted!' => 'Rechnung gelöscht!',
+ 'Invoice posted!' => 'Rechnung verbucht!',
+ 'Item not on file!' => 'Dieser Artikel ist nicht in der Datenbank!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Message' => 'Nachricht',
+ 'Name' => 'Name',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkungen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer fehlt in Zeile',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Order' => 'Auftrag',
+ 'Order Date missing!' => 'Auftragsdatum fehlt!',
+ 'Order Number' => 'Auftragsnummer',
+ 'Order Number missing!' => 'Auftragsnummer fehlt!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Verpackungsliste',
+ 'Packing List Date missing!' => 'Datum für Verpackungsliste fehlt!',
+ 'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
+ 'Part' => 'Ware',
+ 'Payment date missing!' => 'Tag der Zahlung fehlt!',
+ 'Payments' => 'Zahlungen',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Buchen',
+ 'Post as new' => 'Neu buchen',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preis',
+ 'Print' => 'Drucken',
+ 'Printer' => 'Drucker',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
+ 'Purchase Order' => 'Einkaufsbeleg',
+ 'Qty' => 'Anz',
+ 'Recd' => 'Erh',
+ 'Record in' => 'Buchen auf',
+ 'Remaining' => 'Rest',
+ 'Required by' => 'Erforderlich am',
+ 'Sales Order' => 'Verkaufsbeleg',
+ 'Screen' => 'Bildschirm',
+ 'Select from one of the items below' => 'Wählen Sie einen der untenstehenden Einträge',
+ 'Select from one of the names below' => 'Wählen Sie einen der untenstehenden Namen',
+ 'Select from one of the projects below' => 'Wählen Sie eines der untenstehenden Projekte',
+ 'Select postscript or PDF!' => 'Postscript oder PDF auswählen!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienstleistung',
+ 'Ship' => 'Versand',
+ 'Ship to' => 'Verschicken an',
+ 'Ship via' => 'Transportmittel',
+ 'Source' => 'Beleg',
+ 'Subject' => 'Betreff',
+ 'Subtotal' => 'Zwischensumme',
+ 'Tax Included' => 'Steuer im Preis inbegriffen',
+ 'To' => 'An',
+ 'Total' => 'Summe',
+ 'Unit' => 'Einh',
+ 'Update' => 'Erneuern',
+ 'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
+ 'What type of item is this?' => 'Was ist dieser Artikel?',
+ 'Yes' => 'Ja',
+ 'ea' => 'pro',
+ 'emailed to' => 'gemailt an',
+ 'sent to printer' => 'an Drucker geschickt',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'email' => 'e_mail',
+ 'auftrag' => 'order',
+ 'buchen' => 'post',
+ 'neu_buchen' => 'post_as_new',
+ 'drucken' => 'print',
+ 'verschicken_an' => 'ship_to',
+ 'erneuern' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/de/locales.pl b/sql-ledger/locale/de/locales.pl
new file mode 100755
index 0000000..a358a90
--- /dev/null
+++ b/sql-ledger/locale/de/locales.pl
@@ -0,0 +1,303 @@
+#!/usr/bin/perl
+
+# -n do not include custom_ scripts
+
+use FileHandle;
+
+
+$basedir = "../..";
+$bindir = "$basedir/bin/mozilla";
+$menufile = "menu.ini";
+
+foreach $item (@ARGV) {
+ $item =~ s/-//g;
+ $arg{$item} = 1;
+}
+
+opendir DIR, "$bindir" or die "$!";
+@progfiles = grep { /\.pl/; !/(_|^\.)/ } readdir DIR;
+seekdir DIR, 0;
+@customfiles = grep /_/, readdir DIR;
+closedir DIR;
+
+# put customized files into @customfiles
+@customfiles = () if ($arg{n});
+
+if ($arg{n}) {
+ @menufiles = ($menufile);
+} else {
+ opendir DIR, "$basedir" or die "$!";
+ @menufiles = grep { /.*?_$menufile$/ } readdir DIR;
+ closedir DIR;
+ unshift @menufiles, $menufile;
+}
+
+
+# slurp the translations in
+if (-f 'all') {
+ require "all";
+}
+
+
+foreach $file (@progfiles) {
+
+ %locale = ();
+ %submit = ();
+ %subrt = ();
+
+ &scanfile("$bindir/$file");
+
+ # scan custom_{module}.pl or {login}_{module}.pl files
+ foreach $customfile (@customfiles) {
+ if ($customfile =~ /_$file/) {
+ if (-f "$bindir/$customfile") {
+ &scanfile("$bindir/$customfile");
+ }
+ }
+ }
+
+ # if this is the menu.pl file
+ if ($file eq 'menu.pl') {
+ foreach $item (@menufiles) {
+ &scanmenu("$basedir/$item");
+ }
+ }
+
+ $file =~ s/\.pl//;
+
+
+ eval { require 'missing'; };
+ unlink 'missing';
+
+ foreach $text (keys %$missing) {
+ if ($locale{$text}) {
+ unless ($self{texts}{$text}) {
+ $self{texts}{$text} = $missing->{$text};
+ }
+ }
+ }
+
+
+ open FH, ">$file" or die "$! : $file";
+
+ print FH q|$self{texts} = {
+|;
+
+ foreach $key (sort keys %locale) {
+ if ($self{texts}{$key}) {
+ $text = $self{texts}{$key};
+ } else {
+ $text = $key;
+ }
+ $text =~ s/'/\\'/g;
+ $text =~ s/\\$/\\\\/;
+
+ $keytext = $key;
+ $keytext =~ s/'/\\'/g;
+ $keytext =~ s/\\$/\\\\/;
+
+ print FH qq| '$keytext'|.(' ' x (27-length($keytext))).qq| => '$text',\n|;
+ }
+
+ print FH q|};
+
+$self{subs} = {
+|;
+
+ foreach $key (sort keys %subrt) {
+ $text = $key;
+ $text =~ s/'/\\'/g;
+ $text =~ s/\\$/\\\\/;
+ print FH qq| '$text'|.(' ' x (27-length($text))).qq| => '$text',\n|;
+ }
+
+ foreach $key (sort keys %submit) {
+ $text = ($self{texts}{$key}) ? $self{texts}{$key} : $key;
+ $text =~ s/'/\\'/g;
+ $text =~ s/\\$/\\\\/;
+
+ $english_sub = $key;
+ $english_sub =~ s/'/\\'/g;
+ $english_sub =~ s/\\$/\\\\/;
+ $english_sub = lc $key;
+
+ $translated_sub = lc $text;
+ $english_sub =~ s/( |-|,)/_/g;
+ $translated_sub =~ s/( |-|,)/_/g;
+ print FH qq| '$translated_sub'|.(' ' x (27-length($translated_sub))).qq| => '$english_sub',\n|;
+ }
+
+ print FH q|};
+
+1;
+|;
+
+ close FH;
+}
+
+
+# now print out all
+
+open FH, ">all" or die "$! : all";
+
+print FH q|# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+|;
+
+
+foreach $key (sort keys %alllocales) {
+ $text = $self{texts}{$key};
+
+ $count++;
+
+ $text =~ s/'/\\'/g;
+ $text =~ s/\\$/\\\\/;
+ $key =~ s/'/\\'/g;
+ $key =~ s/\\$/\\\\/;
+
+ unless ($text) {
+ $notext++;
+ push @missing, $key;
+ }
+
+ print FH qq| '$key'|.(' ' x (27-length($key))).qq| => '$text',\n|;
+
+}
+
+print FH q|};
+
+1;
+|;
+
+close FH;
+
+
+if (@missing) {
+ open FH, ">missing" or die "$! : missing";
+
+ print FH q|# add the missing texts and run locales.pl to rebuild
+
+$missing = {
+|;
+
+ foreach $text (@missing) {
+ print FH qq| '$text'|.(' ' x (27-length($text))).qq| => '',\n|;
+ }
+
+ print FH q|};
+
+1;
+|;
+
+ close FH;
+
+}
+
+open(FH, "LANGUAGE");
+@language = <FH>;
+close(FH);
+$trlanguage = $language[0];
+chomp $trlanguage;
+
+$per = sprintf("%.1f", ($count - $notext) / $count * 100);
+print "\n$trlanguage - ${per}%\n";
+
+exit;
+# eom
+
+
+sub scanfile {
+ my $file = shift;
+
+ return unless (-f "$file");
+
+ my $fh = new FileHandle;
+ open $fh, "$file" or die "$! : $file";
+
+ while (<$fh>) {
+ # is this another file
+ if (/require\s+\W.*\.pl/) {
+ my $newfile = $&;
+ $newfile =~ s/require\s+\W//;
+ $newfile =~ s/\$form->{path}\///;
+ &scanfile("$bindir/$newfile");
+ }
+
+ # is this a sub ?
+ if (/^sub /) {
+ ($null, $subrt) = split / +/;
+ $subrt{$subrt} = 1;
+ next;
+ }
+
+ my $rc = 1;
+
+ while ($rc) {
+ if (/Locale/) {
+ unless (/^use /) {
+ my ($null, $country) = split /,/;
+ $country =~ s/^ +["']//;
+ $country =~ s/["'].*//;
+ }
+ }
+
+ if (/\$locale->text.*?\W\)/) {
+ my $string = $&;
+ $string =~ s/\$locale->text\(\s*['"(q|qq)]['\/\\\|~]*//;
+ $string =~ s/\W\)+.*$//;
+
+ # if there is no $ in the string record it
+ unless ($string =~ /\$\D.*/) {
+ # this guarantees one instance of string
+ $locale{$string} = 1;
+
+ # this one is for all the locales
+ $alllocales{$string} = 1;
+
+ # is it a submit button before $locale->
+ if (/type=submit/) {
+ $submit{$string} = 1;
+ }
+ }
+ }
+
+ # exit loop if there are no more locales on this line
+ ($rc) = ($' =~ /\$locale->text/);
+ # strip text
+ s/^.*?\$locale->text.*?\)//;
+ }
+ }
+
+ close($fh);
+
+}
+
+
+sub scanmenu {
+ my $file = shift;
+
+ my $fh = new FileHandle;
+ open $fh, "$file" or die "$! : $file";
+
+ my @a = grep /^\[/, <$fh>;
+ close($fh);
+
+ # strip []
+ grep { s/(\[|\])//g } @a;
+
+ foreach my $item (@a) {
+ @b = split /--/, $item;
+ foreach $string (@b) {
+ chomp $string;
+ $locale{$string} = 1;
+ $alllocales{$string} = 1;
+ }
+ }
+
+}
+
+
diff --git a/sql-ledger/locale/de/login b/sql-ledger/locale/de/login
new file mode 100644
index 0000000..c90df6f
--- /dev/null
+++ b/sql-ledger/locale/de/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Über',
+ 'Database Host' => 'Datenbank-Rechner',
+ 'Dataset' => 'Datenbank',
+ 'Incorrect Dataset version!' => 'Datenbankversion stimmt nicht überein!',
+ 'Incorrect Password!' => 'Ungültiges Passwort!',
+ 'Licensed to' => 'Lizensiert für',
+ 'Login' => 'Anmelden',
+ 'Name' => 'Name',
+ 'Password' => 'Passwort',
+ 'User' => 'Benutzer',
+ 'Version' => 'Version',
+ 'You are logged out!' => 'Auf wiedersehen!',
+ 'You did not enter a name!' => 'Sie haben keinen Namen eingegeben!',
+ 'is not a member!' => 'ist kein Mitglied!',
+ 'localhost' => 'lokaler Rechner',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'anmelden' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/de/menu b/sql-ledger/locale/de/menu
new file mode 100644
index 0000000..c61e760
--- /dev/null
+++ b/sql-ledger/locale/de/menu
@@ -0,0 +1,73 @@
+$self{texts} = {
+ 'AP' => 'Verbindlichkeiten',
+ 'AP Aging' => 'Offene Verbindl.',
+ 'AR' => 'Forderungen',
+ 'AR Aging' => 'Offene Forderungen',
+ 'Accounting Menu' => 'Kontoverwaltung',
+ 'Add Account' => 'Konto anlegen',
+ 'Add Assembly' => 'Erzeugnis anlegen',
+ 'Add Customer' => 'Kunde anlegen',
+ 'Add GIFI' => 'GIFI anlegen',
+ 'Add Group' => 'Gruppe anlegen',
+ 'Add Part' => 'Ware anlegen',
+ 'Add Project' => 'Projekt anlegen',
+ 'Add Service' => 'Dienstleistung anlegen',
+ 'Add Transaction' => 'Buchung anlegen',
+ 'Add Vendor' => 'Lieferant anlegen',
+ 'Assemblies' => 'Erzeugnisse',
+ 'Audit Control' => 'Bücherkontrolle',
+ 'Backup' => 'Sicherung',
+ 'Balance Sheet' => 'Bilanz',
+ 'Cash' => 'Kasse',
+ 'Chart of Accounts' => 'Kontenübersicht',
+ 'Check' => 'Scheck',
+ 'Customers' => 'Kunden',
+ 'General Ledger' => 'Hauptbuch',
+ 'Goods & Services' => 'Waren und Dienstleistungen',
+ 'Groups' => 'Gruppen',
+ 'HTML Templates' => 'HTML Vorlagen',
+ 'Income Statement' => 'G & V',
+ 'Invoice' => 'Rechnung',
+ 'LaTeX Templates' => 'LaTeX Vorlagen',
+ 'List Accounts' => 'Kontenliste',
+ 'List GIFI' => 'GIFI aufzeigen',
+ 'Logout' => 'Abmelden',
+ 'Order Entry' => 'Aufträge',
+ 'Packing List' => 'Verpackungsliste',
+ 'Parts' => 'Waren',
+ 'Payment' => 'Zahlung',
+ 'Payments' => 'Zahlungen',
+ 'Preferences' => 'Benutzereinstellungen',
+ 'Projects' => 'Projekte',
+ 'Purchase Order' => 'Einkaufsbeleg',
+ 'Purchase Orders' => 'Einkaufsbelege',
+ 'Receipt' => 'Quittung',
+ 'Receipts' => 'Quittungen',
+ 'Reconciliation' => 'Abgleichung',
+ 'Reports' => 'Berichte',
+ 'Sales Invoice' => 'Ausgangsrechnung',
+ 'Sales Order' => 'Verkaufsbeleg',
+ 'Sales Orders' => 'Verkaufsbelege',
+ 'Save to File' => 'Auf Festplatte speichern',
+ 'Send by E-Mail' => 'Per eMail schicken',
+ 'Services' => 'Leistungen',
+ 'Statement' => 'Sammelrechnung',
+ 'Stock Assembly' => 'Erzeugnis einlagern',
+ 'Stylesheet' => 'Stilvorlage',
+ 'System' => 'System',
+ 'Tax collected' => 'vereinnahmte Steuer',
+ 'Tax paid' => 'Vorsteuer',
+ 'Transactions' => 'Buchungen',
+ 'Trial Balance' => 'Vergleichsbilanz',
+ 'Vendor Invoice' => 'Einkaufsrechnung',
+ 'Vendors' => 'Lieferanten',
+ 'Version' => 'Version',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/de/oe b/sql-ledger/locale/de/oe
new file mode 100644
index 0000000..abf31ba
--- /dev/null
+++ b/sql-ledger/locale/de/oe
@@ -0,0 +1,202 @@
+$self{texts} = {
+ 'Add' => 'Hinzufügen',
+ 'Add Purchase Order' => 'Einkaufsbeleg anlegen',
+ 'Add Sales Invoice' => 'Ausgangsrechnung anlegen',
+ 'Add Sales Order' => 'Verkaufsbeleg anlegen',
+ 'Add Vendor Invoice' => 'Einkaufsrechnung anlegen',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Betrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Order Number' => 'Soll die Bestellung mit folgender Nummer wirklich gelöscht werden:',
+ 'Attachment' => 'als Anhang',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Stellage',
+ 'C' => 'G',
+ 'Cannot delete order!' => 'Bestellung kann nicht gelöscht werden!',
+ 'Cannot save order!' => 'Bestellung kann nicht gespeichert werden!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Geschlossen',
+ 'Confirm!' => 'Bestätigen Sie!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Weiter',
+ 'Copies' => 'Kopien',
+ 'Credit Limit' => 'Kreditlimit',
+ 'Curr' => 'Währung',
+ 'Currency' => 'Währung',
+ 'Customer' => 'Kunde',
+ 'Customer missing!' => 'Kundenname fehlt!',
+ 'Customer not on file!' => 'Kunde ist nicht in der Datenbank!',
+ 'Date' => 'Datum',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Delete' => 'Löschen',
+ 'Delivery Date' => 'Lieferung',
+ 'Description' => 'Beschreibung',
+ 'E-mail' => 'eMail',
+ 'E-mail address missing!' => 'eMail-Adresse fehlt!',
+ 'Edit Purchase Order' => 'Einkaufsbeleg bearbeiten',
+ 'Edit Sales Order' => 'Verkaufsbeleg bearbeiten',
+ 'Exchangerate' => 'Wechselkurs',
+ 'Exchangerate missing!' => 'Es fehlt der Wechselkurs!',
+ 'Extended' => 'Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'From' => 'Von',
+ 'Group' => 'Gruppe',
+ 'Group Items' => 'Waren gruppieren',
+ 'ID' => 'Nr.',
+ 'In-line' => 'im Textkörper (Inline)',
+ 'Include in Report' => 'In Bericht aufnehmen',
+ 'Invoice' => 'Rechnung',
+ 'Invoice Date missing!' => 'Rechnungsdatum fehlt!',
+ 'Invoice Number missing!' => 'Rechnungsnummer fehlt!',
+ 'Item not on file!' => 'Dieser Artikel ist nicht in der Datenbank!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Message' => 'Nachricht',
+ 'Name' => 'Name',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkungen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer fehlt in Zeile',
+ 'O' => 'O',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Open' => 'Offen',
+ 'Order' => 'Auftrag',
+ 'Order Date' => 'Auftragsdatum',
+ 'Order Date missing!' => 'Auftragsdatum fehlt!',
+ 'Order Number' => 'Auftragsnummer',
+ 'Order Number missing!' => 'Auftragsnummer fehlt!',
+ 'Order deleted!' => 'Auftrag gelöscht!',
+ 'Order saved!' => 'Auftrag gespeichert!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Verpackungsliste',
+ 'Packing List Date missing!' => 'Datum für Verpackungsliste fehlt!',
+ 'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
+ 'Part' => 'Ware',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Preis',
+ 'Print' => 'Drucken',
+ 'Printer' => 'Drucker',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
+ 'Purchase Order' => 'Einkaufsbeleg',
+ 'Purchase Orders' => 'Einkaufsbelege',
+ 'Qty' => 'Anz',
+ 'Recd' => 'Erh',
+ 'Remaining' => 'Rest',
+ 'Required by' => 'Erforderlich am',
+ 'Sales Order' => 'Verkaufsbeleg',
+ 'Sales Orders' => 'Verkaufsbelege',
+ 'Save' => 'Speichern',
+ 'Save as new' => 'als neu speichern',
+ 'Screen' => 'Bildschirm',
+ 'Select from one of the items below' => 'Wählen Sie einen der untenstehenden Einträge',
+ 'Select from one of the names below' => 'Wählen Sie einen der untenstehenden Namen',
+ 'Select from one of the projects below' => 'Wählen Sie eines der untenstehenden Projekte',
+ 'Select postscript or PDF!' => 'Postscript oder PDF auswählen!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienstleistung',
+ 'Ship' => 'Versand',
+ 'Ship to' => 'Verschicken an',
+ 'Ship via' => 'Transportmittel',
+ 'Subject' => 'Betreff',
+ 'Subtotal' => 'Zwischensumme',
+ 'Tax' => 'Steuer',
+ 'Tax Included' => 'Steuer im Preis inbegriffen',
+ 'Terms: Net' => 'Zahlungsziel',
+ 'To' => 'An',
+ 'Total' => 'Summe',
+ 'Unit' => 'Einh',
+ 'Update' => 'Erneuern',
+ 'Vendor' => 'Lieferant',
+ 'Vendor missing!' => 'Lieferant fehlt!',
+ 'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
+ 'What type of item is this?' => 'Was ist dieser Artikel?',
+ 'Yes' => 'Ja',
+ 'days' => 'Tage',
+ 'ea' => 'pro',
+ 'emailed to' => 'gemailt an',
+ 'sent to printer' => 'an Drucker geschickt',
+ 'to' => 'bis',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'hinzufügen' => 'add',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'email' => 'e_mail',
+ 'rechnung' => 'invoice',
+ 'drucken' => 'print',
+ 'speichern' => 'save',
+ 'als_neu_speichern' => 'save_as_new',
+ 'verschicken_an' => 'ship_to',
+ 'erneuern' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/de/pe b/sql-ledger/locale/de/pe
new file mode 100644
index 0000000..d3618cc
--- /dev/null
+++ b/sql-ledger/locale/de/pe
@@ -0,0 +1,45 @@
+$self{texts} = {
+ 'Add' => 'Hinzufügen',
+ 'Add Group' => 'Gruppe anlegen',
+ 'Add Project' => 'Projekt anlegen',
+ 'All' => 'Alle',
+ 'Continue' => 'Weiter',
+ 'Delete' => 'Löschen',
+ 'Description' => 'Beschreibung',
+ 'Edit Group' => 'Gruppe editieren',
+ 'Edit Project' => 'Projekt bearbeiten',
+ 'Group' => 'Gruppe',
+ 'Group deleted!' => 'Gruppe gelöscht!',
+ 'Group missing!' => 'Gruppe fehlt!',
+ 'Group saved!' => 'Gruppe gespeichert!',
+ 'Groups' => 'Gruppen',
+ 'Number' => 'Nummer',
+ 'Orphaned' => 'nie benutzt',
+ 'Project' => 'Projekt',
+ 'Project Number missing!' => 'Projektnummer fehlt!',
+ 'Project deleted!' => 'Projekt gelöscht!',
+ 'Project saved!' => 'Projekt gespeichert!',
+ 'Projects' => 'Projekte',
+ 'Save' => 'Speichern',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_partsgroup_footer' => 'form_partsgroup_footer',
+ 'form_partsgroup_header' => 'form_partsgroup_header',
+ 'form_project_footer' => 'form_project_footer',
+ 'form_project_header' => 'form_project_header',
+ 'partsgroup_report' => 'partsgroup_report',
+ 'project_report' => 'project_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'hinzufügen' => 'add',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'speichern' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/de/rc b/sql-ledger/locale/de/rc
new file mode 100644
index 0000000..47f5f6e
--- /dev/null
+++ b/sql-ledger/locale/de/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Balance' => 'Bilanz',
+ 'Cleared Balance' => 'Abgeschlossen',
+ 'Continue' => 'Weiter',
+ 'Date' => 'Datum',
+ 'Deposit' => 'Gutschrift',
+ 'Description' => 'Beschreibung',
+ 'Difference' => 'Differenz',
+ 'Done' => 'Fertig',
+ 'Exchangerate Difference' => 'Wechselkursunterschied',
+ 'From' => 'Von',
+ 'Out of balance!' => 'Summen stimmen nicht überein!',
+ 'Payment' => 'Zahlung',
+ 'Reconciliation' => 'Abgleichung',
+ 'Select all' => 'Alle auswählen',
+ 'Source' => 'Beleg',
+ 'Statement Balance' => 'Sammelrechnungsbilanz',
+ 'Update' => 'Erneuern',
+ 'to' => 'bis',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'weiter' => 'continue',
+ 'fertig' => 'done',
+ 'alle_auswählen' => 'select_all',
+ 'erneuern' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/de/rp b/sql-ledger/locale/de/rp
new file mode 100644
index 0000000..f1ffdf4
--- /dev/null
+++ b/sql-ledger/locale/de/rp
@@ -0,0 +1,119 @@
+$self{texts} = {
+ 'AP Aging' => 'Offene Verbindl.',
+ 'AR Aging' => 'Offene Forderungen',
+ 'Account' => 'Konto',
+ 'Accounts' => 'Konten',
+ 'Amount' => 'Betrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Attachment' => 'als Anhang',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Balance' => 'Bilanz',
+ 'Balance Sheet' => 'Bilanz',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'basierend auf Barzahlung',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Gegenüberstellen zu',
+ 'Continue' => 'Weiter',
+ 'Copies' => 'Kopien',
+ 'Credit' => 'Haben',
+ 'Current' => 'Betrag',
+ 'Customer' => 'Kunde',
+ 'Date' => 'Datum',
+ 'Debit' => 'Soll',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezember',
+ 'Decimalplaces' => 'Dezimalstellen',
+ 'Description' => 'Beschreibung',
+ 'Due' => 'Fällig',
+ 'E-mail' => 'eMail',
+ 'E-mail Statement to' => 'eMail Fälligkeitsabrechnung an',
+ 'Feb' => 'Feb',
+ 'February' => 'Februar',
+ 'From' => 'Von',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Überschrift',
+ 'ID' => 'Nr.',
+ 'In-line' => 'im Textkörper (Inline)',
+ 'Include in Report' => 'In Bericht aufnehmen',
+ 'Income Statement' => 'G & V',
+ 'Invoice' => 'Rechnung',
+ 'Jan' => 'Jan',
+ 'January' => 'Januar',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mär',
+ 'March' => 'März',
+ 'May' => 'Mai',
+ 'May ' => 'Mai',
+ 'Message' => 'Nachricht',
+ 'N/A' => 'N.Z.',
+ 'Nothing selected!' => 'Es wurde nichts ausgewählt!',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Zahlungen',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Drucken',
+ 'Printer' => 'Drucker',
+ 'Project Number' => 'Projektnummer',
+ 'Receipts' => 'Quittungen',
+ 'Report for' => 'Bericht für',
+ 'Retained Earnings' => 'Verbliebenes Einkommen',
+ 'Screen' => 'Bildschirm',
+ 'Select all' => 'Alle auswählen',
+ 'Select postscript or PDF!' => 'Postscript oder PDF auswählen!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Beleg',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Sammelrechnung',
+ 'Statement sent to' => 'Sammelrechnung verschickt an',
+ 'Statements sent to printer!' => 'Sammelrechnungen an Drucker geschickt!',
+ 'Subject' => 'Betreff',
+ 'Subtotal' => 'Zwischensumme',
+ 'Tax' => 'Steuer',
+ 'Tax collected' => 'vereinnahmte Steuer',
+ 'Tax paid' => 'Vorsteuer',
+ 'Total' => 'Summe',
+ 'Trial Balance' => 'Vergleichsbilanz',
+ 'Vendor' => 'Lieferant',
+ 'as at' => 'zum Stand',
+ 'collected on sales' => 'erhalten durch Verkäufe',
+ 'for Period' => 'für den Zeitraum',
+ 'paid on purchases' => 'gezahlt durch Einkäufe',
+ 'to' => 'bis',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'weiter' => 'continue',
+ 'email' => 'e_mail',
+ 'drucken' => 'print',
+ 'alle_auswählen' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/COPYING b/sql-ledger/locale/dk/COPYING
new file mode 100644
index 0000000..e010710
--- /dev/null
+++ b/sql-ledger/locale/dk/COPYING
@@ -0,0 +1,24 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Danish texts:
+#
+# Author: Keld Jørn Simonsen <keld@dkuug.dk>
+# Jonas Smedegaard <jonas@jones.dk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/dk/LANGUAGE b/sql-ledger/locale/dk/LANGUAGE
new file mode 100644
index 0000000..bd082a2
--- /dev/null
+++ b/sql-ledger/locale/dk/LANGUAGE
@@ -0,0 +1 @@
+Danish
diff --git a/sql-ledger/locale/dk/admin b/sql-ledger/locale/dk/admin
new file mode 100644
index 0000000..e74af7d
--- /dev/null
+++ b/sql-ledger/locale/dk/admin
@@ -0,0 +1,122 @@
+$self{texts} = {
+ 'Access Control' => 'Adgangskontrol',
+ 'Accounting' => 'Bogføring',
+ 'Add User' => 'Ny bruger',
+ 'Address' => 'Adresse',
+ 'Administration' => 'Administration',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => 'Alle datasæt opdaterede',
+ 'Change Admin Password' => 'Ændr adgangskode for administrator',
+ 'Change Password' => 'Ændr adgangskode',
+ 'Character Set' => 'Tegnsæt',
+ 'Click on login name to edit!' => 'Klik på brugernavn for at redigere',
+ 'Company' => 'Firma',
+ 'Connect to' => 'Forbind til',
+ 'Continue' => 'Fortsæt',
+ 'Create Chart of Accounts' => 'Opret kontoplan',
+ 'Create Dataset' => 'Opret datasæt',
+ 'DBI not installed!' => 'DBI ikke installeret',
+ 'Database' => 'Database',
+ 'Database Administration' => 'Administration af database',
+ 'Database Driver not checked!' => 'Databasedriver ikke kontrolleret',
+ 'Database User missing!' => 'Bruger af database mangler!',
+ 'Dataset' => 'Datasæt',
+ 'Dataset missing!' => 'Datasæt mangler!',
+ 'Dataset updated!' => 'Datasæt opdateret!',
+ 'Date Format' => 'Datoformat',
+ 'Delete' => 'Fjern',
+ 'Delete Dataset' => 'Fjern datasæt',
+ 'Directory' => 'Katalog',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Grænse for nedtræk',
+ 'E-mail' => 'E-post',
+ 'Edit User' => 'Redigér bruger',
+ 'Existing Datasets' => 'Eksisterende datasæt',
+ 'Fax' => 'Fax',
+ 'Host' => 'Vært',
+ 'Hostname missing!' => 'Værtsnavn mangler',
+ 'Incorrect Password!' => 'Forkert adgangskode',
+ 'Language' => 'Sprog',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Lad felterne "vært" og "port" være tomme medmindre du vil etablere en ekstern forbindelse.',
+ 'Login' => 'Log på',
+ 'Name' => 'Navn',
+ 'New Templates' => 'Nye skabeloner',
+ 'No Database Drivers available!' => 'Ingen databasedrivere tilgængelige',
+ 'No Dataset selected!' => 'Intet datasæt valgt',
+ 'Nothing to delete!' => 'Intet at slette!',
+ 'Number Format' => 'Numerisk format',
+ 'Oracle Database Administration' => 'Oracle Administration af database',
+ 'Password' => 'Adgangskode',
+ 'Password changed!' => 'Adgangskode ændret',
+ 'Pg Database Administration' => 'Pg Administration af database',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port mangler',
+ 'Printer' => 'Printer',
+ 'Save' => 'Gem',
+ 'Select a Dataset to delete and press "Continue"' => 'Vælg et datasæt og tryk "Fortsæt"',
+ 'Setup Templates' => 'Skabeloner for opsætning',
+ 'Ship via' => 'Send via',
+ 'Signature' => 'Underskrift',
+ 'Stylesheet' => 'Stilark',
+ 'Templates' => 'Skabeloner',
+ 'The following Datasets are not in use and can be deleted' => 'De følgende datasæt er ikke i brug og kan slettes',
+ 'The following Datasets need to be updated' => 'De følgende datasæt skal opdateres',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Dette er en indledende kontrol af eksisterende kilder. Ingenting vil blive oprettet eller slettet på dette trin',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Skift brugernavnet for en eksisterende bruger og gem for at tilføje en ny bruger til en gruppe. Den nye bruger vil så bive gemt med de samme indstillinger under det nye brugernavn.',
+ 'Update Dataset' => 'Opdatér datasæt',
+ 'Use Templates' => 'Brug skabeloner',
+ 'User' => 'Bruger',
+ 'User deleted!' => 'Bruger slettet!',
+ 'User saved!' => 'Bruger gemt!',
+ 'Version' => 'Version',
+ 'You must enter a host and port for local and remote connections!' => 'Du skal angive en vært og en port for lokale og eksterne forbindelser!',
+ 'does not exist' => 'eksisterer ikke',
+ 'is already a member!' => 'er allerede et medlem',
+ 'localhost' => 'lokalt',
+ 'successfully created!' => 'oprettet!',
+ 'successfully deleted!' => 'slettet!',
+ 'website' => 'på Internet',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'ny_bruger' => 'add_user',
+ 'Ændr_adgangskode_for_administrator' => 'change_admin_password',
+ 'Ændr_adgangskode' => 'change_password',
+ 'fortsæt' => 'continue',
+ 'opret_datasæt' => 'create_dataset',
+ 'fjern' => 'delete',
+ 'fjern_datasæt' => 'delete_dataset',
+ 'log_på' => 'login',
+ 'oracle_administration_af_database' => 'oracle_database_administration',
+ 'pg_administration_af_database' => 'pg_database_administration',
+ 'gem' => 'save',
+ 'opdatér_datasæt' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/all b/sql-ledger/locale/dk/all
new file mode 100644
index 0000000..e57ed1f
--- /dev/null
+++ b/sql-ledger/locale/dk/all
@@ -0,0 +1,487 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Kreditorer',
+ 'AP Aging' => 'Aldersfordeling',
+ 'AP Transaction' => 'Leverandørfaktura',
+ 'AP Transactions' => 'Leverandørfakturaer',
+ 'AR' => 'Debitorer',
+ 'AR Aging' => 'Aldersfordeling',
+ 'AR Transaction' => 'Debitorpostering',
+ 'AR Transactions' => 'Debitorposteringer',
+ 'About' => 'Om',
+ 'Access Control' => 'Adgangskontrol',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Kontonummer',
+ 'Account Number missing!' => 'Kontonummer mangler!',
+ 'Account Type' => 'Kontotype',
+ 'Account Type missing!' => 'Kontotype mangler!',
+ 'Account deleted!' => 'Konto slettet!',
+ 'Account saved!' => 'Konto gemt!',
+ 'Accounting' => 'Bogføring',
+ 'Accounting Menu' => 'Konto-menu',
+ 'Accounts' => 'Konti',
+ 'Active' => 'Aktiv',
+ 'Add' => 'Tilføj',
+ 'Add Account' => 'Ny konto',
+ 'Add Accounts Payables Transaction' => 'Ny leverandørpostering',
+ 'Add Accounts Receivables Transaction' => 'Ny debitorpostering',
+ 'Add Assembly' => 'Ny sammensætning',
+ 'Add Customer' => 'Ny kunde',
+ 'Add GIFI' => 'Ny GIFI',
+ 'Add General Ledger Transaction' => 'Ny postering i hovedbog',
+ 'Add Part' => 'Ny vare',
+ 'Add Project' => 'Nyt projekt',
+ 'Add Purchase Invoice' => 'Ny indkøbsfaktura',
+ 'Add Purchase Order' => 'Ny indkøbsordre',
+ 'Add Sales Invoice' => 'Ny salgsfaktura',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Add Service' => 'Ny tjeneste',
+ 'Add Transaction' => 'Ny postering',
+ 'Add User' => 'Ny bruger',
+ 'Add Vendor' => 'Ny leverandør',
+ 'Address' => 'Adresse',
+ 'Administration' => 'Administration',
+ 'Administrator' => 'Administrator',
+ 'All' => 'Alt',
+ 'All Datasets up to date!' => 'Alle datasæt opdaterede',
+ 'Amount' => 'Beløb',
+ 'Amount Due' => 'Forfaldent',
+ 'Amount does not equal applied!' => 'Beløb er ikke det samme som brugt!',
+ 'Amount missing!' => 'Konto mangler!',
+ 'Applied' => 'Udført',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Invoice Number' => 'Er du sikker på du vil fjerne fakturanummer',
+ 'Are you sure you want to delete Order Number' => 'Er du sikker på at du vil fjerne ordrenummer',
+ 'Are you sure you want to delete Transaction' => 'Er du sikker på du vil fjerne postering',
+ 'Assemblies' => 'Sammensætninger',
+ 'Assemblies restocked!' => 'Sammensætninger genlagret',
+ 'Assembly Number missing!' => 'Sammensætningsnummer mangler',
+ 'Asset' => 'Aktiv',
+ 'Attachment' => 'Bilag',
+ 'Audit Control' => 'Revisionskontrol',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'BOM' => 'BOM',
+ 'Backup' => 'Sikkerheskopi',
+ 'Backup sent to' => 'Sikkerhedskopier sendt til',
+ 'Balance' => 'Balance',
+ 'Balance Sheet' => 'Status',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Varelager',
+ 'Books are open' => 'Bogføringen er åben for rettelser',
+ 'Bought' => 'Købt',
+ 'Business Number' => 'CVR-nummer',
+ 'C' => 'C',
+ 'COGS' => 'Indkøb',
+ 'Cannot delete account!' => 'Kan ikke slette konto!',
+ 'Cannot delete customer!' => 'Kan ikke slette kunde!',
+ 'Cannot delete default account!' => 'Kan ikke slette standardkonto!',
+ 'Cannot delete invoice!' => 'Kan ikke slette faktura!',
+ 'Cannot delete item already invoiced!' => 'Kan ikke slette allerede faktureret enkeltdel!',
+ 'Cannot delete item on order!' => 'Kan ikke slette bestilt enkeltdel!',
+ 'Cannot delete item which is part of an assembly!' => 'kan ikke slette en enhed som er en del af en sammensætning!',
+ 'Cannot delete item!' => 'Kan ikke slette enhed!',
+ 'Cannot delete order!' => 'Kan ikke slette ordre!',
+ 'Cannot delete transaction!' => 'Kan ikke slette postering!',
+ 'Cannot delete vendor!' => 'Kan ikke slette leverandør!',
+ 'Cannot have a value in both Debit and Credit!' => 'Kan ikke have en værdi i både debet og kredit!',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => 'Kan ikke bogføre faktura for en afsluttet periode!',
+ 'Cannot post invoice!' => 'Kan ikke bogføre faktura!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bogføre betaling for en afsluttet periode',
+ 'Cannot post payment!' => 'Kan ikke bogføre betaling',
+ 'Cannot post transaction for a closed period!' => 'Kan ikke bogføre postering for en afsluttet periode!',
+ 'Cannot post transaction!' => 'Kan ikke bogføre postering!',
+ 'Cannot process payment for a closed period!' => 'Kan ikke behandle betaling for en afsluttet periode!',
+ 'Cannot save account!' => 'Kan ikke gemme konto!',
+ 'Cannot save order!' => 'Kan ikke gemme ordre!',
+ 'Cannot save preferences!' => 'Kan ikke gemme præferencer!',
+ 'Cannot stock assemblies!' => 'Kan ikke genbesætte sammensætninger',
+ 'Cash' => 'Kontanter',
+ 'Cash based' => 'Kontantbaseret',
+ 'Cc' => 'Kopi',
+ 'Change Admin Password' => 'Ændr adgangskode for administrator',
+ 'Change Password' => 'Ændr adgangskode',
+ 'Character Set' => 'Tegnsæt',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check udskrevet',
+ 'Check printing failed!' => 'Udskrivning af check mislykkedes',
+ 'Cleared Balance' => 'Udjævnede balance',
+ 'Click on login name to edit!' => 'Klik på brugernavn for at redigere',
+ 'Close Books up to' => 'Afslut bogføring op til',
+ 'Closed' => 'Afsluttet',
+ 'Company' => 'Firma',
+ 'Compare to' => 'Sammenlign med',
+ 'Confirm!' => 'Bekræft!',
+ 'Connect to' => 'Forbind til',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsæt',
+ 'Copies' => 'Kopier',
+ 'Copy to COA' => 'Kopiér til COA',
+ 'Create Chart of Accounts' => 'Opret kontoplan',
+ 'Create Dataset' => 'Opret datasæt',
+ 'Credit' => 'Kredit',
+ 'Credit Limit' => 'Kreditgrænse',
+ 'Curr' => 'Val',
+ 'Currency' => 'Valuta',
+ 'Current' => '',
+ 'Customer' => 'Kunde',
+ 'Customer deleted!' => 'Kunde slettet!',
+ 'Customer missing!' => 'Kunde mangler!',
+ 'Customer not on file!' => 'Kunde ikke i databasen!',
+ 'Customer saved!' => 'Kunde gemt!',
+ 'Customers' => 'Kunder',
+ 'DBI not installed!' => 'DBI ikke installeret',
+ 'Database' => 'Database',
+ 'Database Administration' => 'Administration af database',
+ 'Database Driver not checked!' => 'Databasedriver ikke kontrolleret',
+ 'Database Host' => 'Database-vært',
+ 'Database User missing!' => 'Bruger af database mangler!',
+ 'Dataset' => 'Datasæt',
+ 'Dataset missing!' => 'Datasæt mangler!',
+ 'Dataset updated!' => 'Datasæt opdateret!',
+ 'Date' => 'Dato',
+ 'Date Due' => 'Forfaldsdato',
+ 'Date Format' => 'Datoformat',
+ 'Date Paid' => 'Betalingsdato',
+ 'Date missing!' => 'Dato mangler!',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet og kredit skal være det samme!',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Decimalplaces' => 'Decimalpladser',
+ 'Delete' => 'Fjern',
+ 'Delete Account' => 'Fjern konto',
+ 'Delete Dataset' => 'Fjern datasæt',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Deposit' => 'Depositum',
+ 'Description' => 'Beskrivelse',
+ 'Difference' => 'Difference',
+ 'Directory' => 'Katalog',
+ 'Discount' => 'Rabat',
+ 'Done' => 'Færdig',
+ 'Drawing' => 'Træk',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Grænse for nedtræk',
+ 'Due' => 'Forfald',
+ 'Due Date' => 'Forfaldsdato',
+ 'Due Date missing!' => 'Forfaldsdato mangler!',
+ 'E-mail' => 'E-post',
+ 'E-mail Statement to' => 'Send opgørelse til',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit' => 'Redigér',
+ 'Edit Account' => 'Redigér konto',
+ 'Edit Accounts Payables Transaction' => 'Redigér leverandørpostering',
+ 'Edit Accounts Receivables Transaction' => 'Redigér debitorpostering',
+ 'Edit Assembly' => 'Redigér sammensætning',
+ 'Edit GIFI' => 'Redigér GIFI',
+ 'Edit General Ledger Transaction' => 'Redigér en postering i hovedbog',
+ 'Edit Part' => 'Redigér vare',
+ 'Edit Preferences for' => 'Redigér opsætning for',
+ 'Edit Project' => 'Redigér præferencer for',
+ 'Edit Purchase Invoice' => 'Redigér projekt',
+ 'Edit Purchase Order' => 'Redigér indkøbsordre',
+ 'Edit Sales Invoice' => 'Redigér salgsfaktura',
+ 'Edit Sales Order' => 'Redigér salgsordre',
+ 'Edit Service' => 'Redigér tjeneste',
+ 'Edit Template' => 'Redigér skabelon',
+ 'Edit User' => 'Redigér bruger',
+ 'Employee' => 'Ansat',
+ 'Enforce transaction reversal for all dates' => 'Gennemtving explicitte rettelser af posteringer for alle datoer',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Angiv op til 3 bogstaver adskilt med kolon (fx DKK:EUR:USD) for dine indenlandske og udenlandske valutaer',
+ 'Equity' => 'Egenkapital',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekselkurs',
+ 'Exchangerate Difference' => 'Difference for vekselkurs',
+ 'Exchangerate for payment missing!' => 'Valutakurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekselkurs mangler!',
+ 'Existing Datasets' => 'Eksisterende datasæt',
+ 'Expense' => 'Udgift',
+ 'Expense Account' => 'Udgiftskonto',
+ 'Expense/Asset' => 'Udgift/Aktiv',
+ 'Extended' => 'Udvidet',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'Foreign Exchange Gain' => 'Gevinst på valutahandel',
+ 'Foreign Exchange Loss' => 'Tab på valutahandel',
+ 'From' => 'Fra',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI slettet!',
+ 'GIFI missing!' => 'GIFI mangler!',
+ 'GIFI saved!' => 'GIFI gemt!',
+ 'GL Transaction' => 'Postering i hovedbog',
+ 'General Ledger' => 'Hovedbog',
+ 'Goods & Services' => 'Varer og tjenester',
+ 'HTML Templates' => 'HTML-skabeloner',
+ 'Heading' => 'Overskrift',
+ 'Host' => 'Vært',
+ 'Hostname missing!' => 'Værtsnavn mangler',
+ 'ID' => 'ID',
+ 'Image' => 'Billede',
+ 'In-line' => 'Indlejret',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Include in drop-down menus' => 'Inkludér i rullegardin-menuer',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Skal denne konto kunne vælges som afgifts- eller momskonto ved oprettelsen af kunder/leverandører?',
+ 'Income' => 'Indtægt',
+ 'Income Account' => 'Indtægtskonto',
+ 'Income Statement' => 'Driftsregnskab',
+ 'Incorrect Dataset version!' => 'Forkert version af datasæt!',
+ 'Incorrect Password!' => 'Forkert adgangskode',
+ 'Individual Items' => 'Individuelle enheder',
+ 'Inventory' => 'Artikler',
+ 'Inventory Account' => 'Lagerkonto',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Lagerbeholdning skal være nul for at du kan forælde denne sammensætning',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Lagerbeholdning skal være nul for at du kan forælde denne enhed',
+ 'Inventory quantity must be zero!' => 'Lagerbeholdning skal være nul',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Invoice deleted!' => 'Faktura slettet!',
+ 'Invoice posted!' => 'Faktura bogført!',
+ 'Invoices' => 'Fakturaer',
+ 'Is this a summary account to record' => 'Samlekonto for',
+ 'Item deleted!' => 'Enkeltdel slettet!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'LaTeX Templates' => 'LaTeX-skabeloner',
+ 'Language' => 'Sprog',
+ 'Last Cost' => 'Seneste pris',
+ 'Last Invoice Number' => 'Seneste fakturanummer',
+ 'Last Numbers & Default Accounts' => 'Løbenumre og standardkonti',
+ 'Last Purchase Order Number' => 'Seneste nummer på indkøbsordre',
+ 'Last Sales Order Number' => 'Seneste salgsordrenummer',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Lad felterne "vært" og "port" være tomme medmindre du vil etablere en ekstern forbindelse.',
+ 'Liability' => 'Passiv',
+ 'Licensed to' => 'Udført for',
+ 'Line Total' => 'Antal linjer',
+ 'Link' => 'Referencer',
+ 'Link Accounts' => 'Forbind konti',
+ 'List Accounts' => 'List konti',
+ 'List GIFI' => 'List GIFI',
+ 'List Price' => 'Listepris',
+ 'List Transactions' => 'Vis bogføringer',
+ 'Login' => 'Log på',
+ 'Logout' => 'Log af',
+ 'Make' => 'Fabrikat',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Message' => 'Besked',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Model',
+ 'N/A' => 'I/T',
+ 'Name' => 'Navn',
+ 'Name missing!' => 'Navn mangler!',
+ 'New Templates' => 'Nye skabeloner',
+ 'No' => 'Nej',
+ 'No Database Drivers available!' => 'Ingen databasedrivere tilgængelige',
+ 'No Dataset selected!' => 'Intet datasæt valgt',
+ 'No email address for' => 'Ingen epostadresse for',
+ 'No.' => '',
+ 'Notes' => 'Bemærkninger',
+ 'Nothing applied!' => 'Ingenting udført!',
+ 'Nothing selected!' => 'Ingenting valgt!',
+ 'Nothing to delete!' => 'Intet at slette!',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Numerisk format',
+ 'Number missing in Row' => 'Tal mangler i række',
+ 'O' => 'O',
+ 'Obsolete' => 'Forældet',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'On Hand' => 'På lager',
+ 'On Order' => 'I ordre',
+ 'Open' => 'Åbn',
+ 'Oracle Database Administration' => 'Oracle Administration af database',
+ 'Order' => 'Ordre',
+ 'Order Date' => 'Ordredato',
+ 'Order Date missing!' => 'Ordredato mangler',
+ 'Order Entry' => 'Ordreindgang',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler',
+ 'Order deleted!' => 'Ordre slettet',
+ 'Order saved!' => 'Ordre gemt',
+ 'Ordered' => 'bestilt',
+ 'Orphaned' => 'Fritstående',
+ 'Out of balance!' => 'Ikke i balance!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Paid' => 'Betalt',
+ 'Paid in full' => '',
+ 'Part' => 'Vare',
+ 'Part Number missing!' => 'Varenummer mangler!',
+ 'Parts' => 'Dele',
+ 'Parts Inventory' => 'Vareliste',
+ 'Password' => 'Adgangskode',
+ 'Password changed!' => 'Adgangskode ændret',
+ 'Payables' => 'Udeståender',
+ 'Payment' => 'Betaling',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payment posted!' => 'Betaling bogført!',
+ 'Payments' => 'Betalinger',
+ 'Pg Database Administration' => 'Pg Administration af database',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port mangler',
+ 'Post' => 'Bogfør',
+ 'Post as new' => 'Bogfør som ny',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Præferencer',
+ 'Preferences saved!' => 'Indstillinger gemt!',
+ 'Price' => 'Pris',
+ 'Print' => 'Udskriv',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Project Number missing!' => 'Projektnummer mangler!',
+ 'Project deleted!' => 'Projekt slettet!',
+ 'Project not on file!' => 'Projekt ikke i databasen!',
+ 'Project saved!' => 'Projekt gemt!',
+ 'Projects' => 'Projekter',
+ 'Purchase Invoice' => 'Indkøbsfaktura',
+ 'Purchase Order' => 'Indkøbsordre',
+ 'Purchase Orders' => 'Indkøbsordrer',
+ 'Qty' => 'Antal',
+ 'ROP' => 'Genbestil ved',
+ 'Rate' => 'Rate',
+ 'Recd' => 'Modtaget',
+ 'Receipt' => 'Kvittering',
+ 'Receipts' => 'Kvitteringer',
+ 'Receivables' => 'Indbetalinger',
+ 'Reconciliation' => 'Afstemning',
+ 'Record in' => 'Bogfør på',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference mangler',
+ 'Remaining' => 'Resterer',
+ 'Report for' => 'Rapport for',
+ 'Reports' => 'Rapporter',
+ 'Required by' => 'Bestilt af',
+ 'Retained Earnings' => 'Realiseret overskud',
+ 'Sales' => 'Salg',
+ 'Sales Invoice' => 'Salgsfaktura',
+ 'Sales Order' => 'Salgsordre',
+ 'Sales Orders' => 'Salgsordrer',
+ 'Save' => 'Gem',
+ 'Save as new' => 'Gem som ny',
+ 'Save to File' => 'Gem i fil',
+ 'Screen' => 'Skærm',
+ 'Select a Dataset to delete and press "Continue"' => 'Vælg et datasæt og tryk "Fortsæt"',
+ 'Select all' => 'Vælg alt',
+ 'Select from one of the items below' => 'Vælg fra en af tingene nedenfor, og tryk "Fortsæt"',
+ 'Select from one of the names below' => 'Vælg en af navnene nedenfor',
+ 'Select from one of the projects below' => 'Vælg et af projekterne nedenfor',
+ 'Select postscript or PDF!' => 'Vælg postscript eller PDF',
+ 'Sell Price' => 'Salgspris',
+ 'Send by E-Mail' => 'Sendt med epost',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Service Items' => 'Tjenester',
+ 'Service Number missing!' => 'Tjenestenummer mangler!',
+ 'Services' => 'Tjenester',
+ 'Setup Templates' => 'Skabeloner for opsætning',
+ 'Ship' => 'Send',
+ 'Ship to' => 'Send til',
+ 'Ship via' => 'Send via',
+ 'Short' => 'Kort',
+ 'Signature' => 'Underskrift',
+ 'Sold' => 'Solgt',
+ 'Source' => 'Bilag',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Opgørelse',
+ 'Statement Balance' => 'Balanceopgørelse',
+ 'Statement sent to' => 'Opgørelse sendt til',
+ 'Statements sent to printer!' => 'Opgørelser sendt til printer',
+ 'Stock Assembly' => 'Lagr sammensætning',
+ 'Stylesheet' => 'Stilark',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'System' => 'System',
+ 'Tax' => 'Afgift/Moms',
+ 'Tax Accounts' => 'Afgift/Momskonti',
+ 'Tax Included' => 'Inkl. afgifter og moms',
+ 'Tax collected' => 'Skat opkrævet',
+ 'Tax paid' => 'Skat betalt',
+ 'Taxable' => 'Afgifts/momspligtig',
+ 'Template saved!' => 'Skabelon gemt!',
+ 'Templates' => 'Skabeloner',
+ 'Terms: Net' => 'Netto',
+ 'The following Datasets are not in use and can be deleted' => 'De følgende datasæt er ikke i brug og kan slettes',
+ 'The following Datasets need to be updated' => 'De følgende datasæt skal opdateres',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Dette er en indledende kontrol af eksisterende kilder. Ingenting vil blive oprettet eller slettet på dette trin',
+ 'To' => 'til',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Skift brugernavnet for en eksisterende bruger og gem for at tilføje en ny bruger til en gruppe. Den nye bruger vil så bive gemt med de samme indstillinger under det nye brugernavn.',
+ 'Top Level' => 'Topniveau',
+ 'Total' => 'I alt',
+ 'Transaction Date missing!' => 'Dato mangler!',
+ 'Transaction deleted!' => 'Postering slettet!',
+ 'Transaction posted!' => 'Postering bogført!',
+ 'Transaction reversal enforced for all dates' => 'Rettelser af posteringer skal altid bogføres explicit',
+ 'Transaction reversal enforced up to' => 'Rettelser af posteringer skal bogføres explicit indtil',
+ 'Transactions' => 'Posteringer',
+ 'Transactions exist, cannot delete customer!' => 'Kunde kan ikke fjernes da der er posteringer!',
+ 'Transactions exist, cannot delete vendor!' => 'Leverandør kan ikke fjernes da der er posteringer!',
+ 'Transactions exist; cannot delete account!' => 'Konto kan ikke fjernes da der er posteringer!',
+ 'Trial Balance' => 'Foreløbig status',
+ 'Unit' => 'Enhed',
+ 'Unit of measure' => 'Måleenhed',
+ 'Update' => 'Opdatér',
+ 'Update Dataset' => 'Opdatér datasæt',
+ 'Updated' => 'Opdateret',
+ 'Use Templates' => 'Brug skabeloner',
+ 'User' => 'Bruger',
+ 'User deleted!' => 'Bruger slettet!',
+ 'User saved!' => 'Bruger gemt!',
+ 'Vendor' => 'Leverandør',
+ 'Vendor deleted!' => 'Leverandør slettet!',
+ 'Vendor missing!' => 'Leverandør mangler!',
+ 'Vendor not on file!' => 'Leverandør ikke i databasen!',
+ 'Vendor saved!' => 'Leverandør gemt!',
+ 'Vendors' => 'Leverandører',
+ 'Version' => 'Version',
+ 'Weight' => 'Vægt',
+ 'Weight Unit' => 'Vægtenhed',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'Year End' => 'Årsafslutning',
+ 'Yes' => 'Ja',
+ 'You are logged out!' => 'Du er logget ud',
+ 'You did not enter a name!' => 'Du angav ikke et navn',
+ 'You must enter a host and port for local and remote connections!' => 'Du skal angive en vært og en port for lokale og eksterne forbindelser!',
+ 'as at' => 'som ved',
+ 'collected on sales' => 'indsamlet ved salg',
+ 'days' => 'dage',
+ 'does not exist' => 'eksisterer ikke',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt via e-post til',
+ 'for Period' => 'for perioden',
+ 'hr' => 'time',
+ 'is already a member!' => 'er allerede et medlem',
+ 'is not a member!' => 'er ikke et medlem!',
+ 'localhost' => 'lokalt',
+ 'paid on purchases' => 'betalt ved indkøb',
+ 'sent to printer' => 'sendt til printer',
+ 'successfully created!' => 'oprettet!',
+ 'successfully deleted!' => 'slettet!',
+ 'to' => 'til',
+ 'website' => 'på Internet',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/am b/sql-ledger/locale/dk/am
new file mode 100644
index 0000000..7546a0d
--- /dev/null
+++ b/sql-ledger/locale/dk/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Kreditorer',
+ 'AR' => 'Debitorer',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Kontonummer',
+ 'Account Number missing!' => 'Kontonummer mangler!',
+ 'Account Type' => 'Kontotype',
+ 'Account Type missing!' => 'Kontotype mangler!',
+ 'Account deleted!' => 'Konto slettet!',
+ 'Account saved!' => 'Konto gemt!',
+ 'Add Account' => 'Ny konto',
+ 'Add GIFI' => 'Ny GIFI',
+ 'Address' => 'Adresse',
+ 'Asset' => 'Aktiv',
+ 'Audit Control' => 'Revisionskontrol',
+ 'Backup sent to' => 'Sikkerhedskopier sendt til',
+ 'Books are open' => 'Bogføringen er åben for rettelser',
+ 'Business Number' => 'CVR-nummer',
+ 'COGS' => 'Indkøb',
+ 'Cannot delete account!' => 'Kan ikke slette konto!',
+ 'Cannot delete default account!' => 'Kan ikke slette standardkonto!',
+ 'Cannot save account!' => 'Kan ikke gemme konto!',
+ 'Cannot save preferences!' => 'Kan ikke gemme præferencer!',
+ 'Character Set' => 'Tegnsæt',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Close Books up to' => 'Afslut bogføring op til',
+ 'Company' => 'Firma',
+ 'Continue' => 'Fortsæt',
+ 'Copy to COA' => 'Kopiér til COA',
+ 'Credit' => 'Kredit',
+ 'Date Format' => 'Datoformat',
+ 'Debit' => 'Debet',
+ 'Delete' => 'Fjern',
+ 'Delete Account' => 'Fjern konto',
+ 'Description' => 'Beskrivelse',
+ 'Dropdown Limit' => 'Grænse for nedtræk',
+ 'E-mail' => 'E-post',
+ 'Edit' => 'Redigér',
+ 'Edit Account' => 'Redigér konto',
+ 'Edit GIFI' => 'Redigér GIFI',
+ 'Edit Preferences for' => 'Redigér opsætning for',
+ 'Edit Template' => 'Redigér skabelon',
+ 'Enforce transaction reversal for all dates' => 'Gennemtving explicitte rettelser af posteringer for alle datoer',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Angiv op til 3 bogstaver adskilt med kolon (fx DKK:EUR:USD) for dine indenlandske og udenlandske valutaer',
+ 'Equity' => 'Egenkapital',
+ 'Expense' => 'Udgift',
+ 'Expense Account' => 'Udgiftskonto',
+ 'Expense/Asset' => 'Udgift/Aktiv',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Gevinst på valutahandel',
+ 'Foreign Exchange Loss' => 'Tab på valutahandel',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI slettet!',
+ 'GIFI missing!' => 'GIFI mangler!',
+ 'GIFI saved!' => 'GIFI gemt!',
+ 'Heading' => 'Overskrift',
+ 'Include in drop-down menus' => 'Inkludér i rullegardin-menuer',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Skal denne konto kunne vælges som afgifts- eller momskonto ved oprettelsen af kunder/leverandører?',
+ 'Income' => 'Indtægt',
+ 'Income Account' => 'Indtægtskonto',
+ 'Inventory' => 'Artikler',
+ 'Inventory Account' => 'Lagerkonto',
+ 'Is this a summary account to record' => 'Samlekonto for',
+ 'Language' => 'Sprog',
+ 'Last Invoice Number' => 'Seneste fakturanummer',
+ 'Last Numbers & Default Accounts' => 'Løbenumre og standardkonti',
+ 'Last Purchase Order Number' => 'Seneste nummer på indkøbsordre',
+ 'Last Sales Order Number' => 'Seneste salgsordrenummer',
+ 'Liability' => 'Passiv',
+ 'Link' => 'Referencer',
+ 'Name' => 'Navn',
+ 'No' => 'Nej',
+ 'No email address for' => 'Ingen epostadresse for',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Numerisk format',
+ 'Parts Inventory' => 'Vareliste',
+ 'Password' => 'Adgangskode',
+ 'Payables' => 'Udeståender',
+ 'Payment' => 'Betaling',
+ 'Phone' => 'Tel.',
+ 'Preferences saved!' => 'Indstillinger gemt!',
+ 'Rate' => 'Rate',
+ 'Receivables' => 'Indbetalinger',
+ 'Sales' => 'Salg',
+ 'Save' => 'Gem',
+ 'Service Items' => 'Tjenester',
+ 'Ship via' => 'Send via',
+ 'Signature' => 'Underskrift',
+ 'Stylesheet' => 'Stilark',
+ 'Tax' => 'Afgift/Moms',
+ 'Tax Accounts' => 'Afgift/Momskonti',
+ 'Template saved!' => 'Skabelon gemt!',
+ 'Transaction reversal enforced for all dates' => 'Rettelser af posteringer skal altid bogføres explicit',
+ 'Transaction reversal enforced up to' => 'Rettelser af posteringer skal bogføres explicit indtil',
+ 'Transactions exist; cannot delete account!' => 'Konto kan ikke fjernes da der er posteringer!',
+ 'Weight Unit' => 'Vægtenhed',
+ 'Year End' => 'Årsafslutning',
+ 'Yes' => 'Ja',
+ 'does not exist' => 'eksisterer ikke',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'ny_konto' => 'add_account',
+ 'fortsæt' => 'continue',
+ 'kopiér_til_coa' => 'copy_to_coa',
+ 'fjern' => 'delete',
+ 'redigér' => 'edit',
+ 'redigér_konto' => 'edit_account',
+ 'gem' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/ap b/sql-ledger/locale/dk/ap
new file mode 100644
index 0000000..424926d
--- /dev/null
+++ b/sql-ledger/locale/dk/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Leverandørfaktura',
+ 'AP Transactions' => 'Leverandørfakturaer',
+ 'Account' => 'Konto',
+ 'Add Accounts Payables Transaction' => 'Ny leverandørpostering',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløb',
+ 'Amount Due' => 'Forfaldent',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Transaction' => 'Er du sikker på du vil fjerne postering',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Cannot delete transaction!' => 'Kan ikke slette postering!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bogføre betaling for en afsluttet periode',
+ 'Cannot post transaction for a closed period!' => 'Kan ikke bogføre postering for en afsluttet periode!',
+ 'Cannot post transaction!' => 'Kan ikke bogføre postering!',
+ 'Closed' => 'Afsluttet',
+ 'Confirm!' => 'Bekræft!',
+ 'Continue' => 'Fortsæt',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Kunde ikke i databasen!',
+ 'Date' => 'Dato',
+ 'Date Paid' => 'Betalingsdato',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Fjern',
+ 'Description' => 'Beskrivelse',
+ 'Due Date' => 'Forfaldsdato',
+ 'Due Date missing!' => 'Forfaldsdato mangler!',
+ 'Edit Accounts Payables Transaction' => 'Redigér leverandørpostering',
+ 'Employee' => 'Ansat',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekselkurs',
+ 'Exchangerate for payment missing!' => 'Valutakurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekselkurs mangler!',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Notes' => 'Bemærkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Open' => 'Åbn',
+ 'Order' => 'Ordre',
+ 'Order Number' => 'Ordrenummer',
+ 'Paid' => 'Betalt',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payments' => 'Betalinger',
+ 'Post' => 'Bogfør',
+ 'Post as new' => 'Bogfør som ny',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt ikke i databasen!',
+ 'Purchase Invoice' => 'Indkøbsfaktura',
+ 'Select from one of the names below' => 'Vælg en af navnene nedenfor',
+ 'Select from one of the projects below' => 'Vælg et af projekterne nedenfor',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Bilag',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Afgift/Moms',
+ 'Tax Included' => 'Inkl. afgifter og moms',
+ 'To' => 'til',
+ 'Total' => 'I alt',
+ 'Transaction deleted!' => 'Postering slettet!',
+ 'Transaction posted!' => 'Postering bogført!',
+ 'Update' => 'Opdatér',
+ 'Vendor' => 'Leverandør',
+ 'Vendor missing!' => 'Leverandør mangler!',
+ 'Vendor not on file!' => 'Leverandør ikke i databasen!',
+ 'Yes' => 'Ja',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'leverandørfaktura' => 'ap_transaction',
+ 'ny_leverandørpostering' => 'add_accounts_payables_transaction',
+ 'fortsæt' => 'continue',
+ 'fjern' => 'delete',
+ 'redigér_leverandørpostering' => 'edit_accounts_payables_transaction',
+ 'bogfør' => 'post',
+ 'bogfør_som_ny' => 'post_as_new',
+ 'indkøbsfaktura' => 'purchase_invoice',
+ 'opdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/ar b/sql-ledger/locale/dk/ar
new file mode 100644
index 0000000..9f778b0
--- /dev/null
+++ b/sql-ledger/locale/dk/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Debitorpostering',
+ 'AR Transactions' => 'Debitorposteringer',
+ 'Account' => 'Konto',
+ 'Add Accounts Receivables Transaction' => 'Ny debitorpostering',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløb',
+ 'Amount Due' => 'Forfaldent',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Transaction' => 'Er du sikker på du vil fjerne postering',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Cannot delete transaction!' => 'Kan ikke slette postering!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bogføre betaling for en afsluttet periode',
+ 'Cannot post transaction for a closed period!' => 'Kan ikke bogføre postering for en afsluttet periode!',
+ 'Cannot post transaction!' => 'Kan ikke bogføre postering!',
+ 'Closed' => 'Afsluttet',
+ 'Confirm!' => 'Bekræft!',
+ 'Continue' => 'Fortsæt',
+ 'Credit Limit' => 'Kreditgrænse',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kunde',
+ 'Customer missing!' => 'Kunde mangler!',
+ 'Customer not on file!' => 'Kunde ikke i databasen!',
+ 'Date' => 'Dato',
+ 'Date Paid' => 'Betalingsdato',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Fjern',
+ 'Description' => 'Beskrivelse',
+ 'Due Date' => 'Forfaldsdato',
+ 'Due Date missing!' => 'Forfaldsdato mangler!',
+ 'Edit Accounts Receivables Transaction' => 'Redigér debitorpostering',
+ 'Employee' => 'Ansat',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekselkurs',
+ 'Exchangerate for payment missing!' => 'Valutakurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekselkurs mangler!',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Notes' => 'Bemærkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Open' => 'Åbn',
+ 'Order' => 'Ordre',
+ 'Order Number' => 'Ordrenummer',
+ 'Paid' => 'Betalt',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payments' => 'Betalinger',
+ 'Post' => 'Bogfør',
+ 'Post as new' => 'Bogfør som ny',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt ikke i databasen!',
+ 'Remaining' => 'Resterer',
+ 'Sales Invoice' => 'Salgsfaktura',
+ 'Select from one of the names below' => 'Vælg en af navnene nedenfor',
+ 'Select from one of the projects below' => 'Vælg et af projekterne nedenfor',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Bilag',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Afgift/Moms',
+ 'Tax Included' => 'Inkl. afgifter og moms',
+ 'To' => 'til',
+ 'Total' => 'I alt',
+ 'Transaction deleted!' => 'Postering slettet!',
+ 'Transaction posted!' => 'Postering bogført!',
+ 'Update' => 'Opdatér',
+ 'Vendor not on file!' => 'Leverandør ikke i databasen!',
+ 'Yes' => 'Ja',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'debitorpostering' => 'ar_transaction',
+ 'fortsæt' => 'continue',
+ 'fjern' => 'delete',
+ 'bogfør' => 'post',
+ 'bogfør_som_ny' => 'post_as_new',
+ 'salgsfaktura' => 'sales_invoice',
+ 'opdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/arap b/sql-ledger/locale/dk/arap
new file mode 100644
index 0000000..af22061
--- /dev/null
+++ b/sql-ledger/locale/dk/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adresse',
+ 'Continue' => 'Fortsæt',
+ 'Customer not on file!' => 'Kunde ikke i databasen!',
+ 'Description' => 'Beskrivelse',
+ 'Number' => 'Nummer',
+ 'Project not on file!' => 'Projekt ikke i databasen!',
+ 'Select from one of the names below' => 'Vælg en af navnene nedenfor',
+ 'Select from one of the projects below' => 'Vælg et af projekterne nedenfor',
+ 'Vendor not on file!' => 'Leverandør ikke i databasen!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'fortsæt' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/ca b/sql-ledger/locale/dk/ca
new file mode 100644
index 0000000..302aeea
--- /dev/null
+++ b/sql-ledger/locale/dk/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Credit' => 'Kredit',
+ 'Date' => 'Dato',
+ 'Debit' => 'Debet',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Description' => 'Beskrivelse',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'List Transactions' => 'Vis bogføringer',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Reference' => 'Reference',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'til',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'vis_bogføringer' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/cp b/sql-ledger/locale/dk/cp
new file mode 100644
index 0000000..79d0579
--- /dev/null
+++ b/sql-ledger/locale/dk/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløb',
+ 'Amount does not equal applied!' => 'Beløb er ikke det samme som brugt!',
+ 'Amount missing!' => 'Konto mangler!',
+ 'Applied' => 'Udført',
+ 'Cannot post payment!' => 'Kan ikke bogføre betaling',
+ 'Cannot process payment for a closed period!' => 'Kan ikke behandle betaling for en afsluttet periode!',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check udskrevet',
+ 'Check printing failed!' => 'Udskrivning af check mislykkedes',
+ 'Continue' => 'Fortsæt',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kunde',
+ 'Customer not on file!' => 'Kunde ikke i databasen!',
+ 'Date' => 'Dato',
+ 'Date missing!' => 'Dato mangler!',
+ 'Description' => 'Beskrivelse',
+ 'Due' => 'Forfald',
+ 'Exchangerate' => 'Vekselkurs',
+ 'From' => 'Fra',
+ 'Invoice' => 'Faktura',
+ 'Invoices' => 'Fakturaer',
+ 'Nothing applied!' => 'Ingenting udført!',
+ 'Number' => 'Nummer',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'Betaling',
+ 'Payment posted!' => 'Betaling bogført!',
+ 'Post' => 'Bogfør',
+ 'Print' => 'Udskriv',
+ 'Printer' => 'Printer',
+ 'Project not on file!' => 'Projekt ikke i databasen!',
+ 'Receipt' => 'Kvittering',
+ 'Reference' => 'Reference',
+ 'Screen' => 'Skærm',
+ 'Select from one of the names below' => 'Vælg en af navnene nedenfor',
+ 'Select from one of the projects below' => 'Vælg et af projekterne nedenfor',
+ 'To' => 'til',
+ 'Update' => 'Opdatér',
+ 'Vendor' => 'Leverandør',
+ 'Vendor not on file!' => 'Leverandør ikke i databasen!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'fortsæt' => 'continue',
+ 'bogfør' => 'post',
+ 'udskriv' => 'print',
+ 'opdatér' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/ct b/sql-ledger/locale/dk/ct
new file mode 100644
index 0000000..2b8f91b
--- /dev/null
+++ b/sql-ledger/locale/dk/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Tilføj',
+ 'Address' => 'Adresse',
+ 'All' => 'Alt',
+ 'Bcc' => 'Blind kopi',
+ 'Cannot delete customer!' => 'Kan ikke slette kunde!',
+ 'Cannot delete vendor!' => 'Kan ikke slette leverandør!',
+ 'Cc' => 'Kopi',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsæt',
+ 'Credit Limit' => 'Kreditgrænse',
+ 'Customer deleted!' => 'Kunde slettet!',
+ 'Customer saved!' => 'Kunde gemt!',
+ 'Customers' => 'Kunder',
+ 'Delete' => 'Fjern',
+ 'Discount' => 'Rabat',
+ 'E-mail' => 'E-post',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Invoice' => 'Faktura',
+ 'Name' => 'Navn',
+ 'Name missing!' => 'Navn mangler!',
+ 'Notes' => 'Bemærkninger',
+ 'Number' => 'Nummer',
+ 'Order' => 'Ordre',
+ 'Orphaned' => 'Fritstående',
+ 'Phone' => 'Tel.',
+ 'Save' => 'Gem',
+ 'Ship to' => 'Send til',
+ 'Tax Included' => 'Inkl. afgifter og moms',
+ 'Taxable' => 'Afgifts/momspligtig',
+ 'Terms: Net' => 'Netto',
+ 'Transactions exist, cannot delete customer!' => 'Kunde kan ikke fjernes da der er posteringer!',
+ 'Transactions exist, cannot delete vendor!' => 'Leverandør kan ikke fjernes da der er posteringer!',
+ 'Vendor deleted!' => 'Leverandør slettet!',
+ 'Vendor saved!' => 'Leverandør gemt!',
+ 'Vendors' => 'Leverandører',
+ 'days' => 'dage',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'tilføj' => 'add',
+ 'fortsæt' => 'continue',
+ 'fjern' => 'delete',
+ 'faktura' => 'invoice',
+ 'ordre' => 'order',
+ 'gem' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/gl b/sql-ledger/locale/dk/gl
new file mode 100644
index 0000000..3693fa2
--- /dev/null
+++ b/sql-ledger/locale/dk/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Leverandørfaktura',
+ 'AR Transaction' => 'Debitorpostering',
+ 'Account' => 'Konto',
+ 'Add General Ledger Transaction' => 'Ny postering i hovedbog',
+ 'Address' => 'Adresse',
+ 'All' => 'Alt',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Transaction' => 'Er du sikker på du vil fjerne postering',
+ 'Asset' => 'Aktiv',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'Kan ikke slette postering!',
+ 'Cannot have a value in both Debit and Credit!' => 'Kan ikke have en værdi i både debet og kredit!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'Kan ikke bogføre postering for en afsluttet periode!',
+ 'Confirm!' => 'Bekræft!',
+ 'Continue' => 'Fortsæt',
+ 'Credit' => 'Kredit',
+ 'Customer not on file!' => 'Kunde ikke i databasen!',
+ 'Date' => 'Dato',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet og kredit skal være det samme!',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Fjern',
+ 'Description' => 'Beskrivelse',
+ 'Edit General Ledger Transaction' => 'Redigér en postering i hovedbog',
+ 'Equity' => 'Egenkapital',
+ 'Expense' => 'Udgift',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'Postering i hovedbog',
+ 'General Ledger' => 'Hovedbog',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Income' => 'Indtægt',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Liability' => 'Passiv',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Notes' => 'Bemærkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Post' => 'Bogfør',
+ 'Post as new' => 'Bogfør som ny',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt ikke i databasen!',
+ 'Purchase Invoice' => 'Indkøbsfaktura',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference mangler',
+ 'Reports' => 'Rapporter',
+ 'Sales Invoice' => 'Salgsfaktura',
+ 'Select from one of the names below' => 'Vælg en af navnene nedenfor',
+ 'Select from one of the projects below' => 'Vælg et af projekterne nedenfor',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Bilag',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'til',
+ 'Transaction Date missing!' => 'Dato mangler!',
+ 'Transaction deleted!' => 'Postering slettet!',
+ 'Transaction posted!' => 'Postering bogført!',
+ 'Update' => 'Opdatér',
+ 'Vendor not on file!' => 'Leverandør ikke i databasen!',
+ 'Yes' => 'Ja',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'leverandørfaktura' => 'ap_transaction',
+ 'debitorpostering' => 'ar_transaction',
+ 'fortsæt' => 'continue',
+ 'fjern' => 'delete',
+ 'postering_i_hovedbog' => 'gl_transaction',
+ 'bogfør' => 'post',
+ 'bogfør_som_ny' => 'post_as_new',
+ 'indkøbsfaktura' => 'purchase_invoice',
+ 'salgsfaktura' => 'sales_invoice',
+ 'opdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/ic b/sql-ledger/locale/dk/ic
new file mode 100644
index 0000000..38e0d70
--- /dev/null
+++ b/sql-ledger/locale/dk/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Aktiv',
+ 'Add' => 'Tilføj',
+ 'Add Assembly' => 'Ny sammensætning',
+ 'Add Part' => 'Ny vare',
+ 'Add Purchase Order' => 'Ny indkøbsordre',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Add Service' => 'Ny tjeneste',
+ 'Address' => 'Adresse',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Assemblies' => 'Sammensætninger',
+ 'Assemblies restocked!' => 'Sammensætninger genlagret',
+ 'Assembly Number missing!' => 'Sammensætningsnummer mangler',
+ 'Attachment' => 'Bilag',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Varelager',
+ 'Bought' => 'Købt',
+ 'COGS' => 'Indkøb',
+ 'Cannot delete item already invoiced!' => 'Kan ikke slette allerede faktureret enkeltdel!',
+ 'Cannot delete item on order!' => 'Kan ikke slette bestilt enkeltdel!',
+ 'Cannot delete item which is part of an assembly!' => 'kan ikke slette en enhed som er en del af en sammensætning!',
+ 'Cannot delete item!' => 'Kan ikke slette enhed!',
+ 'Cannot stock assemblies!' => 'Kan ikke genbesætte sammensætninger',
+ 'Cc' => 'Kopi',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsæt',
+ 'Copies' => 'Kopier',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Fjern',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'Drawing' => 'Træk',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit Assembly' => 'Redigér sammensætning',
+ 'Edit Part' => 'Redigér vare',
+ 'Edit Service' => 'Redigér tjeneste',
+ 'Expense' => 'Udgift',
+ 'Extended' => 'Udvidet',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'Image' => 'Billede',
+ 'In-line' => 'Indlejret',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Income' => 'Indtægt',
+ 'Individual Items' => 'Individuelle enheder',
+ 'Inventory' => 'Artikler',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Lagerbeholdning skal være nul for at du kan forælde denne sammensætning',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Lagerbeholdning skal være nul for at du kan forælde denne enhed',
+ 'Inventory quantity must be zero!' => 'Lagerbeholdning skal være nul',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Item deleted!' => 'Enkeltdel slettet!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Last Cost' => 'Seneste pris',
+ 'Line Total' => 'Antal linjer',
+ 'Link Accounts' => 'Forbind konti',
+ 'List Price' => 'Listepris',
+ 'Make' => 'Fabrikat',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Message' => 'Besked',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Model',
+ 'Name' => 'Navn',
+ 'No.' => 'No.',
+ 'Notes' => 'Bemærkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tal mangler i række',
+ 'Obsolete' => 'Forældet',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'On Hand' => 'På lager',
+ 'On Order' => 'I ordre',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Ordredato mangler',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler',
+ 'Ordered' => 'bestilt',
+ 'Orphaned' => 'Fritstående',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Part Number missing!' => 'Varenummer mangler!',
+ 'Parts' => 'Dele',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Indkøbsordre',
+ 'Qty' => 'Antal',
+ 'ROP' => 'Genbestil ved',
+ 'Recd' => 'Modtaget',
+ 'Required by' => 'Bestilt af',
+ 'Sales' => 'Salg',
+ 'Sales Order' => 'Salgsordre',
+ 'Save' => 'Gem',
+ 'Screen' => 'Skærm',
+ 'Select from one of the items below' => 'Vælg fra en af tingene nedenfor, og tryk "Fortsæt"',
+ 'Select postscript or PDF!' => 'Vælg postscript eller PDF',
+ 'Sell Price' => 'Salgspris',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Service Number missing!' => 'Tjenestenummer mangler!',
+ 'Services' => 'Tjenester',
+ 'Ship' => 'Send',
+ 'Ship to' => 'Send til',
+ 'Short' => 'Kort',
+ 'Sold' => 'Solgt',
+ 'Stock Assembly' => 'Lagr sammensætning',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Afgift/Moms',
+ 'To' => 'til',
+ 'Top Level' => 'Topniveau',
+ 'Total' => 'I alt',
+ 'Unit' => 'Enhed',
+ 'Unit of measure' => 'Måleenhed',
+ 'Update' => 'Opdatér',
+ 'Updated' => 'Opdateret',
+ 'Weight' => 'Vægt',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt via e-post til',
+ 'hr' => 'time',
+ 'sent to printer' => 'sendt til printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'tilføj' => 'add',
+ 'ny_sammensætning' => 'add_assembly',
+ 'ny_vare' => 'add_part',
+ 'ny_tjeneste' => 'add_service',
+ 'fortsæt' => 'continue',
+ 'fjern' => 'delete',
+ 'redigér_sammensætning' => 'edit_assembly',
+ 'redigér_vare' => 'edit_part',
+ 'redigér_tjeneste' => 'edit_service',
+ 'gem' => 'save',
+ 'opdatér' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/io b/sql-ledger/locale/dk/io
new file mode 100644
index 0000000..117e8d2
--- /dev/null
+++ b/sql-ledger/locale/dk/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Ny indkøbsordre',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Address' => 'Adresse',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Attachment' => 'Bilag',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Varelager',
+ 'Cc' => 'Kopi',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsæt',
+ 'Copies' => 'Kopier',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Extended' => 'Udvidet',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'In-line' => 'Indlejret',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Message' => 'Besked',
+ 'Name' => 'Navn',
+ 'No.' => 'No.',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tal mangler i række',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Ordredato mangler',
+ 'Order Number missing!' => 'Ordrenummer mangler',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Indkøbsordre',
+ 'Qty' => 'Antal',
+ 'Recd' => 'Modtaget',
+ 'Required by' => 'Bestilt af',
+ 'Sales Order' => 'Salgsordre',
+ 'Screen' => 'Skærm',
+ 'Select from one of the items below' => 'Vælg fra en af tingene nedenfor, og tryk "Fortsæt"',
+ 'Select postscript or PDF!' => 'Vælg postscript eller PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Ship' => 'Send',
+ 'Ship to' => 'Send til',
+ 'Subject' => 'Emne',
+ 'To' => 'til',
+ 'Unit' => 'Enhed',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'emailed to' => 'sendt via e-post til',
+ 'sent to printer' => 'sendt til printer',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'fortsæt' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/ir b/sql-ledger/locale/dk/ir
new file mode 100644
index 0000000..cf77f62
--- /dev/null
+++ b/sql-ledger/locale/dk/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Invoice' => 'Ny indkøbsfaktura',
+ 'Add Purchase Order' => 'Ny indkøbsordre',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløb',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Invoice Number' => 'Er du sikker på du vil fjerne fakturanummer',
+ 'Attachment' => 'Bilag',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Varelager',
+ 'Cannot delete invoice!' => 'Kan ikke slette faktura!',
+ 'Cannot post invoice for a closed period!' => 'Kan ikke bogføre faktura for en afsluttet periode!',
+ 'Cannot post invoice!' => 'Kan ikke bogføre faktura!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bogføre betaling for en afsluttet periode',
+ 'Cc' => 'Kopi',
+ 'Confirm!' => 'Bekræft!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsæt',
+ 'Copies' => 'Kopier',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Kunde ikke i databasen!',
+ 'Date' => 'Dato',
+ 'Date Due' => 'Forfaldsdato',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Fjern',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit Purchase Invoice' => 'Redigér projekt',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekselkurs',
+ 'Exchangerate for payment missing!' => 'Valutakurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekselkurs mangler!',
+ 'Extended' => 'Udvidet',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'In-line' => 'Indlejret',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Invoice deleted!' => 'Faktura slettet!',
+ 'Invoice posted!' => 'Faktura bogført!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Message' => 'Besked',
+ 'Name' => 'Navn',
+ 'No.' => 'No.',
+ 'Notes' => 'Bemærkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tal mangler i række',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Ordredato mangler',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payments' => 'Betalinger',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Bogfør',
+ 'Post as new' => 'Bogfør som ny',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt ikke i databasen!',
+ 'Purchase Order' => 'Indkøbsordre',
+ 'Qty' => 'Antal',
+ 'Recd' => 'Modtaget',
+ 'Record in' => 'Bogfør på',
+ 'Required by' => 'Bestilt af',
+ 'Sales Order' => 'Salgsordre',
+ 'Screen' => 'Skærm',
+ 'Select from one of the items below' => 'Vælg fra en af tingene nedenfor, og tryk "Fortsæt"',
+ 'Select from one of the names below' => 'Vælg en af navnene nedenfor',
+ 'Select from one of the projects below' => 'Vælg et af projekterne nedenfor',
+ 'Select postscript or PDF!' => 'Vælg postscript eller PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Ship' => 'Send',
+ 'Ship to' => 'Send til',
+ 'Source' => 'Bilag',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Inkl. afgifter og moms',
+ 'To' => 'til',
+ 'Total' => 'I alt',
+ 'Unit' => 'Enhed',
+ 'Update' => 'Opdatér',
+ 'Vendor' => 'Leverandør',
+ 'Vendor missing!' => 'Leverandør mangler!',
+ 'Vendor not on file!' => 'Leverandør ikke i databasen!',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'Yes' => 'Ja',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt via e-post til',
+ 'sent to printer' => 'sendt til printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'fortsæt' => 'continue',
+ 'fjern' => 'delete',
+ 'ordre' => 'order',
+ 'bogfør' => 'post',
+ 'bogfør_som_ny' => 'post_as_new',
+ 'opdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/is b/sql-ledger/locale/dk/is
new file mode 100644
index 0000000..5697185
--- /dev/null
+++ b/sql-ledger/locale/dk/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Order' => 'Ny indkøbsordre',
+ 'Add Sales Invoice' => 'Ny salgsfaktura',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløb',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Invoice Number' => 'Er du sikker på du vil fjerne fakturanummer',
+ 'Attachment' => 'Bilag',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Varelager',
+ 'Cannot delete invoice!' => 'Kan ikke slette faktura!',
+ 'Cannot post invoice for a closed period!' => 'Kan ikke bogføre faktura for en afsluttet periode!',
+ 'Cannot post invoice!' => 'Kan ikke bogføre faktura!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bogføre betaling for en afsluttet periode',
+ 'Cc' => 'Kopi',
+ 'Confirm!' => 'Bekræft!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsæt',
+ 'Copies' => 'Kopier',
+ 'Credit Limit' => 'Kreditgrænse',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kunde',
+ 'Customer missing!' => 'Kunde mangler!',
+ 'Customer not on file!' => 'Kunde ikke i databasen!',
+ 'Date' => 'Dato',
+ 'Date Due' => 'Forfaldsdato',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Fjern',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit Sales Invoice' => 'Redigér salgsfaktura',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekselkurs',
+ 'Exchangerate for payment missing!' => 'Valutakurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekselkurs mangler!',
+ 'Extended' => 'Udvidet',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'In-line' => 'Indlejret',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Invoice deleted!' => 'Faktura slettet!',
+ 'Invoice posted!' => 'Faktura bogført!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Message' => 'Besked',
+ 'Name' => 'Navn',
+ 'No.' => 'No.',
+ 'Notes' => 'Bemærkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tal mangler i række',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Ordredato mangler',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payments' => 'Betalinger',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Bogfør',
+ 'Post as new' => 'Bogfør som ny',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Print' => 'Udskriv',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt ikke i databasen!',
+ 'Purchase Order' => 'Indkøbsordre',
+ 'Qty' => 'Antal',
+ 'Recd' => 'Modtaget',
+ 'Record in' => 'Bogfør på',
+ 'Remaining' => 'Resterer',
+ 'Required by' => 'Bestilt af',
+ 'Sales Order' => 'Salgsordre',
+ 'Screen' => 'Skærm',
+ 'Select from one of the items below' => 'Vælg fra en af tingene nedenfor, og tryk "Fortsæt"',
+ 'Select from one of the names below' => 'Vælg en af navnene nedenfor',
+ 'Select from one of the projects below' => 'Vælg et af projekterne nedenfor',
+ 'Select postscript or PDF!' => 'Vælg postscript eller PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Ship' => 'Send',
+ 'Ship to' => 'Send til',
+ 'Ship via' => 'Send via',
+ 'Source' => 'Bilag',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Inkl. afgifter og moms',
+ 'To' => 'til',
+ 'Total' => 'I alt',
+ 'Unit' => 'Enhed',
+ 'Update' => 'Opdatér',
+ 'Vendor not on file!' => 'Leverandør ikke i databasen!',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'Yes' => 'Ja',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt via e-post til',
+ 'sent to printer' => 'sendt til printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'fortsæt' => 'continue',
+ 'fjern' => 'delete',
+ 'e_post' => 'e_mail',
+ 'ordre' => 'order',
+ 'bogfør' => 'post',
+ 'bogfør_som_ny' => 'post_as_new',
+ 'udskriv' => 'print',
+ 'send_til' => 'ship_to',
+ 'opdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/login b/sql-ledger/locale/dk/login
new file mode 100644
index 0000000..19adf11
--- /dev/null
+++ b/sql-ledger/locale/dk/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'Om',
+ 'Accounting' => 'Bogføring',
+ 'Database Host' => 'Database-vært',
+ 'Dataset' => 'Datasæt',
+ 'Incorrect Dataset version!' => 'Forkert version af datasæt!',
+ 'Incorrect Password!' => 'Forkert adgangskode',
+ 'Licensed to' => 'Udført for',
+ 'Login' => 'Log på',
+ 'Name' => 'Navn',
+ 'Password' => 'Adgangskode',
+ 'User' => 'Bruger',
+ 'Version' => 'Version',
+ 'You are logged out!' => 'Du er logget ud',
+ 'You did not enter a name!' => 'Du angav ikke et navn',
+ 'is not a member!' => 'er ikke et medlem!',
+ 'localhost' => 'lokalt',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'log_på' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/menu b/sql-ledger/locale/dk/menu
new file mode 100644
index 0000000..b4649c6
--- /dev/null
+++ b/sql-ledger/locale/dk/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'Kreditorer',
+ 'AP Aging' => 'Aldersfordeling',
+ 'AR' => 'Debitorer',
+ 'AR Aging' => 'Aldersfordeling',
+ 'Accounting Menu' => 'Konto-menu',
+ 'Add Account' => 'Ny konto',
+ 'Add Assembly' => 'Ny sammensætning',
+ 'Add Customer' => 'Ny kunde',
+ 'Add GIFI' => 'Ny GIFI',
+ 'Add Part' => 'Ny vare',
+ 'Add Project' => 'Nyt projekt',
+ 'Add Service' => 'Ny tjeneste',
+ 'Add Transaction' => 'Ny postering',
+ 'Add Vendor' => 'Ny leverandør',
+ 'Assemblies' => 'Sammensætninger',
+ 'Audit Control' => 'Revisionskontrol',
+ 'Backup' => 'Sikkerheskopi',
+ 'Balance Sheet' => 'Status',
+ 'Cash' => 'Kontanter',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Check' => 'Check',
+ 'Customers' => 'Kunder',
+ 'General Ledger' => 'Hovedbog',
+ 'Goods & Services' => 'Varer og tjenester',
+ 'HTML Templates' => 'HTML-skabeloner',
+ 'Income Statement' => 'Driftsregnskab',
+ 'Invoice' => 'Faktura',
+ 'LaTeX Templates' => 'LaTeX-skabeloner',
+ 'List Accounts' => 'List konti',
+ 'List GIFI' => 'List GIFI',
+ 'Logout' => 'Log af',
+ 'Order Entry' => 'Ordreindgang',
+ 'Packing List' => 'Følgeseddel',
+ 'Parts' => 'Dele',
+ 'Payment' => 'Betaling',
+ 'Payments' => 'Betalinger',
+ 'Preferences' => 'Præferencer',
+ 'Projects' => 'Projekter',
+ 'Purchase Invoice' => 'Indkøbsfaktura',
+ 'Purchase Order' => 'Indkøbsordre',
+ 'Purchase Orders' => 'Indkøbsordrer',
+ 'Receipt' => 'Kvittering',
+ 'Receipts' => 'Kvitteringer',
+ 'Reconciliation' => 'Afstemning',
+ 'Reports' => 'Rapporter',
+ 'Sales Invoice' => 'Salgsfaktura',
+ 'Sales Order' => 'Salgsordre',
+ 'Sales Orders' => 'Salgsordrer',
+ 'Save to File' => 'Gem i fil',
+ 'Send by E-Mail' => 'Sendt med epost',
+ 'Services' => 'Tjenester',
+ 'Statement' => 'Opgørelse',
+ 'Stock Assembly' => 'Lagr sammensætning',
+ 'Stylesheet' => 'Stilark',
+ 'System' => 'System',
+ 'Tax collected' => 'Skat opkrævet',
+ 'Tax paid' => 'Skat betalt',
+ 'Transactions' => 'Posteringer',
+ 'Trial Balance' => 'Foreløbig status',
+ 'Vendors' => 'Leverandører',
+ 'Version' => 'Version',
+ 'localhost' => 'lokalt',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/oe b/sql-ledger/locale/dk/oe
new file mode 100644
index 0000000..1b58c08
--- /dev/null
+++ b/sql-ledger/locale/dk/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Tilføj',
+ 'Add Purchase Invoice' => 'Ny indkøbsfaktura',
+ 'Add Purchase Order' => 'Ny indkøbsordre',
+ 'Add Sales Invoice' => 'Ny salgsfaktura',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløb',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Order Number' => 'Er du sikker på at du vil fjerne ordrenummer',
+ 'Attachment' => 'Bilag',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Varelager',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Kan ikke slette ordre!',
+ 'Cannot save order!' => 'Kan ikke gemme ordre!',
+ 'Cc' => 'Kopi',
+ 'Closed' => 'Afsluttet',
+ 'Confirm!' => 'Bekræft!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsæt',
+ 'Copies' => 'Kopier',
+ 'Credit Limit' => 'Kreditgrænse',
+ 'Curr' => 'Val',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kunde',
+ 'Customer missing!' => 'Kunde mangler!',
+ 'Customer not on file!' => 'Kunde ikke i databasen!',
+ 'Date' => 'Dato',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Fjern',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit Purchase Order' => 'Redigér indkøbsordre',
+ 'Edit Sales Order' => 'Redigér salgsordre',
+ 'Exchangerate' => 'Vekselkurs',
+ 'Exchangerate missing!' => 'Vekselkurs mangler!',
+ 'Extended' => 'Udvidet',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'ID' => 'ID',
+ 'In-line' => 'Indlejret',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Message' => 'Besked',
+ 'Name' => 'Navn',
+ 'No.' => 'No.',
+ 'Notes' => 'Bemærkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tal mangler i række',
+ 'O' => 'O',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Open' => 'Åbn',
+ 'Order' => 'Ordre',
+ 'Order Date' => 'Ordredato',
+ 'Order Date missing!' => 'Ordredato mangler',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler',
+ 'Order deleted!' => 'Ordre slettet',
+ 'Order saved!' => 'Ordre gemt',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Print' => 'Udskriv',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt ikke i databasen!',
+ 'Purchase Order' => 'Indkøbsordre',
+ 'Purchase Orders' => 'Indkøbsordrer',
+ 'Qty' => 'Antal',
+ 'Recd' => 'Modtaget',
+ 'Remaining' => 'Resterer',
+ 'Required by' => 'Bestilt af',
+ 'Sales Order' => 'Salgsordre',
+ 'Sales Orders' => 'Salgsordrer',
+ 'Save' => 'Gem',
+ 'Save as new' => 'Gem som ny',
+ 'Screen' => 'Skærm',
+ 'Select from one of the items below' => 'Vælg fra en af tingene nedenfor, og tryk "Fortsæt"',
+ 'Select from one of the names below' => 'Vælg en af navnene nedenfor',
+ 'Select from one of the projects below' => 'Vælg et af projekterne nedenfor',
+ 'Select postscript or PDF!' => 'Vælg postscript eller PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Ship' => 'Send',
+ 'Ship to' => 'Send til',
+ 'Ship via' => 'Send via',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Afgift/Moms',
+ 'Tax Included' => 'Inkl. afgifter og moms',
+ 'Terms: Net' => 'Netto',
+ 'To' => 'til',
+ 'Total' => 'I alt',
+ 'Unit' => 'Enhed',
+ 'Update' => 'Opdatér',
+ 'Vendor' => 'Leverandør',
+ 'Vendor missing!' => 'Leverandør mangler!',
+ 'Vendor not on file!' => 'Leverandør ikke i databasen!',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'Yes' => 'Ja',
+ 'days' => 'dage',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt via e-post til',
+ 'sent to printer' => 'sendt til printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'tilføj' => 'add',
+ 'fortsæt' => 'continue',
+ 'fjern' => 'delete',
+ 'e_post' => 'e_mail',
+ 'faktura' => 'invoice',
+ 'udskriv' => 'print',
+ 'gem' => 'save',
+ 'gem_som_ny' => 'save_as_new',
+ 'send_til' => 'ship_to',
+ 'opdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/pe b/sql-ledger/locale/dk/pe
new file mode 100644
index 0000000..66c62ee
--- /dev/null
+++ b/sql-ledger/locale/dk/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Tilføj',
+ 'Add Project' => 'Nyt projekt',
+ 'All' => 'Alt',
+ 'Continue' => 'Fortsæt',
+ 'Delete' => 'Fjern',
+ 'Description' => 'Beskrivelse',
+ 'Edit Project' => 'Redigér præferencer for',
+ 'Number' => 'Nummer',
+ 'Orphaned' => 'Fritstående',
+ 'Project' => 'Projekt',
+ 'Project Number missing!' => 'Projektnummer mangler!',
+ 'Project deleted!' => 'Projekt slettet!',
+ 'Project saved!' => 'Projekt gemt!',
+ 'Projects' => 'Projekter',
+ 'Save' => 'Gem',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'tilføj' => 'add',
+ 'fortsæt' => 'continue',
+ 'fjern' => 'delete',
+ 'gem' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/rc b/sql-ledger/locale/dk/rc
new file mode 100644
index 0000000..ea645b9
--- /dev/null
+++ b/sql-ledger/locale/dk/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Udjævnede balance',
+ 'Continue' => 'Fortsæt',
+ 'Date' => 'Dato',
+ 'Deposit' => 'Depositum',
+ 'Description' => 'Beskrivelse',
+ 'Difference' => 'Difference',
+ 'Done' => 'Færdig',
+ 'Exchangerate Difference' => 'Difference for vekselkurs',
+ 'From' => 'Fra',
+ 'Out of balance!' => 'Ikke i balance!',
+ 'Payment' => 'Betaling',
+ 'Reconciliation' => 'Afstemning',
+ 'Select all' => 'Vælg alt',
+ 'Source' => 'Bilag',
+ 'Statement Balance' => 'Balanceopgørelse',
+ 'To' => 'til',
+ 'Update' => 'Opdatér',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'fortsæt' => 'continue',
+ 'færdig' => 'done',
+ 'vælg_alt' => 'select_all',
+ 'opdatér' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/dk/rp b/sql-ledger/locale/dk/rp
new file mode 100644
index 0000000..607d80c
--- /dev/null
+++ b/sql-ledger/locale/dk/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Aldersfordeling',
+ 'AR Aging' => 'Aldersfordeling',
+ 'Account' => 'Konto',
+ 'Accounts' => 'Konti',
+ 'Amount' => 'Beløb',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Attachment' => 'Bilag',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Balance Sheet' => 'Status',
+ 'Bcc' => 'Blind kopi',
+ 'Cash based' => 'Kontantbaseret',
+ 'Cc' => 'Kopi',
+ 'Compare to' => 'Sammenlign med',
+ 'Continue' => 'Fortsæt',
+ 'Copies' => 'Kopier',
+ 'Credit' => 'Kredit',
+ 'Current' => 'Current',
+ 'Customer' => 'Kunde',
+ 'Date' => 'Dato',
+ 'Debit' => 'Debet',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Decimalplaces' => 'Decimalpladser',
+ 'Description' => 'Beskrivelse',
+ 'Due' => 'Forfald',
+ 'E-mail' => 'E-post',
+ 'E-mail Statement to' => 'Send opgørelse til',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Overskrift',
+ 'ID' => 'ID',
+ 'In-line' => 'Indlejret',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Income Statement' => 'Driftsregnskab',
+ 'Invoice' => 'Faktura',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'marts',
+ 'May' => 'maj',
+ 'May ' => 'maj ',
+ 'Message' => 'Besked',
+ 'N/A' => 'I/T',
+ 'Nothing selected!' => 'Ingenting valgt!',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Betalinger',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Udskriv',
+ 'Printer' => 'Printer',
+ 'Receipts' => 'Kvitteringer',
+ 'Report for' => 'Rapport for',
+ 'Retained Earnings' => 'Realiseret overskud',
+ 'Screen' => 'Skærm',
+ 'Select all' => 'Vælg alt',
+ 'Select postscript or PDF!' => 'Vælg postscript eller PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Bilag',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Opgørelse',
+ 'Statement sent to' => 'Opgørelse sendt til',
+ 'Statements sent to printer!' => 'Opgørelser sendt til printer',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Afgift/Moms',
+ 'Tax collected' => 'Skat opkrævet',
+ 'Tax paid' => 'Skat betalt',
+ 'To' => 'til',
+ 'Total' => 'I alt',
+ 'Trial Balance' => 'Foreløbig status',
+ 'Vendor' => 'Leverandør',
+ 'as at' => 'som ved',
+ 'collected on sales' => 'indsamlet ved salg',
+ 'for Period' => 'for perioden',
+ 'paid on purchases' => 'betalt ved indkøb',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'fortsæt' => 'continue',
+ 'e_post' => 'e_mail',
+ 'udskriv' => 'print',
+ 'vælg_alt' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/COPYING b/sql-ledger/locale/ee/COPYING
new file mode 100644
index 0000000..fe5ef7d
--- /dev/null
+++ b/sql-ledger/locale/ee/COPYING
@@ -0,0 +1,25 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Estonian texts:
+#
+# Author: Martin Lillepuu <martin@lillepuu.com>
+# Lauri Jesmin <jesmin@ut.ee>
+# Tanel Kurvits <rauge@hot.ee>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/ee/LANGUAGE b/sql-ledger/locale/ee/LANGUAGE
new file mode 100644
index 0000000..5d88c2d
--- /dev/null
+++ b/sql-ledger/locale/ee/LANGUAGE
@@ -0,0 +1 @@
+Estonian
diff --git a/sql-ledger/locale/ee/admin b/sql-ledger/locale/ee/admin
new file mode 100644
index 0000000..00c683e
--- /dev/null
+++ b/sql-ledger/locale/ee/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Ligipääsukontroll',
+ 'Accounting' => 'Raamatupidamine',
+ 'Add User' => 'Lisa kasutaja',
+ 'Address' => 'Aadress',
+ 'Administration' => 'Administreerimine',
+ 'Administrator' => 'Administraator',
+ 'All Datasets up to date!' => 'Kõik andmebaasid on uuendatud',
+ 'Change Admin Password' => 'Muuda admini parool',
+ 'Change Password' => 'Muuda parool',
+ 'Character Set' => 'Kooditabel',
+ 'Click on login name to edit!' => 'Redigeerimiseks kliki kasutajanimel',
+ 'Company' => 'Ettevõte',
+ 'Connect to' => 'Ühenda',
+ 'Continue' => 'Edasi',
+ 'Create Chart of Accounts' => 'Uus kontoplaan',
+ 'Create Dataset' => 'Uus andmebaas',
+ 'DBI not installed!' => 'DBI on installeerimata',
+ 'Database' => 'Andmebaas',
+ 'Database Administration' => 'Andmebaasi administreerimine',
+ 'Database Driver not checked!' => 'Andmebaasi draiver valimata!',
+ 'Database User missing!' => 'Andmebaasi kasutaja puudub',
+ 'Dataset' => 'Andmebaas',
+ 'Dataset missing!' => 'Andmebaas puudub!',
+ 'Dataset updated!' => 'Andmebaas uuendatud!',
+ 'Date Format' => 'Kuupäeva formaat',
+ 'Delete' => 'Kustuta',
+ 'Delete Dataset' => 'Kustuta andmebaas',
+ 'Directory' => 'Kataloog',
+ 'Driver' => 'Draiver',
+ 'Dropdown Limit' => 'Rippmenüü piirang',
+ 'E-mail' => 'E-mail',
+ 'Edit User' => 'Kasutajaandmete muutmine',
+ 'Existing Datasets' => 'Olemasolevad andmebaasid',
+ 'Fax' => 'Faks',
+ 'Host' => 'Server',
+ 'Hostname missing!' => 'Serveri nimi puudub!',
+ 'Incorrect Password!' => 'Vale parool!',
+ 'Language' => 'Keel',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Jäta serveri ja pordi väljad tühjaks kui sa ei soovi kaugühendust luua',
+ 'Login' => 'Login',
+ 'Multibyte Encoding' => 'Mitmebaidine kodeering',
+ 'Name' => 'Nimi',
+ 'New Templates' => 'Uued dokumendipõhjad',
+ 'No Database Drivers available!' => 'Ühtegi andmebaasidraiverit ei leitud!',
+ 'No Dataset selected!' => 'Andmebaas valimata!',
+ 'Nothing to delete!' => 'Midagi ei ole kustutada',
+ 'Number Format' => 'Numbri formaat',
+ 'Oracle Database Administration' => 'Oracle andmebaasi administreerimine',
+ 'Password' => 'Parool',
+ 'Password changed!' => 'Parool muudetud',
+ 'Pg Database Administration' => 'Pg andmebaasi administreerimine',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port puudub',
+ 'Printer' => 'Printer',
+ 'Save' => 'Salvesta',
+ 'Select a Dataset to delete and press "Continue"' => 'Vali andmebaas ja vajuta "Jätka"',
+ 'Setup Templates' => 'Dokumendipõhjade seadistamine',
+ 'Ship via' => 'Tarneviis',
+ 'Signature' => 'Signatuur',
+ 'Stylesheet' => 'Laaditabel',
+ 'Templates' => 'Dokumendipõhjad',
+ 'The following Datasets are not in use and can be deleted' => 'Järgnevad andmebaasid ei ole kasutusel ning võib kustutada',
+ 'The following Datasets need to be updated' => 'Järgmised andmebaasid vajavad uuendamist',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Olemasolevate allikate eelkontroll. Praeguses staadiumis ei toimu andmete lisamist ega kustutamist.',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Kasutaja gruppi lisamiseks redigeeri nime, muuda kasutajanimi ja salvesta. Luuakse samade parameetritega uus kasutaja',
+ 'Update Dataset' => 'Uuenda andmebaas',
+ 'Use Templates' => 'Kasuta dokumendipõhja',
+ 'User' => 'Kasutaja',
+ 'User deleted!' => 'Kasutaja kustutatud!',
+ 'User saved!' => 'Kasutaja salvestatud!',
+ 'Version' => 'Versioon',
+ 'You must enter a host and port for local and remote connections!' => 'Ühenduse loomiseks palun sisesta serveri nimi ja port',
+ 'does not exist' => 'ei eksisteeri',
+ 'is already a member!' => 'on juba kasutaja!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'lukustatud!',
+ 'successfully created!' => 'loodud!',
+ 'successfully deleted!' => 'kustutatud!',
+ 'website' => 'kodulehekülg',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'lisa_kasutaja' => 'add_user',
+ 'muuda_admini_parool' => 'change_admin_password',
+ 'muuda_parool' => 'change_password',
+ 'edasi' => 'continue',
+ 'uus_andmebaas' => 'create_dataset',
+ 'kustuta' => 'delete',
+ 'kustuta_andmebaas' => 'delete_dataset',
+ 'login' => 'login',
+ 'oracle_andmebaasi_administreerimine' => 'oracle_database_administration',
+ 'pg_andmebaasi_administreerimine' => 'pg_database_administration',
+ 'salvesta' => 'save',
+ 'uuenda_andmebaas' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/all b/sql-ledger/locale/ee/all
new file mode 100644
index 0000000..122f34a
--- /dev/null
+++ b/sql-ledger/locale/ee/all
@@ -0,0 +1,497 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Kohustused',
+ 'AP Aging' => 'Võlad',
+ 'AP Transaction' => 'Kohustuste kanne',
+ 'AP Transactions' => 'Kohustuste kanded',
+ 'AR' => 'Nõuded',
+ 'AR Aging' => 'Võlglased',
+ 'AR Transaction' => 'Nõuete kanne',
+ 'AR Transactions' => 'Nõuete kanded',
+ 'About' => 'Programmi Info',
+ 'Access Control' => 'Ligipääsukontroll',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Konto number',
+ 'Account Number missing!' => 'Konto number puudub',
+ 'Account Type' => 'Konto tüüp',
+ 'Account Type missing!' => 'Konto tüüp puudub!',
+ 'Account deleted!' => 'Konto kustutatud!',
+ 'Account saved!' => 'Konto salvestatud',
+ 'Accounting' => 'Raamatupidamine',
+ 'Accounting Menu' => 'Raamatupidamise Menüü',
+ 'Accounts' => 'Kontod',
+ 'Active' => 'Aktiva',
+ 'Add' => 'Lisa',
+ 'Add Account' => 'Lisa konto',
+ 'Add Accounts Payables Transaction' => 'Lisa kohustuste kanne',
+ 'Add Accounts Receivables Transaction' => 'Lisa nõuete kanne',
+ 'Add Assembly' => 'Lisa komplekt',
+ 'Add Customer' => 'Lisa klient',
+ 'Add GIFI' => 'Lisa GIFI',
+ 'Add General Ledger Transaction' => 'Lisa pearaamatu kanne',
+ 'Add Part' => 'Lisa toode',
+ 'Add Project' => 'Lisa Projekt',
+ 'Add Purchase Order' => 'Lisa ostutellimus',
+ 'Add Sales Invoice' => 'Lisa Müügiarve',
+ 'Add Sales Order' => 'Lisa müügitellimus',
+ 'Add Service' => 'Lisa teenus',
+ 'Add Transaction' => 'Lisa kanne',
+ 'Add User' => 'Lisa kasutaja',
+ 'Add Vendor' => 'Lisa hankija',
+ 'Add Vendor Invoice' => '',
+ 'Address' => 'Aadress',
+ 'Administration' => 'Administreerimine',
+ 'Administrator' => 'Administraator',
+ 'All' => 'Kõik',
+ 'All Datasets up to date!' => 'Kõik andmebaasid on uuendatud',
+ 'Amount' => 'Summa',
+ 'Amount Due' => 'Tasumata',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Summa puudub!',
+ 'Applied' => 'Makstud',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Are you sure you want to delete Invoice Number' => 'Kas oled kindel, et soovid kustutada arve',
+ 'Are you sure you want to delete Order Number' => 'Kas oled kindel, et soovid kustutada tellimuse',
+ 'Are you sure you want to delete Transaction' => 'Kas oled kindel, et soovid kustutada kande',
+ 'Assemblies' => 'Komplektid',
+ 'Assemblies restocked!' => 'Komplektid lattu tagastatud!',
+ 'Assembly Number missing!' => 'Komplekti number puudub!',
+ 'Asset' => 'Vara',
+ 'Attachment' => 'Kaasatud fail',
+ 'Audit Control' => 'Audit',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'BOM' => 'Materjalide nimekiri',
+ 'Backup' => 'Varukoopia',
+ 'Backup sent to' => 'Varukoopia saadetakse',
+ 'Balance' => 'Bilanss',
+ 'Balance Sheet' => 'Bilansitabel',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Kast',
+ 'Books are open' => 'Kanded on avatud',
+ 'Bought' => 'Ostetud',
+ 'Business Number' => 'Ettevõtte kood',
+ 'C' => 'C',
+ 'COGS' => 'COGS',
+ 'Cannot delete account!' => 'Kontot ei saa kustutada!',
+ 'Cannot delete customer!' => 'Kienti ei saa kustutada!',
+ 'Cannot delete default account!' => 'Vaikimisi kontot ei saa kustutada!',
+ 'Cannot delete invoice!' => 'Arvet ei saa kustutada',
+ 'Cannot delete item already invoiced!' => 'Esitatud arvega toodet ei saa kustutada!',
+ 'Cannot delete item on order!' => 'Tellimusega seotud artiklit ei saa kustutada!',
+ 'Cannot delete item which is part of an assembly!' => 'Komplekti kuuluvat toodet ei saa kustutada!',
+ 'Cannot delete item!' => 'Toodet ei saa kustutada!',
+ 'Cannot delete order!' => 'Tellimust ei saa kustutada!',
+ 'Cannot delete transaction!' => 'Kannet ei saa kustutada!',
+ 'Cannot delete vendor!' => 'Tarnijat ei saa kustutada!',
+ 'Cannot have a value in both Debit and Credit!' => 'Deebet ja Kreedit väljad ei tohi olla samaaegselt täidetud!',
+ 'Cannot post a transaction without a value!' => 'Tühja väärtusega kannet pole võimalik salvestada!',
+ 'Cannot post invoice for a closed period!' => 'Arvet ei saa salvestada suletud perioodile!',
+ 'Cannot post invoice!' => 'Arvet ei saa saata!',
+ 'Cannot post payment for a closed period!' => 'Makset ei saa salvestada suletud perioodile',
+ 'Cannot post payment!' => 'Makset ei saa salvestada!',
+ 'Cannot post transaction for a closed period!' => 'Kannet ei saa salvestada suletud perioodile',
+ 'Cannot post transaction!' => 'Kannet ei saa salvestada!',
+ 'Cannot process payment for a closed period!' => 'Suletud perioodi makset ei saa töödelda!',
+ 'Cannot save account!' => 'Kontot ei saa salvestada',
+ 'Cannot save order!' => 'Arvet ei saa salvestada',
+ 'Cannot save preferences!' => 'Maaranguid ei saa salvestada',
+ 'Cannot stock assemblies!' => 'Komplekte ei saa lattu võtta',
+ 'Cash' => 'Kassa',
+ 'Cash based' => 'Kassapõhine',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => 'Muuda admini parool',
+ 'Change Password' => 'Muuda parool',
+ 'Character Set' => 'Kooditabel',
+ 'Chart of Accounts' => 'Kontoplaan',
+ 'Check' => 'T?ekk',
+ 'Check printed!' => 'T?ekk on türkitud',
+ 'Check printing failed!' => 'T?eki trükkimine ebaõnnestus',
+ 'Cleared Balance' => 'Puhastatud bilanss',
+ 'Click on login name to edit!' => 'Redigeerimiseks kliki kasutajanimel',
+ 'Close Books up to' => 'Sulge kanded kuni',
+ 'Closed' => 'Suletud',
+ 'Company' => 'Ettevõte',
+ 'Compare to' => 'Võrdlus perioodiga',
+ 'Confirm!' => 'Kinnita!',
+ 'Connect to' => 'Ühenda',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Edasi',
+ 'Copies' => 'koopiat',
+ 'Copy to COA' => 'Kopeeri kontoplaani',
+ 'Create Chart of Accounts' => 'Uus kontoplaan',
+ 'Create Dataset' => 'Uus andmebaas',
+ 'Credit' => 'Kreedit',
+ 'Credit Limit' => 'Krediidilimiit',
+ 'Curr' => 'Val.',
+ 'Currency' => 'Valuuta',
+ 'Current' => 'Praegune',
+ 'Customer' => 'Klient',
+ 'Customer deleted!' => 'Klient on kustutatud!',
+ 'Customer missing!' => 'Klienti pole määratud!',
+ 'Customer not on file!' => 'Klienti pole failis!',
+ 'Customer saved!' => 'Klient salvestatud',
+ 'Customers' => 'Kliendid',
+ 'DBI not installed!' => 'DBI on installeerimata',
+ 'Database' => 'Andmebaas',
+ 'Database Administration' => 'Andmebaasi administreerimine',
+ 'Database Driver not checked!' => 'Andmebaasi draiver valimata!',
+ 'Database Host' => 'Andmebaasiserver',
+ 'Database User missing!' => 'Andmebaasi kasutaja puudub',
+ 'Dataset' => 'Andmebaas',
+ 'Dataset missing!' => 'Andmebaas puudub!',
+ 'Dataset updated!' => 'Andmebaas uuendatud!',
+ 'Date' => 'Kuupäev',
+ 'Date Format' => 'Kuupäeva formaat',
+ 'Date Paid' => 'Maksekuupäev',
+ 'Date missing!' => 'Kuupäev puudub!',
+ 'Debit' => 'Deebet',
+ 'Debit and credit out of balance!' => 'Deebet ja Kreedit tasakaalust väljas!',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Decimalplaces' => 'Komakohti',
+ 'Delete' => 'Kustuta',
+ 'Delete Account' => 'Kustuta konto',
+ 'Delete Dataset' => 'Kustuta andmebaas',
+ 'Delivery Date' => 'Tarne kuupäev',
+ 'Department' => 'Osakond',
+ 'Deposit' => 'Tarnimata',
+ 'Description' => 'Selgitus',
+ 'Difference' => 'Vahe',
+ 'Directory' => 'Kataloog',
+ 'Discount' => 'Allahindlus',
+ 'Done' => 'Teostatud',
+ 'Drawing' => 'Pildid',
+ 'Driver' => 'Draiver',
+ 'Dropdown Limit' => 'Rippmenüü piirang',
+ 'Due' => 'Tasuda',
+ 'Due Date' => 'Maksetähtaeg',
+ 'Due Date missing!' => 'Maksetähtaeg puudub',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'E-mail teatis',
+ 'E-mail address missing!' => 'E-maili aadress puudub',
+ 'Edit' => 'Muudatused',
+ 'Edit Account' => 'Konto muudatused',
+ 'Edit Accounts Payables Transaction' => 'Muuda nõuete kannet',
+ 'Edit Accounts Receivables Transaction' => 'Muuda kohustuste kannet',
+ 'Edit Assembly' => 'Muuda Komplekti',
+ 'Edit Customer' => 'Muuda Kliendi andmeid',
+ 'Edit GIFI' => 'Muuda GIFI',
+ 'Edit General Ledger Transaction' => 'Pearaamatu kande redigeerimine',
+ 'Edit Part' => 'Toote redigeerimine',
+ 'Edit Preferences for' => 'Määrangute muutmine: ',
+ 'Edit Project' => 'Muuda Projekti',
+ 'Edit Purchase Order' => 'Ostutellimuse muutmine',
+ 'Edit Sales Invoice' => 'Müügiarve muutmine',
+ 'Edit Sales Order' => 'Müügitellimuse muutmine',
+ 'Edit Service' => 'Teenuse muutmine',
+ 'Edit Template' => 'Dokumendipõhja muutmine',
+ 'Edit User' => 'Kasutajaandmete muutmine',
+ 'Edit Vendor' => 'Muuda Tarnija andmeid',
+ 'Edit Vendor Invoice' => '',
+ 'Employee' => 'Töötaja',
+ 'Enforce transaction reversal for all dates' => 'Muuda kannete pööramine kõikide kuupäevade ulatuses kohustuslikuks',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Sisesta kohalikud- ja välisvaluutad (kuni 3 tähemärki, koolonitega eraltatud, nt. CAD:USD:EUR)',
+ 'Equity' => 'Omakapital',
+ 'Exch' => 'Kurss',
+ 'Exchangerate' => 'Valuutakurss',
+ 'Exchangerate Difference' => 'Valuutakursi muutus',
+ 'Exchangerate for payment missing!' => 'Maksel ei ole valuutakurssi!',
+ 'Exchangerate missing!' => 'Valuutakurssi ei ole',
+ 'Existing Datasets' => 'Olemasolevad andmebaasid',
+ 'Expense' => 'Kulu',
+ 'Expense Account' => 'Kulukonto',
+ 'Expense/Asset' => 'Kulu/Vara',
+ 'Extended' => 'Summa',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'Foreign Exchange Gain' => 'Valuutakursside vahe kasum',
+ 'Foreign Exchange Loss' => 'Valuutakursside vahe kahjum',
+ 'From' => 'Alates',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI kustutatud',
+ 'GIFI missing!' => 'GIFI puudub',
+ 'GIFI saved!' => 'GIFI salvestatud',
+ 'GL Transaction' => 'Pearaamatu kanne',
+ 'General Ledger' => 'Pearaamat',
+ 'Goods & Services' => 'Tooted ja teenused',
+ 'Group' => '',
+ 'Group Items' => '',
+ 'HTML Templates' => 'HTML dokumendipõhjad',
+ 'Heading' => 'Päis',
+ 'Host' => 'Server',
+ 'Hostname missing!' => 'Serveri nimi puudub!',
+ 'ID' => 'ID',
+ 'Image' => 'Pilt',
+ 'In-line' => 'Dokumendisisene',
+ 'Include in Report' => 'Kaasa aruandesse',
+ 'Include in drop-down menus' => 'Kaasa valikmenüüdes',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Kaasa antud konto klient/tarnija vormides, et märkida klient/tarnija maksustatavaks',
+ 'Income' => 'Tulu',
+ 'Income Account' => 'Tulukonto',
+ 'Income Statement' => 'Kasumiaruanne',
+ 'Incorrect Dataset version!' => 'Vale andmebaasi versioon',
+ 'Incorrect Password!' => 'Vale parool!',
+ 'Individual Items' => 'Komponendid',
+ 'Inventory' => 'Ladu',
+ 'Inventory Account' => 'Laokonto',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Enne komplekti aegunuks märkimist peab laoseis null olema!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Enne toote aegunuks märkimist peab laoseis null olema!',
+ 'Inventory quantity must be zero!' => 'Laoseis peab null olema!',
+ 'Invoice' => 'Arve',
+ 'Invoice Date' => 'Arve kuupäev',
+ 'Invoice Date missing!' => 'Arve kuupäev puudub!',
+ 'Invoice Number' => 'Arve number',
+ 'Invoice Number missing!' => 'Arve number puudub!',
+ 'Invoice deleted!' => 'Arve kustutatud!',
+ 'Invoice posted!' => 'Arve salvestatud!',
+ 'Invoices' => 'Arved',
+ 'Is this a summary account to record' => 'Kirje summaarne konto',
+ 'Item deleted!' => 'Toode kustutatud!',
+ 'Item not on file!' => 'Toode puudub andmebaasist!',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'LaTeX Templates' => 'LaTeX dokumendipõhjad',
+ 'Language' => 'Keel',
+ 'Last Cost' => 'Viimane ostuhind',
+ 'Last Invoice Number' => 'Viimane arve number',
+ 'Last Numbers & Default Accounts' => 'Viimased numbrid ja vaikimisi kontod',
+ 'Last Purchase Order Number' => 'Viimane ostutellimuse number',
+ 'Last Sales Order Number' => 'Viimane müügitellimuse number',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Jäta serveri ja pordi väljad tühjaks kui sa ei soovi kaugühendust luua',
+ 'Liability' => 'Kohustus',
+ 'Licensed to' => 'Kasutaja andmed:',
+ 'Line Total' => 'Rea summa',
+ 'Link' => 'Seosed',
+ 'Link Accounts' => 'Seosta kontod',
+ 'List Accounts' => 'Kontode nimekiri',
+ 'List GIFI' => 'GIFI nimekiri',
+ 'List Price' => 'Hinnakirja hind',
+ 'List Transactions' => 'Kannete sirvimine',
+ 'Login' => 'Login',
+ 'Logout' => 'Logi välja',
+ 'Make' => 'Tootja',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Teade',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Mudel',
+ 'Multibyte Encoding' => 'Mitmebaidine kodeering',
+ 'N/A' => 'Puudub',
+ 'Name' => 'Nimi',
+ 'Name missing!' => 'Nimi puudub!',
+ 'New Templates' => 'Uued dokumendipõhjad',
+ 'No' => 'Ei',
+ 'No Database Drivers available!' => 'Ühtegi andmebaasidraiverit ei leitud!',
+ 'No Dataset selected!' => 'Andmebaas valimata!',
+ 'No email address for' => 'E-maili aadress puudub',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Märkused',
+ 'Nothing applied!' => 'Midagi ei muudetud',
+ 'Nothing selected!' => 'Midagi ei ole valitud',
+ 'Nothing to delete!' => 'Midagi ei ole kustutada',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Kood',
+ 'Number Format' => 'Numbri formaat',
+ 'Number missing in Row' => 'Antud real puudub kood',
+ 'O' => 'O',
+ 'Obsolete' => 'Aegunud',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'On Hand' => 'Laos',
+ 'On Order' => 'Tellimisel',
+ 'Open' => 'Avatud',
+ 'Oracle Database Administration' => 'Oracle andmebaasi administreerimine',
+ 'Order' => 'Tellimus',
+ 'Order Date' => 'Tellimuse kuupäev',
+ 'Order Date missing!' => 'Tellimuse kuupäev puudub',
+ 'Order Entry' => 'Tellimuse sisestamine',
+ 'Order Number' => 'Tellimuse number',
+ 'Order Number missing!' => 'Tellimuse number puudub',
+ 'Order deleted!' => 'Tellimus kustutatud',
+ 'Order saved!' => 'Tellimus salvestatud',
+ 'Ordered' => 'Tellitud',
+ 'Orphaned' => 'Seosteta',
+ 'Out of balance!' => 'Bilanss ei klapi!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Saateleht',
+ 'Packing List Date missing!' => 'Saatelehe kuupäev puudub',
+ 'Packing List Number missing!' => 'Saatelehe number puudub',
+ 'Paid' => 'Makstud',
+ 'Paid in full' => 'Täielikult tasutud',
+ 'Part' => 'Toode',
+ 'Part Number missing!' => 'Toote kood puudub',
+ 'Parts' => 'Tooted',
+ 'Parts Inventory' => 'Tooted',
+ 'Password' => 'Parool',
+ 'Password changed!' => 'Parool muudetud',
+ 'Payables' => 'Kohustused',
+ 'Payment' => 'Maksed',
+ 'Payment date missing!' => 'Maksekuupäev puudub',
+ 'Payment posted!' => 'Makse salvestatud',
+ 'Payments' => 'Maksed',
+ 'Pg Database Administration' => 'Pg andmebaasi administreerimine',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port puudub',
+ 'Post' => 'Salvesta',
+ 'Post as new' => 'Salvesta uuena',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Määrangud',
+ 'Preferences saved!' => 'Määrangud salvestatud',
+ 'Price' => 'Hind',
+ 'Print' => 'Trüki',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Project Number' => 'Projekti number',
+ 'Project Number missing!' => 'Projekti number puudub',
+ 'Project deleted!' => 'Projekt kustutatud',
+ 'Project not on file!' => 'Projekti pole failis',
+ 'Project saved!' => 'Projekt salvestatud',
+ 'Projects' => 'Projektid',
+ 'Purchase Order' => 'Ostutellimus',
+ 'Purchase Orders' => 'Ostutellimused',
+ 'Qty' => 'Kogus',
+ 'ROP' => 'TM',
+ 'Rate' => 'Määr',
+ 'Recd' => 'Saabunud',
+ 'Receipt' => 'Laekumised',
+ 'Receipt printed!' => 'Tshekk trükitud',
+ 'Receipt printing failed!' => 'Tsheki trükkkimine ebaõnnestus',
+ 'Receipts' => 'Laekumised',
+ 'Receivables' => 'Nõuded',
+ 'Reconciliation' => 'Tasaarveldused',
+ 'Record in' => 'Sihtkonto',
+ 'Reference' => 'Viide',
+ 'Reference missing!' => 'Viide puudub!',
+ 'Remaining' => 'Kasutamata',
+ 'Report for' => 'Aruanne',
+ 'Reports' => 'Aruanded',
+ 'Required by' => 'Tarneaeg',
+ 'Retained Earnings' => 'Jaotamata kasum',
+ 'Sales' => 'Müük',
+ 'Sales Invoice' => 'Müügiarve',
+ 'Sales Order' => 'Müügitellimus',
+ 'Sales Orders' => 'Müügitellimused',
+ 'Salesperson' => '',
+ 'Save' => 'Salvesta',
+ 'Save as new' => 'Salvesta uuena',
+ 'Save to File' => 'Salvesta faili',
+ 'Screen' => 'Ekraan',
+ 'Select a Dataset to delete and press "Continue"' => 'Vali andmebaas ja vajuta "Jätka"',
+ 'Select all' => 'Vali kõik',
+ 'Select from one of the items below' => 'Vali üks alltoodud toodetest',
+ 'Select from one of the names below' => 'Vali üks alltoodud nimedest',
+ 'Select from one of the projects below' => 'Vali üks alltoodud projektidest',
+ 'Select postscript or PDF!' => 'Vali kas postscript või PDF',
+ 'Sell Price' => 'Müügihind',
+ 'Send by E-Mail' => 'Saada e-postiga',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Service' => 'Teenus',
+ 'Service Items' => 'Teenused',
+ 'Service Number missing!' => 'teenuse kood puudub!',
+ 'Services' => 'Teenused',
+ 'Setup Templates' => 'Dokumendipõhjade seadistamine',
+ 'Ship' => 'Tarnimine',
+ 'Ship to' => 'Tarneaadress',
+ 'Ship via' => 'Tarneviis',
+ 'Short' => 'Lühike',
+ 'Signature' => 'Signatuur',
+ 'Sold' => 'Müüdud',
+ 'Source' => 'Allikas',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Aruanne',
+ 'Statement Balance' => 'Bilansiaruanne',
+ 'Statement sent to' => 'Saata aruanne aadressil',
+ 'Statements sent to printer!' => 'Saata aruanne printerile',
+ 'Stock Assembly' => 'Komplekti lattu võtmine',
+ 'Stylesheet' => 'Laaditabel',
+ 'Subject' => 'Pealkiri',
+ 'Subtotal' => 'Vahesumma',
+ 'System' => 'Süsteem',
+ 'Tax' => 'Maks',
+ 'Tax Accounts' => 'Maksukontod',
+ 'Tax Included' => 'Koos maksuga',
+ 'Tax collected' => 'Kogutud maksud',
+ 'Tax paid' => 'Makstud makse',
+ 'Taxable' => 'Maksustatav',
+ 'Template saved!' => 'Dokumendipõhjad salvestatud!',
+ 'Templates' => 'Dokumendipõhjad',
+ 'Terms: Net' => 'Maksetingimus',
+ 'The following Datasets are not in use and can be deleted' => 'Järgnevad andmebaasid ei ole kasutusel ning võib kustutada',
+ 'The following Datasets need to be updated' => 'Järgmised andmebaasid vajavad uuendamist',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Olemasolevate allikate eelkontroll. Praeguses staadiumis ei toimu andmete lisamist ega kustutamist.',
+ 'To' => 'Kuhu',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Kasutaja gruppi lisamiseks redigeeri nime, muuda kasutajanimi ja salvesta. Luuakse samade parameetritega uus kasutaja',
+ 'Top Level' => 'Ülemine tase',
+ 'Total' => 'Kokku',
+ 'Transaction Date missing!' => 'Kande kuupäev puudub!',
+ 'Transaction deleted!' => 'Kanne kustutatud!',
+ 'Transaction posted!' => 'Kanne tud!',
+ 'Transaction reversal enforced for all dates' => 'Kannete pööramine on kohustuslik kõikide kuupäevade ulatuses',
+ 'Transaction reversal enforced up to' => 'Kannete pööramine on kohustuslik kuni',
+ 'Transactions' => 'Kanded',
+ 'Transactions exist, cannot delete customer!' => 'Kanded aktiivsed, klienti ei saa kustutada!',
+ 'Transactions exist, cannot delete vendor!' => 'Kanded aktiivsed, hankijat ei saa kustutada!',
+ 'Transactions exist; cannot delete account!' => 'Kanded aktiivsed; kontot ei saa kustutada!',
+ 'Trial Balance' => 'Proovibilanss',
+ 'Unit' => 'Ühik',
+ 'Unit of measure' => 'Mõõtühik',
+ 'Update' => 'Uuenda',
+ 'Update Dataset' => 'Uuenda andmebaas',
+ 'Updated' => 'Uuendatud',
+ 'Use Templates' => 'Kasuta dokumendipõhja',
+ 'User' => 'Kasutaja',
+ 'User deleted!' => 'Kasutaja kustutatud!',
+ 'User saved!' => 'Kasutaja salvestatud!',
+ 'Vendor' => 'Hankija',
+ 'Vendor Invoice' => '',
+ 'Vendor deleted!' => 'Hankija kustutatud!',
+ 'Vendor missing!' => 'Hankija puudub!',
+ 'Vendor not on file!' => 'Hankijat pole failis!',
+ 'Vendor saved!' => 'Hankija salvestatud!',
+ 'Vendors' => 'Hankijad',
+ 'Version' => 'Versioon',
+ 'Weight' => 'Kaal',
+ 'Weight Unit' => 'Kaaluühik',
+ 'What type of item is this?' => 'Mis tüüpi tootega on tegemist?',
+ 'Year End' => 'Aasta lõpp',
+ 'Yes' => 'Jah',
+ 'You are logged out!' => 'Oled välja loginud!',
+ 'You did not enter a name!' => 'Nimi sisestamata!',
+ 'You must enter a host and port for local and remote connections!' => 'Ühenduse loomiseks palun sisesta serveri nimi ja port',
+ 'as at' => 'Seisuga',
+ 'collected on sales' => 'kogutud müügilt',
+ 'days' => 'päeva',
+ 'does not exist' => 'ei eksisteeri',
+ 'ea' => 'tk',
+ 'emailed to' => 'salvestatud aadressile',
+ 'for Period' => 'Periood',
+ 'hr' => 't',
+ 'is already a member!' => 'on juba kasutaja!',
+ 'is not a member!' => 'ei ole kasutaja!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'lukustatud!',
+ 'paid on purchases' => 'makstud ostudelt',
+ 'sent to printer' => 'printerile saadetud',
+ 'successfully created!' => 'loodud!',
+ 'successfully deleted!' => 'kustutatud!',
+ 'to' => 'kuni',
+ 'website' => 'kodulehekülg',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/am b/sql-ledger/locale/ee/am
new file mode 100644
index 0000000..ebf0bf1
--- /dev/null
+++ b/sql-ledger/locale/ee/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Kohustused',
+ 'AR' => 'Nõuded',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Konto number',
+ 'Account Number missing!' => 'Konto number puudub',
+ 'Account Type' => 'Konto tüüp',
+ 'Account Type missing!' => 'Konto tüüp puudub!',
+ 'Account deleted!' => 'Konto kustutatud!',
+ 'Account saved!' => 'Konto salvestatud',
+ 'Add Account' => 'Lisa konto',
+ 'Add GIFI' => 'Lisa GIFI',
+ 'Address' => 'Aadress',
+ 'Asset' => 'Vara',
+ 'Audit Control' => 'Audit',
+ 'Backup sent to' => 'Varukoopia saadetakse',
+ 'Books are open' => 'Kanded on avatud',
+ 'Business Number' => 'Ettevõtte kood',
+ 'COGS' => 'COGS',
+ 'Cannot delete account!' => 'Kontot ei saa kustutada!',
+ 'Cannot delete default account!' => 'Vaikimisi kontot ei saa kustutada!',
+ 'Cannot save account!' => 'Kontot ei saa salvestada',
+ 'Cannot save preferences!' => 'Maaranguid ei saa salvestada',
+ 'Character Set' => 'Kooditabel',
+ 'Chart of Accounts' => 'Kontoplaan',
+ 'Close Books up to' => 'Sulge kanded kuni',
+ 'Company' => 'Ettevõte',
+ 'Continue' => 'Edasi',
+ 'Copy to COA' => 'Kopeeri kontoplaani',
+ 'Credit' => 'Kreedit',
+ 'Date Format' => 'Kuupäeva formaat',
+ 'Debit' => 'Deebet',
+ 'Delete' => 'Kustuta',
+ 'Delete Account' => 'Kustuta konto',
+ 'Description' => 'Selgitus',
+ 'Dropdown Limit' => 'Rippmenüü piirang',
+ 'E-mail' => 'E-mail',
+ 'Edit' => 'Muudatused',
+ 'Edit Account' => 'Konto muudatused',
+ 'Edit GIFI' => 'Muuda GIFI',
+ 'Edit Preferences for' => 'Määrangute muutmine: ',
+ 'Edit Template' => 'Dokumendipõhja muutmine',
+ 'Enforce transaction reversal for all dates' => 'Muuda kannete pööramine kõikide kuupäevade ulatuses kohustuslikuks',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Sisesta kohalikud- ja välisvaluutad (kuni 3 tähemärki, koolonitega eraltatud, nt. CAD:USD:EUR)',
+ 'Equity' => 'Omakapital',
+ 'Expense' => 'Kulu',
+ 'Expense Account' => 'Kulukonto',
+ 'Expense/Asset' => 'Kulu/Vara',
+ 'Fax' => 'Faks',
+ 'Foreign Exchange Gain' => 'Valuutakursside vahe kasum',
+ 'Foreign Exchange Loss' => 'Valuutakursside vahe kahjum',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI kustutatud',
+ 'GIFI missing!' => 'GIFI puudub',
+ 'GIFI saved!' => 'GIFI salvestatud',
+ 'Heading' => 'Päis',
+ 'Include in drop-down menus' => 'Kaasa valikmenüüdes',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Kaasa antud konto klient/tarnija vormides, et märkida klient/tarnija maksustatavaks',
+ 'Income' => 'Tulu',
+ 'Income Account' => 'Tulukonto',
+ 'Inventory' => 'Ladu',
+ 'Inventory Account' => 'Laokonto',
+ 'Is this a summary account to record' => 'Kirje summaarne konto',
+ 'Language' => 'Keel',
+ 'Last Invoice Number' => 'Viimane arve number',
+ 'Last Numbers & Default Accounts' => 'Viimased numbrid ja vaikimisi kontod',
+ 'Last Purchase Order Number' => 'Viimane ostutellimuse number',
+ 'Last Sales Order Number' => 'Viimane müügitellimuse number',
+ 'Liability' => 'Kohustus',
+ 'Link' => 'Seosed',
+ 'Name' => 'Nimi',
+ 'No' => 'Ei',
+ 'No email address for' => 'E-maili aadress puudub',
+ 'Number' => 'Kood',
+ 'Number Format' => 'Numbri formaat',
+ 'Parts Inventory' => 'Tooted',
+ 'Password' => 'Parool',
+ 'Payables' => 'Kohustused',
+ 'Payment' => 'Maksed',
+ 'Phone' => 'Telefon',
+ 'Preferences saved!' => 'Määrangud salvestatud',
+ 'Rate' => 'Määr',
+ 'Receivables' => 'Nõuded',
+ 'Sales' => 'Müük',
+ 'Save' => 'Salvesta',
+ 'Service Items' => 'Teenused',
+ 'Ship via' => 'Tarneviis',
+ 'Signature' => 'Signatuur',
+ 'Stylesheet' => 'Laaditabel',
+ 'Tax' => 'Maks',
+ 'Tax Accounts' => 'Maksukontod',
+ 'Template saved!' => 'Dokumendipõhjad salvestatud!',
+ 'Transaction reversal enforced for all dates' => 'Kannete pööramine on kohustuslik kõikide kuupäevade ulatuses',
+ 'Transaction reversal enforced up to' => 'Kannete pööramine on kohustuslik kuni',
+ 'Transactions exist; cannot delete account!' => 'Kanded aktiivsed; kontot ei saa kustutada!',
+ 'Weight Unit' => 'Kaaluühik',
+ 'Year End' => 'Aasta lõpp',
+ 'Yes' => 'Jah',
+ 'does not exist' => 'ei eksisteeri',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'lisa_konto' => 'add_account',
+ 'edasi' => 'continue',
+ 'kopeeri_kontoplaani' => 'copy_to_coa',
+ 'kustuta' => 'delete',
+ 'muudatused' => 'edit',
+ 'konto_muudatused' => 'edit_account',
+ 'salvesta' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/ap b/sql-ledger/locale/ee/ap
new file mode 100644
index 0000000..f2b3052
--- /dev/null
+++ b/sql-ledger/locale/ee/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Kohustuste kanne',
+ 'AP Transactions' => 'Kohustuste kanded',
+ 'Account' => 'Konto',
+ 'Add Accounts Payables Transaction' => 'Lisa kohustuste kanne',
+ 'Address' => 'Aadress',
+ 'Amount' => 'Summa',
+ 'Amount Due' => 'Tasumata',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Are you sure you want to delete Transaction' => 'Kas oled kindel, et soovid kustutada kande',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Cannot delete transaction!' => 'Kannet ei saa kustutada!',
+ 'Cannot post payment for a closed period!' => 'Makset ei saa salvestada suletud perioodile',
+ 'Cannot post transaction for a closed period!' => 'Kannet ei saa salvestada suletud perioodile',
+ 'Cannot post transaction!' => 'Kannet ei saa salvestada!',
+ 'Closed' => 'Suletud',
+ 'Confirm!' => 'Kinnita!',
+ 'Continue' => 'Edasi',
+ 'Currency' => 'Valuuta',
+ 'Customer not on file!' => 'Klienti pole failis!',
+ 'Date' => 'Kuupäev',
+ 'Date Paid' => 'Maksekuupäev',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Delete' => 'Kustuta',
+ 'Description' => 'Selgitus',
+ 'Due Date' => 'Maksetähtaeg',
+ 'Due Date missing!' => 'Maksetähtaeg puudub',
+ 'Edit Accounts Payables Transaction' => 'Muuda nõuete kannet',
+ 'Employee' => 'Töötaja',
+ 'Exch' => 'Kurss',
+ 'Exchangerate' => 'Valuutakurss',
+ 'Exchangerate for payment missing!' => 'Maksel ei ole valuutakurssi!',
+ 'Exchangerate missing!' => 'Valuutakurssi ei ole',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'From' => 'Alates',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Kaasa aruandesse',
+ 'Invoice' => 'Arve',
+ 'Invoice Date' => 'Arve kuupäev',
+ 'Invoice Date missing!' => 'Arve kuupäev puudub!',
+ 'Invoice Number' => 'Arve number',
+ 'Invoice Number missing!' => 'Arve number puudub!',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Notes' => 'Märkused',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Kood',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'Open' => 'Avatud',
+ 'Order' => 'Tellimus',
+ 'Order Number' => 'Tellimuse number',
+ 'Paid' => 'Makstud',
+ 'Payment date missing!' => 'Maksekuupäev puudub',
+ 'Payments' => 'Maksed',
+ 'Post' => 'Salvesta',
+ 'Post as new' => 'Salvesta uuena',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekti pole failis',
+ 'Select from one of the names below' => 'Vali üks alltoodud nimedest',
+ 'Select from one of the projects below' => 'Vali üks alltoodud projektidest',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Source' => 'Allikas',
+ 'Subtotal' => 'Vahesumma',
+ 'Tax' => 'Maks',
+ 'Tax Included' => 'Koos maksuga',
+ 'Total' => 'Kokku',
+ 'Transaction deleted!' => 'Kanne kustutatud!',
+ 'Transaction posted!' => 'Kanne tud!',
+ 'Update' => 'Uuenda',
+ 'Vendor' => 'Hankija',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendor missing!' => 'Hankija puudub!',
+ 'Vendor not on file!' => 'Hankijat pole failis!',
+ 'Yes' => 'Jah',
+ 'to' => 'kuni',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'kohustuste_kanne' => 'ap_transaction',
+ 'lisa_kohustuste_kanne' => 'add_accounts_payables_transaction',
+ 'edasi' => 'continue',
+ 'kustuta' => 'delete',
+ 'muuda_nõuete_kannet' => 'edit_accounts_payables_transaction',
+ 'salvesta' => 'post',
+ 'salvesta_uuena' => 'post_as_new',
+ 'uuenda' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'jah' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/ar b/sql-ledger/locale/ee/ar
new file mode 100644
index 0000000..e940d94
--- /dev/null
+++ b/sql-ledger/locale/ee/ar
@@ -0,0 +1,134 @@
+$self{texts} = {
+ 'AR Transaction' => 'Nõuete kanne',
+ 'AR Transactions' => 'Nõuete kanded',
+ 'Account' => 'Konto',
+ 'Add Accounts Receivables Transaction' => 'Lisa nõuete kanne',
+ 'Address' => 'Aadress',
+ 'Amount' => 'Summa',
+ 'Amount Due' => 'Tasumata',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Are you sure you want to delete Transaction' => 'Kas oled kindel, et soovid kustutada kande',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Cannot delete transaction!' => 'Kannet ei saa kustutada!',
+ 'Cannot post payment for a closed period!' => 'Makset ei saa salvestada suletud perioodile',
+ 'Cannot post transaction for a closed period!' => 'Kannet ei saa salvestada suletud perioodile',
+ 'Cannot post transaction!' => 'Kannet ei saa salvestada!',
+ 'Closed' => 'Suletud',
+ 'Confirm!' => 'Kinnita!',
+ 'Continue' => 'Edasi',
+ 'Credit Limit' => 'Krediidilimiit',
+ 'Currency' => 'Valuuta',
+ 'Customer' => 'Klient',
+ 'Customer missing!' => 'Klienti pole määratud!',
+ 'Customer not on file!' => 'Klienti pole failis!',
+ 'Date' => 'Kuupäev',
+ 'Date Paid' => 'Maksekuupäev',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Delete' => 'Kustuta',
+ 'Description' => 'Selgitus',
+ 'Due Date' => 'Maksetähtaeg',
+ 'Due Date missing!' => 'Maksetähtaeg puudub',
+ 'Edit Accounts Receivables Transaction' => 'Muuda kohustuste kannet',
+ 'Exch' => 'Kurss',
+ 'Exchangerate' => 'Valuutakurss',
+ 'Exchangerate for payment missing!' => 'Maksel ei ole valuutakurssi!',
+ 'Exchangerate missing!' => 'Valuutakurssi ei ole',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'From' => 'Alates',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Kaasa aruandesse',
+ 'Invoice' => 'Arve',
+ 'Invoice Date' => 'Arve kuupäev',
+ 'Invoice Date missing!' => 'Arve kuupäev puudub!',
+ 'Invoice Number' => 'Arve number',
+ 'Invoice Number missing!' => 'Arve number puudub!',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Notes' => 'Märkused',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Kood',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'Open' => 'Avatud',
+ 'Order' => 'Tellimus',
+ 'Order Number' => 'Tellimuse number',
+ 'Paid' => 'Makstud',
+ 'Payment date missing!' => 'Maksekuupäev puudub',
+ 'Payments' => 'Maksed',
+ 'Post' => 'Salvesta',
+ 'Post as new' => 'Salvesta uuena',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekti pole failis',
+ 'Remaining' => 'Kasutamata',
+ 'Sales Invoice' => 'Müügiarve',
+ 'Salesperson' => 'Salesperson',
+ 'Select from one of the names below' => 'Vali üks alltoodud nimedest',
+ 'Select from one of the projects below' => 'Vali üks alltoodud projektidest',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Ship via' => 'Tarneviis',
+ 'Source' => 'Allikas',
+ 'Subtotal' => 'Vahesumma',
+ 'Tax' => 'Maks',
+ 'Tax Included' => 'Koos maksuga',
+ 'Total' => 'Kokku',
+ 'Transaction deleted!' => 'Kanne kustutatud!',
+ 'Transaction posted!' => 'Kanne tud!',
+ 'Update' => 'Uuenda',
+ 'Vendor not on file!' => 'Hankijat pole failis!',
+ 'Yes' => 'Jah',
+ 'to' => 'kuni',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'nõuete_kanne' => 'ar_transaction',
+ 'edasi' => 'continue',
+ 'kustuta' => 'delete',
+ 'salvesta' => 'post',
+ 'salvesta_uuena' => 'post_as_new',
+ 'müügiarve' => 'sales_invoice',
+ 'uuenda' => 'update',
+ 'jah' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/arap b/sql-ledger/locale/ee/arap
new file mode 100644
index 0000000..061f6d3
--- /dev/null
+++ b/sql-ledger/locale/ee/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Aadress',
+ 'Continue' => 'Edasi',
+ 'Customer not on file!' => 'Klienti pole failis!',
+ 'Description' => 'Selgitus',
+ 'Number' => 'Kood',
+ 'Project not on file!' => 'Projekti pole failis',
+ 'Select from one of the names below' => 'Vali üks alltoodud nimedest',
+ 'Select from one of the projects below' => 'Vali üks alltoodud projektidest',
+ 'Vendor not on file!' => 'Hankijat pole failis!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'edasi' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/ca b/sql-ledger/locale/ee/ca
new file mode 100644
index 0000000..4695ea4
--- /dev/null
+++ b/sql-ledger/locale/ee/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Balance' => 'Bilanss',
+ 'Chart of Accounts' => 'Kontoplaan',
+ 'Credit' => 'Kreedit',
+ 'Date' => 'Kuupäev',
+ 'Debit' => 'Deebet',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Description' => 'Selgitus',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'From' => 'Alates',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Kaasa aruandesse',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'List Transactions' => 'Kannete sirvimine',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'Reference' => 'Viide',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Subtotal' => 'Vahesumma',
+ 'to' => 'kuni',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'kannete_sirvimine' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/cp b/sql-ledger/locale/ee/cp
new file mode 100644
index 0000000..c1353d5
--- /dev/null
+++ b/sql-ledger/locale/ee/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Address' => 'Aadress',
+ 'Amount' => 'Summa',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Summa puudub!',
+ 'Applied' => 'Makstud',
+ 'Cannot post payment!' => 'Makset ei saa salvestada!',
+ 'Cannot process payment for a closed period!' => 'Suletud perioodi makset ei saa töödelda!',
+ 'Check' => 'T?ekk',
+ 'Check printed!' => 'T?ekk on türkitud',
+ 'Check printing failed!' => 'T?eki trükkimine ebaõnnestus',
+ 'Continue' => 'Edasi',
+ 'Currency' => 'Valuuta',
+ 'Customer' => 'Klient',
+ 'Customer not on file!' => 'Klienti pole failis!',
+ 'Date' => 'Kuupäev',
+ 'Date missing!' => 'Kuupäev puudub!',
+ 'Description' => 'Selgitus',
+ 'Due' => 'Tasuda',
+ 'Exchangerate' => 'Valuutakurss',
+ 'From' => 'Alates',
+ 'Invoice' => 'Arve',
+ 'Invoices' => 'Arved',
+ 'Nothing applied!' => 'Midagi ei muudetud',
+ 'Number' => 'Kood',
+ 'Paid in full' => 'Täielikult tasutud',
+ 'Payment' => 'Maksed',
+ 'Payment posted!' => 'Makse salvestatud',
+ 'Post' => 'Salvesta',
+ 'Print' => 'Trüki',
+ 'Printer' => 'Printer',
+ 'Project not on file!' => 'Projekti pole failis',
+ 'Receipt' => 'Laekumised',
+ 'Receipt printed!' => 'Tshekk trükitud',
+ 'Receipt printing failed!' => 'Tsheki trükkkimine ebaõnnestus',
+ 'Reference' => 'Viide',
+ 'Screen' => 'Ekraan',
+ 'Select from one of the names below' => 'Vali üks alltoodud nimedest',
+ 'Select from one of the projects below' => 'Vali üks alltoodud projektidest',
+ 'Update' => 'Uuenda',
+ 'Vendor' => 'Hankija',
+ 'Vendor not on file!' => 'Hankijat pole failis!',
+ 'to' => 'kuni',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'edasi' => 'continue',
+ 'salvesta' => 'post',
+ 'trüki' => 'print',
+ 'uuenda' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/ct b/sql-ledger/locale/ee/ct
new file mode 100644
index 0000000..4d167b2
--- /dev/null
+++ b/sql-ledger/locale/ee/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Lisa',
+ 'Address' => 'Aadress',
+ 'All' => 'Kõik',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Kienti ei saa kustutada!',
+ 'Cannot delete vendor!' => 'Tarnijat ei saa kustutada!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Edasi',
+ 'Credit Limit' => 'Krediidilimiit',
+ 'Customer deleted!' => 'Klient on kustutatud!',
+ 'Customer saved!' => 'Klient salvestatud',
+ 'Customers' => 'Kliendid',
+ 'Delete' => 'Kustuta',
+ 'Discount' => 'Allahindlus',
+ 'E-mail' => 'E-mail',
+ 'Edit Customer' => 'Muuda Kliendi andmeid',
+ 'Edit Vendor' => 'Muuda Tarnija andmeid',
+ 'Fax' => 'Faks',
+ 'Include in Report' => 'Kaasa aruandesse',
+ 'Invoice' => 'Arve',
+ 'Name' => 'Nimi',
+ 'Name missing!' => 'Nimi puudub!',
+ 'Notes' => 'Märkused',
+ 'Number' => 'Kood',
+ 'Order' => 'Tellimus',
+ 'Orphaned' => 'Seosteta',
+ 'Phone' => 'Telefon',
+ 'Save' => 'Salvesta',
+ 'Ship to' => 'Tarneaadress',
+ 'Tax Included' => 'Koos maksuga',
+ 'Taxable' => 'Maksustatav',
+ 'Terms: Net' => 'Maksetingimus',
+ 'Transactions exist, cannot delete customer!' => 'Kanded aktiivsed, klienti ei saa kustutada!',
+ 'Transactions exist, cannot delete vendor!' => 'Kanded aktiivsed, hankijat ei saa kustutada!',
+ 'Vendor deleted!' => 'Hankija kustutatud!',
+ 'Vendor saved!' => 'Hankija salvestatud!',
+ 'Vendors' => 'Hankijad',
+ 'days' => 'päeva',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'lisa' => 'add',
+ 'edasi' => 'continue',
+ 'kustuta' => 'delete',
+ 'arve' => 'invoice',
+ 'tellimus' => 'order',
+ 'salvesta' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/gl b/sql-ledger/locale/ee/gl
new file mode 100644
index 0000000..dd25e8f
--- /dev/null
+++ b/sql-ledger/locale/ee/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Kohustuste kanne',
+ 'AR Transaction' => 'Nõuete kanne',
+ 'Account' => 'Konto',
+ 'Add General Ledger Transaction' => 'Lisa pearaamatu kanne',
+ 'Address' => 'Aadress',
+ 'All' => 'Kõik',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Are you sure you want to delete Transaction' => 'Kas oled kindel, et soovid kustutada kande',
+ 'Asset' => 'Vara',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Balance' => 'Bilanss',
+ 'Cannot delete transaction!' => 'Kannet ei saa kustutada!',
+ 'Cannot have a value in both Debit and Credit!' => 'Deebet ja Kreedit väljad ei tohi olla samaaegselt täidetud!',
+ 'Cannot post a transaction without a value!' => 'Tühja väärtusega kannet pole võimalik salvestada!',
+ 'Cannot post transaction for a closed period!' => 'Kannet ei saa salvestada suletud perioodile',
+ 'Confirm!' => 'Kinnita!',
+ 'Continue' => 'Edasi',
+ 'Credit' => 'Kreedit',
+ 'Customer not on file!' => 'Klienti pole failis!',
+ 'Date' => 'Kuupäev',
+ 'Debit' => 'Deebet',
+ 'Debit and credit out of balance!' => 'Deebet ja Kreedit tasakaalust väljas!',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Delete' => 'Kustuta',
+ 'Description' => 'Selgitus',
+ 'Edit General Ledger Transaction' => 'Pearaamatu kande redigeerimine',
+ 'Equity' => 'Omakapital',
+ 'Expense' => 'Kulu',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'From' => 'Alates',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'Pearaamatu kanne',
+ 'General Ledger' => 'Pearaamat',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Kaasa aruandesse',
+ 'Income' => 'Tulu',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'Liability' => 'Kohustus',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Notes' => 'Märkused',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Kood',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'Post' => 'Salvesta',
+ 'Post as new' => 'Salvesta uuena',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekti pole failis',
+ 'Reference' => 'Viide',
+ 'Reference missing!' => 'Viide puudub!',
+ 'Reports' => 'Aruanded',
+ 'Sales Invoice' => 'Müügiarve',
+ 'Select from one of the names below' => 'Vali üks alltoodud nimedest',
+ 'Select from one of the projects below' => 'Vali üks alltoodud projektidest',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Source' => 'Allikas',
+ 'Subtotal' => 'Vahesumma',
+ 'Transaction Date missing!' => 'Kande kuupäev puudub!',
+ 'Transaction deleted!' => 'Kanne kustutatud!',
+ 'Transaction posted!' => 'Kanne tud!',
+ 'Update' => 'Uuenda',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendor not on file!' => 'Hankijat pole failis!',
+ 'Yes' => 'Jah',
+ 'to' => 'kuni',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'kohustuste_kanne' => 'ap_transaction',
+ 'nõuete_kanne' => 'ar_transaction',
+ 'edasi' => 'continue',
+ 'kustuta' => 'delete',
+ 'pearaamatu_kanne' => 'gl_transaction',
+ 'salvesta' => 'post',
+ 'salvesta_uuena' => 'post_as_new',
+ 'müügiarve' => 'sales_invoice',
+ 'uuenda' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'jah' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/ic b/sql-ledger/locale/ee/ic
new file mode 100644
index 0000000..7e86e29
--- /dev/null
+++ b/sql-ledger/locale/ee/ic
@@ -0,0 +1,208 @@
+$self{texts} = {
+ 'Active' => 'Aktiva',
+ 'Add' => 'Lisa',
+ 'Add Assembly' => 'Lisa komplekt',
+ 'Add Part' => 'Lisa toode',
+ 'Add Purchase Order' => 'Lisa ostutellimus',
+ 'Add Sales Order' => 'Lisa müügitellimus',
+ 'Add Service' => 'Lisa teenus',
+ 'Address' => 'Aadress',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Assemblies' => 'Komplektid',
+ 'Assemblies restocked!' => 'Komplektid lattu tagastatud!',
+ 'Assembly Number missing!' => 'Komplekti number puudub!',
+ 'Attachment' => 'Kaasatud fail',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'BOM' => 'Materjalide nimekiri',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Kast',
+ 'Bought' => 'Ostetud',
+ 'COGS' => 'COGS',
+ 'Cannot delete item already invoiced!' => 'Esitatud arvega toodet ei saa kustutada!',
+ 'Cannot delete item on order!' => 'Tellimusega seotud artiklit ei saa kustutada!',
+ 'Cannot delete item which is part of an assembly!' => 'Komplekti kuuluvat toodet ei saa kustutada!',
+ 'Cannot delete item!' => 'Toodet ei saa kustutada!',
+ 'Cannot stock assemblies!' => 'Komplekte ei saa lattu võtta',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Edasi',
+ 'Copies' => 'koopiat',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Delete' => 'Kustuta',
+ 'Delivery Date' => 'Tarne kuupäev',
+ 'Description' => 'Selgitus',
+ 'Drawing' => 'Pildid',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-maili aadress puudub',
+ 'Edit Assembly' => 'Muuda Komplekti',
+ 'Edit Part' => 'Toote redigeerimine',
+ 'Edit Service' => 'Teenuse muutmine',
+ 'Expense' => 'Kulu',
+ 'Extended' => 'Summa',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'From' => 'Alates',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'Image' => 'Pilt',
+ 'In-line' => 'Dokumendisisene',
+ 'Include in Report' => 'Kaasa aruandesse',
+ 'Income' => 'Tulu',
+ 'Individual Items' => 'Komponendid',
+ 'Inventory' => 'Ladu',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Enne komplekti aegunuks märkimist peab laoseis null olema!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Enne toote aegunuks märkimist peab laoseis null olema!',
+ 'Inventory quantity must be zero!' => 'Laoseis peab null olema!',
+ 'Invoice' => 'Arve',
+ 'Invoice Date missing!' => 'Arve kuupäev puudub!',
+ 'Invoice Number' => 'Arve number',
+ 'Invoice Number missing!' => 'Arve number puudub!',
+ 'Item deleted!' => 'Toode kustutatud!',
+ 'Item not on file!' => 'Toode puudub andmebaasist!',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'Last Cost' => 'Viimane ostuhind',
+ 'Line Total' => 'Rea summa',
+ 'Link Accounts' => 'Seosta kontod',
+ 'List Price' => 'Hinnakirja hind',
+ 'Make' => 'Tootja',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Teade',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Mudel',
+ 'Name' => 'Nimi',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Märkused',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Kood',
+ 'Number missing in Row' => 'Antud real puudub kood',
+ 'Obsolete' => 'Aegunud',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'On Hand' => 'Laos',
+ 'On Order' => 'Tellimisel',
+ 'Order' => 'Tellimus',
+ 'Order Date missing!' => 'Tellimuse kuupäev puudub',
+ 'Order Number' => 'Tellimuse number',
+ 'Order Number missing!' => 'Tellimuse number puudub',
+ 'Ordered' => 'Tellitud',
+ 'Orphaned' => 'Seosteta',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Saateleht',
+ 'Packing List Date missing!' => 'Saatelehe kuupäev puudub',
+ 'Packing List Number missing!' => 'Saatelehe number puudub',
+ 'Part' => 'Toode',
+ 'Part Number missing!' => 'Toote kood puudub',
+ 'Parts' => 'Tooted',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hind',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Ostutellimus',
+ 'Qty' => 'Kogus',
+ 'ROP' => 'TM',
+ 'Recd' => 'Saabunud',
+ 'Required by' => 'Tarneaeg',
+ 'Sales' => 'Müük',
+ 'Sales Order' => 'Müügitellimus',
+ 'Save' => 'Salvesta',
+ 'Screen' => 'Ekraan',
+ 'Select from one of the items below' => 'Vali üks alltoodud toodetest',
+ 'Select postscript or PDF!' => 'Vali kas postscript või PDF',
+ 'Sell Price' => 'Müügihind',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Service' => 'Teenus',
+ 'Service Number missing!' => 'teenuse kood puudub!',
+ 'Services' => 'Teenused',
+ 'Ship' => 'Tarnimine',
+ 'Ship to' => 'Tarneaadress',
+ 'Short' => 'Lühike',
+ 'Sold' => 'Müüdud',
+ 'Stock Assembly' => 'Komplekti lattu võtmine',
+ 'Subject' => 'Pealkiri',
+ 'Subtotal' => 'Vahesumma',
+ 'Tax' => 'Maks',
+ 'To' => 'Kuhu',
+ 'Top Level' => 'Ülemine tase',
+ 'Total' => 'Kokku',
+ 'Unit' => 'Ühik',
+ 'Unit of measure' => 'Mõõtühik',
+ 'Update' => 'Uuenda',
+ 'Updated' => 'Uuendatud',
+ 'Weight' => 'Kaal',
+ 'What type of item is this?' => 'Mis tüüpi tootega on tegemist?',
+ 'ea' => 'tk',
+ 'emailed to' => 'salvestatud aadressile',
+ 'hr' => 't',
+ 'sent to printer' => 'printerile saadetud',
+ 'to' => 'kuni',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'lisa' => 'add',
+ 'lisa_komplekt' => 'add_assembly',
+ 'lisa_toode' => 'add_part',
+ 'lisa_teenus' => 'add_service',
+ 'edasi' => 'continue',
+ 'kustuta' => 'delete',
+ 'muuda_komplekti' => 'edit_assembly',
+ 'toote_redigeerimine' => 'edit_part',
+ 'teenuse_muutmine' => 'edit_service',
+ 'salvesta' => 'save',
+ 'uuenda' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/io b/sql-ledger/locale/ee/io
new file mode 100644
index 0000000..ccf21af
--- /dev/null
+++ b/sql-ledger/locale/ee/io
@@ -0,0 +1,108 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Lisa ostutellimus',
+ 'Add Sales Order' => 'Lisa müügitellimus',
+ 'Address' => 'Aadress',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Attachment' => 'Kaasatud fail',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Kast',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Edasi',
+ 'Copies' => 'koopiat',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Delivery Date' => 'Tarne kuupäev',
+ 'Description' => 'Selgitus',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-maili aadress puudub',
+ 'Extended' => 'Summa',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'Dokumendisisene',
+ 'Invoice' => 'Arve',
+ 'Invoice Date missing!' => 'Arve kuupäev puudub!',
+ 'Invoice Number missing!' => 'Arve number puudub!',
+ 'Item not on file!' => 'Toode puudub andmebaasist!',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Teade',
+ 'Name' => 'Nimi',
+ 'No.' => 'Nr.',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Kood',
+ 'Number missing in Row' => 'Antud real puudub kood',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'Order' => 'Tellimus',
+ 'Order Date missing!' => 'Tellimuse kuupäev puudub',
+ 'Order Number missing!' => 'Tellimuse number puudub',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Saateleht',
+ 'Packing List Date missing!' => 'Saatelehe kuupäev puudub',
+ 'Packing List Number missing!' => 'Saatelehe number puudub',
+ 'Part' => 'Toode',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hind',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Ostutellimus',
+ 'Qty' => 'Kogus',
+ 'Recd' => 'Saabunud',
+ 'Required by' => 'Tarneaeg',
+ 'Sales Order' => 'Müügitellimus',
+ 'Screen' => 'Ekraan',
+ 'Select from one of the items below' => 'Vali üks alltoodud toodetest',
+ 'Select postscript or PDF!' => 'Vali kas postscript või PDF',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Service' => 'Teenus',
+ 'Ship' => 'Tarnimine',
+ 'Ship to' => 'Tarneaadress',
+ 'Subject' => 'Pealkiri',
+ 'To' => 'Kuhu',
+ 'Unit' => 'Ühik',
+ 'What type of item is this?' => 'Mis tüüpi tootega on tegemist?',
+ 'emailed to' => 'salvestatud aadressile',
+ 'sent to printer' => 'printerile saadetud',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'edasi' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/ir b/sql-ledger/locale/ee/ir
new file mode 100644
index 0000000..0606a42
--- /dev/null
+++ b/sql-ledger/locale/ee/ir
@@ -0,0 +1,180 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Order' => 'Lisa ostutellimus',
+ 'Add Sales Order' => 'Lisa müügitellimus',
+ 'Add Vendor Invoice' => 'Add Vendor Invoice',
+ 'Address' => 'Aadress',
+ 'Amount' => 'Summa',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Are you sure you want to delete Invoice Number' => 'Kas oled kindel, et soovid kustutada arve',
+ 'Attachment' => 'Kaasatud fail',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Kast',
+ 'Cannot delete invoice!' => 'Arvet ei saa kustutada',
+ 'Cannot post invoice for a closed period!' => 'Arvet ei saa salvestada suletud perioodile!',
+ 'Cannot post invoice!' => 'Arvet ei saa saata!',
+ 'Cannot post payment for a closed period!' => 'Makset ei saa salvestada suletud perioodile',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Kinnita!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Edasi',
+ 'Copies' => 'koopiat',
+ 'Currency' => 'Valuuta',
+ 'Customer not on file!' => 'Klienti pole failis!',
+ 'Date' => 'Kuupäev',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Delete' => 'Kustuta',
+ 'Delivery Date' => 'Tarne kuupäev',
+ 'Description' => 'Selgitus',
+ 'Due Date' => 'Maksetähtaeg',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-maili aadress puudub',
+ 'Edit Vendor Invoice' => 'Edit Vendor Invoice',
+ 'Exch' => 'Kurss',
+ 'Exchangerate' => 'Valuutakurss',
+ 'Exchangerate for payment missing!' => 'Maksel ei ole valuutakurssi!',
+ 'Exchangerate missing!' => 'Valuutakurssi ei ole',
+ 'Extended' => 'Summa',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'Dokumendisisene',
+ 'Invoice' => 'Arve',
+ 'Invoice Date' => 'Arve kuupäev',
+ 'Invoice Date missing!' => 'Arve kuupäev puudub!',
+ 'Invoice Number' => 'Arve number',
+ 'Invoice Number missing!' => 'Arve number puudub!',
+ 'Invoice deleted!' => 'Arve kustutatud!',
+ 'Invoice posted!' => 'Arve salvestatud!',
+ 'Item not on file!' => 'Toode puudub andmebaasist!',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Teade',
+ 'Name' => 'Nimi',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Märkused',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Kood',
+ 'Number missing in Row' => 'Antud real puudub kood',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'Order' => 'Tellimus',
+ 'Order Date missing!' => 'Tellimuse kuupäev puudub',
+ 'Order Number' => 'Tellimuse number',
+ 'Order Number missing!' => 'Tellimuse number puudub',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Saateleht',
+ 'Packing List Date missing!' => 'Saatelehe kuupäev puudub',
+ 'Packing List Number missing!' => 'Saatelehe number puudub',
+ 'Part' => 'Toode',
+ 'Payment date missing!' => 'Maksekuupäev puudub',
+ 'Payments' => 'Maksed',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Salvesta',
+ 'Post as new' => 'Salvesta uuena',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hind',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekti pole failis',
+ 'Purchase Order' => 'Ostutellimus',
+ 'Qty' => 'Kogus',
+ 'Recd' => 'Saabunud',
+ 'Record in' => 'Sihtkonto',
+ 'Required by' => 'Tarneaeg',
+ 'Sales Order' => 'Müügitellimus',
+ 'Screen' => 'Ekraan',
+ 'Select from one of the items below' => 'Vali üks alltoodud toodetest',
+ 'Select from one of the names below' => 'Vali üks alltoodud nimedest',
+ 'Select from one of the projects below' => 'Vali üks alltoodud projektidest',
+ 'Select postscript or PDF!' => 'Vali kas postscript või PDF',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Service' => 'Teenus',
+ 'Ship' => 'Tarnimine',
+ 'Ship to' => 'Tarneaadress',
+ 'Source' => 'Allikas',
+ 'Subject' => 'Pealkiri',
+ 'Subtotal' => 'Vahesumma',
+ 'Tax Included' => 'Koos maksuga',
+ 'To' => 'Kuhu',
+ 'Total' => 'Kokku',
+ 'Unit' => 'Ühik',
+ 'Update' => 'Uuenda',
+ 'Vendor' => 'Hankija',
+ 'Vendor missing!' => 'Hankija puudub!',
+ 'Vendor not on file!' => 'Hankijat pole failis!',
+ 'What type of item is this?' => 'Mis tüüpi tootega on tegemist?',
+ 'Yes' => 'Jah',
+ 'ea' => 'tk',
+ 'emailed to' => 'salvestatud aadressile',
+ 'sent to printer' => 'printerile saadetud',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'edasi' => 'continue',
+ 'kustuta' => 'delete',
+ 'tellimus' => 'order',
+ 'salvesta' => 'post',
+ 'salvesta_uuena' => 'post_as_new',
+ 'uuenda' => 'update',
+ 'jah' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/is b/sql-ledger/locale/ee/is
new file mode 100644
index 0000000..c380e76
--- /dev/null
+++ b/sql-ledger/locale/ee/is
@@ -0,0 +1,187 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Order' => 'Lisa ostutellimus',
+ 'Add Sales Invoice' => 'Lisa Müügiarve',
+ 'Add Sales Order' => 'Lisa müügitellimus',
+ 'Address' => 'Aadress',
+ 'Amount' => 'Summa',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Are you sure you want to delete Invoice Number' => 'Kas oled kindel, et soovid kustutada arve',
+ 'Attachment' => 'Kaasatud fail',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Kast',
+ 'Cannot delete invoice!' => 'Arvet ei saa kustutada',
+ 'Cannot post invoice for a closed period!' => 'Arvet ei saa salvestada suletud perioodile!',
+ 'Cannot post invoice!' => 'Arvet ei saa saata!',
+ 'Cannot post payment for a closed period!' => 'Makset ei saa salvestada suletud perioodile',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Kinnita!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Edasi',
+ 'Copies' => 'koopiat',
+ 'Credit Limit' => 'Krediidilimiit',
+ 'Currency' => 'Valuuta',
+ 'Customer' => 'Klient',
+ 'Customer missing!' => 'Klienti pole määratud!',
+ 'Customer not on file!' => 'Klienti pole failis!',
+ 'Date' => 'Kuupäev',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Delete' => 'Kustuta',
+ 'Delivery Date' => 'Tarne kuupäev',
+ 'Description' => 'Selgitus',
+ 'Due Date' => 'Maksetähtaeg',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-maili aadress puudub',
+ 'Edit Sales Invoice' => 'Müügiarve muutmine',
+ 'Exch' => 'Kurss',
+ 'Exchangerate' => 'Valuutakurss',
+ 'Exchangerate for payment missing!' => 'Maksel ei ole valuutakurssi!',
+ 'Exchangerate missing!' => 'Valuutakurssi ei ole',
+ 'Extended' => 'Summa',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'Dokumendisisene',
+ 'Invoice' => 'Arve',
+ 'Invoice Date' => 'Arve kuupäev',
+ 'Invoice Date missing!' => 'Arve kuupäev puudub!',
+ 'Invoice Number' => 'Arve number',
+ 'Invoice Number missing!' => 'Arve number puudub!',
+ 'Invoice deleted!' => 'Arve kustutatud!',
+ 'Invoice posted!' => 'Arve salvestatud!',
+ 'Item not on file!' => 'Toode puudub andmebaasist!',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Teade',
+ 'Name' => 'Nimi',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Märkused',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Kood',
+ 'Number missing in Row' => 'Antud real puudub kood',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'Order' => 'Tellimus',
+ 'Order Date missing!' => 'Tellimuse kuupäev puudub',
+ 'Order Number' => 'Tellimuse number',
+ 'Order Number missing!' => 'Tellimuse number puudub',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Saateleht',
+ 'Packing List Date missing!' => 'Saatelehe kuupäev puudub',
+ 'Packing List Number missing!' => 'Saatelehe number puudub',
+ 'Part' => 'Toode',
+ 'Payment date missing!' => 'Maksekuupäev puudub',
+ 'Payments' => 'Maksed',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Salvesta',
+ 'Post as new' => 'Salvesta uuena',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hind',
+ 'Print' => 'Trüki',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekti pole failis',
+ 'Purchase Order' => 'Ostutellimus',
+ 'Qty' => 'Kogus',
+ 'Recd' => 'Saabunud',
+ 'Record in' => 'Sihtkonto',
+ 'Remaining' => 'Kasutamata',
+ 'Required by' => 'Tarneaeg',
+ 'Sales Order' => 'Müügitellimus',
+ 'Screen' => 'Ekraan',
+ 'Select from one of the items below' => 'Vali üks alltoodud toodetest',
+ 'Select from one of the names below' => 'Vali üks alltoodud nimedest',
+ 'Select from one of the projects below' => 'Vali üks alltoodud projektidest',
+ 'Select postscript or PDF!' => 'Vali kas postscript või PDF',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Service' => 'Teenus',
+ 'Ship' => 'Tarnimine',
+ 'Ship to' => 'Tarneaadress',
+ 'Ship via' => 'Tarneviis',
+ 'Source' => 'Allikas',
+ 'Subject' => 'Pealkiri',
+ 'Subtotal' => 'Vahesumma',
+ 'Tax Included' => 'Koos maksuga',
+ 'To' => 'Kuhu',
+ 'Total' => 'Kokku',
+ 'Unit' => 'Ühik',
+ 'Update' => 'Uuenda',
+ 'Vendor not on file!' => 'Hankijat pole failis!',
+ 'What type of item is this?' => 'Mis tüüpi tootega on tegemist?',
+ 'Yes' => 'Jah',
+ 'ea' => 'tk',
+ 'emailed to' => 'salvestatud aadressile',
+ 'sent to printer' => 'printerile saadetud',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'edasi' => 'continue',
+ 'kustuta' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'tellimus' => 'order',
+ 'salvesta' => 'post',
+ 'salvesta_uuena' => 'post_as_new',
+ 'trüki' => 'print',
+ 'tarneaadress' => 'ship_to',
+ 'uuenda' => 'update',
+ 'jah' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/login b/sql-ledger/locale/ee/login
new file mode 100644
index 0000000..18cb05b
--- /dev/null
+++ b/sql-ledger/locale/ee/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Programmi Info',
+ 'Database Host' => 'Andmebaasiserver',
+ 'Dataset' => 'Andmebaas',
+ 'Incorrect Dataset version!' => 'Vale andmebaasi versioon',
+ 'Incorrect Password!' => 'Vale parool!',
+ 'Licensed to' => 'Kasutaja andmed:',
+ 'Login' => 'Login',
+ 'Name' => 'Nimi',
+ 'Password' => 'Parool',
+ 'User' => 'Kasutaja',
+ 'Version' => 'Versioon',
+ 'You are logged out!' => 'Oled välja loginud!',
+ 'You did not enter a name!' => 'Nimi sisestamata!',
+ 'is not a member!' => 'ei ole kasutaja!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/menu b/sql-ledger/locale/ee/menu
new file mode 100644
index 0000000..7d77737
--- /dev/null
+++ b/sql-ledger/locale/ee/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Kohustused',
+ 'AP Aging' => 'Võlad',
+ 'AR' => 'Nõuded',
+ 'AR Aging' => 'Võlglased',
+ 'Accounting Menu' => 'Raamatupidamise Menüü',
+ 'Add Account' => 'Lisa konto',
+ 'Add Assembly' => 'Lisa komplekt',
+ 'Add Customer' => 'Lisa klient',
+ 'Add GIFI' => 'Lisa GIFI',
+ 'Add Part' => 'Lisa toode',
+ 'Add Project' => 'Lisa Projekt',
+ 'Add Service' => 'Lisa teenus',
+ 'Add Transaction' => 'Lisa kanne',
+ 'Add Vendor' => 'Lisa hankija',
+ 'Assemblies' => 'Komplektid',
+ 'Audit Control' => 'Audit',
+ 'Backup' => 'Varukoopia',
+ 'Balance Sheet' => 'Bilansitabel',
+ 'Cash' => 'Kassa',
+ 'Chart of Accounts' => 'Kontoplaan',
+ 'Check' => 'T?ekk',
+ 'Customers' => 'Kliendid',
+ 'General Ledger' => 'Pearaamat',
+ 'Goods & Services' => 'Tooted ja teenused',
+ 'HTML Templates' => 'HTML dokumendipõhjad',
+ 'Income Statement' => 'Kasumiaruanne',
+ 'Invoice' => 'Arve',
+ 'LaTeX Templates' => 'LaTeX dokumendipõhjad',
+ 'List Accounts' => 'Kontode nimekiri',
+ 'List GIFI' => 'GIFI nimekiri',
+ 'Logout' => 'Logi välja',
+ 'Order Entry' => 'Tellimuse sisestamine',
+ 'Packing List' => 'Saateleht',
+ 'Parts' => 'Tooted',
+ 'Payment' => 'Maksed',
+ 'Payments' => 'Maksed',
+ 'Preferences' => 'Määrangud',
+ 'Projects' => 'Projektid',
+ 'Purchase Order' => 'Ostutellimus',
+ 'Purchase Orders' => 'Ostutellimused',
+ 'Receipt' => 'Laekumised',
+ 'Receipts' => 'Laekumised',
+ 'Reconciliation' => 'Tasaarveldused',
+ 'Reports' => 'Aruanded',
+ 'Sales Invoice' => 'Müügiarve',
+ 'Sales Order' => 'Müügitellimus',
+ 'Sales Orders' => 'Müügitellimused',
+ 'Save to File' => 'Salvesta faili',
+ 'Send by E-Mail' => 'Saada e-postiga',
+ 'Services' => 'Teenused',
+ 'Statement' => 'Aruanne',
+ 'Stock Assembly' => 'Komplekti lattu võtmine',
+ 'Stylesheet' => 'Laaditabel',
+ 'System' => 'Süsteem',
+ 'Tax collected' => 'Kogutud maksud',
+ 'Tax paid' => 'Makstud makse',
+ 'Transactions' => 'Kanded',
+ 'Trial Balance' => 'Proovibilanss',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendors' => 'Hankijad',
+ 'Version' => 'Versioon',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/oe b/sql-ledger/locale/ee/oe
new file mode 100644
index 0000000..dd5a09b
--- /dev/null
+++ b/sql-ledger/locale/ee/oe
@@ -0,0 +1,202 @@
+$self{texts} = {
+ 'Add' => 'Lisa',
+ 'Add Purchase Order' => 'Lisa ostutellimus',
+ 'Add Sales Invoice' => 'Lisa Müügiarve',
+ 'Add Sales Order' => 'Lisa müügitellimus',
+ 'Add Vendor Invoice' => 'Add Vendor Invoice',
+ 'Address' => 'Aadress',
+ 'Amount' => 'Summa',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Are you sure you want to delete Order Number' => 'Kas oled kindel, et soovid kustutada tellimuse',
+ 'Attachment' => 'Kaasatud fail',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Kast',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Tellimust ei saa kustutada!',
+ 'Cannot save order!' => 'Arvet ei saa salvestada',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Suletud',
+ 'Confirm!' => 'Kinnita!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Edasi',
+ 'Copies' => 'koopiat',
+ 'Credit Limit' => 'Krediidilimiit',
+ 'Curr' => 'Val.',
+ 'Currency' => 'Valuuta',
+ 'Customer' => 'Klient',
+ 'Customer missing!' => 'Klienti pole määratud!',
+ 'Customer not on file!' => 'Klienti pole failis!',
+ 'Date' => 'Kuupäev',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Delete' => 'Kustuta',
+ 'Delivery Date' => 'Tarne kuupäev',
+ 'Description' => 'Selgitus',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-maili aadress puudub',
+ 'Edit Purchase Order' => 'Ostutellimuse muutmine',
+ 'Edit Sales Order' => 'Müügitellimuse muutmine',
+ 'Exchangerate' => 'Valuutakurss',
+ 'Exchangerate missing!' => 'Valuutakurssi ei ole',
+ 'Extended' => 'Summa',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'From' => 'Alates',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'ID' => 'ID',
+ 'In-line' => 'Dokumendisisene',
+ 'Include in Report' => 'Kaasa aruandesse',
+ 'Invoice' => 'Arve',
+ 'Invoice Date missing!' => 'Arve kuupäev puudub!',
+ 'Invoice Number missing!' => 'Arve number puudub!',
+ 'Item not on file!' => 'Toode puudub andmebaasist!',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Teade',
+ 'Name' => 'Nimi',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Märkused',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Kood',
+ 'Number missing in Row' => 'Antud real puudub kood',
+ 'O' => 'O',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'Open' => 'Avatud',
+ 'Order' => 'Tellimus',
+ 'Order Date' => 'Tellimuse kuupäev',
+ 'Order Date missing!' => 'Tellimuse kuupäev puudub',
+ 'Order Number' => 'Tellimuse number',
+ 'Order Number missing!' => 'Tellimuse number puudub',
+ 'Order deleted!' => 'Tellimus kustutatud',
+ 'Order saved!' => 'Tellimus salvestatud',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Saateleht',
+ 'Packing List Date missing!' => 'Saatelehe kuupäev puudub',
+ 'Packing List Number missing!' => 'Saatelehe number puudub',
+ 'Part' => 'Toode',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hind',
+ 'Print' => 'Trüki',
+ 'Printer' => 'Printer',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekti pole failis',
+ 'Purchase Order' => 'Ostutellimus',
+ 'Purchase Orders' => 'Ostutellimused',
+ 'Qty' => 'Kogus',
+ 'Recd' => 'Saabunud',
+ 'Remaining' => 'Kasutamata',
+ 'Required by' => 'Tarneaeg',
+ 'Sales Order' => 'Müügitellimus',
+ 'Sales Orders' => 'Müügitellimused',
+ 'Save' => 'Salvesta',
+ 'Save as new' => 'Salvesta uuena',
+ 'Screen' => 'Ekraan',
+ 'Select from one of the items below' => 'Vali üks alltoodud toodetest',
+ 'Select from one of the names below' => 'Vali üks alltoodud nimedest',
+ 'Select from one of the projects below' => 'Vali üks alltoodud projektidest',
+ 'Select postscript or PDF!' => 'Vali kas postscript või PDF',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Service' => 'Teenus',
+ 'Ship' => 'Tarnimine',
+ 'Ship to' => 'Tarneaadress',
+ 'Ship via' => 'Tarneviis',
+ 'Subject' => 'Pealkiri',
+ 'Subtotal' => 'Vahesumma',
+ 'Tax' => 'Maks',
+ 'Tax Included' => 'Koos maksuga',
+ 'Terms: Net' => 'Maksetingimus',
+ 'To' => 'Kuhu',
+ 'Total' => 'Kokku',
+ 'Unit' => 'Ühik',
+ 'Update' => 'Uuenda',
+ 'Vendor' => 'Hankija',
+ 'Vendor missing!' => 'Hankija puudub!',
+ 'Vendor not on file!' => 'Hankijat pole failis!',
+ 'What type of item is this?' => 'Mis tüüpi tootega on tegemist?',
+ 'Yes' => 'Jah',
+ 'days' => 'päeva',
+ 'ea' => 'tk',
+ 'emailed to' => 'salvestatud aadressile',
+ 'sent to printer' => 'printerile saadetud',
+ 'to' => 'kuni',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'lisa' => 'add',
+ 'edasi' => 'continue',
+ 'kustuta' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'arve' => 'invoice',
+ 'trüki' => 'print',
+ 'salvesta' => 'save',
+ 'salvesta_uuena' => 'save_as_new',
+ 'tarneaadress' => 'ship_to',
+ 'uuenda' => 'update',
+ 'jah' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/pe b/sql-ledger/locale/ee/pe
new file mode 100644
index 0000000..7ce3815
--- /dev/null
+++ b/sql-ledger/locale/ee/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Lisa',
+ 'Add Project' => 'Lisa Projekt',
+ 'All' => 'Kõik',
+ 'Continue' => 'Edasi',
+ 'Delete' => 'Kustuta',
+ 'Description' => 'Selgitus',
+ 'Edit Project' => 'Muuda Projekti',
+ 'Number' => 'Kood',
+ 'Orphaned' => 'Seosteta',
+ 'Project' => 'Projekt',
+ 'Project Number missing!' => 'Projekti number puudub',
+ 'Project deleted!' => 'Projekt kustutatud',
+ 'Project saved!' => 'Projekt salvestatud',
+ 'Projects' => 'Projektid',
+ 'Save' => 'Salvesta',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'lisa' => 'add',
+ 'edasi' => 'continue',
+ 'kustuta' => 'delete',
+ 'salvesta' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/rc b/sql-ledger/locale/ee/rc
new file mode 100644
index 0000000..af52fde
--- /dev/null
+++ b/sql-ledger/locale/ee/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Balance' => 'Bilanss',
+ 'Cleared Balance' => 'Puhastatud bilanss',
+ 'Continue' => 'Edasi',
+ 'Date' => 'Kuupäev',
+ 'Deposit' => 'Tarnimata',
+ 'Description' => 'Selgitus',
+ 'Difference' => 'Vahe',
+ 'Done' => 'Teostatud',
+ 'Exchangerate Difference' => 'Valuutakursi muutus',
+ 'From' => 'Alates',
+ 'Out of balance!' => 'Bilanss ei klapi!',
+ 'Payment' => 'Maksed',
+ 'Reconciliation' => 'Tasaarveldused',
+ 'Select all' => 'Vali kõik',
+ 'Source' => 'Allikas',
+ 'Statement Balance' => 'Bilansiaruanne',
+ 'Update' => 'Uuenda',
+ 'to' => 'kuni',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'edasi' => 'continue',
+ 'teostatud' => 'done',
+ 'vali_kõik' => 'select_all',
+ 'uuenda' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ee/rp b/sql-ledger/locale/ee/rp
new file mode 100644
index 0000000..9d0e6bc
--- /dev/null
+++ b/sql-ledger/locale/ee/rp
@@ -0,0 +1,120 @@
+$self{texts} = {
+ 'AP Aging' => 'Võlad',
+ 'AR Aging' => 'Võlglased',
+ 'Account' => 'Konto',
+ 'Accounts' => 'Kontod',
+ 'Amount' => 'Summa',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprill',
+ 'Attachment' => 'Kaasatud fail',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Balance' => 'Bilanss',
+ 'Balance Sheet' => 'Bilansitabel',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Kassapõhine',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Võrdlus perioodiga',
+ 'Continue' => 'Edasi',
+ 'Copies' => 'koopiat',
+ 'Credit' => 'Kreedit',
+ 'Current' => 'Praegune',
+ 'Customer' => 'Klient',
+ 'Date' => 'Kuupäev',
+ 'Debit' => 'Deebet',
+ 'Dec' => 'Dets',
+ 'December' => 'Detsember',
+ 'Decimalplaces' => 'Komakohti',
+ 'Department' => 'Osakond',
+ 'Description' => 'Selgitus',
+ 'Due' => 'Tasuda',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'E-mail teatis',
+ 'Feb' => 'Veebr',
+ 'February' => 'Veebruar',
+ 'From' => 'Alates',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Päis',
+ 'ID' => 'ID',
+ 'In-line' => 'Dokumendisisene',
+ 'Include in Report' => 'Kaasa aruandesse',
+ 'Income Statement' => 'Kasumiaruanne',
+ 'Invoice' => 'Arve',
+ 'Jan' => 'Jaan',
+ 'January' => 'Jaanuar',
+ 'Jul' => 'Juul',
+ 'July' => 'Juuli',
+ 'Jun' => 'Juun',
+ 'June' => 'Juuni',
+ 'Mar' => 'Mär',
+ 'March' => 'Märts',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Teade',
+ 'N/A' => 'Puudub',
+ 'Nothing selected!' => 'Midagi ei ole valitud',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktoober',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Maksed',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Trüki',
+ 'Printer' => 'Printer',
+ 'Project Number' => 'Projekti number',
+ 'Receipts' => 'Laekumised',
+ 'Report for' => 'Aruanne',
+ 'Retained Earnings' => 'Jaotamata kasum',
+ 'Screen' => 'Ekraan',
+ 'Select all' => 'Vali kõik',
+ 'Select postscript or PDF!' => 'Vali kas postscript või PDF',
+ 'Sep' => 'Sept',
+ 'September' => 'September',
+ 'Source' => 'Allikas',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Aruanne',
+ 'Statement sent to' => 'Saata aruanne aadressil',
+ 'Statements sent to printer!' => 'Saata aruanne printerile',
+ 'Subject' => 'Pealkiri',
+ 'Subtotal' => 'Vahesumma',
+ 'Tax' => 'Maks',
+ 'Tax collected' => 'Kogutud maksud',
+ 'Tax paid' => 'Makstud makse',
+ 'Total' => 'Kokku',
+ 'Trial Balance' => 'Proovibilanss',
+ 'Vendor' => 'Hankija',
+ 'as at' => 'Seisuga',
+ 'collected on sales' => 'kogutud müügilt',
+ 'for Period' => 'Periood',
+ 'paid on purchases' => 'makstud ostudelt',
+ 'to' => 'kuni',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'edasi' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'trüki' => 'print',
+ 'vali_kõik' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/COPYING b/sql-ledger/locale/en_GB/COPYING
new file mode 100644
index 0000000..ceaa769
--- /dev/null
+++ b/sql-ledger/locale/en_GB/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2003
+#
+# British English texts:
+#
+# Author:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/en_GB/LANGUAGE b/sql-ledger/locale/en_GB/LANGUAGE
new file mode 100644
index 0000000..bed69f7
--- /dev/null
+++ b/sql-ledger/locale/en_GB/LANGUAGE
@@ -0,0 +1 @@
+British English
diff --git a/sql-ledger/locale/en_GB/admin b/sql-ledger/locale/en_GB/admin
new file mode 100644
index 0000000..580d1c6
--- /dev/null
+++ b/sql-ledger/locale/en_GB/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Access Control',
+ 'Accounting' => 'Accounting',
+ 'Add User' => 'Add User',
+ 'Address' => 'Address',
+ 'Administration' => 'Administration',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => 'All Datasets up to date!',
+ 'Change Admin Password' => 'Change Admin Password',
+ 'Change Password' => 'Change Password',
+ 'Character Set' => 'Character Set',
+ 'Click on login name to edit!' => 'Click on login name to edit!',
+ 'Company' => 'Company',
+ 'Connect to' => 'Connect to',
+ 'Continue' => 'Continue',
+ 'Create Chart of Accounts' => 'Create Chart of Accounts',
+ 'Create Dataset' => 'Create Dataset',
+ 'DBI not installed!' => 'DBI not installed!',
+ 'Database' => 'Database',
+ 'Database Administration' => 'Database Administration',
+ 'Database Driver not checked!' => 'Database Driver not checked!',
+ 'Database User missing!' => 'Database User missing!',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Dataset missing!',
+ 'Dataset updated!' => 'Dataset updated!',
+ 'Date Format' => 'Date Format',
+ 'Delete' => 'Delete',
+ 'Delete Dataset' => 'Delete Dataset',
+ 'Directory' => 'Directory',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'E-mail',
+ 'Edit User' => 'Edit User',
+ 'Existing Datasets' => 'Existing Datasets',
+ 'Fax' => 'Fax',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Hostname missing!',
+ 'Incorrect Password!' => 'Incorrect Password!',
+ 'Language' => 'Language',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Leave host and port field empty unless you want to make a remote connection.',
+ 'Login' => 'Login',
+ 'Multibyte Encoding' => 'Multibyte Encoding',
+ 'Name' => 'Name',
+ 'New Templates' => 'New Templates',
+ 'No Database Drivers available!' => 'No Database Drivers available!',
+ 'No Dataset selected!' => 'No Dataset selected!',
+ 'Nothing to delete!' => 'Nothing to delete!',
+ 'Number Format' => 'Number Format',
+ 'Oracle Database Administration' => 'Oracle Database Administration',
+ 'Password' => 'Password',
+ 'Password changed!' => 'Password changed!',
+ 'Pg Database Administration' => 'Pg Database Administration',
+ 'Phone' => 'Phone',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port missing!',
+ 'Printer' => 'Printer',
+ 'Save' => 'Save',
+ 'Select a Dataset to delete and press "Continue"' => 'Select a Dataset to delete and press "Continue"',
+ 'Setup Templates' => 'Setup Templates',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Signature',
+ 'Stylesheet' => 'Stylesheet',
+ 'Templates' => 'Templates',
+ 'The following Datasets are not in use and can be deleted' => 'The following Datasets are not in use and can be deleted',
+ 'The following Datasets need to be updated' => 'The following Datasets need to be updated',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.',
+ 'Update Dataset' => 'Update Dataset',
+ 'Use Templates' => 'Use Templates',
+ 'User' => 'User',
+ 'User deleted!' => 'User deleted!',
+ 'User saved!' => 'User saved!',
+ 'Version' => 'Version',
+ 'You must enter a host and port for local and remote connections!' => 'You must enter a host and port for local and remote connections!',
+ 'does not exist' => 'does not exist',
+ 'is already a member!' => 'is already a member!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'locked!',
+ 'successfully created!' => 'successfully created!',
+ 'successfully deleted!' => 'successfully deleted!',
+ 'website' => 'website',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'add_user' => 'add_user',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'login' => 'login',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/all b/sql-ledger/locale/en_GB/all
new file mode 100644
index 0000000..e45542a
--- /dev/null
+++ b/sql-ledger/locale/en_GB/all
@@ -0,0 +1,499 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Purchases',
+ 'AP Aging' => 'Creditor Aging',
+ 'AP Transaction' => 'Purchase Transaction',
+ 'AP Transactions' => 'Purchase Transactions',
+ 'AR' => 'Sales',
+ 'AR Aging' => 'Debtor Aging',
+ 'AR Transaction' => 'Sales Transaction',
+ 'AR Transactions' => 'Sales Transactions',
+ 'About' => '',
+ 'Access Control' => '',
+ 'Account' => '',
+ 'Account Number' => '',
+ 'Account Number missing!' => '',
+ 'Account Type' => '',
+ 'Account Type missing!' => '',
+ 'Account deleted!' => '',
+ 'Account saved!' => '',
+ 'Accounting' => '',
+ 'Accounting Menu' => '',
+ 'Accounts' => '',
+ 'Active' => '',
+ 'Add' => '',
+ 'Add Account' => '',
+ 'Add Accounts Payables Transaction' => 'Add Purchase Transaction',
+ 'Add Accounts Receivables Transaction' => 'Add Sales Transaction',
+ 'Add Assembly' => '',
+ 'Add Customer' => '',
+ 'Add GIFI' => '',
+ 'Add General Ledger Transaction' => '',
+ 'Add Group' => '',
+ 'Add Part' => '',
+ 'Add Project' => '',
+ 'Add Purchase Order' => '',
+ 'Add Sales Invoice' => '',
+ 'Add Sales Order' => '',
+ 'Add Service' => '',
+ 'Add Transaction' => '',
+ 'Add User' => '',
+ 'Add Vendor' => '',
+ 'Add Vendor Invoice' => '',
+ 'Address' => '',
+ 'Administration' => '',
+ 'Administrator' => '',
+ 'All' => '',
+ 'All Datasets up to date!' => '',
+ 'Amount' => '',
+ 'Amount Due' => '',
+ 'Amount does not equal applied!' => '',
+ 'Amount missing!' => '',
+ 'Applied' => '',
+ 'Apr' => '',
+ 'April' => '',
+ 'Are you sure you want to delete Invoice Number' => '',
+ 'Are you sure you want to delete Order Number' => '',
+ 'Are you sure you want to delete Transaction' => '',
+ 'Assemblies' => '',
+ 'Assemblies restocked!' => '',
+ 'Assembly Number missing!' => '',
+ 'Asset' => '',
+ 'Attachment' => '',
+ 'Audit Control' => '',
+ 'Aug' => '',
+ 'August' => '',
+ 'BOM' => '',
+ 'Backup' => '',
+ 'Backup sent to' => '',
+ 'Balance' => '',
+ 'Balance Sheet' => '',
+ 'Bcc' => '',
+ 'Bin' => '',
+ 'Books are open' => '',
+ 'Bought' => '',
+ 'Business Number' => '',
+ 'C' => '',
+ 'COGS' => '',
+ 'Cannot delete account!' => '',
+ 'Cannot delete customer!' => '',
+ 'Cannot delete default account!' => '',
+ 'Cannot delete invoice!' => '',
+ 'Cannot delete item!' => '',
+ 'Cannot delete order!' => '',
+ 'Cannot delete transaction!' => '',
+ 'Cannot delete vendor!' => '',
+ 'Cannot have a value in both Debit and Credit!' => '',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => '',
+ 'Cannot post invoice!' => '',
+ 'Cannot post payment for a closed period!' => '',
+ 'Cannot post payment!' => '',
+ 'Cannot post transaction for a closed period!' => '',
+ 'Cannot post transaction!' => '',
+ 'Cannot process payment for a closed period!' => '',
+ 'Cannot save account!' => '',
+ 'Cannot save order!' => '',
+ 'Cannot save preferences!' => '',
+ 'Cannot stock assemblies!' => '',
+ 'Cash' => '',
+ 'Cash based' => '',
+ 'Cc' => '',
+ 'Change Admin Password' => '',
+ 'Change Password' => '',
+ 'Character Set' => '',
+ 'Chart of Accounts' => '',
+ 'Check' => 'Cheque',
+ 'Check printed!' => '',
+ 'Check printing failed!' => '',
+ 'Cleared Balance' => '',
+ 'Click on login name to edit!' => '',
+ 'Close Books up to' => '',
+ 'Closed' => '',
+ 'Company' => '',
+ 'Compare to' => '',
+ 'Confirm!' => '',
+ 'Connect to' => '',
+ 'Contact' => '',
+ 'Continue' => '',
+ 'Copies' => '',
+ 'Copy to COA' => '',
+ 'Create Chart of Accounts' => '',
+ 'Create Dataset' => '',
+ 'Credit' => '',
+ 'Credit Limit' => '',
+ 'Curr' => '',
+ 'Currency' => '',
+ 'Current' => '',
+ 'Customer' => '',
+ 'Customer deleted!' => '',
+ 'Customer missing!' => '',
+ 'Customer not on file!' => '',
+ 'Customer saved!' => '',
+ 'Customers' => '',
+ 'DBI not installed!' => '',
+ 'Database' => '',
+ 'Database Administration' => '',
+ 'Database Driver not checked!' => '',
+ 'Database Host' => '',
+ 'Database User missing!' => '',
+ 'Dataset' => '',
+ 'Dataset missing!' => '',
+ 'Dataset updated!' => '',
+ 'Date' => '',
+ 'Date Format' => '',
+ 'Date Paid' => '',
+ 'Date missing!' => '',
+ 'Debit' => '',
+ 'Debit and credit out of balance!' => '',
+ 'Dec' => '',
+ 'December' => '',
+ 'Decimalplaces' => '',
+ 'Delete' => '',
+ 'Delete Account' => '',
+ 'Delete Dataset' => '',
+ 'Delivery Date' => '',
+ 'Deposit' => '',
+ 'Description' => '',
+ 'Difference' => '',
+ 'Directory' => '',
+ 'Discount' => '',
+ 'Done' => '',
+ 'Drawing' => '',
+ 'Driver' => '',
+ 'Dropdown Limit' => '',
+ 'Due' => '',
+ 'Due Date' => '',
+ 'Due Date missing!' => '',
+ 'E-mail' => '',
+ 'E-mail Statement to' => '',
+ 'E-mail address missing!' => '',
+ 'Edit' => '',
+ 'Edit Account' => '',
+ 'Edit Accounts Payables Transaction' => 'Edit Creditor Transaction',
+ 'Edit Accounts Receivables Transaction' => 'Edit Debtor Transaction',
+ 'Edit Assembly' => '',
+ 'Edit Customer' => '',
+ 'Edit GIFI' => '',
+ 'Edit General Ledger Transaction' => '',
+ 'Edit Group' => '',
+ 'Edit Part' => '',
+ 'Edit Preferences for' => '',
+ 'Edit Project' => '',
+ 'Edit Purchase Order' => '',
+ 'Edit Sales Invoice' => '',
+ 'Edit Sales Order' => '',
+ 'Edit Service' => '',
+ 'Edit Template' => '',
+ 'Edit User' => '',
+ 'Edit Vendor' => '',
+ 'Edit Vendor Invoice' => '',
+ 'Employee' => '',
+ 'Enforce transaction reversal for all dates' => '',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => '',
+ 'Equity' => '',
+ 'Exch' => '',
+ 'Exchangerate' => '',
+ 'Exchangerate Difference' => '',
+ 'Exchangerate for payment missing!' => '',
+ 'Exchangerate missing!' => '',
+ 'Existing Datasets' => '',
+ 'Expense' => '',
+ 'Expense Account' => '',
+ 'Expense/Asset' => '',
+ 'Extended' => '',
+ 'Fax' => '',
+ 'Feb' => '',
+ 'February' => '',
+ 'Foreign Exchange Gain' => '',
+ 'Foreign Exchange Loss' => '',
+ 'From' => '',
+ 'GIFI' => '',
+ 'GIFI deleted!' => '',
+ 'GIFI missing!' => '',
+ 'GIFI saved!' => '',
+ 'GL Transaction' => '',
+ 'General Ledger' => '',
+ 'Goods & Services' => '',
+ 'Group' => '',
+ 'Group Items' => '',
+ 'Group deleted!' => '',
+ 'Group missing!' => '',
+ 'Group saved!' => '',
+ 'Groups' => '',
+ 'HTML Templates' => '',
+ 'Heading' => '',
+ 'Host' => '',
+ 'Hostname missing!' => '',
+ 'ID' => '',
+ 'Image' => '',
+ 'In-line' => '',
+ 'Include in Report' => '',
+ 'Include in drop-down menus' => '',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Include this account on debtor/creditor forms to set debtor/creditor taxable?',
+ 'Income' => 'Revenue',
+ 'Income Account' => 'Revenue Account',
+ 'Income Statement' => '',
+ 'Incorrect Dataset version!' => '',
+ 'Incorrect Password!' => '',
+ 'Individual Items' => '',
+ 'Inventory' => '',
+ 'Inventory Account' => '',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => '',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => '',
+ 'Invoice' => '',
+ 'Invoice Date' => '',
+ 'Invoice Date missing!' => '',
+ 'Invoice Number' => '',
+ 'Invoice Number missing!' => '',
+ 'Invoice deleted!' => '',
+ 'Invoice posted!' => '',
+ 'Invoices' => '',
+ 'Is this a summary account to record' => '',
+ 'Item deleted!' => '',
+ 'Item not on file!' => '',
+ 'Jan' => '',
+ 'January' => '',
+ 'Jul' => '',
+ 'July' => '',
+ 'Jun' => '',
+ 'June' => '',
+ 'LaTeX Templates' => '',
+ 'Language' => '',
+ 'Last Cost' => '',
+ 'Last Invoice Number' => '',
+ 'Last Numbers & Default Accounts' => '',
+ 'Last Purchase Order Number' => '',
+ 'Last Sales Order Number' => '',
+ 'Leave host and port field empty unless you want to make a remote connection.' => '',
+ 'Liability' => '',
+ 'Licensed to' => '',
+ 'Line Total' => '',
+ 'Link' => '',
+ 'Link Accounts' => '',
+ 'List Accounts' => '',
+ 'List GIFI' => '',
+ 'List Price' => '',
+ 'List Transactions' => '',
+ 'Login' => '',
+ 'Logout' => '',
+ 'Make' => '',
+ 'Mar' => '',
+ 'March' => '',
+ 'May' => '',
+ 'May ' => '',
+ 'Message' => '',
+ 'Microfiche' => '',
+ 'Model' => '',
+ 'Multibyte Encoding' => '',
+ 'N/A' => '',
+ 'Name' => '',
+ 'Name missing!' => '',
+ 'New Templates' => '',
+ 'No' => '',
+ 'No Database Drivers available!' => '',
+ 'No Dataset selected!' => '',
+ 'No email address for' => '',
+ 'No.' => '',
+ 'Notes' => '',
+ 'Nothing applied!' => '',
+ 'Nothing selected!' => '',
+ 'Nothing to delete!' => '',
+ 'Nov' => '',
+ 'November' => '',
+ 'Number' => '',
+ 'Number Format' => '',
+ 'Number missing in Row' => '',
+ 'O' => '',
+ 'Obsolete' => '',
+ 'Oct' => '',
+ 'October' => '',
+ 'On Hand' => '',
+ 'On Order' => '',
+ 'Open' => '',
+ 'Oracle Database Administration' => '',
+ 'Order' => '',
+ 'Order Date' => '',
+ 'Order Date missing!' => '',
+ 'Order Entry' => '',
+ 'Order Number' => '',
+ 'Order Number missing!' => '',
+ 'Order deleted!' => '',
+ 'Order saved!' => '',
+ 'Ordered' => '',
+ 'Orphaned' => '',
+ 'Out of balance!' => '',
+ 'PDF' => '',
+ 'Packing List' => '',
+ 'Packing List Date missing!' => '',
+ 'Packing List Number missing!' => '',
+ 'Paid' => '',
+ 'Paid in full' => '',
+ 'Part' => '',
+ 'Part Number missing!' => '',
+ 'Parts' => '',
+ 'Parts Inventory' => '',
+ 'Password' => '',
+ 'Password changed!' => '',
+ 'Payables' => '',
+ 'Payment' => '',
+ 'Payment date missing!' => '',
+ 'Payment posted!' => '',
+ 'Payments' => '',
+ 'Pg Database Administration' => '',
+ 'Phone' => '',
+ 'Port' => '',
+ 'Port missing!' => '',
+ 'Post' => '',
+ 'Post as new' => '',
+ 'Postscript' => '',
+ 'Preferences' => '',
+ 'Preferences saved!' => '',
+ 'Price' => '',
+ 'Print' => '',
+ 'Printer' => '',
+ 'Project' => '',
+ 'Project Number' => '',
+ 'Project Number missing!' => '',
+ 'Project deleted!' => '',
+ 'Project not on file!' => '',
+ 'Project saved!' => '',
+ 'Projects' => '',
+ 'Purchase Order' => '',
+ 'Purchase Orders' => '',
+ 'Qty' => '',
+ 'ROP' => '',
+ 'Rate' => '',
+ 'Recd' => '',
+ 'Receipt' => '',
+ 'Receipt printed!' => '',
+ 'Receipt printing failed!' => '',
+ 'Receipts' => '',
+ 'Receivables' => '',
+ 'Reconciliation' => '',
+ 'Record in' => '',
+ 'Reference' => '',
+ 'Reference missing!' => '',
+ 'Remaining' => '',
+ 'Report for' => '',
+ 'Reports' => '',
+ 'Required by' => '',
+ 'Retained Earnings' => '',
+ 'Sales' => '',
+ 'Sales Invoice' => '',
+ 'Sales Order' => '',
+ 'Sales Orders' => '',
+ 'Salesperson' => '',
+ 'Save' => '',
+ 'Save as new' => '',
+ 'Save to File' => '',
+ 'Screen' => '',
+ 'Select a Dataset to delete and press "Continue"' => '',
+ 'Select all' => '',
+ 'Select from one of the items below' => '',
+ 'Select from one of the names below' => '',
+ 'Select from one of the projects below' => '',
+ 'Select postscript or PDF!' => '',
+ 'Sell Price' => '',
+ 'Send by E-Mail' => '',
+ 'Sep' => '',
+ 'September' => '',
+ 'Service' => '',
+ 'Service Items' => '',
+ 'Service Number missing!' => '',
+ 'Services' => '',
+ 'Setup Templates' => '',
+ 'Ship' => '',
+ 'Ship to' => '',
+ 'Ship via' => '',
+ 'Short' => '',
+ 'Signature' => '',
+ 'Sold' => '',
+ 'Source' => '',
+ 'Standard' => '',
+ 'Statement' => '',
+ 'Statement Balance' => '',
+ 'Statement sent to' => '',
+ 'Statements sent to printer!' => '',
+ 'Stock' => '',
+ 'Stock Assembly' => '',
+ 'Stylesheet' => '',
+ 'Subject' => '',
+ 'Subtotal' => '',
+ 'System' => '',
+ 'Tax' => '',
+ 'Tax Accounts' => '',
+ 'Tax Included' => '',
+ 'Tax collected' => '',
+ 'Tax paid' => '',
+ 'Taxable' => '',
+ 'Template saved!' => '',
+ 'Templates' => '',
+ 'Terms: Net' => '',
+ 'The following Datasets are not in use and can be deleted' => '',
+ 'The following Datasets need to be updated' => '',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => '',
+ 'To' => '',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => '',
+ 'Top Level' => '',
+ 'Total' => '',
+ 'Transaction Date missing!' => '',
+ 'Transaction deleted!' => '',
+ 'Transaction posted!' => '',
+ 'Transaction reversal enforced for all dates' => '',
+ 'Transaction reversal enforced up to' => '',
+ 'Transactions' => '',
+ 'Transactions exist, cannot delete customer!' => '',
+ 'Transactions exist, cannot delete vendor!' => '',
+ 'Transactions exist; cannot delete account!' => '',
+ 'Trial Balance' => '',
+ 'Unit' => '',
+ 'Unit of measure' => '',
+ 'Update' => '',
+ 'Update Dataset' => '',
+ 'Updated' => '',
+ 'Use Templates' => '',
+ 'User' => '',
+ 'User deleted!' => '',
+ 'User saved!' => '',
+ 'Vendor' => '',
+ 'Vendor Invoice' => '',
+ 'Vendor deleted!' => '',
+ 'Vendor missing!' => '',
+ 'Vendor not on file!' => '',
+ 'Vendor saved!' => '',
+ 'Vendors' => '',
+ 'Version' => '',
+ 'Weight' => '',
+ 'Weight Unit' => '',
+ 'What type of item is this?' => '',
+ 'Year End' => '',
+ 'Yes' => '',
+ 'You are logged out!' => '',
+ 'You did not enter a name!' => '',
+ 'You must enter a host and port for local and remote connections!' => '',
+ 'as at' => '',
+ 'collected on sales' => '',
+ 'days' => '',
+ 'does not exist' => '',
+ 'ea' => '',
+ 'emailed to' => '',
+ 'for Period' => '',
+ 'hr' => '',
+ 'is already a member!' => '',
+ 'is not a member!' => '',
+ 'localhost' => '',
+ 'locked!' => '',
+ 'paid on purchases' => '',
+ 'sent to printer' => '',
+ 'successfully created!' => '',
+ 'successfully deleted!' => '',
+ 'to' => '',
+ 'website' => '',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/am b/sql-ledger/locale/en_GB/am
new file mode 100644
index 0000000..6e322ca
--- /dev/null
+++ b/sql-ledger/locale/en_GB/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Purchases',
+ 'AR' => 'Sales',
+ 'Account' => 'Account',
+ 'Account Number' => 'Account Number',
+ 'Account Number missing!' => 'Account Number missing!',
+ 'Account Type' => 'Account Type',
+ 'Account Type missing!' => 'Account Type missing!',
+ 'Account deleted!' => 'Account deleted!',
+ 'Account saved!' => 'Account saved!',
+ 'Add Account' => 'Add Account',
+ 'Add GIFI' => 'Add GIFI',
+ 'Address' => 'Address',
+ 'Asset' => 'Asset',
+ 'Audit Control' => 'Audit Control',
+ 'Backup sent to' => 'Backup sent to',
+ 'Books are open' => 'Books are open',
+ 'Business Number' => 'Business Number',
+ 'COGS' => 'COGS',
+ 'Cannot delete account!' => 'Cannot delete account!',
+ 'Cannot delete default account!' => 'Cannot delete default account!',
+ 'Cannot save account!' => 'Cannot save account!',
+ 'Cannot save preferences!' => 'Cannot save preferences!',
+ 'Character Set' => 'Character Set',
+ 'Chart of Accounts' => 'Chart of Accounts',
+ 'Close Books up to' => 'Close Books up to',
+ 'Company' => 'Company',
+ 'Continue' => 'Continue',
+ 'Copy to COA' => 'Copy to COA',
+ 'Credit' => 'Credit',
+ 'Date Format' => 'Date Format',
+ 'Debit' => 'Debit',
+ 'Delete' => 'Delete',
+ 'Delete Account' => 'Delete Account',
+ 'Description' => 'Description',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'E-mail',
+ 'Edit' => 'Edit',
+ 'Edit Account' => 'Edit Account',
+ 'Edit GIFI' => 'Edit GIFI',
+ 'Edit Preferences for' => 'Edit Preferences for',
+ 'Edit Template' => 'Edit Template',
+ 'Enforce transaction reversal for all dates' => 'Enforce transaction reversal for all dates',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies',
+ 'Equity' => 'Equity',
+ 'Expense' => 'Expense',
+ 'Expense Account' => 'Expense Account',
+ 'Expense/Asset' => 'Expense/Asset',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Foreign Exchange Gain',
+ 'Foreign Exchange Loss' => 'Foreign Exchange Loss',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI deleted!',
+ 'GIFI missing!' => 'GIFI missing!',
+ 'GIFI saved!' => 'GIFI saved!',
+ 'Heading' => 'Heading',
+ 'Include in drop-down menus' => 'Include in drop-down menus',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Include this account on debtor/creditor forms to set debtor/creditor taxable?',
+ 'Income' => 'Revenue',
+ 'Income Account' => 'Revenue Account',
+ 'Inventory' => 'Inventory',
+ 'Inventory Account' => 'Inventory Account',
+ 'Is this a summary account to record' => 'Is this a summary account to record',
+ 'Language' => 'Language',
+ 'Last Invoice Number' => 'Last Invoice Number',
+ 'Last Numbers & Default Accounts' => 'Last Numbers & Default Accounts',
+ 'Last Purchase Order Number' => 'Last Purchase Order Number',
+ 'Last Sales Order Number' => 'Last Sales Order Number',
+ 'Liability' => 'Liability',
+ 'Link' => 'Link',
+ 'Name' => 'Name',
+ 'No' => 'No',
+ 'No email address for' => 'No email address for',
+ 'Number' => 'Number',
+ 'Number Format' => 'Number Format',
+ 'Parts Inventory' => 'Parts Inventory',
+ 'Password' => 'Password',
+ 'Payables' => 'Payables',
+ 'Payment' => 'Payment',
+ 'Phone' => 'Phone',
+ 'Preferences saved!' => 'Preferences saved!',
+ 'Rate' => 'Rate',
+ 'Receivables' => 'Receivables',
+ 'Sales' => 'Sales',
+ 'Save' => 'Save',
+ 'Service Items' => 'Service Items',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Signature',
+ 'Stylesheet' => 'Stylesheet',
+ 'Tax' => 'Tax',
+ 'Tax Accounts' => 'Tax Accounts',
+ 'Template saved!' => 'Template saved!',
+ 'Transaction reversal enforced for all dates' => 'Transaction reversal enforced for all dates',
+ 'Transaction reversal enforced up to' => 'Transaction reversal enforced up to',
+ 'Transactions exist; cannot delete account!' => 'Transactions exist; cannot delete account!',
+ 'Weight Unit' => 'Weight Unit',
+ 'Year End' => 'Year End',
+ 'Yes' => 'Yes',
+ 'does not exist' => 'does not exist',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'add_account' => 'add_account',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'edit_account' => 'edit_account',
+ 'save' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/ap b/sql-ledger/locale/en_GB/ap
new file mode 100644
index 0000000..4cad878
--- /dev/null
+++ b/sql-ledger/locale/en_GB/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Purchase Transaction',
+ 'AP Transactions' => 'Purchase Transactions',
+ 'Account' => 'Account',
+ 'Add Accounts Payables Transaction' => 'Add Purchase Transaction',
+ 'Address' => 'Address',
+ 'Amount' => 'Amount',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Transaction' => 'Are you sure you want to delete Transaction',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'Cannot post transaction for a closed period!',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Closed',
+ 'Confirm!' => 'Confirm!',
+ 'Continue' => 'Continue',
+ 'Currency' => 'Currency',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Date',
+ 'Date Paid' => 'Date Paid',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Delete',
+ 'Description' => 'Description',
+ 'Due Date' => 'Due Date',
+ 'Due Date missing!' => 'Due Date missing!',
+ 'Edit Accounts Payables Transaction' => 'Edit Creditor Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Exch',
+ 'Exchangerate' => 'Exchangerate',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'From' => 'From',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Include in Report',
+ 'Invoice' => 'Invoice',
+ 'Invoice Date' => 'Invoice Date',
+ 'Invoice Date missing!' => 'Invoice Date missing!',
+ 'Invoice Number' => 'Invoice Number',
+ 'Invoice Number missing!' => 'Invoice Number missing!',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Number',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'Open' => 'Open',
+ 'Order' => 'Order',
+ 'Order Number' => 'Order Number',
+ 'Paid' => 'Paid',
+ 'Payment date missing!' => 'Payment date missing!',
+ 'Payments' => 'Payments',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Source',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Tax',
+ 'Tax Included' => 'Tax Included',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor' => 'Vendor',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Yes',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'purchase_transaction' => 'ap_transaction',
+ 'add_purchase_transaction' => 'add_accounts_payables_transaction',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit_creditor_transaction' => 'edit_accounts_payables_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/ar b/sql-ledger/locale/en_GB/ar
new file mode 100644
index 0000000..926d80a
--- /dev/null
+++ b/sql-ledger/locale/en_GB/ar
@@ -0,0 +1,134 @@
+$self{texts} = {
+ 'AR Transaction' => 'Sales Transaction',
+ 'AR Transactions' => 'Sales Transactions',
+ 'Account' => 'Account',
+ 'Add Accounts Receivables Transaction' => 'Add Sales Transaction',
+ 'Address' => 'Address',
+ 'Amount' => 'Amount',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Transaction' => 'Are you sure you want to delete Transaction',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'Cannot post transaction for a closed period!',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Closed',
+ 'Confirm!' => 'Confirm!',
+ 'Continue' => 'Continue',
+ 'Credit Limit' => 'Credit Limit',
+ 'Currency' => 'Currency',
+ 'Customer' => 'Customer',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Date',
+ 'Date Paid' => 'Date Paid',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Delete',
+ 'Description' => 'Description',
+ 'Due Date' => 'Due Date',
+ 'Due Date missing!' => 'Due Date missing!',
+ 'Edit Accounts Receivables Transaction' => 'Edit Debtor Transaction',
+ 'Exch' => 'Exch',
+ 'Exchangerate' => 'Exchangerate',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'From' => 'From',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Include in Report',
+ 'Invoice' => 'Invoice',
+ 'Invoice Date' => 'Invoice Date',
+ 'Invoice Date missing!' => 'Invoice Date missing!',
+ 'Invoice Number' => 'Invoice Number',
+ 'Invoice Number missing!' => 'Invoice Number missing!',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Number',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'Open' => 'Open',
+ 'Order' => 'Order',
+ 'Order Number' => 'Order Number',
+ 'Paid' => 'Paid',
+ 'Payment date missing!' => 'Payment date missing!',
+ 'Payments' => 'Payments',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Remaining' => 'Remaining',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Salesperson' => 'Salesperson',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Ship via' => 'Ship via',
+ 'Source' => 'Source',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Tax',
+ 'Tax Included' => 'Tax Included',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Yes',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'sales_transaction' => 'ar_transaction',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'yes' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/arap b/sql-ledger/locale/en_GB/arap
new file mode 100644
index 0000000..fe711dd
--- /dev/null
+++ b/sql-ledger/locale/en_GB/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Address',
+ 'Continue' => 'Continue',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Description' => 'Description',
+ 'Number' => 'Number',
+ 'Project not on file!' => 'Project not on file!',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'continue' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/bp b/sql-ledger/locale/en_GB/bp
new file mode 100644
index 0000000..fa9e347
--- /dev/null
+++ b/sql-ledger/locale/en_GB/bp
@@ -0,0 +1,54 @@
+$self{texts} = {
+ 'Account' => 'Account',
+ 'Are you sure you want to remove the marked entries from the queue?' => 'Are you sure you want to remove the marked entries from the queue?',
+ 'Cannot remove files!' => 'Cannot remove files!',
+ 'Checks' => 'Cheques',
+ 'Confirm!' => 'Confirm!',
+ 'Continue' => 'Continue',
+ 'Customer' => 'Debtor',
+ 'Date' => 'Date',
+ 'From' => 'From',
+ 'Invoice' => 'Invoice',
+ 'Invoice Number' => 'Invoice Number',
+ 'Marked entries printed!' => 'Marked entries printed!',
+ 'Order' => 'Order',
+ 'Order Number' => 'Order Number',
+ 'Packing Lists' => 'Packing Lists',
+ 'Print' => 'Print',
+ 'Printing ... ' => 'Printing ... ',
+ 'Purchase Orders' => 'Purchase Orders',
+ 'Quotation' => 'Quotation',
+ 'Quotation Number' => 'Quotation Number',
+ 'Quotations' => 'Quotations',
+ 'RFQs' => 'RFQs',
+ 'Receipts' => 'Receipts',
+ 'Reference' => 'Reference',
+ 'Remove' => 'Remove',
+ 'Removed spoolfiles!' => 'Removed spoolfiles!',
+ 'Removing marked entries from queue ...' => 'Removing marked entries from queue ...',
+ 'Sales Invoices' => 'Sales Invoices',
+ 'Sales Orders' => 'Sales Orders',
+ 'Select all' => 'Select all',
+ 'Spoolfile' => 'Spoolfile',
+ 'To' => 'To',
+ 'Vendor' => 'Creditor',
+ 'Yes' => 'Yes',
+ 'done' => 'done',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'list_spool' => 'list_spool',
+ 'print' => 'print',
+ 'remove' => 'remove',
+ 'search' => 'search',
+ 'select_all' => 'select_all',
+ 'yes' => 'yes',
+ 'continue' => 'continue',
+ 'print' => 'print',
+ 'remove' => 'remove',
+ 'select_all' => 'select_all',
+ 'yes' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/ca b/sql-ledger/locale/en_GB/ca
new file mode 100644
index 0000000..ed5ddc2
--- /dev/null
+++ b/sql-ledger/locale/en_GB/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Account',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'Chart of Accounts',
+ 'Credit' => 'Credit',
+ 'Date' => 'Date',
+ 'Debit' => 'Debit',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Description' => 'Description',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'From' => 'From',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Include in Report',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'List Transactions' => 'List Transactions',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'Reference' => 'Reference',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Subtotal' => 'Subtotal',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'list_transactions' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/cp b/sql-ledger/locale/en_GB/cp
new file mode 100644
index 0000000..fd0ade6
--- /dev/null
+++ b/sql-ledger/locale/en_GB/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'Account',
+ 'Address' => 'Address',
+ 'Amount' => 'Amount',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Amount missing!',
+ 'Applied' => 'Applied',
+ 'Cannot post payment!' => 'Cannot post payment!',
+ 'Cannot process payment for a closed period!' => 'Cannot process payment for a closed period!',
+ 'Check' => 'Cheque',
+ 'Check printed!' => 'Check printed!',
+ 'Check printing failed!' => 'Check printing failed!',
+ 'Continue' => 'Continue',
+ 'Currency' => 'Currency',
+ 'Customer' => 'Customer',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Date',
+ 'Date missing!' => 'Date missing!',
+ 'Description' => 'Description',
+ 'Due' => 'Due',
+ 'Exchangerate' => 'Exchangerate',
+ 'From' => 'From',
+ 'Invoice' => 'Invoice',
+ 'Invoices' => 'Invoices',
+ 'Nothing applied!' => 'Nothing applied!',
+ 'Number' => 'Number',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'Payment',
+ 'Payment posted!' => 'Payment posted!',
+ 'Post' => 'Post',
+ 'Print' => 'Print',
+ 'Printer' => 'Printer',
+ 'Project not on file!' => 'Project not on file!',
+ 'Receipt' => 'Receipt',
+ 'Receipt printed!' => 'Receipt printed!',
+ 'Receipt printing failed!' => 'Receipt printing failed!',
+ 'Reference' => 'Reference',
+ 'Screen' => 'Screen',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Update' => 'Update',
+ 'Vendor' => 'Vendor',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'continue' => 'continue',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/ct b/sql-ledger/locale/en_GB/ct
new file mode 100644
index 0000000..3daa8f4
--- /dev/null
+++ b/sql-ledger/locale/en_GB/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Add',
+ 'Address' => 'Address',
+ 'All' => 'All',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Cannot delete customer!',
+ 'Cannot delete vendor!' => 'Cannot delete vendor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continue',
+ 'Credit Limit' => 'Credit Limit',
+ 'Customer deleted!' => 'Customer deleted!',
+ 'Customer saved!' => 'Customer saved!',
+ 'Customers' => 'Customers',
+ 'Delete' => 'Delete',
+ 'Discount' => 'Discount',
+ 'E-mail' => 'E-mail',
+ 'Edit Customer' => 'Edit Customer',
+ 'Edit Vendor' => 'Edit Vendor',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Include in Report',
+ 'Invoice' => 'Invoice',
+ 'Name' => 'Name',
+ 'Name missing!' => 'Name missing!',
+ 'Notes' => 'Notes',
+ 'Number' => 'Number',
+ 'Order' => 'Order',
+ 'Orphaned' => 'Orphaned',
+ 'Phone' => 'Phone',
+ 'Save' => 'Save',
+ 'Ship to' => 'Ship to',
+ 'Tax Included' => 'Tax Included',
+ 'Taxable' => 'Taxable',
+ 'Terms: Net' => 'Terms: Net',
+ 'Transactions exist, cannot delete customer!' => 'Transactions exist, cannot delete customer!',
+ 'Transactions exist, cannot delete vendor!' => 'Transactions exist, cannot delete vendor!',
+ 'Vendor deleted!' => 'Vendor deleted!',
+ 'Vendor saved!' => 'Vendor saved!',
+ 'Vendors' => 'Vendors',
+ 'days' => 'days',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'invoice' => 'invoice',
+ 'order' => 'order',
+ 'save' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/gl b/sql-ledger/locale/en_GB/gl
new file mode 100644
index 0000000..dae8e86
--- /dev/null
+++ b/sql-ledger/locale/en_GB/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Purchase Transaction',
+ 'AR Transaction' => 'Sales Transaction',
+ 'Account' => 'Account',
+ 'Add General Ledger Transaction' => 'Add General Ledger Transaction',
+ 'Address' => 'Address',
+ 'All' => 'All',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Transaction' => 'Are you sure you want to delete Transaction',
+ 'Asset' => 'Asset',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot have a value in both Debit and Credit!' => 'Cannot have a value in both Debit and Credit!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'Cannot post transaction for a closed period!',
+ 'Confirm!' => 'Confirm!',
+ 'Continue' => 'Continue',
+ 'Credit' => 'Credit',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Date',
+ 'Debit' => 'Debit',
+ 'Debit and credit out of balance!' => 'Debit and credit out of balance!',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Delete',
+ 'Description' => 'Description',
+ 'Edit General Ledger Transaction' => 'Edit General Ledger Transaction',
+ 'Equity' => 'Equity',
+ 'Expense' => 'Expense',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'From' => 'From',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'GL Transaction',
+ 'General Ledger' => 'General Ledger',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Include in Report',
+ 'Income' => 'Revenue',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'Liability' => 'Liability',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Number',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference missing!',
+ 'Reports' => 'Reports',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Source',
+ 'Subtotal' => 'Subtotal',
+ 'Transaction Date missing!' => 'Transaction Date missing!',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Yes',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'purchase_transaction' => 'ap_transaction',
+ 'sales_transaction' => 'ar_transaction',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'gl_transaction' => 'gl_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/ic b/sql-ledger/locale/en_GB/ic
new file mode 100644
index 0000000..2e61619
--- /dev/null
+++ b/sql-ledger/locale/en_GB/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Active',
+ 'Add' => 'Add',
+ 'Add Assembly' => 'Add Assembly',
+ 'Add Part' => 'Add Part',
+ 'Add Purchase Order' => 'Add Purchase Order',
+ 'Add Sales Order' => 'Add Sales Order',
+ 'Add Service' => 'Add Service',
+ 'Address' => 'Address',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Assemblies' => 'Assemblies',
+ 'Assemblies restocked!' => 'Assemblies restocked!',
+ 'Assembly Number missing!' => 'Assembly Number missing!',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Bought' => 'Bought',
+ 'COGS' => 'COGS',
+ 'Cannot delete item!' => 'Cannot delete item!',
+ 'Cannot stock assemblies!' => 'Cannot stock assemblies!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Closed',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continue',
+ 'Copies' => 'Copies',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Delete',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Description',
+ 'Drawing' => 'Drawing',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail address missing!',
+ 'Edit Assembly' => 'Edit Assembly',
+ 'Edit Part' => 'Edit Part',
+ 'Edit Service' => 'Edit Service',
+ 'Expense' => 'Expense',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'From' => 'From',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'Image' => 'Image',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Include in Report',
+ 'Income' => 'Revenue',
+ 'Individual Items' => 'Individual Items',
+ 'Inventory' => 'Inventory',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Inventory quantity must be zero before you can set this assembly obsolete!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Inventory quantity must be zero before you can set this part obsolete!',
+ 'Invoice' => 'Invoice',
+ 'Invoice Date missing!' => 'Invoice Date missing!',
+ 'Invoice Number' => 'Invoice Number',
+ 'Invoice Number missing!' => 'Invoice Number missing!',
+ 'Item deleted!' => 'Item deleted!',
+ 'Item not on file!' => 'Item not on file!',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'Last Cost' => 'Last Cost',
+ 'Line Total' => 'Line Total',
+ 'Link Accounts' => 'Link Accounts',
+ 'List Price' => 'List Price',
+ 'Make' => 'Make',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Message' => 'Message',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Model',
+ 'Name' => 'Name',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Number',
+ 'Number missing in Row' => 'Number missing in Row',
+ 'Obsolete' => 'Obsolete',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'On Hand' => 'On Hand',
+ 'On Order' => 'On Order',
+ 'Order' => 'Order',
+ 'Order Date missing!' => 'Order Date missing!',
+ 'Order Number' => 'Order Number',
+ 'Order Number missing!' => 'Order Number missing!',
+ 'Ordered' => 'Ordered',
+ 'Orphaned' => 'Orphaned',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packing List',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Part',
+ 'Part Number missing!' => 'Part Number missing!',
+ 'Parts' => 'Parts',
+ 'Phone' => 'Phone',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Price',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Purchase Order',
+ 'Qty' => 'Qty',
+ 'ROP' => 'ROP',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Required by',
+ 'Sales' => 'Sales',
+ 'Sales Order' => 'Sales Order',
+ 'Save' => 'Save',
+ 'Save as new' => 'Save as new',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Select from one of the items below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sell Price' => 'Sell Price',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Service',
+ 'Service Number missing!' => 'Service Number missing!',
+ 'Services' => 'Services',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Short' => 'Short',
+ 'Sold' => 'Sold',
+ 'Stock' => 'Stock',
+ 'Stock Assembly' => 'Stock Assembly',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Tax',
+ 'To' => 'To',
+ 'Top Level' => 'Top Level',
+ 'Total' => 'Total',
+ 'Unit' => 'Unit',
+ 'Unit of measure' => 'Unit of measure',
+ 'Update' => 'Update',
+ 'Updated' => 'Updated',
+ 'Weight' => 'Weight',
+ 'What type of item is this?' => 'What type of item is this?',
+ 'ea' => 'ea',
+ 'emailed to' => 'emailed to',
+ 'hr' => 'hr',
+ 'sent to printer' => 'sent to printer',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'add' => 'add',
+ 'add_assembly' => 'add_assembly',
+ 'add_part' => 'add_part',
+ 'add_service' => 'add_service',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit_assembly' => 'edit_assembly',
+ 'edit_part' => 'edit_part',
+ 'edit_service' => 'edit_service',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/io b/sql-ledger/locale/en_GB/io
new file mode 100644
index 0000000..1deb6dc
--- /dev/null
+++ b/sql-ledger/locale/en_GB/io
@@ -0,0 +1,108 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Add Purchase Order',
+ 'Add Sales Order' => 'Add Sales Order',
+ 'Address' => 'Address',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continue',
+ 'Copies' => 'Copies',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Description',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail address missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Invoice',
+ 'Invoice Date missing!' => 'Invoice Date missing!',
+ 'Invoice Number missing!' => 'Invoice Number missing!',
+ 'Item not on file!' => 'Item not on file!',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Message' => 'Message',
+ 'Name' => 'Name',
+ 'No.' => 'No.',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Number',
+ 'Number missing in Row' => 'Number missing in Row',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'Order' => 'Order',
+ 'Order Date missing!' => 'Order Date missing!',
+ 'Order Number missing!' => 'Order Number missing!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packing List',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Part',
+ 'Phone' => 'Phone',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Price',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Purchase Order',
+ 'Qty' => 'Qty',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Required by',
+ 'Sales Order' => 'Sales Order',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Select from one of the items below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Service',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Subject' => 'Subject',
+ 'To' => 'To',
+ 'Unit' => 'Unit',
+ 'What type of item is this?' => 'What type of item is this?',
+ 'emailed to' => 'emailed to',
+ 'sent to printer' => 'sent to printer',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continue' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/ir b/sql-ledger/locale/en_GB/ir
new file mode 100644
index 0000000..a87c72a
--- /dev/null
+++ b/sql-ledger/locale/en_GB/ir
@@ -0,0 +1,180 @@
+$self{texts} = {
+ 'Account' => 'Account',
+ 'Add Purchase Order' => 'Add Purchase Order',
+ 'Add Sales Order' => 'Add Sales Order',
+ 'Add Vendor Invoice' => 'Add Vendor Invoice',
+ 'Address' => 'Address',
+ 'Amount' => 'Amount',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Invoice Number' => 'Are you sure you want to delete Invoice Number',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirm!',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continue',
+ 'Copies' => 'Copies',
+ 'Currency' => 'Currency',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Date',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Delete',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Description',
+ 'Due Date' => 'Due Date',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail address missing!',
+ 'Edit Vendor Invoice' => 'Edit Vendor Invoice',
+ 'Exch' => 'Exch',
+ 'Exchangerate' => 'Exchangerate',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Invoice',
+ 'Invoice Date' => 'Invoice Date',
+ 'Invoice Date missing!' => 'Invoice Date missing!',
+ 'Invoice Number' => 'Invoice Number',
+ 'Invoice Number missing!' => 'Invoice Number missing!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'Item not on file!',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Message' => 'Message',
+ 'Name' => 'Name',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Number',
+ 'Number missing in Row' => 'Number missing in Row',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'Order' => 'Order',
+ 'Order Date missing!' => 'Order Date missing!',
+ 'Order Number' => 'Order Number',
+ 'Order Number missing!' => 'Order Number missing!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packing List',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Part',
+ 'Payment date missing!' => 'Payment date missing!',
+ 'Payments' => 'Payments',
+ 'Phone' => 'Phone',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Price',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Purchase Order',
+ 'Qty' => 'Qty',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Record in',
+ 'Required by' => 'Required by',
+ 'Sales Order' => 'Sales Order',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Select from one of the items below',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Service',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Source' => 'Source',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Tax Included',
+ 'To' => 'To',
+ 'Total' => 'Total',
+ 'Unit' => 'Unit',
+ 'Update' => 'Update',
+ 'Vendor' => 'Vendor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'What type of item is this?',
+ 'Yes' => 'Yes',
+ 'ea' => 'ea',
+ 'emailed to' => 'emailed to',
+ 'sent to printer' => 'sent to printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'update' => 'update',
+ 'yes' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/is b/sql-ledger/locale/en_GB/is
new file mode 100644
index 0000000..bbfa3f0
--- /dev/null
+++ b/sql-ledger/locale/en_GB/is
@@ -0,0 +1,187 @@
+$self{texts} = {
+ 'Account' => 'Account',
+ 'Add Purchase Order' => 'Add Purchase Order',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Add Sales Order',
+ 'Address' => 'Address',
+ 'Amount' => 'Amount',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Invoice Number' => 'Are you sure you want to delete Invoice Number',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirm!',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continue',
+ 'Copies' => 'Copies',
+ 'Credit Limit' => 'Credit Limit',
+ 'Currency' => 'Currency',
+ 'Customer' => 'Customer',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Date',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Delete',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Description',
+ 'Due Date' => 'Due Date',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail address missing!',
+ 'Edit Sales Invoice' => 'Edit Sales Invoice',
+ 'Exch' => 'Exch',
+ 'Exchangerate' => 'Exchangerate',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Invoice',
+ 'Invoice Date' => 'Invoice Date',
+ 'Invoice Date missing!' => 'Invoice Date missing!',
+ 'Invoice Number' => 'Invoice Number',
+ 'Invoice Number missing!' => 'Invoice Number missing!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'Item not on file!',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Message' => 'Message',
+ 'Name' => 'Name',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Number',
+ 'Number missing in Row' => 'Number missing in Row',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'Order' => 'Order',
+ 'Order Date missing!' => 'Order Date missing!',
+ 'Order Number' => 'Order Number',
+ 'Order Number missing!' => 'Order Number missing!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packing List',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Part',
+ 'Payment date missing!' => 'Payment date missing!',
+ 'Payments' => 'Payments',
+ 'Phone' => 'Phone',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Price',
+ 'Print' => 'Print',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Purchase Order',
+ 'Qty' => 'Qty',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Record in',
+ 'Remaining' => 'Remaining',
+ 'Required by' => 'Required by',
+ 'Sales Order' => 'Sales Order',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Select from one of the items below',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Service',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Source' => 'Source',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Tax Included',
+ 'To' => 'To',
+ 'Total' => 'Total',
+ 'Unit' => 'Unit',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'What type of item is this?',
+ 'Yes' => 'Yes',
+ 'ea' => 'ea',
+ 'emailed to' => 'emailed to',
+ 'sent to printer' => 'sent to printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'yes' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/login b/sql-ledger/locale/en_GB/login
new file mode 100644
index 0000000..262a18c
--- /dev/null
+++ b/sql-ledger/locale/en_GB/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'About',
+ 'Database Host' => 'Database Host',
+ 'Dataset' => 'Dataset',
+ 'Incorrect Dataset version!' => 'Incorrect Dataset version!',
+ 'Incorrect Password!' => 'Incorrect Password!',
+ 'Licensed to' => 'Licensed to',
+ 'Login' => 'Login',
+ 'Name' => 'Name',
+ 'Password' => 'Password',
+ 'User' => 'User',
+ 'Version' => 'Version',
+ 'You are logged out!' => 'You are logged out!',
+ 'You did not enter a name!' => 'You did not enter a name!',
+ 'is not a member!' => 'is not a member!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/menu b/sql-ledger/locale/en_GB/menu
new file mode 100644
index 0000000..4e47815
--- /dev/null
+++ b/sql-ledger/locale/en_GB/menu
@@ -0,0 +1,73 @@
+$self{texts} = {
+ 'AP' => 'Purchases',
+ 'AP Aging' => 'Creditor Aging',
+ 'AR' => 'Sales',
+ 'AR Aging' => 'Debtor Aging',
+ 'Accounting Menu' => 'Accounting Menu',
+ 'Add Account' => 'Add Account',
+ 'Add Assembly' => 'Add Assembly',
+ 'Add Customer' => 'Add Customer',
+ 'Add GIFI' => 'Add GIFI',
+ 'Add Group' => 'Add Group',
+ 'Add Part' => 'Add Part',
+ 'Add Project' => 'Add Project',
+ 'Add Service' => 'Add Service',
+ 'Add Transaction' => 'Add Transaction',
+ 'Add Vendor' => 'Add Vendor',
+ 'Assemblies' => 'Assemblies',
+ 'Audit Control' => 'Audit Control',
+ 'Backup' => 'Backup',
+ 'Balance Sheet' => 'Balance Sheet',
+ 'Cash' => 'Cash',
+ 'Chart of Accounts' => 'Chart of Accounts',
+ 'Check' => 'Cheque',
+ 'Customers' => 'Customers',
+ 'General Ledger' => 'General Ledger',
+ 'Goods & Services' => 'Goods & Services',
+ 'Groups' => 'Groups',
+ 'HTML Templates' => 'HTML Templates',
+ 'Income Statement' => 'Income Statement',
+ 'Invoice' => 'Invoice',
+ 'LaTeX Templates' => 'LaTeX Templates',
+ 'List Accounts' => 'List Accounts',
+ 'List GIFI' => 'List GIFI',
+ 'Logout' => 'Logout',
+ 'Order Entry' => 'Order Entry',
+ 'Packing List' => 'Packing List',
+ 'Parts' => 'Parts',
+ 'Payment' => 'Payment',
+ 'Payments' => 'Payments',
+ 'Preferences' => 'Preferences',
+ 'Projects' => 'Projects',
+ 'Purchase Order' => 'Purchase Order',
+ 'Purchase Orders' => 'Purchase Orders',
+ 'Receipt' => 'Receipt',
+ 'Receipts' => 'Receipts',
+ 'Reconciliation' => 'Reconciliation',
+ 'Reports' => 'Reports',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Sales Order' => 'Sales Order',
+ 'Sales Orders' => 'Sales Orders',
+ 'Save to File' => 'Save to File',
+ 'Send by E-Mail' => 'Send by E-Mail',
+ 'Services' => 'Services',
+ 'Statement' => 'Statement',
+ 'Stock Assembly' => 'Stock Assembly',
+ 'Stylesheet' => 'Stylesheet',
+ 'System' => 'System',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'Transactions' => 'Transactions',
+ 'Trial Balance' => 'Trial Balance',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendors' => 'Vendors',
+ 'Version' => 'Version',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/oe b/sql-ledger/locale/en_GB/oe
new file mode 100644
index 0000000..2dfbb47
--- /dev/null
+++ b/sql-ledger/locale/en_GB/oe
@@ -0,0 +1,202 @@
+$self{texts} = {
+ 'Add' => 'Add',
+ 'Add Purchase Order' => 'Add Purchase Order',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Add Sales Order',
+ 'Add Vendor Invoice' => 'Add Vendor Invoice',
+ 'Address' => 'Address',
+ 'Amount' => 'Amount',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Order Number' => 'Are you sure you want to delete Order Number',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Cannot delete order!',
+ 'Cannot save order!' => 'Cannot save order!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Closed',
+ 'Confirm!' => 'Confirm!',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continue',
+ 'Copies' => 'Copies',
+ 'Credit Limit' => 'Credit Limit',
+ 'Curr' => 'Curr',
+ 'Currency' => 'Currency',
+ 'Customer' => 'Customer',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Date',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Delete',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Description',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail address missing!',
+ 'Edit Purchase Order' => 'Edit Purchase Order',
+ 'Edit Sales Order' => 'Edit Sales Order',
+ 'Exchangerate' => 'Exchangerate',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'From' => 'From',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'ID' => 'ID',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Include in Report',
+ 'Invoice' => 'Invoice',
+ 'Invoice Date missing!' => 'Invoice Date missing!',
+ 'Invoice Number missing!' => 'Invoice Number missing!',
+ 'Item not on file!' => 'Item not on file!',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Message' => 'Message',
+ 'Name' => 'Name',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Number',
+ 'Number missing in Row' => 'Number missing in Row',
+ 'O' => 'O',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'Open' => 'Open',
+ 'Order' => 'Order',
+ 'Order Date' => 'Order Date',
+ 'Order Date missing!' => 'Order Date missing!',
+ 'Order Number' => 'Order Number',
+ 'Order Number missing!' => 'Order Number missing!',
+ 'Order deleted!' => 'Order deleted!',
+ 'Order saved!' => 'Order saved!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packing List',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Part',
+ 'Phone' => 'Phone',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Price',
+ 'Print' => 'Print',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Purchase Order',
+ 'Purchase Orders' => 'Purchase Orders',
+ 'Qty' => 'Qty',
+ 'Recd' => 'Recd',
+ 'Remaining' => 'Remaining',
+ 'Required by' => 'Required by',
+ 'Sales Order' => 'Sales Order',
+ 'Sales Orders' => 'Sales Orders',
+ 'Save' => 'Save',
+ 'Save as new' => 'Save as new',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Select from one of the items below',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Service',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Tax',
+ 'Tax Included' => 'Tax Included',
+ 'Terms: Net' => 'Terms: Net',
+ 'To' => 'To',
+ 'Total' => 'Total',
+ 'Unit' => 'Unit',
+ 'Update' => 'Update',
+ 'Vendor' => 'Vendor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'What type of item is this?',
+ 'Yes' => 'Yes',
+ 'days' => 'days',
+ 'ea' => 'ea',
+ 'emailed to' => 'emailed to',
+ 'sent to printer' => 'sent to printer',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'invoice' => 'invoice',
+ 'print' => 'print',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'yes' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/pe b/sql-ledger/locale/en_GB/pe
new file mode 100644
index 0000000..58cd57a
--- /dev/null
+++ b/sql-ledger/locale/en_GB/pe
@@ -0,0 +1,45 @@
+$self{texts} = {
+ 'Add' => 'Add',
+ 'Add Group' => 'Add Group',
+ 'Add Project' => 'Add Project',
+ 'All' => 'All',
+ 'Continue' => 'Continue',
+ 'Delete' => 'Delete',
+ 'Description' => 'Description',
+ 'Edit Group' => 'Edit Group',
+ 'Edit Project' => 'Edit Project',
+ 'Group' => 'Group',
+ 'Group deleted!' => 'Group deleted!',
+ 'Group missing!' => 'Group missing!',
+ 'Group saved!' => 'Group saved!',
+ 'Groups' => 'Groups',
+ 'Number' => 'Number',
+ 'Orphaned' => 'Orphaned',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Project Number missing!',
+ 'Project deleted!' => 'Project deleted!',
+ 'Project saved!' => 'Project saved!',
+ 'Projects' => 'Projects',
+ 'Save' => 'Save',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_partsgroup_footer' => 'form_partsgroup_footer',
+ 'form_partsgroup_header' => 'form_partsgroup_header',
+ 'form_project_footer' => 'form_project_footer',
+ 'form_project_header' => 'form_project_header',
+ 'partsgroup_report' => 'partsgroup_report',
+ 'project_report' => 'project_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'save' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/rc b/sql-ledger/locale/en_GB/rc
new file mode 100644
index 0000000..952c378
--- /dev/null
+++ b/sql-ledger/locale/en_GB/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Account',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'Continue',
+ 'Date' => 'Date',
+ 'Deposit' => 'Deposit',
+ 'Description' => 'Description',
+ 'Difference' => 'Difference',
+ 'Done' => 'Done',
+ 'Exchangerate Difference' => 'Exchangerate Difference',
+ 'From' => 'From',
+ 'Out of balance!' => 'Out of balance!',
+ 'Payment' => 'Payment',
+ 'Reconciliation' => 'Reconciliation',
+ 'Select all' => 'Select all',
+ 'Source' => 'Source',
+ 'Statement Balance' => 'Statement Balance',
+ 'Update' => 'Update',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continue' => 'continue',
+ 'done' => 'done',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/en_GB/rp b/sql-ledger/locale/en_GB/rp
new file mode 100644
index 0000000..a66828e
--- /dev/null
+++ b/sql-ledger/locale/en_GB/rp
@@ -0,0 +1,119 @@
+$self{texts} = {
+ 'AP Aging' => 'Creditor Aging',
+ 'AR Aging' => 'Debtor Aging',
+ 'Account' => 'Account',
+ 'Accounts' => 'Accounts',
+ 'Amount' => 'Amount',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aug',
+ 'August' => 'August',
+ 'Balance' => 'Balance',
+ 'Balance Sheet' => 'Balance Sheet',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Compare to',
+ 'Continue' => 'Continue',
+ 'Copies' => 'Copies',
+ 'Credit' => 'Credit',
+ 'Current' => 'Current',
+ 'Customer' => 'Customer',
+ 'Date' => 'Date',
+ 'Debit' => 'Debit',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Decimalplaces' => 'Decimalplaces',
+ 'Description' => 'Description',
+ 'Due' => 'Due',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'E-mail Statement to',
+ 'Feb' => 'Feb',
+ 'February' => 'February',
+ 'From' => 'From',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Heading',
+ 'ID' => 'ID',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Include in Report',
+ 'Income Statement' => 'Income Statement',
+ 'Invoice' => 'Invoice',
+ 'Jan' => 'Jan',
+ 'January' => 'January',
+ 'Jul' => 'Jul',
+ 'July' => 'July',
+ 'Jun' => 'Jun',
+ 'June' => 'June',
+ 'Mar' => 'Mar',
+ 'March' => 'March',
+ 'May' => 'May',
+ 'May ' => 'May ',
+ 'Message' => 'Message',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Nothing selected!',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Oct',
+ 'October' => 'October',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Payments',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Print',
+ 'Printer' => 'Printer',
+ 'Project Number' => 'Project Number',
+ 'Receipts' => 'Receipts',
+ 'Report for' => 'Report for',
+ 'Retained Earnings' => 'Retained Earnings',
+ 'Screen' => 'Screen',
+ 'Select all' => 'Select all',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Source',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Statement',
+ 'Statement sent to' => 'Statement sent to',
+ 'Statements sent to printer!' => 'Statements sent to printer!',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Tax',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Trial Balance',
+ 'Vendor' => 'Vendor',
+ 'as at' => 'as at',
+ 'collected on sales' => 'collected on sales',
+ 'for Period' => 'for Period',
+ 'paid on purchases' => 'paid on purchases',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'print' => 'print',
+ 'select_all' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/es/COPYING b/sql-ledger/locale/es/COPYING
new file mode 100644
index 0000000..bf7ca4b
--- /dev/null
+++ b/sql-ledger/locale/es/COPYING
@@ -0,0 +1,26 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2002
+#
+# Spanish texts:
+#
+# Author: Maria Gabriela Fong <mgfong@maga.tzo.org>
+# John Stoddart <jstypo@imagencolor.com.ve>
+# Federico Montesino Pouzols <fedemp@arrok.com>
+# Tomás Pereira <topec@percar.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/es/LANGUAGE b/sql-ledger/locale/es/LANGUAGE
new file mode 100644
index 0000000..c1a0de2
--- /dev/null
+++ b/sql-ledger/locale/es/LANGUAGE
@@ -0,0 +1 @@
+Spanish
diff --git a/sql-ledger/locale/es/Num2text b/sql-ledger/locale/es/Num2text
new file mode 100644
index 0000000..a5424ff
--- /dev/null
+++ b/sql-ledger/locale/es/Num2text
@@ -0,0 +1,195 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+
+
+sub init {
+ my $self = shift;
+
+ %{ $self->{numbername} } =
+ (0 => 'cero',
+ 1 => 'un',
+ '1o' => 'uno',
+ 2 => 'dos',
+ 3 => 'tres',
+ 4 => 'cuatro',
+ 5 => 'cinco',
+ 6 => 'seis',
+ 7 => 'siete',
+ 8 => 'ocho',
+ 9 => 'nueve',
+ 10 => 'diez',
+ 11 => 'once',
+ 12 => 'doce',
+ 13 => 'trece',
+ 14 => 'catorce',
+ 15 => 'quince',
+ 16 => 'dieciséis',
+ 17 => 'diecisiete',
+ 18 => 'dieciocho',
+ 19 => 'diecinueve',
+ 20 => 'veinte',
+ 21 => 'veintiún',
+ '21o' => 'veintiuno',
+ 22 => 'veintidós',
+ 23 => 'veintitrés',
+ 24 => 'veinticuatro',
+ 25 => 'veinticinco',
+ 26 => 'veintiséis',
+ 27 => 'veintisiete',
+ 28 => 'veintiocho',
+ 29 => 'veintinueve',
+ 30 => 'treinta',
+ 40 => 'cuarenta',
+ 50 => 'cincuenta',
+ 60 => 'sesenta',
+ 70 => 'setenta',
+ 80 => 'ochenta',
+ 90 => 'noventa',
+ 10**2 => 'ciento',
+ 10**3 => 'mil',
+ 10**6 => 'millón',
+ 10**9 => 'millardo',
+ 10**12 => 'billón',
+ );
+
+}
+
+
+sub num2text {
+ my ($self, $amount) = @_;
+
+ return $self->{numbername}{0} unless $amount;
+
+ my @textnumber = ();
+
+ # split amount into chunks of 3
+ my @num = reverse split //, $amount;
+ my @numblock = ();
+ my $stripun = 0;
+ my @a = ();
+ my $i;
+
+ while (@num) {
+ @a = ();
+ for (1 .. 3) {
+ push @a, shift @num;
+ }
+ push @numblock, join / /, reverse @a;
+ }
+
+ # special case for 1000
+ if ($numblock[1] eq '1' && $numblock[0] gt '000') {
+ # remove first array element from textnumber
+ $stripun = 1;
+ }
+
+ while (@numblock) {
+
+ $i = $#numblock;
+ @num = split //, $numblock[$i];
+
+ $numblock[$i] *= 1;
+
+ if ($numblock[$i] == 0) {
+ pop @numblock;
+ next;
+ }
+
+ if ($numblock[$i] > 99) {
+ if ($num[0] == 1) {
+ push @textnumber, $self->{numbername}{10**2};
+ } else {
+ # the one from hundreds, append cientos
+ push @textnumber, $self->{numbername}{$num[0]}.$self->{numbername}{10**2}.'s';
+ }
+
+ # reduce numblock
+ $numblock[$i] -= $num[0] * 100;
+ }
+
+ if ($numblock[$i] > 9) {
+ # tens
+ push @textnumber, $self->format_ten($numblock[$i], $i);
+ } elsif ($numblock[$i] > 0) {
+ # ones
+ $num = $numblock[$i];
+ $num .= 'o' if ($num == 1 && $i == 0);
+ push @textnumber, $self->{numbername}{$num};
+ }
+
+ # add thousand, million
+ if ($i) {
+ $num = 10**($i * 3);
+ if ($numblock[$i] > 1) {
+ if ($i == 2 || $i == 4) {
+ $a = $self->{numbername}{$num}."es";
+ $a =~ s/ó/o/;
+ push @textnumber, $a;
+ } else {
+ if ($i == 1) {
+ push @textnumber, $self->{numbername}{$num};
+ } else {
+ push @textnumber, $self->{numbername}{$num}.'s';
+ }
+ }
+ } else {
+ push @textnumber, $self->{numbername}{$num};
+ }
+ }
+
+ pop @numblock;
+
+ }
+
+ shift @textnumber if $stripun;
+
+ join ' ', @textnumber;
+
+}
+
+
+sub format_ten {
+ my ($self, $amount, $i) = @_;
+
+ my $textnumber = "";
+ my @num = split //, $amount;
+
+ if ($amount > 30) {
+ $textnumber = $self->{numbername}{$num[0]*10};
+ $amount = $num[1];
+ } else {
+ $amount .= 'o' if ($num[1] == 1 && $i == 0);
+ $textnumber = $self->{numbername}{$amount};
+ $amount = 0;
+ }
+
+ $textnumber .= " y ".$self->{numbername}{$amount} if $amount;
+
+ $textnumber;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/locale/es/admin b/sql-ledger/locale/es/admin
new file mode 100644
index 0000000..a78f755
--- /dev/null
+++ b/sql-ledger/locale/es/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Control de Acceso',
+ 'Accounting' => 'Contabilidad',
+ 'Add User' => 'Añadir usuario',
+ 'Address' => 'Dirección',
+ 'Administration' => 'Administración',
+ 'Administrator' => 'Administrador',
+ 'All Datasets up to date!' => 'Todas las bases de datos están actualizadas',
+ 'Change Admin Password' => 'Cambiar la contraseña del administrador',
+ 'Change Password' => 'Cambiar contraseña',
+ 'Character Set' => 'Conjunto de caracteres',
+ 'Click on login name to edit!' => 'Haga clic en el nombre de usuario por
+editar',
+ 'Company' => 'Compañía',
+ 'Connect to' => 'Conectar a',
+ 'Continue' => 'Continuar',
+ 'Create Chart of Accounts' => 'Crear catálogo de cuentas',
+ 'Create Dataset' => 'Crear base de datos',
+ 'DBI not installed!' => 'No se ha instalado DBI',
+ 'Database' => 'Base de datos',
+ 'Database Administration' => 'Administración de las bases de datos',
+ 'Database Driver not checked!' => 'No se ha podido verificar el gestor de la base de datos',
+ 'Database User missing!' => 'No se ha definido el usuario de la base de datos',
+ 'Dataset' => 'Base de datos',
+ 'Dataset missing!' => 'No se ha definido la base de datos',
+ 'Dataset updated!' => 'Base de datos actualizada',
+ 'Date Format' => 'Formato de fecha',
+ 'Delete' => 'Borrar',
+ 'Delete Dataset' => 'Borrar base de datos',
+ 'Directory' => 'Directorio',
+ 'Driver' => 'Gestor',
+ 'Dropdown Limit' => 'Límite de efectivo',
+ 'E-mail' => 'Correo electrónico',
+ 'Edit User' => 'Editar usuario',
+ 'Existing Datasets' => 'Bases de datos existentes',
+ 'Fax' => 'Fax',
+ 'File locked!' => 'File locked!',
+ 'Host' => 'Máquina servidor de base de datos',
+ 'Hostname missing!' => 'No se ha definido la máquina servidor de base de datos',
+ 'Incorrect Password!' => 'Contraseña incorrecta',
+ 'Language' => 'Lenguaje',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deje los campos de máquina servidor de base de datos y puerto vacíos al menos que quiera hacer una conexión remota',
+ 'Login' => 'Entrar',
+ 'Name' => 'Nombre',
+ 'New Templates' => 'Nuevas plantillas',
+ 'No Database Drivers available!' => 'No hay ningún gestor de base de datos disponible',
+ 'No Dataset selected!' => 'No se ha seleccionado ninguna base de datos',
+ 'Nothing to delete!' => '¡No hay nada para borrar!',
+ 'Number Format' => 'Formato de número',
+ 'Oracle Database Administration' => 'Administración de la base de datos Oracle',
+ 'Password' => 'Contraseña',
+ 'Password changed!' => '¡Contraseña cambiada!',
+ 'Pg Database Administration' => 'Administración de la base de datos PostgreSQL',
+ 'Phone' => 'Teléfono',
+ 'Port' => 'Puerto',
+ 'Port missing!' => 'No se ha definido el puerto',
+ 'Printer' => 'Impresora',
+ 'Save' => 'Guardar',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione una base de datos para borrar y presione "Continuar"',
+ 'Setup Templates' => 'Configurar plantillas',
+ 'Ship via' => 'Envio por',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Hoja de estilo',
+ 'Templates' => 'Plantillas',
+ 'The following Datasets are not in use and can be deleted' => 'Las siguientes bases de datos no están en uso y se pueden borrar',
+ 'The following Datasets need to be updated' => 'Es necesario actualizar las siguientes bases de datos',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta es una verificacion preliminar de fuentes existentes. No se creará ni borrará nada durante esta etapa',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para añadir un usuario a un grupo, edite un nombre, cambie el nombre de usuario (login) y guarde los cambios. Un nuevo usuario, con las mismas propiedades se guardará bajo el nuevo nombre de usuario (login).',
+ 'Update Dataset' => 'Actualizar base de datos',
+ 'Use Templates' => 'Plantillas de usuarios',
+ 'User' => 'Usuario',
+ 'User deleted!' => '¡Usuario borrado!',
+ 'User saved!' => '¡Usuario guardado!',
+ 'Version' => 'Versión',
+ 'You must enter a host and port for local and remote connections!' => 'Debe introducir una máquina servidor de bases de datos y un puerto para conexiones locales y remotas',
+ 'does not exist' => 'no existe',
+ 'is already a member!' => 'ya es actualmente un miembro',
+ 'localhost' => 'máquina local',
+ 'successfully created!' => 'creado satisfactoriamente',
+ 'successfully deleted!' => 'borrado satisfactoriamente',
+ 'website' => 'sitio web',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'añadir_usuario' => 'add_user',
+ 'cambiar_la_contraseña_del_administrador' => 'change_admin_password',
+ 'cambiar_contraseña' => 'change_password',
+ 'continuar' => 'continue',
+ 'crear_base_de_datos' => 'create_dataset',
+ 'borrar' => 'delete',
+ 'borrar_base_de_datos' => 'delete_dataset',
+ 'entrar' => 'login',
+ 'administración_de_la_base_de_datos_oracle' => 'oracle_database_administration',
+ 'administración_de_la_base_de_datos_postgresql' => 'pg_database_administration',
+ 'guardar' => 'save',
+ 'actualizar_base_de_datos' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/es/all b/sql-ledger/locale/es/all
new file mode 100644
index 0000000..5e33b01
--- /dev/null
+++ b/sql-ledger/locale/es/all
@@ -0,0 +1,490 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Cartera de pagos',
+ 'AP Aging' => 'Diario resumido de pagos',
+ 'AP Transaction' => 'Gestión se pago',
+ 'AP Transactions' => 'Gestiones de pagos',
+ 'AR' => 'Cartera de cobros',
+ 'AR Aging' => 'Diario resumido de cobros ',
+ 'AR Transaction' => 'Gestión de cobro',
+ 'AR Transactions' => 'Gestiones de cobros',
+ 'About' => 'Acerca de',
+ 'Access Control' => 'Control de Acceso',
+ 'Account' => 'Cuenta',
+ 'Account Number' => 'Número de cuenta',
+ 'Account Number missing!' => 'No se ha definido el número de la cuenta',
+ 'Account Type' => 'Categoría de cuenta',
+ 'Account Type missing!' => 'No se ha definido el tipo de la cuenta',
+ 'Account deleted!' => '¡Cuenta borraba!',
+ 'Account saved!' => '¡Cuenta guardada!',
+ 'Accounting' => 'Contabilidad',
+ 'Accounting Menu' => 'Menú general',
+ 'Accounts' => 'Cuentas',
+ 'Active' => 'Activo',
+ 'Add' => 'Añadir',
+ 'Add Account' => 'Añadir cuenta',
+ 'Add Accounts Payables Transaction' => 'Añadir cuenta de transacciones a pagar',
+ 'Add Accounts Receivables Transaction' => 'Añadir cuenta de transacciones a cobrar',
+ 'Add Assembly' => 'Añadir compuesto',
+ 'Add Customer' => 'Añadir cliente',
+ 'Add GIFI' => 'Añadir código GIFI',
+ 'Add General Ledger Transaction' => 'Añadir transacción al libro mayor general',
+ 'Add Part' => 'Añadir artículo',
+ 'Add Project' => 'Añadir proyecto',
+ 'Add Purchase Invoice' => 'Añadir factura de compra',
+ 'Add Purchase Order' => 'Añadir pedido',
+ 'Add Sales Invoice' => 'Añadir factura',
+ 'Add Sales Order' => 'Añadir presupuesto',
+ 'Add Service' => 'Añadir servicio',
+ 'Add Transaction' => 'Añadir',
+ 'Add User' => 'Añadir usuario',
+ 'Add Vendor' => 'Añadir proveedor',
+ 'Address' => 'Dirección',
+ 'Administration' => 'Administración',
+ 'Administrator' => 'Administrador',
+ 'All' => 'Todos',
+ 'All Datasets up to date!' => 'Todas las bases de datos están actualizadas',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Cantidad adeudada',
+ 'Amount does not equal applied!' => '¡La cantidad no es igual a lo aplicado!',
+ 'Amount missing!' => '¡Falta la cantidad!',
+ 'Applied' => 'Aplicado',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Esta seguro de que desea borrar la factura número',
+ 'Are you sure you want to delete Order Number' => '¿Esta seguro de que desea
+borrar la orden número?',
+ 'Are you sure you want to delete Transaction' => '¿Está seguro de que desea borrar la transacción?',
+ 'Assemblies' => 'Compuestos',
+ 'Assemblies restocked!' => '¡Compuestos actualizados en almacen!',
+ 'Assembly Number missing!' => 'No se ha definido el número de compuesto',
+ 'Asset' => 'Activo',
+ 'Attachment' => 'Adjunto',
+ 'Audit Control' => 'Control de auditoría',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'Listado de piezas',
+ 'Backup' => 'Copia de seguridad de los datos',
+ 'Backup sent to' => 'Copia de seguridad enviada a',
+ 'Balance' => 'Balance',
+ 'Balance Sheet' => 'Hoja de balance',
+ 'Bcc' => '',
+ 'Bin' => 'Bin',
+ 'Books are open' => 'Los libros están abiertos',
+ 'Bought' => 'Comprado',
+ 'Business Number' => 'Numero de negocio',
+ 'C' => '',
+ 'COGS' => 'Costo de los artículos',
+ 'Cannot delete account!' => '¡No se puede borrar la cuenta!',
+ 'Cannot delete customer!' => '¡No se puede borrar el cliente!',
+ 'Cannot delete default account!' => 'No se puede borrar la cuenta por omisión',
+ 'Cannot delete invoice!' => '¡No se puede borrar la factura!',
+ 'Cannot delete item already invoiced!' => 'No se puede borrar un artículo ya facturado',
+ 'Cannot delete item on order!' => 'No se puede eliminar un elemento presente en una orden',
+ 'Cannot delete item which is part of an assembly!' => 'No puede eliminar un artículo que es parte de un compuesto',
+ 'Cannot delete item!' => '¡No se puede borrar el artículo!',
+ 'Cannot delete order!' => '¡No se puede borrar el pedido!',
+ 'Cannot delete transaction!' => '¡No se puede borrar la transacción!',
+ 'Cannot delete vendor!' => '¡No se puede borrar el vendedor!',
+ 'Cannot have a value in both Debit and Credit!' => 'No puede tener un valor en débito y crédito simultáneamente!',
+ 'Cannot post a transaction without a value!' => '¡No se puede registrar una transacción sin valor!',
+ 'Cannot post invoice for a closed period!' => '¡No se puede registrar una factura en un periodo ya cerrado!',
+ 'Cannot post invoice!' => '¡No se puede registrar la factura!',
+ 'Cannot post payment for a closed period!' => '¡No se puede registrar un pago en un periodo ya cerrado!',
+ 'Cannot post payment!' => '¡No se puede registrar el pago!',
+ 'Cannot post transaction for a closed period!' => '¡No se puede registrar una transacción para un periodo cerrado',
+ 'Cannot post transaction!' => '¡No se puede registrar la transacción',
+ 'Cannot process payment for a closed period!' => '¡No se puede procesar un pago de un periodo ya cerrado!',
+ 'Cannot save account!' => '¡No se puede guardar la cuenta!',
+ 'Cannot save order!' => '¡No se puede guardar el pedido!',
+ 'Cannot save preferences!' => '¡No se puede guardar las preferencias!',
+ 'Cannot stock assemblies!' => '¡No se pueden almacenar los compuestos!',
+ 'Cash' => 'Efectivo',
+ 'Cash based' => 'Efectivo inicial',
+ 'Cc' => '',
+ 'Change Admin Password' => 'Cambiar la contraseña del administrador',
+ 'Change Password' => 'Cambiar contraseña',
+ 'Character Set' => 'Conjunto de caracteres',
+ 'Chart of Accounts' => 'Cuadro de cuentas',
+ 'Check' => 'Cheque',
+ 'Check printed!' => '¡Cheque impreso!',
+ 'Check printing failed!' => '¡Fallo al imprimir el cheque!',
+ 'Cleared Balance' => 'Balance cerrado',
+ 'Click on login name to edit!' => 'Haga clic en el nombre de usuario por
+editar',
+ 'Close Books up to' => 'Cerrar los libros hasta',
+ 'Closed' => 'Cerrado',
+ 'Company' => 'Compañía',
+ 'Compare to' => 'Comparar con',
+ 'Confirm!' => 'Confirmar',
+ 'Connect to' => 'Conectar a',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Copy to COA' => 'Copiar al catálogo de cuentas',
+ 'Create Chart of Accounts' => 'Crear catálogo de cuentas',
+ 'Create Dataset' => 'Crear base de datos',
+ 'Credit' => 'Crédito',
+ 'Credit Limit' => 'Limite de credito',
+ 'Curr' => 'Mon.',
+ 'Currency' => 'Moneda',
+ 'Current' => 'Actual',
+ 'Customer' => 'Cliente',
+ 'Customer deleted!' => '¡Cliente borrado!',
+ 'Customer missing!' => '¡Falta el cliente!',
+ 'Customer not on file!' => '¡El cliente no existe!',
+ 'Customer saved!' => '¡Cliente guardado!',
+ 'Customers' => 'Clientes',
+ 'DBI not installed!' => 'No se ha instalado DBI',
+ 'Database' => 'Base de datos',
+ 'Database Administration' => 'Administración de las bases de datos',
+ 'Database Driver not checked!' => 'No se ha podido verificar el gestor de la base de datos',
+ 'Database Host' => 'Máquina servidor de base de datos',
+ 'Database User missing!' => 'No se ha definido el usuario de la base de datos',
+ 'Dataset' => 'Base de datos',
+ 'Dataset missing!' => 'No se ha definido la base de datos',
+ 'Dataset updated!' => 'Base de datos actualizada',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Fecha de vencimiento',
+ 'Date Format' => 'Formato de fecha',
+ 'Date Paid' => 'Fecha de pago',
+ 'Date missing!' => '¡Falta la fecha!',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Los débitos y créditos están fuera de balance',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Decimalplaces' => 'Lugar de los decimales',
+ 'Delete' => 'Borrar',
+ 'Delete Account' => 'Borrar cuenta',
+ 'Delete Dataset' => 'Borrar base de datos',
+ 'Delivery Date' => 'Fecha de entrega',
+ 'Deposit' => 'Depósito',
+ 'Description' => 'Descripción',
+ 'Difference' => 'Diferencia',
+ 'Directory' => 'Directorio',
+ 'Discount' => 'Descuento',
+ 'Done' => 'Hecho',
+ 'Drawing' => 'Reintegro',
+ 'Driver' => 'Gestor',
+ 'Dropdown Limit' => 'Límite de efectivo',
+ 'Due' => 'Vence',
+ 'Due Date' => 'Fecha de vencimiento',
+ 'Due Date missing!' => 'Falta la fecha de vencimiento',
+ 'E-mail' => 'Correo electrónico',
+ 'E-mail Statement to' => 'Enviar comprobante por correo electrónico a',
+ 'E-mail address missing!' => 'No se ha definido el correo electrónico',
+ 'Edit' => 'Editar',
+ 'Edit Account' => 'Editar cuenta',
+ 'Edit Accounts Payables Transaction' => 'Editar las cuentas de las transacciones a pagar',
+ 'Edit Accounts Receivables Transaction' => 'Editar las cuentas de las transacciones a cobrar',
+ 'Edit Assembly' => 'Editar compuesto',
+ 'Edit GIFI' => 'Editar GIFI',
+ 'Edit General Ledger Transaction' => 'Editar transacción del libro mayor general',
+ 'Edit Part' => 'Editar compuesto',
+ 'Edit Preferences for' => 'Editar preferencias de',
+ 'Edit Project' => 'Editar proyecto',
+ 'Edit Purchase Invoice' => 'Editar factura de compra',
+ 'Edit Purchase Order' => 'Editar pedido',
+ 'Edit Sales Invoice' => 'Edirar factura de venta',
+ 'Edit Sales Order' => 'Editar presupuesto',
+ 'Edit Service' => 'Editar servicio',
+ 'Edit Template' => 'Editar plantilla',
+ 'Edit User' => 'Editar usuario',
+ 'Employee' => 'Colaborador/Empleado',
+ 'Enforce transaction reversal for all dates' => 'Forzar la anulación de las transacciones para todas las fechas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Introduzca hasta 3 letras separadas por dos puntos (p.e. CAD:USD:EUR) para las monedas locales y las extranjeras',
+ 'Equity' => 'Balance',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasa de cambio',
+ 'Exchangerate Difference' => 'Diferencia en la tasa cambio a moneda extranjera',
+ 'Exchangerate for payment missing!' => '¡Falta la tasa de cambio para el pago!',
+ 'Exchangerate missing!' => '¡Falta la tasa de cambio!',
+ 'Existing Datasets' => 'Bases de datos existentes',
+ 'Expense' => 'Gastos',
+ 'Expense Account' => 'Cuenta de gastos',
+ 'Expense/Asset' => 'Gastos/Activo',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'File locked!' => '',
+ 'Foreign Exchange Gain' => 'Ganancia en moneda extranjera',
+ 'Foreign Exchange Loss' => 'Pérdida en moneda extranjera',
+ 'From' => 'Desde',
+ 'GIFI' => 'Código GIFI',
+ 'GIFI deleted!' => '¡Borrado el código GIFI!',
+ 'GIFI missing!' => 'No se ha definido el código GIFI',
+ 'GIFI saved!' => '¡Guardado el código GIFI!',
+ 'GL Transaction' => 'Transacción en el libro mayor',
+ 'General Ledger' => 'Libro mayor general',
+ 'Goods & Services' => 'Bienes y servicios',
+ 'HTML Templates' => 'Plantillas HTML',
+ 'Heading' => 'Encabezado',
+ 'Host' => 'Máquina servidor de base de datos',
+ 'Hostname missing!' => 'No se ha definido la máquina servidor de base de datos',
+ 'ID' => 'ID',
+ 'Image' => 'Imagen',
+ 'In-line' => 'Incrustado',
+ 'Include in Report' => 'Incluir en informe',
+ 'Include in drop-down menus' => 'Incluir en menúes desplegables:',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Mostrar esta cuenta en los formularios de cliente/proveedor para seleccionar si hay que aplicar impuestos al cliente/proveedor?',
+ 'Income' => 'Ingresos',
+ 'Income Account' => 'Cuenta de ingresos',
+ 'Income Statement' => 'Balance de situación',
+ 'Incorrect Dataset version!' => 'Versión de base de datos incorrecta',
+ 'Incorrect Password!' => 'Contraseña incorrecta',
+ 'Individual Items' => 'Artículos individuales',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Cuenta de inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar este compuesto a obsoleto',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar este artículo a obsoleto',
+ 'Inventory quantity must be zero!' => 'La cantidad en inventario debe ser cero',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de factura',
+ 'Invoice Date missing!' => 'No se ha definido la fecha de la factura',
+ 'Invoice Number' => 'Número de factura',
+ 'Invoice Number missing!' => 'No se ha definido el número de la factura',
+ 'Invoice deleted!' => '¡Factura borrada!',
+ 'Invoice posted!' => '¡Factura registrada!',
+ 'Invoices' => 'Facturas',
+ 'Is this a summary account to record' => '¿Es esta una cuenta de resumen a registrar?',
+ 'Item deleted!' => '¡Concepto borrado!',
+ 'Item not on file!' => 'El concepto no se encuentra en ningún archivo',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'LaTeX Templates' => 'Plantillas LaTeX',
+ 'Language' => 'Lenguaje',
+ 'Last Cost' => 'Ultimo costo',
+ 'Last Invoice Number' => 'Último número de factura',
+ 'Last Numbers & Default Accounts' => 'Últimos números y cuentas por omisión',
+ 'Last Purchase Order Number' => 'Último pedido',
+ 'Last Sales Order Number' => 'Número del último presupuesto',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deje los campos de máquina servidor de base de datos y puerto vacíos al menos que quiera hacer una conexión remota',
+ 'Liability' => 'Pasivo',
+ 'Licensed to' => 'Adaptado para',
+ 'Line Total' => 'Total de la línea',
+ 'Link' => 'Enlaces',
+ 'Link Accounts' => 'Enlazar cuentas',
+ 'List Accounts' => 'Listar cuentas',
+ 'List GIFI' => 'Listar código GIFI',
+ 'List Price' => 'Precio de lista',
+ 'List Transactions' => 'Listar transacciones',
+ 'Login' => 'Entrar',
+ 'Logout' => 'Salir',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Microfiche' => 'Microficha',
+ 'Model' => 'Modelo',
+ 'N/A' => 'Sin respuesta',
+ 'Name' => 'Nombre',
+ 'Name missing!' => '¡Falta el nombre!',
+ 'New Templates' => 'Nuevas plantillas',
+ 'No' => 'No',
+ 'No Database Drivers available!' => 'No hay ningún gestor de base de datos disponible',
+ 'No Dataset selected!' => 'No se ha seleccionado ninguna base de datos',
+ 'No email address for' => 'Falta la dirección de correo electrónico de',
+ 'No.' => '',
+ 'Notes' => 'Notas',
+ 'Nothing applied!' => '¡No es aplicable a nada!',
+ 'Nothing selected!' => '¡No es seleccionado nada!',
+ 'Nothing to delete!' => '¡No hay nada para borrar!',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato de número',
+ 'Number missing in Row' => 'No se ha definido el número en la fila',
+ 'O' => '',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'On Hand' => 'Disponible',
+ 'On Order' => 'En pedido',
+ 'Open' => 'Abierto',
+ 'Oracle Database Administration' => 'Administración de la base de datos Oracle',
+ 'Order' => 'Orden',
+ 'Order Date' => 'Fecha de elaboración',
+ 'Order Date missing!' => 'No se ha definido la fecha de la elaboración',
+ 'Order Entry' => 'Presupuestos y pedidos',
+ 'Order Number' => 'Número de orden',
+ 'Order Number missing!' => 'No se ha definido el número de la orden',
+ 'Order deleted!' => '¡Orden borrada!',
+ 'Order saved!' => '¡Orden guardada!',
+ 'Ordered' => 'Pedido realizado',
+ 'Orphaned' => 'Huérfano',
+ 'Out of balance!' => '¡Fuera de balance!',
+ 'PDF' => '',
+ 'Packing List' => 'Albarán',
+ 'Packing List Date missing!' => 'No se ha definido la fecha del albarán',
+ 'Packing List Number missing!' => 'No se ha definido el número del albarán',
+ 'Paid' => 'Pagado',
+ 'Paid in full' => 'Pago al completo',
+ 'Part' => 'Artículo',
+ 'Part Number missing!' => 'No se ha definido el número del artículo',
+ 'Parts' => 'Artículos',
+ 'Parts Inventory' => 'Inventario de artículos',
+ 'Password' => 'Contraseña',
+ 'Password changed!' => '¡Contraseña cambiada!',
+ 'Payables' => 'Pagos',
+ 'Payment' => 'Pago',
+ 'Payment date missing!' => 'No se encuentra la fecha de pago',
+ 'Payment posted!' => '¡Pago registrado!',
+ 'Payments' => 'Vencimientos impagados',
+ 'Pg Database Administration' => 'Administración de la base de datos PostgreSQL',
+ 'Phone' => 'Teléfono',
+ 'Port' => 'Puerto',
+ 'Port missing!' => 'No se ha definido el puerto',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Postscript' => '',
+ 'Preferences' => 'Preferencias',
+ 'Preferences saved!' => 'Preferencias guardadas',
+ 'Price' => 'Precio',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Project Number missing!' => '¡Falta el número de proyecto!',
+ 'Project deleted!' => '¡Proyecto borrado!',
+ 'Project not on file!' => '¡No se encuentra el proyecto en la base de datos!',
+ 'Project saved!' => '¡Proyecto guardado ',
+ 'Projects' => 'Proyectos',
+ 'Purchase Invoice' => 'Factura de compras',
+ 'Purchase Order' => 'Pedido',
+ 'Purchase Orders' => 'Pedidos',
+ 'Qty' => 'Cantidad',
+ 'ROP' => 'Tope de envio',
+ 'Rate' => 'Tarifa',
+ 'Recd' => 'Cobrado',
+ 'Receipt' => 'Recibo',
+ 'Receipts' => 'Recibos',
+ 'Receivables' => 'Cobros',
+ 'Reconciliation' => 'Reconciliación',
+ 'Record in' => 'Registrar en',
+ 'Reference' => 'Referencia',
+ 'Reference missing!' => '¡Falta la referencia!',
+ 'Remaining' => 'Resto',
+ 'Report for' => 'Informe para',
+ 'Reports' => 'Informes',
+ 'Required by' => 'Aceptado el',
+ 'Retained Earnings' => 'Ganacias retenidas',
+ 'Sales' => 'Ventas',
+ 'Sales Invoice' => 'Facturas de ventas',
+ 'Sales Order' => 'Presupuesto',
+ 'Sales Orders' => 'Presupuestos',
+ 'Save' => 'Guardar',
+ 'Save as new' => 'Guardar como nuevo',
+ 'Save to File' => 'Guardar en un archivo',
+ 'Screen' => 'Pantalla',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione una base de datos para borrar y presione "Continuar"',
+ 'Select all' => 'Guardar todo',
+ 'Select from one of the items below' => 'Seleccione uno de los artículos siguientes',
+ 'Select from one of the names below' => 'Seleccione uno de los nombres de la lista',
+ 'Select from one of the projects below' => 'Seleccione uno de los proyectos de la lista',
+ 'Select postscript or PDF!' => '¡Seleccione postscript o PDF',
+ 'Sell Price' => 'Precio de venta',
+ 'Send by E-Mail' => 'Enviar por correo electrónico',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Service Items' => 'Servicios',
+ 'Service Number missing!' => 'No se ha definido el número de servicio',
+ 'Services' => 'Servicios',
+ 'Setup Templates' => 'Configurar plantillas',
+ 'Ship' => 'Envio',
+ 'Ship to' => 'Destino',
+ 'Ship via' => 'Envio por',
+ 'Short' => 'Corto',
+ 'Signature' => 'Firma',
+ 'Sold' => 'Vendido',
+ 'Source' => 'Fuente',
+ 'Standard' => 'Estándard',
+ 'Statement' => 'Estado de cuenta',
+ 'Statement Balance' => 'Balance de cuenta',
+ 'Statement sent to' => 'Estado de cuenta enviado a',
+ 'Statements sent to printer!' => '¡Estado de cuenta enviado a la impresora!',
+ 'Stock Assembly' => 'Inventariar compuesto',
+ 'Stylesheet' => 'Hoja de estilo',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'System' => 'Sistema',
+ 'Tax' => 'Impuesto',
+ 'Tax Accounts' => 'Cuentas de impuestos',
+ 'Tax Included' => 'Impuestos incluidos en el precio',
+ 'Tax collected' => 'Impuestos cobrados',
+ 'Tax paid' => 'Impuestos pagados',
+ 'Taxable' => 'Impuestos gravables',
+ 'Template saved!' => '¡Plantilla guardada!',
+ 'Templates' => 'Plantillas',
+ 'Terms: Net' => 'Crédito',
+ 'The following Datasets are not in use and can be deleted' => 'Las siguientes bases de datos no están en uso y se pueden borrar',
+ 'The following Datasets need to be updated' => 'Es necesario actualizar las siguientes bases de datos',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta es una verificacion preliminar de fuentes existentes. No se creará ni borrará nada durante esta etapa',
+ 'To' => 'Hasta ',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para añadir un usuario a un grupo, edite un nombre, cambie el nombre de usuario (login) y guarde los cambios. Un nuevo usuario, con las mismas propiedades se guardará bajo el nuevo nombre de usuario (login).',
+ 'Top Level' => '',
+ 'Total' => 'Total',
+ 'Transaction Date missing!' => 'No se ha definido la fecha de la transacción',
+ 'Transaction deleted!' => '¡Transacción borrada!',
+ 'Transaction posted!' => '¡Transacción registrada!',
+ 'Transaction reversal enforced for all dates' => 'Se ha forzado la anulación de las transacciones para todas las fechas',
+ 'Transaction reversal enforced up to' => 'Se ha forzado la anulación de las transacciones hasta',
+ 'Transactions' => 'Impagados',
+ 'Transactions exist, cannot delete customer!' => 'Existen transacciones para este cliente, por tanto, no puede borrarlo',
+ 'Transactions exist, cannot delete vendor!' => 'Existen transacciones para este proveedor, por tanto, no puede borrarlo',
+ 'Transactions exist; cannot delete account!' => 'Las transacciones existen, no puede suprimir la cuenta!',
+ 'Trial Balance' => 'Balance de comprobación',
+ 'Unit' => 'Unidad',
+ 'Unit of measure' => 'Unidad de medida',
+ 'Update' => 'Actualizar',
+ 'Update Dataset' => 'Actualizar base de datos',
+ 'Updated' => '¡Actualizado!',
+ 'Use Templates' => 'Plantillas de usuarios',
+ 'User' => 'Usuario',
+ 'User deleted!' => '¡Usuario borrado!',
+ 'User saved!' => '¡Usuario guardado!',
+ 'Vendor' => 'Proveedor',
+ 'Vendor deleted!' => '¡Proveedor borrado!',
+ 'Vendor missing!' => '¡Falta el proveedor!',
+ 'Vendor not on file!' => '¡No se encuentra el proveedor en la base de datos!',
+ 'Vendor saved!' => '¡Proveedor guardado!',
+ 'Vendors' => 'Proveedores',
+ 'Version' => 'Versión',
+ 'Weight' => 'Peso',
+ 'Weight Unit' => 'Unidad de peso',
+ 'What type of item is this?' => '¿De qué tipo es este concepto?',
+ 'Year End' => 'Fin del año fiscal',
+ 'Yes' => 'Si',
+ 'You are logged out!' => '¡Ya está desconectado del sistema!',
+ 'You did not enter a name!' => 'No ha introducido el nombre',
+ 'You must enter a host and port for local and remote connections!' => 'Debe introducir una máquina servidor de bases de datos y un puerto para conexiones locales y remotas',
+ 'as at' => 'al',
+ 'collected on sales' => 'ingresado en ventas',
+ 'days' => 'días',
+ 'does not exist' => 'no existe',
+ 'ea' => 'unid.',
+ 'emailed to' => 'enviado por correo electrónico a',
+ 'for Period' => 'para el periodo',
+ 'hr' => 'hr',
+ 'is already a member!' => 'ya es actualmente un miembro',
+ 'is not a member!' => 'no es miembro',
+ 'localhost' => 'máquina local',
+ 'paid on purchases' => 'pagado en compras',
+ 'sent to printer' => 'enviado a la impresora',
+ 'successfully created!' => 'creado satisfactoriamente',
+ 'successfully deleted!' => 'borrado satisfactoriamente',
+ 'to' => 'a',
+ 'website' => 'sitio web',
+};
+
+1;
diff --git a/sql-ledger/locale/es/am b/sql-ledger/locale/es/am
new file mode 100644
index 0000000..a19042d
--- /dev/null
+++ b/sql-ledger/locale/es/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Cartera de pagos',
+ 'AR' => 'Cartera de cobros',
+ 'Account' => 'Cuenta',
+ 'Account Number' => 'Número de cuenta',
+ 'Account Number missing!' => 'No se ha definido el número de la cuenta',
+ 'Account Type' => 'Categoría de cuenta',
+ 'Account Type missing!' => 'No se ha definido el tipo de la cuenta',
+ 'Account deleted!' => '¡Cuenta borraba!',
+ 'Account saved!' => '¡Cuenta guardada!',
+ 'Add Account' => 'Añadir cuenta',
+ 'Add GIFI' => 'Añadir código GIFI',
+ 'Address' => 'Dirección',
+ 'Asset' => 'Activo',
+ 'Audit Control' => 'Control de auditoría',
+ 'Backup sent to' => 'Copia de seguridad enviada a',
+ 'Books are open' => 'Los libros están abiertos',
+ 'Business Number' => 'Numero de negocio',
+ 'COGS' => 'Costo de los artículos',
+ 'Cannot delete account!' => '¡No se puede borrar la cuenta!',
+ 'Cannot delete default account!' => 'No se puede borrar la cuenta por omisión',
+ 'Cannot save account!' => '¡No se puede guardar la cuenta!',
+ 'Cannot save preferences!' => '¡No se puede guardar las preferencias!',
+ 'Character Set' => 'Conjunto de caracteres',
+ 'Chart of Accounts' => 'Cuadro de cuentas',
+ 'Close Books up to' => 'Cerrar los libros hasta',
+ 'Company' => 'Compañía',
+ 'Continue' => 'Continuar',
+ 'Copy to COA' => 'Copiar al catálogo de cuentas',
+ 'Credit' => 'Crédito',
+ 'Date Format' => 'Formato de fecha',
+ 'Debit' => 'Débito',
+ 'Delete' => 'Borrar',
+ 'Delete Account' => 'Borrar cuenta',
+ 'Description' => 'Descripción',
+ 'Dropdown Limit' => 'Límite de efectivo',
+ 'E-mail' => 'Correo electrónico',
+ 'Edit' => 'Editar',
+ 'Edit Account' => 'Editar cuenta',
+ 'Edit GIFI' => 'Editar GIFI',
+ 'Edit Preferences for' => 'Editar preferencias de',
+ 'Edit Template' => 'Editar plantilla',
+ 'Enforce transaction reversal for all dates' => 'Forzar la anulación de las transacciones para todas las fechas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Introduzca hasta 3 letras separadas por dos puntos (p.e. CAD:USD:EUR) para las monedas locales y las extranjeras',
+ 'Equity' => 'Balance',
+ 'Expense' => 'Gastos',
+ 'Expense Account' => 'Cuenta de gastos',
+ 'Expense/Asset' => 'Gastos/Activo',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Ganancia en moneda extranjera',
+ 'Foreign Exchange Loss' => 'Pérdida en moneda extranjera',
+ 'GIFI' => 'Código GIFI',
+ 'GIFI deleted!' => '¡Borrado el código GIFI!',
+ 'GIFI missing!' => 'No se ha definido el código GIFI',
+ 'GIFI saved!' => '¡Guardado el código GIFI!',
+ 'Heading' => 'Encabezado',
+ 'Include in drop-down menus' => 'Incluir en menúes desplegables:',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Mostrar esta cuenta en los formularios de cliente/proveedor para seleccionar si hay que aplicar impuestos al cliente/proveedor?',
+ 'Income' => 'Ingresos',
+ 'Income Account' => 'Cuenta de ingresos',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Cuenta de inventario',
+ 'Is this a summary account to record' => '¿Es esta una cuenta de resumen a registrar?',
+ 'Language' => 'Lenguaje',
+ 'Last Invoice Number' => 'Último número de factura',
+ 'Last Numbers & Default Accounts' => 'Últimos números y cuentas por omisión',
+ 'Last Purchase Order Number' => 'Último pedido',
+ 'Last Sales Order Number' => 'Número del último presupuesto',
+ 'Liability' => 'Pasivo',
+ 'Link' => 'Enlaces',
+ 'Name' => 'Nombre',
+ 'No' => 'No',
+ 'No email address for' => 'Falta la dirección de correo electrónico de',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato de número',
+ 'Parts Inventory' => 'Inventario de artículos',
+ 'Password' => 'Contraseña',
+ 'Payables' => 'Pagos',
+ 'Payment' => 'Pago',
+ 'Phone' => 'Teléfono',
+ 'Preferences saved!' => 'Preferencias guardadas',
+ 'Rate' => 'Tarifa',
+ 'Receivables' => 'Cobros',
+ 'Sales' => 'Ventas',
+ 'Save' => 'Guardar',
+ 'Service Items' => 'Servicios',
+ 'Ship via' => 'Envio por',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Hoja de estilo',
+ 'Tax' => 'Impuesto',
+ 'Tax Accounts' => 'Cuentas de impuestos',
+ 'Template saved!' => '¡Plantilla guardada!',
+ 'Transaction reversal enforced for all dates' => 'Se ha forzado la anulación de las transacciones para todas las fechas',
+ 'Transaction reversal enforced up to' => 'Se ha forzado la anulación de las transacciones hasta',
+ 'Transactions exist; cannot delete account!' => 'Las transacciones existen, no puede suprimir la cuenta!',
+ 'Weight Unit' => 'Unidad de peso',
+ 'Year End' => 'Fin del año fiscal',
+ 'Yes' => 'Si',
+ 'does not exist' => 'no existe',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'añadir_cuenta' => 'add_account',
+ 'continuar' => 'continue',
+ 'copiar_al_catálogo_de_cuentas' => 'copy_to_coa',
+ 'borrar' => 'delete',
+ 'editar' => 'edit',
+ 'editar_cuenta' => 'edit_account',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/es/ap b/sql-ledger/locale/es/ap
new file mode 100644
index 0000000..1a8f37c
--- /dev/null
+++ b/sql-ledger/locale/es/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Gestión se pago',
+ 'AP Transactions' => 'Gestiones de pagos',
+ 'Account' => 'Cuenta',
+ 'Add Accounts Payables Transaction' => 'Añadir cuenta de transacciones a pagar',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Cantidad adeudada',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => '¿Está seguro de que desea borrar la transacción?',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => '¡No se puede borrar la transacción!',
+ 'Cannot post payment for a closed period!' => '¡No se puede registrar un pago en un periodo ya cerrado!',
+ 'Cannot post transaction for a closed period!' => '¡No se puede registrar una transacción para un periodo cerrado',
+ 'Cannot post transaction!' => '¡No se puede registrar la transacción',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moneda',
+ 'Customer not on file!' => '¡El cliente no existe!',
+ 'Date' => 'Fecha',
+ 'Date Paid' => 'Fecha de pago',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Due Date' => 'Fecha de vencimiento',
+ 'Due Date missing!' => 'Falta la fecha de vencimiento',
+ 'Edit Accounts Payables Transaction' => 'Editar las cuentas de las transacciones a pagar',
+ 'Employee' => 'Colaborador/Empleado',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasa de cambio',
+ 'Exchangerate for payment missing!' => '¡Falta la tasa de cambio para el pago!',
+ 'Exchangerate missing!' => '¡Falta la tasa de cambio!',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluir en informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de factura',
+ 'Invoice Date missing!' => 'No se ha definido la fecha de la factura',
+ 'Invoice Number' => 'Número de factura',
+ 'Invoice Number missing!' => 'No se ha definido el número de la factura',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Number' => 'Número de orden',
+ 'Paid' => 'Pagado',
+ 'Payment date missing!' => 'No se encuentra la fecha de pago',
+ 'Payments' => 'Vencimientos impagados',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => '¡No se encuentra el proyecto en la base de datos!',
+ 'Purchase Invoice' => 'Factura de compras',
+ 'Select from one of the names below' => 'Seleccione uno de los nombres de la lista',
+ 'Select from one of the projects below' => 'Seleccione uno de los proyectos de la lista',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax Included' => 'Impuestos incluidos en el precio',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => '¡Transacción borrada!',
+ 'Transaction posted!' => '¡Transacción registrada!',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => '¡Falta el proveedor!',
+ 'Vendor not on file!' => '¡No se encuentra el proveedor en la base de datos!',
+ 'Yes' => 'Si',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'gestión_se_pago' => 'ap_transaction',
+ 'añadir_cuenta_de_transacciones_a_pagar' => 'add_accounts_payables_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'editar_las_cuentas_de_las_transacciones_a_pagar' => 'edit_accounts_payables_transaction',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'factura_de_compras' => 'purchase_invoice',
+ 'actualizar' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/es/ar b/sql-ledger/locale/es/ar
new file mode 100644
index 0000000..e24b004
--- /dev/null
+++ b/sql-ledger/locale/es/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Gestión de cobro',
+ 'AR Transactions' => 'Gestiones de cobros',
+ 'Account' => 'Cuenta',
+ 'Add Accounts Receivables Transaction' => 'Añadir cuenta de transacciones a cobrar',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Cantidad adeudada',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => '¿Está seguro de que desea borrar la transacción?',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => '¡No se puede borrar la transacción!',
+ 'Cannot post payment for a closed period!' => '¡No se puede registrar un pago en un periodo ya cerrado!',
+ 'Cannot post transaction for a closed period!' => '¡No se puede registrar una transacción para un periodo cerrado',
+ 'Cannot post transaction!' => '¡No se puede registrar la transacción',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de credito',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => '¡Falta el cliente!',
+ 'Customer not on file!' => '¡El cliente no existe!',
+ 'Date' => 'Fecha',
+ 'Date Paid' => 'Fecha de pago',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Due Date' => 'Fecha de vencimiento',
+ 'Due Date missing!' => 'Falta la fecha de vencimiento',
+ 'Edit Accounts Receivables Transaction' => 'Editar las cuentas de las transacciones a cobrar',
+ 'Employee' => 'Colaborador/Empleado',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasa de cambio',
+ 'Exchangerate for payment missing!' => '¡Falta la tasa de cambio para el pago!',
+ 'Exchangerate missing!' => '¡Falta la tasa de cambio!',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluir en informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de factura',
+ 'Invoice Date missing!' => 'No se ha definido la fecha de la factura',
+ 'Invoice Number' => 'Número de factura',
+ 'Invoice Number missing!' => 'No se ha definido el número de la factura',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Number' => 'Número de orden',
+ 'Paid' => 'Pagado',
+ 'Payment date missing!' => 'No se encuentra la fecha de pago',
+ 'Payments' => 'Vencimientos impagados',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => '¡No se encuentra el proyecto en la base de datos!',
+ 'Remaining' => 'Resto',
+ 'Sales Invoice' => 'Facturas de ventas',
+ 'Select from one of the names below' => 'Seleccione uno de los nombres de la lista',
+ 'Select from one of the projects below' => 'Seleccione uno de los proyectos de la lista',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax Included' => 'Impuestos incluidos en el precio',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => '¡Transacción borrada!',
+ 'Transaction posted!' => '¡Transacción registrada!',
+ 'Update' => 'Actualizar',
+ 'Vendor not on file!' => '¡No se encuentra el proveedor en la base de datos!',
+ 'Yes' => 'Si',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'gestión_de_cobro' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'facturas_de_ventas' => 'sales_invoice',
+ 'actualizar' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/es/arap b/sql-ledger/locale/es/arap
new file mode 100644
index 0000000..be33676
--- /dev/null
+++ b/sql-ledger/locale/es/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Dirección',
+ 'Continue' => 'Continuar',
+ 'Customer not on file!' => '¡El cliente no existe!',
+ 'Description' => 'Descripción',
+ 'Number' => 'Número',
+ 'Project not on file!' => '¡No se encuentra el proyecto en la base de datos!',
+ 'Select from one of the names below' => 'Seleccione uno de los nombres de la lista',
+ 'Select from one of the projects below' => 'Seleccione uno de los proyectos de la lista',
+ 'Vendor not on file!' => '¡No se encuentra el proveedor en la base de datos!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/es/ca b/sql-ledger/locale/es/ca
new file mode 100644
index 0000000..536d00a
--- /dev/null
+++ b/sql-ledger/locale/es/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'Cuadro de cuentas',
+ 'Credit' => 'Crédito',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Description' => 'Descripción',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'Código GIFI',
+ 'Include in Report' => 'Incluir en informe',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'List Transactions' => 'Listar transacciones',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Reference' => 'Referencia',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Hasta ',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'listar_transacciones' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/es/cp b/sql-ledger/locale/es/cp
new file mode 100644
index 0000000..aa93a34
--- /dev/null
+++ b/sql-ledger/locale/es/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Amount does not equal applied!' => '¡La cantidad no es igual a lo aplicado!',
+ 'Amount missing!' => '¡Falta la cantidad!',
+ 'Applied' => 'Aplicado',
+ 'Cannot post payment!' => '¡No se puede registrar el pago!',
+ 'Cannot process payment for a closed period!' => '¡No se puede procesar un pago de un periodo ya cerrado!',
+ 'Check' => 'Cheque',
+ 'Check printed!' => '¡Cheque impreso!',
+ 'Check printing failed!' => '¡Fallo al imprimir el cheque!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer not on file!' => '¡El cliente no existe!',
+ 'Date' => 'Fecha',
+ 'Date missing!' => '¡Falta la fecha!',
+ 'Description' => 'Descripción',
+ 'Due' => 'Vence',
+ 'Exchangerate' => 'Tasa de cambio',
+ 'From' => 'Desde',
+ 'Invoice' => 'Factura',
+ 'Invoices' => 'Facturas',
+ 'Nothing applied!' => '¡No es aplicable a nada!',
+ 'Number' => 'Número',
+ 'Paid in full' => 'Pago al completo',
+ 'Payment' => 'Pago',
+ 'Payment posted!' => '¡Pago registrado!',
+ 'Post' => 'Registrar',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Project not on file!' => '¡No se encuentra el proyecto en la base de datos!',
+ 'Receipt' => 'Recibo',
+ 'Reference' => 'Referencia',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the names below' => 'Seleccione uno de los nombres de la lista',
+ 'Select from one of the projects below' => 'Seleccione uno de los proyectos de la lista',
+ 'To' => 'Hasta ',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Proveedor',
+ 'Vendor not on file!' => '¡No se encuentra el proveedor en la base de datos!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+ 'registrar' => 'post',
+ 'imprimir' => 'print',
+ 'actualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/es/ct b/sql-ledger/locale/es/ct
new file mode 100644
index 0000000..e37ddd8
--- /dev/null
+++ b/sql-ledger/locale/es/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Añadir',
+ 'Address' => 'Dirección',
+ 'All' => 'Todos',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => '¡No se puede borrar el cliente!',
+ 'Cannot delete vendor!' => '¡No se puede borrar el vendedor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de credito',
+ 'Customer deleted!' => '¡Cliente borrado!',
+ 'Customer saved!' => '¡Cliente guardado!',
+ 'Customers' => 'Clientes',
+ 'Delete' => 'Borrar',
+ 'Discount' => 'Descuento',
+ 'E-mail' => 'Correo electrónico',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Incluir en informe',
+ 'Invoice' => 'Factura',
+ 'Name' => 'Nombre',
+ 'Name missing!' => '¡Falta el nombre!',
+ 'Notes' => 'Notas',
+ 'Number' => 'Número',
+ 'Order' => 'Orden',
+ 'Orphaned' => 'Huérfano',
+ 'Phone' => 'Teléfono',
+ 'Save' => 'Guardar',
+ 'Ship to' => 'Destino',
+ 'Tax Included' => 'Impuestos incluidos en el precio',
+ 'Taxable' => 'Impuestos gravables',
+ 'Terms: Net' => 'Crédito',
+ 'Transactions exist, cannot delete customer!' => 'Existen transacciones para este cliente, por tanto, no puede borrarlo',
+ 'Transactions exist, cannot delete vendor!' => 'Existen transacciones para este proveedor, por tanto, no puede borrarlo',
+ 'Vendor deleted!' => '¡Proveedor borrado!',
+ 'Vendor saved!' => '¡Proveedor guardado!',
+ 'Vendors' => 'Proveedores',
+ 'days' => 'días',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'añadir' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'factura' => 'invoice',
+ 'orden' => 'order',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/es/gl b/sql-ledger/locale/es/gl
new file mode 100644
index 0000000..10978f9
--- /dev/null
+++ b/sql-ledger/locale/es/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Gestión se pago',
+ 'AR Transaction' => 'Gestión de cobro',
+ 'Account' => 'Cuenta',
+ 'Add General Ledger Transaction' => 'Añadir transacción al libro mayor general',
+ 'Address' => 'Dirección',
+ 'All' => 'Todos',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => '¿Está seguro de que desea borrar la transacción?',
+ 'Asset' => 'Activo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => '¡No se puede borrar la transacción!',
+ 'Cannot have a value in both Debit and Credit!' => 'No puede tener un valor en débito y crédito simultáneamente!',
+ 'Cannot post a transaction without a value!' => '¡No se puede registrar una transacción sin valor!',
+ 'Cannot post transaction for a closed period!' => '¡No se puede registrar una transacción para un periodo cerrado',
+ 'Confirm!' => 'Confirmar',
+ 'Continue' => 'Continuar',
+ 'Credit' => 'Crédito',
+ 'Customer not on file!' => '¡El cliente no existe!',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Los débitos y créditos están fuera de balance',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Edit General Ledger Transaction' => 'Editar transacción del libro mayor general',
+ 'Equity' => 'Balance',
+ 'Expense' => 'Gastos',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'Código GIFI',
+ 'GL Transaction' => 'Transacción en el libro mayor',
+ 'General Ledger' => 'Libro mayor general',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluir en informe',
+ 'Income' => 'Ingresos',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Liability' => 'Pasivo',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => '¡No se encuentra el proyecto en la base de datos!',
+ 'Purchase Invoice' => 'Factura de compras',
+ 'Reference' => 'Referencia',
+ 'Reference missing!' => '¡Falta la referencia!',
+ 'Reports' => 'Informes',
+ 'Sales Invoice' => 'Facturas de ventas',
+ 'Select from one of the names below' => 'Seleccione uno de los nombres de la lista',
+ 'Select from one of the projects below' => 'Seleccione uno de los proyectos de la lista',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Hasta ',
+ 'Transaction Date missing!' => 'No se ha definido la fecha de la transacción',
+ 'Transaction deleted!' => '¡Transacción borrada!',
+ 'Transaction posted!' => '¡Transacción registrada!',
+ 'Update' => 'Actualizar',
+ 'Vendor not on file!' => '¡No se encuentra el proveedor en la base de datos!',
+ 'Yes' => 'Si',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'gestión_se_pago' => 'ap_transaction',
+ 'gestión_de_cobro' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'transacción_en_el_libro_mayor' => 'gl_transaction',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'factura_de_compras' => 'purchase_invoice',
+ 'facturas_de_ventas' => 'sales_invoice',
+ 'actualizar' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/es/ic b/sql-ledger/locale/es/ic
new file mode 100644
index 0000000..9db330b
--- /dev/null
+++ b/sql-ledger/locale/es/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Activo',
+ 'Add' => 'Añadir',
+ 'Add Assembly' => 'Añadir compuesto',
+ 'Add Part' => 'Añadir artículo',
+ 'Add Purchase Order' => 'Añadir pedido',
+ 'Add Sales Order' => 'Añadir presupuesto',
+ 'Add Service' => 'Añadir servicio',
+ 'Address' => 'Dirección',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Assemblies' => 'Compuestos',
+ 'Assemblies restocked!' => '¡Compuestos actualizados en almacen!',
+ 'Assembly Number missing!' => 'No se ha definido el número de compuesto',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'Listado de piezas',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Bought' => 'Comprado',
+ 'COGS' => 'Costo de los artículos',
+ 'Cannot delete item already invoiced!' => 'No se puede borrar un artículo ya facturado',
+ 'Cannot delete item on order!' => 'No se puede eliminar un elemento presente en una orden',
+ 'Cannot delete item which is part of an assembly!' => 'No puede eliminar un artículo que es parte de un compuesto',
+ 'Cannot delete item!' => '¡No se puede borrar el artículo!',
+ 'Cannot stock assemblies!' => '¡No se pueden almacenar los compuestos!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Fecha de entrega',
+ 'Description' => 'Descripción',
+ 'Drawing' => 'Reintegro',
+ 'E-mail' => 'Correo electrónico',
+ 'E-mail address missing!' => 'No se ha definido el correo electrónico',
+ 'Edit Assembly' => 'Editar compuesto',
+ 'Edit Part' => 'Editar compuesto',
+ 'Edit Service' => 'Editar servicio',
+ 'Expense' => 'Gastos',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'Image' => 'Imagen',
+ 'In-line' => 'Incrustado',
+ 'Include in Report' => 'Incluir en informe',
+ 'Income' => 'Ingresos',
+ 'Individual Items' => 'Artículos individuales',
+ 'Inventory' => 'Inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar este compuesto a obsoleto',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar este artículo a obsoleto',
+ 'Inventory quantity must be zero!' => 'La cantidad en inventario debe ser cero',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'No se ha definido la fecha de la factura',
+ 'Invoice Number' => 'Número de factura',
+ 'Invoice Number missing!' => 'No se ha definido el número de la factura',
+ 'Item deleted!' => '¡Concepto borrado!',
+ 'Item not on file!' => 'El concepto no se encuentra en ningún archivo',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Last Cost' => 'Ultimo costo',
+ 'Line Total' => 'Total de la línea',
+ 'Link Accounts' => 'Enlazar cuentas',
+ 'List Price' => 'Precio de lista',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Microfiche' => 'Microficha',
+ 'Model' => 'Modelo',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se ha definido el número en la fila',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'On Hand' => 'Disponible',
+ 'On Order' => 'En pedido',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se ha definido la fecha de la elaboración',
+ 'Order Number' => 'Número de orden',
+ 'Order Number missing!' => 'No se ha definido el número de la orden',
+ 'Ordered' => 'Pedido realizado',
+ 'Orphaned' => 'Huérfano',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarán',
+ 'Packing List Date missing!' => 'No se ha definido la fecha del albarán',
+ 'Packing List Number missing!' => 'No se ha definido el número del albarán',
+ 'Part' => 'Artículo',
+ 'Part Number missing!' => 'No se ha definido el número del artículo',
+ 'Parts' => 'Artículos',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Purchase Order' => 'Pedido',
+ 'Qty' => 'Cantidad',
+ 'ROP' => 'Tope de envio',
+ 'Recd' => 'Cobrado',
+ 'Required by' => 'Aceptado el',
+ 'Sales' => 'Ventas',
+ 'Sales Order' => 'Presupuesto',
+ 'Save' => 'Guardar',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los artículos siguientes',
+ 'Select postscript or PDF!' => '¡Seleccione postscript o PDF',
+ 'Sell Price' => 'Precio de venta',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Service Number missing!' => 'No se ha definido el número de servicio',
+ 'Services' => 'Servicios',
+ 'Ship' => 'Envio',
+ 'Ship to' => 'Destino',
+ 'Short' => 'Corto',
+ 'Sold' => 'Vendido',
+ 'Stock Assembly' => 'Inventariar compuesto',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'To' => 'Hasta ',
+ 'Top Level' => 'Top Level',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Unit of measure' => 'Unidad de medida',
+ 'Update' => 'Actualizar',
+ 'Updated' => '¡Actualizado!',
+ 'Weight' => 'Peso',
+ 'What type of item is this?' => '¿De qué tipo es este concepto?',
+ 'ea' => 'unid.',
+ 'emailed to' => 'enviado por correo electrónico a',
+ 'hr' => 'hr',
+ 'sent to printer' => 'enviado a la impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'añadir' => 'add',
+ 'añadir_compuesto' => 'add_assembly',
+ 'añadir_artículo' => 'add_part',
+ 'añadir_servicio' => 'add_service',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'editar_compuesto' => 'edit_assembly',
+ 'editar_compuesto' => 'edit_part',
+ 'editar_servicio' => 'edit_service',
+ 'guardar' => 'save',
+ 'actualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/es/io b/sql-ledger/locale/es/io
new file mode 100644
index 0000000..0f12d08
--- /dev/null
+++ b/sql-ledger/locale/es/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Añadir pedido',
+ 'Add Sales Order' => 'Añadir presupuesto',
+ 'Address' => 'Dirección',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delivery Date' => 'Fecha de entrega',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo electrónico',
+ 'E-mail address missing!' => 'No se ha definido el correo electrónico',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'In-line' => 'Incrustado',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'No se ha definido la fecha de la factura',
+ 'Invoice Number missing!' => 'No se ha definido el número de la factura',
+ 'Item not on file!' => 'El concepto no se encuentra en ningún archivo',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se ha definido el número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se ha definido la fecha de la elaboración',
+ 'Order Number missing!' => 'No se ha definido el número de la orden',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarán',
+ 'Packing List Date missing!' => 'No se ha definido la fecha del albarán',
+ 'Packing List Number missing!' => 'No se ha definido el número del albarán',
+ 'Part' => 'Artículo',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Purchase Order' => 'Pedido',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Cobrado',
+ 'Required by' => 'Aceptado el',
+ 'Sales Order' => 'Presupuesto',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los artículos siguientes',
+ 'Select postscript or PDF!' => '¡Seleccione postscript o PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Envio',
+ 'Ship to' => 'Destino',
+ 'Subject' => 'Asunto',
+ 'To' => 'Hasta ',
+ 'Unit' => 'Unidad',
+ 'What type of item is this?' => '¿De qué tipo es este concepto?',
+ 'emailed to' => 'enviado por correo electrónico a',
+ 'sent to printer' => 'enviado a la impresora',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/es/ir b/sql-ledger/locale/es/ir
new file mode 100644
index 0000000..0e0aa7b
--- /dev/null
+++ b/sql-ledger/locale/es/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Add Purchase Invoice' => 'Añadir factura de compra',
+ 'Add Purchase Order' => 'Añadir pedido',
+ 'Add Sales Order' => 'Añadir presupuesto',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Esta seguro de que desea borrar la factura número',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => '¡No se puede borrar la factura!',
+ 'Cannot post invoice for a closed period!' => '¡No se puede registrar una factura en un periodo ya cerrado!',
+ 'Cannot post invoice!' => '¡No se puede registrar la factura!',
+ 'Cannot post payment for a closed period!' => '¡No se puede registrar un pago en un periodo ya cerrado!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Currency' => 'Moneda',
+ 'Customer not on file!' => '¡El cliente no existe!',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Fecha de vencimiento',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Fecha de entrega',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo electrónico',
+ 'E-mail address missing!' => 'No se ha definido el correo electrónico',
+ 'Edit Purchase Invoice' => 'Editar factura de compra',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasa de cambio',
+ 'Exchangerate for payment missing!' => '¡Falta la tasa de cambio para el pago!',
+ 'Exchangerate missing!' => '¡Falta la tasa de cambio!',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'In-line' => 'Incrustado',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de factura',
+ 'Invoice Date missing!' => 'No se ha definido la fecha de la factura',
+ 'Invoice Number' => 'Número de factura',
+ 'Invoice Number missing!' => 'No se ha definido el número de la factura',
+ 'Invoice deleted!' => '¡Factura borrada!',
+ 'Invoice posted!' => '¡Factura registrada!',
+ 'Item not on file!' => 'El concepto no se encuentra en ningún archivo',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se ha definido el número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se ha definido la fecha de la elaboración',
+ 'Order Number' => 'Número de orden',
+ 'Order Number missing!' => 'No se ha definido el número de la orden',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarán',
+ 'Packing List Date missing!' => 'No se ha definido la fecha del albarán',
+ 'Packing List Number missing!' => 'No se ha definido el número del albarán',
+ 'Part' => 'Artículo',
+ 'Payment date missing!' => 'No se encuentra la fecha de pago',
+ 'Payments' => 'Vencimientos impagados',
+ 'Phone' => 'Teléfono',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => '¡No se encuentra el proyecto en la base de datos!',
+ 'Purchase Order' => 'Pedido',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Cobrado',
+ 'Record in' => 'Registrar en',
+ 'Required by' => 'Aceptado el',
+ 'Sales Order' => 'Presupuesto',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los artículos siguientes',
+ 'Select from one of the names below' => 'Seleccione uno de los nombres de la lista',
+ 'Select from one of the projects below' => 'Seleccione uno de los proyectos de la lista',
+ 'Select postscript or PDF!' => '¡Seleccione postscript o PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Envio',
+ 'Ship to' => 'Destino',
+ 'Source' => 'Fuente',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impuestos incluidos en el precio',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => '¡Falta el proveedor!',
+ 'Vendor not on file!' => '¡No se encuentra el proveedor en la base de datos!',
+ 'What type of item is this?' => '¿De qué tipo es este concepto?',
+ 'Yes' => 'Si',
+ 'ea' => 'unid.',
+ 'emailed to' => 'enviado por correo electrónico a',
+ 'sent to printer' => 'enviado a la impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'orden' => 'order',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'actualizar' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/es/is b/sql-ledger/locale/es/is
new file mode 100644
index 0000000..c1fa75a
--- /dev/null
+++ b/sql-ledger/locale/es/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Add Purchase Order' => 'Añadir pedido',
+ 'Add Sales Invoice' => 'Añadir factura',
+ 'Add Sales Order' => 'Añadir presupuesto',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Esta seguro de que desea borrar la factura número',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => '¡No se puede borrar la factura!',
+ 'Cannot post invoice for a closed period!' => '¡No se puede registrar una factura en un periodo ya cerrado!',
+ 'Cannot post invoice!' => '¡No se puede registrar la factura!',
+ 'Cannot post payment for a closed period!' => '¡No se puede registrar un pago en un periodo ya cerrado!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit Limit' => 'Limite de credito',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => '¡Falta el cliente!',
+ 'Customer not on file!' => '¡El cliente no existe!',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Fecha de vencimiento',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Fecha de entrega',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo electrónico',
+ 'E-mail address missing!' => 'No se ha definido el correo electrónico',
+ 'Edit Sales Invoice' => 'Edirar factura de venta',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasa de cambio',
+ 'Exchangerate for payment missing!' => '¡Falta la tasa de cambio para el pago!',
+ 'Exchangerate missing!' => '¡Falta la tasa de cambio!',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'In-line' => 'Incrustado',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de factura',
+ 'Invoice Date missing!' => 'No se ha definido la fecha de la factura',
+ 'Invoice Number' => 'Número de factura',
+ 'Invoice Number missing!' => 'No se ha definido el número de la factura',
+ 'Invoice deleted!' => '¡Factura borrada!',
+ 'Invoice posted!' => '¡Factura registrada!',
+ 'Item not on file!' => 'El concepto no se encuentra en ningún archivo',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se ha definido el número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se ha definido la fecha de la elaboración',
+ 'Order Number' => 'Número de orden',
+ 'Order Number missing!' => 'No se ha definido el número de la orden',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarán',
+ 'Packing List Date missing!' => 'No se ha definido la fecha del albarán',
+ 'Packing List Number missing!' => 'No se ha definido el número del albarán',
+ 'Part' => 'Artículo',
+ 'Payment date missing!' => 'No se encuentra la fecha de pago',
+ 'Payments' => 'Vencimientos impagados',
+ 'Phone' => 'Teléfono',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => '¡No se encuentra el proyecto en la base de datos!',
+ 'Purchase Order' => 'Pedido',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Cobrado',
+ 'Record in' => 'Registrar en',
+ 'Remaining' => 'Resto',
+ 'Required by' => 'Aceptado el',
+ 'Sales Order' => 'Presupuesto',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los artículos siguientes',
+ 'Select from one of the names below' => 'Seleccione uno de los nombres de la lista',
+ 'Select from one of the projects below' => 'Seleccione uno de los proyectos de la lista',
+ 'Select postscript or PDF!' => '¡Seleccione postscript o PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Envio',
+ 'Ship to' => 'Destino',
+ 'Ship via' => 'Envio por',
+ 'Source' => 'Fuente',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impuestos incluidos en el precio',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Actualizar',
+ 'Vendor not on file!' => '¡No se encuentra el proveedor en la base de datos!',
+ 'What type of item is this?' => '¿De qué tipo es este concepto?',
+ 'Yes' => 'Si',
+ 'ea' => 'unid.',
+ 'emailed to' => 'enviado por correo electrónico a',
+ 'sent to printer' => 'enviado a la impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'correo_electrónico' => 'e_mail',
+ 'orden' => 'order',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'imprimir' => 'print',
+ 'destino' => 'ship_to',
+ 'actualizar' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/es/login b/sql-ledger/locale/es/login
new file mode 100644
index 0000000..f7a7cf0
--- /dev/null
+++ b/sql-ledger/locale/es/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Acerca de',
+ 'Database Host' => 'Máquina servidor de base de datos',
+ 'Dataset' => 'Base de datos',
+ 'Incorrect Dataset version!' => 'Versión de base de datos incorrecta',
+ 'Incorrect Password!' => 'Contraseña incorrecta',
+ 'Licensed to' => 'Adaptado para',
+ 'Login' => 'Entrar',
+ 'Name' => 'Nombre',
+ 'Password' => 'Contraseña',
+ 'User' => 'Usuario',
+ 'Version' => 'Versión',
+ 'You are logged out!' => '¡Ya está desconectado del sistema!',
+ 'You did not enter a name!' => 'No ha introducido el nombre',
+ 'is not a member!' => 'no es miembro',
+ 'localhost' => 'máquina local',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'entrar' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/es/menu b/sql-ledger/locale/es/menu
new file mode 100644
index 0000000..d9aa9e0
--- /dev/null
+++ b/sql-ledger/locale/es/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Cartera de pagos',
+ 'AP Aging' => 'Diario resumido de pagos',
+ 'AR' => 'Cartera de cobros',
+ 'AR Aging' => 'Diario resumido de cobros ',
+ 'Accounting Menu' => 'Menú general',
+ 'Add Account' => 'Añadir cuenta',
+ 'Add Assembly' => 'Añadir compuesto',
+ 'Add Customer' => 'Añadir cliente',
+ 'Add GIFI' => 'Añadir código GIFI',
+ 'Add Part' => 'Añadir artículo',
+ 'Add Project' => 'Añadir proyecto',
+ 'Add Service' => 'Añadir servicio',
+ 'Add Transaction' => 'Añadir',
+ 'Add Vendor' => 'Añadir proveedor',
+ 'Assemblies' => 'Compuestos',
+ 'Audit Control' => 'Control de auditoría',
+ 'Backup' => 'Copia de seguridad de los datos',
+ 'Balance Sheet' => 'Hoja de balance',
+ 'Cash' => 'Efectivo',
+ 'Chart of Accounts' => 'Cuadro de cuentas',
+ 'Check' => 'Cheque',
+ 'Customers' => 'Clientes',
+ 'General Ledger' => 'Libro mayor general',
+ 'Goods & Services' => 'Bienes y servicios',
+ 'HTML Templates' => 'Plantillas HTML',
+ 'Income Statement' => 'Balance de situación',
+ 'Invoice' => 'Factura',
+ 'LaTeX Templates' => 'Plantillas LaTeX',
+ 'List Accounts' => 'Listar cuentas',
+ 'List GIFI' => 'Listar código GIFI',
+ 'Logout' => 'Salir',
+ 'Order Entry' => 'Presupuestos y pedidos',
+ 'Packing List' => 'Albarán',
+ 'Parts' => 'Artículos',
+ 'Payment' => 'Pago',
+ 'Payments' => 'Vencimientos impagados',
+ 'Preferences' => 'Preferencias',
+ 'Projects' => 'Proyectos',
+ 'Purchase Invoice' => 'Factura de compras',
+ 'Purchase Order' => 'Pedido',
+ 'Purchase Orders' => 'Pedidos',
+ 'Receipt' => 'Recibo',
+ 'Receipts' => 'Recibos',
+ 'Reconciliation' => 'Reconciliación',
+ 'Reports' => 'Informes',
+ 'Sales Invoice' => 'Facturas de ventas',
+ 'Sales Order' => 'Presupuesto',
+ 'Sales Orders' => 'Presupuestos',
+ 'Save to File' => 'Guardar en un archivo',
+ 'Send by E-Mail' => 'Enviar por correo electrónico',
+ 'Services' => 'Servicios',
+ 'Statement' => 'Estado de cuenta',
+ 'Stock Assembly' => 'Inventariar compuesto',
+ 'Stylesheet' => 'Hoja de estilo',
+ 'System' => 'Sistema',
+ 'Tax collected' => 'Impuestos cobrados',
+ 'Tax paid' => 'Impuestos pagados',
+ 'Transactions' => 'Impagados',
+ 'Trial Balance' => 'Balance de comprobación',
+ 'Vendors' => 'Proveedores',
+ 'Version' => 'Versión',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/es/oe b/sql-ledger/locale/es/oe
new file mode 100644
index 0000000..3eb55b9
--- /dev/null
+++ b/sql-ledger/locale/es/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'Añadir',
+ 'Add Purchase Invoice' => 'Añadir factura de compra',
+ 'Add Purchase Order' => 'Añadir pedido',
+ 'Add Sales Invoice' => 'Añadir factura',
+ 'Add Sales Order' => 'Añadir presupuesto',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Order Number' => '¿Esta seguro de que desea
+borrar la orden número?',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'C' => 'C',
+ 'Cannot delete order!' => '¡No se puede borrar el pedido!',
+ 'Cannot save order!' => '¡No se puede guardar el pedido!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit Limit' => 'Limite de credito',
+ 'Curr' => 'Mon.',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => '¡Falta el cliente!',
+ 'Customer not on file!' => '¡El cliente no existe!',
+ 'Date' => 'Fecha',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Fecha de entrega',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo electrónico',
+ 'E-mail address missing!' => 'No se ha definido el correo electrónico',
+ 'Edit Purchase Order' => 'Editar pedido',
+ 'Edit Sales Order' => 'Editar presupuesto',
+ 'Exchangerate' => 'Tasa de cambio',
+ 'Exchangerate missing!' => '¡Falta la tasa de cambio!',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'In-line' => 'Incrustado',
+ 'Include in Report' => 'Incluir en informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'No se ha definido la fecha de la factura',
+ 'Invoice Number missing!' => 'No se ha definido el número de la factura',
+ 'Item not on file!' => 'El concepto no se encuentra en ningún archivo',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se ha definido el número en la fila',
+ 'O' => 'O',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Date' => 'Fecha de elaboración',
+ 'Order Date missing!' => 'No se ha definido la fecha de la elaboración',
+ 'Order Number' => 'Número de orden',
+ 'Order Number missing!' => 'No se ha definido el número de la orden',
+ 'Order deleted!' => '¡Orden borrada!',
+ 'Order saved!' => '¡Orden guardada!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Albarán',
+ 'Packing List Date missing!' => 'No se ha definido la fecha del albarán',
+ 'Packing List Number missing!' => 'No se ha definido el número del albarán',
+ 'Part' => 'Artículo',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => '¡No se encuentra el proyecto en la base de datos!',
+ 'Purchase Order' => 'Pedido',
+ 'Purchase Orders' => 'Pedidos',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Cobrado',
+ 'Remaining' => 'Resto',
+ 'Required by' => 'Aceptado el',
+ 'Sales Order' => 'Presupuesto',
+ 'Sales Orders' => 'Presupuestos',
+ 'Save' => 'Guardar',
+ 'Save as new' => 'Guardar como nuevo',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los artículos siguientes',
+ 'Select from one of the names below' => 'Seleccione uno de los nombres de la lista',
+ 'Select from one of the projects below' => 'Seleccione uno de los proyectos de la lista',
+ 'Select postscript or PDF!' => '¡Seleccione postscript o PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Envio',
+ 'Ship to' => 'Destino',
+ 'Ship via' => 'Envio por',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax Included' => 'Impuestos incluidos en el precio',
+ 'Terms: Net' => 'Crédito',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => '¡Falta el proveedor!',
+ 'Vendor not on file!' => '¡No se encuentra el proveedor en la base de datos!',
+ 'What type of item is this?' => '¿De qué tipo es este concepto?',
+ 'Yes' => 'Si',
+ 'days' => 'días',
+ 'ea' => 'unid.',
+ 'emailed to' => 'enviado por correo electrónico a',
+ 'sent to printer' => 'enviado a la impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'añadir' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'correo_electrónico' => 'e_mail',
+ 'factura' => 'invoice',
+ 'imprimir' => 'print',
+ 'guardar' => 'save',
+ 'guardar_como_nuevo' => 'save_as_new',
+ 'destino' => 'ship_to',
+ 'actualizar' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/es/pe b/sql-ledger/locale/es/pe
new file mode 100644
index 0000000..3599b7e
--- /dev/null
+++ b/sql-ledger/locale/es/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Añadir',
+ 'Add Project' => 'Añadir proyecto',
+ 'All' => 'Todos',
+ 'Continue' => 'Continuar',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Edit Project' => 'Editar proyecto',
+ 'Number' => 'Número',
+ 'Orphaned' => 'Huérfano',
+ 'Project' => 'Proyecto',
+ 'Project Number missing!' => '¡Falta el número de proyecto!',
+ 'Project deleted!' => '¡Proyecto borrado!',
+ 'Project saved!' => '¡Proyecto guardado ',
+ 'Projects' => 'Proyectos',
+ 'Save' => 'Guardar',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'añadir' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/es/rc b/sql-ledger/locale/es/rc
new file mode 100644
index 0000000..20183f1
--- /dev/null
+++ b/sql-ledger/locale/es/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Balance cerrado',
+ 'Continue' => 'Continuar',
+ 'Date' => 'Fecha',
+ 'Deposit' => 'Depósito',
+ 'Description' => 'Descripción',
+ 'Difference' => 'Diferencia',
+ 'Done' => 'Hecho',
+ 'Exchangerate Difference' => 'Diferencia en la tasa cambio a moneda extranjera',
+ 'From' => 'Desde',
+ 'Out of balance!' => '¡Fuera de balance!',
+ 'Payment' => 'Pago',
+ 'Reconciliation' => 'Reconciliación',
+ 'Select all' => 'Guardar todo',
+ 'Source' => 'Fuente',
+ 'Statement Balance' => 'Balance de cuenta',
+ 'To' => 'Hasta ',
+ 'Update' => 'Actualizar',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continuar' => 'continue',
+ 'hecho' => 'done',
+ 'guardar_todo' => 'select_all',
+ 'actualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/es/rp b/sql-ledger/locale/es/rp
new file mode 100644
index 0000000..bce27f7
--- /dev/null
+++ b/sql-ledger/locale/es/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Diario resumido de pagos',
+ 'AR Aging' => 'Diario resumido de cobros ',
+ 'Account' => 'Cuenta',
+ 'Accounts' => 'Cuentas',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance Sheet' => 'Hoja de balance',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Efectivo inicial',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Comparar con',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit' => 'Crédito',
+ 'Current' => 'Actual',
+ 'Customer' => 'Cliente',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Decimalplaces' => 'Lugar de los decimales',
+ 'Description' => 'Descripción',
+ 'Due' => 'Vence',
+ 'E-mail' => 'Correo electrónico',
+ 'E-mail Statement to' => 'Enviar comprobante por correo electrónico a',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'Código GIFI',
+ 'Heading' => 'Encabezado',
+ 'ID' => 'ID',
+ 'In-line' => 'Incrustado',
+ 'Include in Report' => 'Incluir en informe',
+ 'Income Statement' => 'Balance de situación',
+ 'Invoice' => 'Factura',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'N/A' => 'Sin respuesta',
+ 'Nothing selected!' => '¡No es seleccionado nada!',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Vencimientos impagados',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Receipts' => 'Recibos',
+ 'Report for' => 'Informe para',
+ 'Retained Earnings' => 'Ganacias retenidas',
+ 'Screen' => 'Pantalla',
+ 'Select all' => 'Guardar todo',
+ 'Select postscript or PDF!' => '¡Seleccione postscript o PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Standard' => 'Estándard',
+ 'Statement' => 'Estado de cuenta',
+ 'Statement sent to' => 'Estado de cuenta enviado a',
+ 'Statements sent to printer!' => '¡Estado de cuenta enviado a la impresora!',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax collected' => 'Impuestos cobrados',
+ 'Tax paid' => 'Impuestos pagados',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Balance de comprobación',
+ 'Vendor' => 'Proveedor',
+ 'as at' => 'al',
+ 'collected on sales' => 'ingresado en ventas',
+ 'for Period' => 'para el periodo',
+ 'paid on purchases' => 'pagado en compras',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continuar' => 'continue',
+ 'correo_electrónico' => 'e_mail',
+ 'imprimir' => 'print',
+ 'guardar_todo' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/COPYING b/sql-ledger/locale/fi/COPYING
new file mode 100644
index 0000000..823094c
--- /dev/null
+++ b/sql-ledger/locale/fi/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2002
+#
+# Finish texts:
+#
+# Author: Petri Leppänen <mpj@mail.htk.fi>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/fi/LANGUAGE b/sql-ledger/locale/fi/LANGUAGE
new file mode 100644
index 0000000..3435014
--- /dev/null
+++ b/sql-ledger/locale/fi/LANGUAGE
@@ -0,0 +1 @@
+Finnish
diff --git a/sql-ledger/locale/fi/admin b/sql-ledger/locale/fi/admin
new file mode 100644
index 0000000..b59d03b
--- /dev/null
+++ b/sql-ledger/locale/fi/admin
@@ -0,0 +1,126 @@
+$self{texts} = {
+ 'Access Control' => 'Kulunvalvonta',
+ 'Accounting' => 'Kirjanpito',
+ 'Add User' => 'Lisää käyttäjä',
+ 'Address' => 'Osoite',
+ 'Administration' => 'Ylläpito',
+ 'Administrator' => 'Pääkäyttäjä',
+ 'All Datasets up to date!' => 'Kaikki tietolähteet ajan tasalla',
+ 'Change Admin Password' => 'Muuta pääkäyttäjän salasana',
+ 'Change Password' => 'Muuta salasana',
+ 'Character Set' => 'Näppäimistökartta ',
+ 'Click on login name to edit!' => 'Klikkaa kirjautumisnimeä muokataksesi sitä!',
+ 'Company' => 'Yritys',
+ 'Connect to' => 'Yhdistä',
+ 'Continue' => 'Jatka',
+ 'Create Chart of Accounts' => 'Luo tilikartta',
+ 'Create Dataset' => 'Luo tietolähteet',
+ 'DBI not installed!' => 'DBI ei ole asennettu!',
+ 'Database' => 'Tietokanta',
+ 'Database Administration' => 'Tietokannan ylläpito',
+ 'Database Driver not checked!' => 'Tietokanta-ajuria ei ole tarkastettu',
+ 'Database User missing!' => 'Tietokannan käyttäjä puuttuu',
+ 'Dataset' => 'Tietolähde',
+ 'Dataset missing!' => 'Tietolähde puuttuu',
+ 'Dataset updated!' => 'Tietolähde päivitetty',
+ 'Date Format' => 'Päiväyksen muoto',
+ 'Delete' => 'Poista',
+ 'Delete Dataset' => 'Poista tietolähde',
+ 'Directory' => 'Hakemisto',
+ 'Driver' => 'Ajuri',
+ 'Dropdown Limit' => 'Pudotusvalikkon rivimäärä',
+ 'E-mail' => 'Sähköposti',
+ 'Edit User' => 'Muokkaa käyttäjää',
+ 'Existing Datasets' => 'Nykyiset tietolähteet',
+ 'Fax' => 'Faksi',
+ 'File locked!' => 'Tiedosto lukittu',
+ 'Host' => 'Isäntätietokone',
+ 'Hostname missing!' => 'Isäntätietokoneen nimi puuttuu',
+ 'Incorrect Password!' => 'Väärä salasana!',
+ 'Language' => 'Kieli',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Jätä isäntä- ja porttikentät tyhjiksi mikäli et halua ottaa etäyhteyttä.',
+ 'Login' => 'Kirjaudu',
+ 'Multibyte Encoding' => 'Itämaisten kielten tuki',
+ 'Name' => 'Nimi',
+ 'New Templates' => 'Uusi malli',
+ 'No Database Drivers available!' => 'Tietokanta-ajuria ei saatavilla!',
+ 'No Dataset selected!' => 'Ei tietolähdettä valittuna!',
+ 'Nothing to delete!' => 'Ei poistettavaa!',
+ 'Number Format' => 'Numeron muoto',
+ 'Oracle Database Administration' => 'Oracle-tietokannan ylläpito',
+ 'Password' => 'Salasana',
+ 'Password changed!' => 'Salasana muutettu!',
+ 'Pg Database Administration' => 'Postgres tietokannan ylläpito',
+ 'Phone' => 'Puhelin',
+ 'Port' => 'Portti',
+ 'Port missing!' => 'Portti puuttuu!',
+ 'Printer' => 'Kirjoitin',
+ 'Save' => 'Tallenna',
+ 'Select a Dataset to delete and press "Continue"' => 'Valitse poistettava tietolähde ja
+paina jatka',
+ 'Setup Templates' => 'Aseta mallit',
+ 'Ship via' => 'Lähetä kautta',
+ 'Signature' => 'Allekirjoitus',
+ 'Stylesheet' => 'Tyylimalli',
+ 'Templates' => 'Mallit',
+ 'The following Datasets are not in use and can be deleted' => 'Seuraavat tietolähteet
+eivät ole käytössä ja voidaan poistaa',
+ 'The following Datasets need to be updated' => 'Seuraavat tietolähteet päivitettävä',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Tämä on olemassa olevien lähteiden ennakkotarkistus. Mitään ei luoda tai poisteta tässä vaiheessa!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Lisätäksesi käyttäjän ryhmään muokkaa nimeä, muuta kirjautumisnimi ja tallenna.',
+ 'Update Dataset' => 'Päivitä tietolähde',
+ 'Use Templates' => 'Käytä mallia',
+ 'User' => 'Käyttäjä',
+ 'User deleted!' => 'Käyttäjä poistettu!',
+ 'User saved!' => 'Käyttäjä tallennettu!',
+ 'Version' => 'Versio',
+ 'You must enter a host and port for local and remote connections!' => 'Sinun täytyy antaa isäntäkone ja portti paikallisille ja etäyhteyksille!',
+ 'does not exist' => 'ei löydy',
+ 'is already a member!' => 'on jo käyttäjä',
+ 'localhost' => 'paikallinen tietokone',
+ 'successfully created!' => 'onnistuneesti luotu',
+ 'successfully deleted!' => 'onnistuneesti poistettu',
+ 'website' => 'www-sivu',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'lisää_käyttäjä' => 'add_user',
+ 'muuta_pääkäyttäjän_salasana' => 'change_admin_password',
+ 'muuta_salasana' => 'change_password',
+ 'jatka' => 'continue',
+ 'luo_tietolähteet' => 'create_dataset',
+ 'poista' => 'delete',
+ 'poista_tietolähde' => 'delete_dataset',
+ 'kirjaudu' => 'login',
+ 'oracle_tietokannan_ylläpito' => 'oracle_database_administration',
+ 'postgres_tietokannan_ylläpito' => 'pg_database_administration',
+ 'tallenna' => 'save',
+ 'päivitä_tietolähde' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/all b/sql-ledger/locale/fi/all
new file mode 100644
index 0000000..a3c22c5
--- /dev/null
+++ b/sql-ledger/locale/fi/all
@@ -0,0 +1,494 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Ostot',
+ 'AP Aging' => 'Erääntyvät ostolaskut',
+ 'AP Transaction' => 'Ostotapahtuma',
+ 'AP Transactions' => 'Ostotapahtumat',
+ 'AR' => 'Myynnit',
+ 'AR Aging' => 'Erääntyvät myyntilaskut',
+ 'AR Transaction' => 'Myyntitapahtuma',
+ 'AR Transactions' => 'Myyntitapahtumat',
+ 'About' => 'Lisätietoja',
+ 'Access Control' => 'Kulunvalvonta',
+ 'Account' => 'Tili',
+ 'Account Number' => 'Tilinumero',
+ 'Account Number missing!' => 'Tilinumero puuttuu',
+ 'Account Type' => 'Tilityyppi',
+ 'Account Type missing!' => 'Tilityyppi puuttuu',
+ 'Account deleted!' => 'Tili poistettu',
+ 'Account saved!' => 'Tili lisätty',
+ 'Accounting' => 'Kirjanpito',
+ 'Accounting Menu' => 'Kirjanpitovalikko',
+ 'Accounts' => 'Tilit',
+ 'Active' => 'Avoin',
+ 'Add' => 'Lisää',
+ 'Add Account' => 'Lisää tili',
+ 'Add Accounts Payables Transaction' => 'Lisää ostotapahtuma',
+ 'Add Accounts Receivables Transaction' => 'Lisää myyntitapahtuma',
+ 'Add Assembly' => 'Lisää tuote',
+ 'Add Customer' => 'Lisää asiakas',
+ 'Add GIFI' => 'Lisää GIFI',
+ 'Add General Ledger Transaction' => 'Lisää pääkirjatapahtuma',
+ 'Add Part' => 'Lisää raaka-aine/tarvike',
+ 'Add Project' => 'Lisää projekti',
+ 'Add Purchase Invoice' => 'Lisää ostolasku',
+ 'Add Purchase Order' => 'Ostotilaus',
+ 'Add Sales Invoice' => 'Lisää myyntilasku',
+ 'Add Sales Order' => 'Lisää tilausvahvistus',
+ 'Add Service' => 'Lisää palvelu',
+ 'Add Transaction' => 'Lisää tapahtuma',
+ 'Add User' => 'Lisää käyttäjä',
+ 'Add Vendor' => 'Lisää toimittaja',
+ 'Address' => 'Osoite',
+ 'Administration' => 'Ylläpito',
+ 'Administrator' => 'Pääkäyttäjä',
+ 'All' => 'Kaikki',
+ 'All Datasets up to date!' => 'Kaikki tietolähteet ajan tasalla',
+ 'Amount' => 'Summa',
+ 'Amount Due' => 'Erääntyvä summa',
+ 'Amount does not equal applied!' => 'Määrä eri kuin sovellettu',
+ 'Amount missing!' => 'Määrä puuttuu',
+ 'Applied' => 'Sovellettu',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Are you sure you want to delete Invoice Number' => 'Haluatko poistaa laskun numero?',
+ 'Are you sure you want to delete Order Number' => 'Haluatko poistaa tilauksen numero',
+ 'Are you sure you want to delete Transaction' => 'Haluatko poistaa viennin?',
+ 'Assemblies' => 'Tuotteet',
+ 'Assemblies restocked!' => 'Tuotteet viety varastoon',
+ 'Assembly Number missing!' => 'Tuotenumero puuttuu!',
+ 'Asset' => 'Vastaavaa',
+ 'Attachment' => 'Liite',
+ 'Audit Control' => 'Tilien tarkistus',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'BOM' => 'Materiaalilista',
+ 'Backup' => 'Varmuuskopio',
+ 'Backup sent to' => 'Varmuuskopio lähetetty',
+ 'Balance' => 'Tase',
+ 'Balance Sheet' => 'Taselaskelma',
+ 'Bcc' => 'Näkymätön kopio',
+ 'Bin' => 'Varastopaikka',
+ 'Books are open' => 'Kirjat ovat avoinna',
+ 'Bought' => 'Ostettu',
+ 'Business Number' => 'Y-numero',
+ 'C' => 'C',
+ 'COGS' => 'Myydyn tuotteen kulut',
+ 'Cannot delete account!' => 'Tiliä ei voi poistaa!',
+ 'Cannot delete customer!' => 'Asiakasta ei voi poistaa!',
+ 'Cannot delete default account!' => 'Oletustiliä ei voi poistaa!',
+ 'Cannot delete invoice!' => 'Laskua ei voi poistaa!',
+ 'Cannot delete item already invoiced!' => 'Laskutettua nimikettä ei voi poistaa!',
+ 'Cannot delete item on order!' => 'Nimikettä tilauksessa ei voi poistaa',
+ 'Cannot delete item which is part of an assembly!' => 'Tuotteen raaka-ainetta/tarviketta ei voi poistaa!',
+ 'Cannot delete item!' => 'Nimikettä ei voi poistaa!',
+ 'Cannot delete order!' => 'Tilausta ei voi poistaa!',
+ 'Cannot delete transaction!' => 'Vientiä ei voi poistaa',
+ 'Cannot delete vendor!' => 'Toimittajaa ei voi poistaa!',
+ 'Cannot have a value in both Debit and Credit!' => 'Arvo sekä Kreditissä että Debetissä kielletty!',
+ 'Cannot post a transaction without a value!' => 'Viennin kirjaus ilman arvoa kielletty!',
+ 'Cannot post invoice for a closed period!' => 'Laskun kirjaus suljetulle ajanjaksolle kielletty!',
+ 'Cannot post invoice!' => 'Laskua ei voi kirjata!',
+ 'Cannot post payment for a closed period!' => 'Maksun kirjaus suljetulle ajanjaksolle kielletty ',
+ 'Cannot post payment!' => 'Maksua ei voi kirjata!',
+ 'Cannot post transaction for a closed period!' => 'Viennin kirjaus suljetulle ajanjaksolle kielletty',
+ 'Cannot post transaction!' => 'Vientiä ei voi kirjata',
+ 'Cannot process payment for a closed period!' => 'Suljetun ajanjakson maksua ei voi käsitellä',
+ 'Cannot save account!' => 'Tilin tallennus ei onnistu!',
+ 'Cannot save order!' => 'Tilauksen tallennus ei onnistu!',
+ 'Cannot save preferences!' => 'Asetuksien tallennus ei onnistu!',
+ 'Cannot stock assemblies!' => 'Tuotteiden varastointi ei onnistu!',
+ 'Cash' => 'Käteiskauppa',
+ 'Cash based' => 'Käteiseen perustuva',
+ 'Cc' => 'Kopio',
+ 'Change Admin Password' => 'Muuta pääkäyttäjän salasana',
+ 'Change Password' => 'Muuta salasana',
+ 'Character Set' => 'Näppäimistökartta ',
+ 'Chart of Accounts' => 'Tilikartta',
+ 'Check' => 'Sekki',
+ 'Check printed!' => 'Sekki tulostettu!',
+ 'Check printing failed!' => 'Sekin tulostus epäonnistui!',
+ 'Cleared Balance' => 'Tarkistettu tase',
+ 'Click on login name to edit!' => 'Klikkaa kirjautumisnimeä muokataksesi sitä!',
+ 'Close Books up to' => 'Sulje kirjat hetkeen',
+ 'Closed' => 'Suljettu',
+ 'Company' => 'Yritys',
+ 'Compare to' => 'verrattuna',
+ 'Confirm!' => 'Vahvista!',
+ 'Connect to' => 'Yhdistä',
+ 'Contact' => 'Yhteyshenkilö',
+ 'Continue' => 'Jatka',
+ 'Copies' => 'Kopiot',
+ 'Copy to COA' => 'Kopioi tilikarttaan',
+ 'Create Chart of Accounts' => 'Luo tilikartta',
+ 'Create Dataset' => 'Luo tietolähteet',
+ 'Credit' => 'Kredit',
+ 'Credit Limit' => 'Luottoraja',
+ 'Curr' => 'Valuutta',
+ 'Currency' => 'Valuutta',
+ 'Current' => 'Erääntyy',
+ 'Customer' => 'Asiakas',
+ 'Customer deleted!' => 'Asiakas poistettu!',
+ 'Customer missing!' => 'Asiakas puuttuu!',
+ 'Customer not on file!' => 'Asiakas ei järjestelmässä!',
+ 'Customer saved!' => 'Asiakas tallennettu!',
+ 'Customers' => 'Asiakkaat',
+ 'DBI not installed!' => 'DBI ei ole asennettu!',
+ 'Database' => 'Tietokanta',
+ 'Database Administration' => 'Tietokannan ylläpito',
+ 'Database Driver not checked!' => 'Tietokanta-ajuria ei ole tarkastettu',
+ 'Database Host' => 'Tietokannan isäntä',
+ 'Database User missing!' => 'Tietokannan käyttäjä puuttuu',
+ 'Dataset' => 'Tietolähde',
+ 'Dataset missing!' => 'Tietolähde puuttuu',
+ 'Dataset updated!' => 'Tietolähde päivitetty',
+ 'Date' => 'Päiväys',
+ 'Date Due' => 'Eräpäivä',
+ 'Date Format' => 'Päiväyksen muoto',
+ 'Date Paid' => 'Maksupäivä',
+ 'Date missing!' => 'Päiväys puuttuu',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet ja kredit erisuuruiset',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Decimalplaces' => 'Desimaalipaikkoja',
+ 'Delete' => 'Poista',
+ 'Delete Account' => 'Poista tili',
+ 'Delete Dataset' => 'Poista tietolähde',
+ 'Delivery Date' => 'Toimituspäivä',
+ 'Deposit' => 'Rahatallennus',
+ 'Description' => 'Kuvaus',
+ 'Difference' => 'Ero',
+ 'Directory' => 'Hakemisto',
+ 'Discount' => 'Alennus',
+ 'Done' => 'Suoritettu!',
+ 'Drawing' => 'Piirros',
+ 'Driver' => 'Ajuri',
+ 'Dropdown Limit' => 'Pudotusvalikkon rivimäärä',
+ 'Due' => 'Eräpv',
+ 'Due Date' => 'Eräpäivä',
+ 'Due Date missing!' => 'Eräpäivä puuttuu!',
+ 'E-mail' => 'Sähköposti',
+ 'E-mail Statement to' => 'Sähköpostilla tiliote kenelle',
+ 'E-mail address missing!' => 'Sähköpostiosoite puuttuu!',
+ 'Edit' => 'Muokkaa',
+ 'Edit Account' => 'Muokkaa tiliä',
+ 'Edit Accounts Payables Transaction' => 'Muokkaa ostovientiä',
+ 'Edit Accounts Receivables Transaction' => 'Muokkaa myyntivientiä',
+ 'Edit Assembly' => 'Muokkaa tuotetta',
+ 'Edit Customer' => 'Muokkaa asiakas',
+ 'Edit GIFI' => 'Muokkaa GIFI',
+ 'Edit General Ledger Transaction' => 'Muokkaa pääkirjavientiä',
+ 'Edit Part' => 'Muokkaa raaka-ainetta/tarviketta',
+ 'Edit Preferences for' => 'Muokkaa asetuksia',
+ 'Edit Project' => 'Muokkaa projektia',
+ 'Edit Purchase Invoice' => 'Muokkaa ostolaskua',
+ 'Edit Purchase Order' => 'Muokkaa ostotilausta',
+ 'Edit Sales Invoice' => 'Muokkaa myyntilaskua',
+ 'Edit Sales Order' => 'Muokkaa myyntitilausta',
+ 'Edit Service' => 'Muokkaa palvelua',
+ 'Edit Template' => 'Muokkaa mallia',
+ 'Edit User' => 'Muokkaa käyttäjää',
+ 'Edit Vendor' => 'Muokkaa ',
+ 'Employee' => 'Työntekijä',
+ 'Enforce transaction reversal for all dates' => 'Pakota muunnos kaikille viennille',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Merkitse käyttämäsi valuutat 3 kirjaimella ja erota ne kaksoispisteellä, esim.(EUR:USD:SEK).',
+ 'Equity' => 'Oma pääoma',
+ 'Exch' => 'Vaihtokurssi',
+ 'Exchangerate' => 'Vaihtokurssi',
+ 'Exchangerate Difference' => 'Vaihtokurssin ero',
+ 'Exchangerate for payment missing!' => 'Maksun vaihtokurssi puuttuu',
+ 'Exchangerate missing!' => 'Vaihtokurssi puuttuu',
+ 'Existing Datasets' => 'Nykyiset tietolähteet',
+ 'Expense' => 'Menot',
+ 'Expense Account' => 'Menotili',
+ 'Expense/Asset' => 'Menot/Varat',
+ 'Extended' => 'Pidennetty',
+ 'Fax' => 'Faksi',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'File locked!' => 'Tiedosto lukittu',
+ 'Foreign Exchange Gain' => 'Vaihtokurssivoitto',
+ 'Foreign Exchange Loss' => 'Vaihtokurssitappio',
+ 'From' => 'Alkaen',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI poistettu!',
+ 'GIFI missing!' => 'GIFI puuttuu!',
+ 'GIFI saved!' => 'GIFI tallennettu!',
+ 'GL Transaction' => 'Pääkirjavienti',
+ 'General Ledger' => 'Pääkirja',
+ 'Goods & Services' => 'Hyödykkeet ja palvelut',
+ 'HTML Templates' => 'HTML mallit',
+ 'Heading' => 'Otsikko',
+ 'Host' => 'Isäntätietokone',
+ 'Hostname missing!' => 'Isäntätietokoneen nimi puuttuu',
+ 'ID' => 'ID',
+ 'Image' => 'Kuva',
+ 'In-line' => 'Linjalla',
+ 'Include in Report' => 'Sisällytä raporttiin',
+ 'Include in drop-down menus' => 'Sisällytä pudotusvalikkoon',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Liitetäänkö tämä tili
+asiakas/toimittaja-lomakkeisiin merkitäkseen hänet verokelpoiseksi!',
+ 'Income' => 'Tulot',
+ 'Income Account' => 'Tulotili',
+ 'Income Statement' => 'Tuloslaskelma',
+ 'Incorrect Dataset version!' => 'Väärä tietolähdeversio!',
+ 'Incorrect Password!' => 'Väärä salasana!',
+ 'Individual Items' => 'Yksittäiset nimikkeet',
+ 'Inventory' => 'Varasto',
+ 'Inventory Account' => 'Varastotili',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Tuotteen varaston on oltava nolla ennen asettamista epäkurantiksi!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Raaka-aineen/tarvikkeen varaston määrä on oltava nolla ennen asettamista epäkurantiksi!',
+ 'Inventory quantity must be zero!' => 'Varaston määrä on oltava nolla!',
+ 'Invoice' => 'Lasku',
+ 'Invoice Date' => 'Laskun päiväys',
+ 'Invoice Date missing!' => 'Laskun päiväys puuttuu!',
+ 'Invoice Number' => 'Laskun numero',
+ 'Invoice Number missing!' => 'Laskun numero puuttuu!',
+ 'Invoice deleted!' => 'Lasku poistettu!',
+ 'Invoice posted!' => 'Lasku kirjattu!',
+ 'Invoices' => 'Laskut',
+ 'Is this a summary account to record' => 'Onko tämä tallennettava yhteenvetotili?',
+ 'Item deleted!' => 'Nimike poistettu!',
+ 'Item not on file!' => 'Nimikettä ei ole järjestelmässä!',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'LaTeX Templates' => 'LaTeX mallit',
+ 'Language' => 'Kieli',
+ 'Last Cost' => 'Edellinen kustannus',
+ 'Last Invoice Number' => 'Edellinen laskunumero',
+ 'Last Numbers & Default Accounts' => 'Edelliset numerot ja oletustilit',
+ 'Last Purchase Order Number' => 'Edellisen ostotilauksen numero',
+ 'Last Sales Order Number' => 'Edellinen myyntinumero',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Jätä isäntä- ja porttikentät tyhjiksi mikäli et halua ottaa etäyhteyttä.',
+ 'Liability' => 'Vastattavaa',
+ 'Licensed to' => 'Lisenssin omistaja',
+ 'Line Total' => 'Rivi yhteensä',
+ 'Link' => 'Linkki',
+ 'Link Accounts' => 'Linkkaa tilit',
+ 'List Accounts' => 'Listaa tilit',
+ 'List GIFI' => 'Listaa GIFI',
+ 'List Price' => 'Listaa hinnat',
+ 'List Transactions' => 'Listaa viennit',
+ 'Login' => 'Kirjaudu',
+ 'Logout' => 'Kirjaudu ulos',
+ 'Make' => 'Valmistaja',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Message' => 'Viesti',
+ 'Microfiche' => 'Mikrokuva',
+ 'Model' => 'Tuotenimi',
+ 'Multibyte Encoding' => 'Itämaisten kielten tuki',
+ 'N/A' => 'Ei saatavilla',
+ 'Name' => 'Nimi',
+ 'Name missing!' => 'Nimi puuttuu!',
+ 'New Templates' => 'Uusi malli',
+ 'No' => 'Ei',
+ 'No Database Drivers available!' => 'Tietokanta-ajuria ei saatavilla!',
+ 'No Dataset selected!' => 'Ei tietolähdettä valittuna!',
+ 'No email address for' => 'Sähköpostiosoite puuttuu',
+ 'No.' => 'no',
+ 'Notes' => 'Lisätietoja',
+ 'Nothing applied!' => 'Mitään soveltamatta!',
+ 'Nothing selected!' => 'Mitään valitsematta!',
+ 'Nothing to delete!' => 'Ei poistettavaa!',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Number' => 'Numero',
+ 'Number Format' => 'Numeron muoto',
+ 'Number missing in Row' => 'Numero puuttuu kannan riviltä',
+ 'O' => 'O',
+ 'Obsolete' => 'Epäkurantti',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'On Hand' => 'Varastossa',
+ 'On Order' => 'Tilauksesta',
+ 'Open' => 'Avoinna',
+ 'Oracle Database Administration' => 'Oracle-tietokannan ylläpito',
+ 'Order' => 'Tilaus',
+ 'Order Date' => 'Tilauspäivämäärä',
+ 'Order Date missing!' => 'Tilauspäivämäärä puuttuu!',
+ 'Order Entry' => 'Tilauksen kirjaus',
+ 'Order Number' => 'Tilausnumero',
+ 'Order Number missing!' => 'Tilausnumero puuttuu!',
+ 'Order deleted!' => 'Tilaus poistettu!',
+ 'Order saved!' => 'Tilaus tallennettu!',
+ 'Ordered' => 'Tilattu',
+ 'Orphaned' => 'Hylätyt',
+ 'Out of balance!' => 'Ei tasapainossa',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakkauslista',
+ 'Packing List Date missing!' => 'Pakkauslistan päiväys puuttuu!',
+ 'Packing List Number missing!' => 'Pakkauslistan numero puuttuu!',
+ 'Paid' => 'Maksettu',
+ 'Paid in full' => 'Täysin maksettu',
+ 'Part' => 'Raaka-aine/tarvike',
+ 'Part Number missing!' => 'Raaka-aine/tarvikenumero puuttuu!',
+ 'Parts' => 'Raaka-aineet/tarvikkeet',
+ 'Parts Inventory' => 'Raaka-aine/tarvikevarasto',
+ 'Password' => 'Salasana',
+ 'Password changed!' => 'Salasana muutettu!',
+ 'Payables' => 'Maksettavaa',
+ 'Payment' => 'Maksu',
+ 'Payment date missing!' => 'Maksupäivä puuttuu!',
+ 'Payment posted!' => 'Maksu kirjattu!',
+ 'Payments' => 'Maksut',
+ 'Pg Database Administration' => 'Postgres tietokannan ylläpito',
+ 'Phone' => 'Puhelin',
+ 'Port' => 'Portti',
+ 'Port missing!' => 'Portti puuttuu!',
+ 'Post' => 'Kirjaa',
+ 'Post as new' => 'Kirjaa uutena',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Asetukset',
+ 'Preferences saved!' => 'Asetukset tallennettu!',
+ 'Price' => 'Hinta',
+ 'Print' => 'Tulosta',
+ 'Printer' => 'Kirjoitin',
+ 'Project' => 'Projekti',
+ 'Project Number missing!' => 'Projektinumero puuttuu!',
+ 'Project deleted!' => 'Projekti poistettu!',
+ 'Project not on file!' => 'Projekti ei ole järjestelmässä!',
+ 'Project saved!' => 'Projekti tallennettu!',
+ 'Projects' => 'Projektit',
+ 'Purchase Invoice' => 'Ostolasku',
+ 'Purchase Order' => 'Ostotilaus',
+ 'Purchase Orders' => 'Ostotilaukset',
+ 'Qty' => 'Määrä',
+ 'ROP' => 'Uudelleentilausraja',
+ 'Rate' => 'Kurssi',
+ 'Recd' => 'Vastaanotettu',
+ 'Receipt' => 'Kuitti',
+ 'Receipts' => 'Kuitit',
+ 'Receivables' => 'Saamiset',
+ 'Reconciliation' => 'Sovitus',
+ 'Record in' => 'Talleta tilille',
+ 'Reference' => 'Viite',
+ 'Reference missing!' => 'Viite puuttuu',
+ 'Remaining' => 'Jäljellä',
+ 'Report for' => 'Raportti',
+ 'Reports' => 'Raportit',
+ 'Required by' => 'Toimituspäivä',
+ 'Retained Earnings' => 'Käyttörahasto\jakamaton voitto',
+ 'Sales' => 'Myynti',
+ 'Sales Invoice' => 'Myyntilasku',
+ 'Sales Order' => 'Tilausvahvistus',
+ 'Sales Orders' => 'Tilausvahvistukset',
+ 'Save' => 'Tallenna',
+ 'Save as new' => 'Tallenna uutena',
+ 'Save to File' => 'Tallenna tiedostoon',
+ 'Screen' => 'Näyttö',
+ 'Select a Dataset to delete and press "Continue"' => 'Valitse poistettava tietolähde ja
+paina jatka',
+ 'Select all' => 'Valitse kaikki',
+ 'Select from one of the items below' => 'Valitse yksi nimike alapuolelta',
+ 'Select from one of the names below' => 'Valitse yksi nimi alapuolelta',
+ 'Select from one of the projects below' => 'Valitse yksi projekti alapuolelta',
+ 'Select postscript or PDF!' => 'Valitse postscript tai PDF',
+ 'Sell Price' => 'Myyntihinta',
+ 'Send by E-Mail' => 'Lähetä sähköpostilla',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Service' => 'Palvelu',
+ 'Service Items' => 'Palvelun nimikkeet',
+ 'Service Number missing!' => 'Palvelun numero puuttuu',
+ 'Services' => 'Palvelut',
+ 'Setup Templates' => 'Aseta mallit',
+ 'Ship' => 'Lähetä',
+ 'Ship to' => 'Toimitusosoite',
+ 'Ship via' => 'Lähetä kautta',
+ 'Short' => 'Lyhytaikaiset',
+ 'Signature' => 'Allekirjoitus',
+ 'Sold' => 'Myyty',
+ 'Source' => 'Lähde',
+ 'Standard' => 'Vakio',
+ 'Statement' => 'Tiliote',
+ 'Statement Balance' => 'Tiliotteen tase',
+ 'Statement sent to' => 'Tiliote lähetetty',
+ 'Statements sent to printer!' => 'Tiliotteet lähetetty tulostimelle!',
+ 'Stock Assembly' => 'Varastoi tuote',
+ 'Stylesheet' => 'Tyylimalli',
+ 'Subject' => 'Aihe',
+ 'Subtotal' => 'Välisumma',
+ 'System' => 'Järjestelmä',
+ 'Tax' => 'Vero',
+ 'Tax Accounts' => 'Verotilit',
+ 'Tax Included' => 'ALV sisältyy ',
+ 'Tax collected' => 'Veroa kerätty',
+ 'Tax paid' => 'Veroa maksettu ',
+ 'Taxable' => 'Verotettavaa',
+ 'Template saved!' => 'Malli tallennettu',
+ 'Templates' => 'Mallit',
+ 'Terms: Net' => 'Maksuehto',
+ 'The following Datasets are not in use and can be deleted' => 'Seuraavat tietolähteet
+eivät ole käytössä ja voidaan poistaa',
+ 'The following Datasets need to be updated' => 'Seuraavat tietolähteet päivitettävä',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Tämä on olemassa olevien lähteiden ennakkotarkistus. Mitään ei luoda tai poisteta tässä vaiheessa!',
+ 'To' => 'Hetkeen',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Lisätäksesi käyttäjän ryhmään muokkaa nimeä, muuta kirjautumisnimi ja tallenna.',
+ 'Top Level' => 'Ylin taso',
+ 'Total' => 'Yhteensä',
+ 'Transaction Date missing!' => 'Viennin päiväys puuttuu!',
+ 'Transaction deleted!' => 'Vienti poistettu!',
+ 'Transaction posted!' => 'Vienti kirjattu!',
+ 'Transaction reversal enforced for all dates' => 'Kirjaukset muunnettu kaikille päiväyksille',
+ 'Transaction reversal enforced up to' => 'Kirjaukset muunnnettu hetkeen ',
+ 'Transactions' => 'Tapahtumat',
+ 'Transactions exist, cannot delete customer!' => 'Vientejä olemassa. Asiakasta ei voi poistaa!',
+ 'Transactions exist, cannot delete vendor!' => 'Vientejä olemassa. Toimittajaa ei voi poistaa!',
+ 'Transactions exist; cannot delete account!' => 'Vientejä olemassa. Tiliä ei voi poistaa!',
+ 'Trial Balance' => 'Saldolista',
+ 'Unit' => 'Yksikkö',
+ 'Unit of measure' => 'mittayksikkö',
+ 'Update' => 'Päivitä',
+ 'Update Dataset' => 'Päivitä tietolähde',
+ 'Updated' => 'Päivitetty',
+ 'Use Templates' => 'Käytä mallia',
+ 'User' => 'Käyttäjä',
+ 'User deleted!' => 'Käyttäjä poistettu!',
+ 'User saved!' => 'Käyttäjä tallennettu!',
+ 'Vendor' => 'Toimittaja',
+ 'Vendor deleted!' => 'Toimittaja poistettu!',
+ 'Vendor missing!' => 'Toimittaja puuttuu!',
+ 'Vendor not on file!' => 'Toimittajaa ei järjestelmässä!',
+ 'Vendor saved!' => 'Toimittaja tallennettu',
+ 'Vendors' => 'Toimittajat',
+ 'Version' => 'Versio',
+ 'Weight' => 'Paino',
+ 'Weight Unit' => 'Painoyksikkö',
+ 'What type of item is this?' => 'Minkä tyyppinen nimike tämä on?',
+ 'Year End' => 'Tilikauden loppuun',
+ 'Yes' => 'Kyllä',
+ 'You are logged out!' => 'Olet poistunut järjestelmästä',
+ 'You did not enter a name!' => 'Et kirjoittanut nimeä',
+ 'You must enter a host and port for local and remote connections!' => 'Sinun täytyy antaa isäntäkone ja portti paikallisille ja etäyhteyksille!',
+ 'as at' => 'päivänä ',
+ 'collected on sales' => 'Kerätty myynneistä',
+ 'days' => 'päivää',
+ 'does not exist' => 'ei löydy',
+ 'ea' => 'kpl',
+ 'emailed to' => 'lähetetty sähköpostilla',
+ 'for Period' => 'jaksolta',
+ 'hr' => 't',
+ 'is already a member!' => 'on jo käyttäjä',
+ 'is not a member!' => 'ei ole käyttäjä',
+ 'localhost' => 'paikallinen tietokone',
+ 'paid on purchases' => 'maksettu ostoista',
+ 'sent to printer' => 'lähetetty tulostimelle',
+ 'successfully created!' => 'onnistuneesti luotu',
+ 'successfully deleted!' => 'onnistuneesti poistettu',
+ 'to' => 'Kenelle',
+ 'website' => 'www-sivu',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/am b/sql-ledger/locale/fi/am
new file mode 100644
index 0000000..061e862
--- /dev/null
+++ b/sql-ledger/locale/fi/am
@@ -0,0 +1,140 @@
+$self{texts} = {
+ 'AP' => 'Ostot',
+ 'AR' => 'Myynnit',
+ 'Account' => 'Tili',
+ 'Account Number' => 'Tilinumero',
+ 'Account Number missing!' => 'Tilinumero puuttuu',
+ 'Account Type' => 'Tilityyppi',
+ 'Account Type missing!' => 'Tilityyppi puuttuu',
+ 'Account deleted!' => 'Tili poistettu',
+ 'Account saved!' => 'Tili lisätty',
+ 'Add Account' => 'Lisää tili',
+ 'Add GIFI' => 'Lisää GIFI',
+ 'Address' => 'Osoite',
+ 'Asset' => 'Vastaavaa',
+ 'Audit Control' => 'Tilien tarkistus',
+ 'Backup sent to' => 'Varmuuskopio lähetetty',
+ 'Books are open' => 'Kirjat ovat avoinna',
+ 'Business Number' => 'Y-numero',
+ 'COGS' => 'Myydyn tuotteen kulut',
+ 'Cannot delete account!' => 'Tiliä ei voi poistaa!',
+ 'Cannot delete default account!' => 'Oletustiliä ei voi poistaa!',
+ 'Cannot save account!' => 'Tilin tallennus ei onnistu!',
+ 'Cannot save preferences!' => 'Asetuksien tallennus ei onnistu!',
+ 'Character Set' => 'Näppäimistökartta ',
+ 'Chart of Accounts' => 'Tilikartta',
+ 'Close Books up to' => 'Sulje kirjat hetkeen',
+ 'Company' => 'Yritys',
+ 'Continue' => 'Jatka',
+ 'Copy to COA' => 'Kopioi tilikarttaan',
+ 'Credit' => 'Kredit',
+ 'Date Format' => 'Päiväyksen muoto',
+ 'Debit' => 'Debet',
+ 'Delete' => 'Poista',
+ 'Delete Account' => 'Poista tili',
+ 'Description' => 'Kuvaus',
+ 'Dropdown Limit' => 'Pudotusvalikkon rivimäärä',
+ 'E-mail' => 'Sähköposti',
+ 'Edit' => 'Muokkaa',
+ 'Edit Account' => 'Muokkaa tiliä',
+ 'Edit GIFI' => 'Muokkaa GIFI',
+ 'Edit Preferences for' => 'Muokkaa asetuksia',
+ 'Edit Template' => 'Muokkaa mallia',
+ 'Enforce transaction reversal for all dates' => 'Pakota muunnos kaikille viennille',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Merkitse käyttämäsi valuutat 3 kirjaimella ja erota ne kaksoispisteellä, esim.(EUR:USD:SEK).',
+ 'Equity' => 'Oma pääoma',
+ 'Expense' => 'Menot',
+ 'Expense Account' => 'Menotili',
+ 'Expense/Asset' => 'Menot/Varat',
+ 'Fax' => 'Faksi',
+ 'Foreign Exchange Gain' => 'Vaihtokurssivoitto',
+ 'Foreign Exchange Loss' => 'Vaihtokurssitappio',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI poistettu!',
+ 'GIFI missing!' => 'GIFI puuttuu!',
+ 'GIFI saved!' => 'GIFI tallennettu!',
+ 'Heading' => 'Otsikko',
+ 'Include in drop-down menus' => 'Sisällytä pudotusvalikkoon',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Liitetäänkö tämä tili
+asiakas/toimittaja-lomakkeisiin merkitäkseen hänet verokelpoiseksi!',
+ 'Income' => 'Tulot',
+ 'Income Account' => 'Tulotili',
+ 'Inventory' => 'Varasto',
+ 'Inventory Account' => 'Varastotili',
+ 'Is this a summary account to record' => 'Onko tämä tallennettava yhteenvetotili?',
+ 'Language' => 'Kieli',
+ 'Last Invoice Number' => 'Edellinen laskunumero',
+ 'Last Numbers & Default Accounts' => 'Edelliset numerot ja oletustilit',
+ 'Last Purchase Order Number' => 'Edellisen ostotilauksen numero',
+ 'Last Sales Order Number' => 'Edellinen myyntinumero',
+ 'Liability' => 'Vastattavaa',
+ 'Link' => 'Linkki',
+ 'Name' => 'Nimi',
+ 'No' => 'Ei',
+ 'No email address for' => 'Sähköpostiosoite puuttuu',
+ 'Number' => 'Numero',
+ 'Number Format' => 'Numeron muoto',
+ 'Parts Inventory' => 'Raaka-aine/tarvikevarasto',
+ 'Password' => 'Salasana',
+ 'Payables' => 'Maksettavaa',
+ 'Payment' => 'Maksu',
+ 'Phone' => 'Puhelin',
+ 'Preferences saved!' => 'Asetukset tallennettu!',
+ 'Rate' => 'Kurssi',
+ 'Receivables' => 'Saamiset',
+ 'Sales' => 'Myynti',
+ 'Save' => 'Tallenna',
+ 'Service Items' => 'Palvelun nimikkeet',
+ 'Ship via' => 'Lähetä kautta',
+ 'Signature' => 'Allekirjoitus',
+ 'Stylesheet' => 'Tyylimalli',
+ 'Tax' => 'Vero',
+ 'Tax Accounts' => 'Verotilit',
+ 'Template saved!' => 'Malli tallennettu',
+ 'Transaction reversal enforced for all dates' => 'Kirjaukset muunnettu kaikille päiväyksille',
+ 'Transaction reversal enforced up to' => 'Kirjaukset muunnnettu hetkeen ',
+ 'Transactions exist; cannot delete account!' => 'Vientejä olemassa. Tiliä ei voi poistaa!',
+ 'Weight Unit' => 'Painoyksikkö',
+ 'Year End' => 'Tilikauden loppuun',
+ 'Yes' => 'Kyllä',
+ 'does not exist' => 'ei löydy',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'lisää_tili' => 'add_account',
+ 'jatka' => 'continue',
+ 'kopioi_tilikarttaan' => 'copy_to_coa',
+ 'poista' => 'delete',
+ 'muokkaa' => 'edit',
+ 'muokkaa_tiliä' => 'edit_account',
+ 'tallenna' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/ap b/sql-ledger/locale/fi/ap
new file mode 100644
index 0000000..ba053c8
--- /dev/null
+++ b/sql-ledger/locale/fi/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Ostotapahtuma',
+ 'AP Transactions' => 'Ostotapahtumat',
+ 'Account' => 'Tili',
+ 'Add Accounts Payables Transaction' => 'Lisää ostotapahtuma',
+ 'Address' => 'Osoite',
+ 'Amount' => 'Summa',
+ 'Amount Due' => 'Erääntyvä summa',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Are you sure you want to delete Transaction' => 'Haluatko poistaa viennin?',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'Cannot delete transaction!' => 'Vientiä ei voi poistaa',
+ 'Cannot post payment for a closed period!' => 'Maksun kirjaus suljetulle ajanjaksolle kielletty ',
+ 'Cannot post transaction for a closed period!' => 'Viennin kirjaus suljetulle ajanjaksolle kielletty',
+ 'Cannot post transaction!' => 'Vientiä ei voi kirjata',
+ 'Closed' => 'Suljettu',
+ 'Confirm!' => 'Vahvista!',
+ 'Continue' => 'Jatka',
+ 'Currency' => 'Valuutta',
+ 'Customer not on file!' => 'Asiakas ei järjestelmässä!',
+ 'Date' => 'Päiväys',
+ 'Date Paid' => 'Maksupäivä',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Delete' => 'Poista',
+ 'Description' => 'Kuvaus',
+ 'Due Date' => 'Eräpäivä',
+ 'Due Date missing!' => 'Eräpäivä puuttuu!',
+ 'Edit Accounts Payables Transaction' => 'Muokkaa ostovientiä',
+ 'Employee' => 'Työntekijä',
+ 'Exch' => 'Vaihtokurssi',
+ 'Exchangerate' => 'Vaihtokurssi',
+ 'Exchangerate for payment missing!' => 'Maksun vaihtokurssi puuttuu',
+ 'Exchangerate missing!' => 'Vaihtokurssi puuttuu',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'From' => 'Alkaen',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Sisällytä raporttiin',
+ 'Invoice' => 'Lasku',
+ 'Invoice Date' => 'Laskun päiväys',
+ 'Invoice Date missing!' => 'Laskun päiväys puuttuu!',
+ 'Invoice Number' => 'Laskun numero',
+ 'Invoice Number missing!' => 'Laskun numero puuttuu!',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Notes' => 'Lisätietoja',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Number' => 'Numero',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'Open' => 'Avoinna',
+ 'Order' => 'Tilaus',
+ 'Order Number' => 'Tilausnumero',
+ 'Paid' => 'Maksettu',
+ 'Payment date missing!' => 'Maksupäivä puuttuu!',
+ 'Payments' => 'Maksut',
+ 'Post' => 'Kirjaa',
+ 'Post as new' => 'Kirjaa uutena',
+ 'Project' => 'Projekti',
+ 'Project not on file!' => 'Projekti ei ole järjestelmässä!',
+ 'Purchase Invoice' => 'Ostolasku',
+ 'Select from one of the names below' => 'Valitse yksi nimi alapuolelta',
+ 'Select from one of the projects below' => 'Valitse yksi projekti alapuolelta',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Source' => 'Lähde',
+ 'Subtotal' => 'Välisumma',
+ 'Tax' => 'Vero',
+ 'Tax Included' => 'ALV sisältyy ',
+ 'To' => 'Hetkeen',
+ 'Total' => 'Yhteensä',
+ 'Transaction deleted!' => 'Vienti poistettu!',
+ 'Transaction posted!' => 'Vienti kirjattu!',
+ 'Update' => 'Päivitä',
+ 'Vendor' => 'Toimittaja',
+ 'Vendor missing!' => 'Toimittaja puuttuu!',
+ 'Vendor not on file!' => 'Toimittajaa ei järjestelmässä!',
+ 'Yes' => 'Kyllä',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ostotapahtuma' => 'ap_transaction',
+ 'lisää_ostotapahtuma' => 'add_accounts_payables_transaction',
+ 'jatka' => 'continue',
+ 'poista' => 'delete',
+ 'muokkaa_ostovientiä' => 'edit_accounts_payables_transaction',
+ 'kirjaa' => 'post',
+ 'kirjaa_uutena' => 'post_as_new',
+ 'ostolasku' => 'purchase_invoice',
+ 'päivitä' => 'update',
+ 'kyllä' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/ar b/sql-ledger/locale/fi/ar
new file mode 100644
index 0000000..0394021
--- /dev/null
+++ b/sql-ledger/locale/fi/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Myyntitapahtuma',
+ 'AR Transactions' => 'Myyntitapahtumat',
+ 'Account' => 'Tili',
+ 'Add Accounts Receivables Transaction' => 'Lisää myyntitapahtuma',
+ 'Address' => 'Osoite',
+ 'Amount' => 'Summa',
+ 'Amount Due' => 'Erääntyvä summa',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Are you sure you want to delete Transaction' => 'Haluatko poistaa viennin?',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'Cannot delete transaction!' => 'Vientiä ei voi poistaa',
+ 'Cannot post payment for a closed period!' => 'Maksun kirjaus suljetulle ajanjaksolle kielletty ',
+ 'Cannot post transaction for a closed period!' => 'Viennin kirjaus suljetulle ajanjaksolle kielletty',
+ 'Cannot post transaction!' => 'Vientiä ei voi kirjata',
+ 'Closed' => 'Suljettu',
+ 'Confirm!' => 'Vahvista!',
+ 'Continue' => 'Jatka',
+ 'Credit Limit' => 'Luottoraja',
+ 'Currency' => 'Valuutta',
+ 'Customer' => 'Asiakas',
+ 'Customer missing!' => 'Asiakas puuttuu!',
+ 'Customer not on file!' => 'Asiakas ei järjestelmässä!',
+ 'Date' => 'Päiväys',
+ 'Date Paid' => 'Maksupäivä',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Delete' => 'Poista',
+ 'Description' => 'Kuvaus',
+ 'Due Date' => 'Eräpäivä',
+ 'Due Date missing!' => 'Eräpäivä puuttuu!',
+ 'Edit Accounts Receivables Transaction' => 'Muokkaa myyntivientiä',
+ 'Employee' => 'Työntekijä',
+ 'Exch' => 'Vaihtokurssi',
+ 'Exchangerate' => 'Vaihtokurssi',
+ 'Exchangerate for payment missing!' => 'Maksun vaihtokurssi puuttuu',
+ 'Exchangerate missing!' => 'Vaihtokurssi puuttuu',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'From' => 'Alkaen',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Sisällytä raporttiin',
+ 'Invoice' => 'Lasku',
+ 'Invoice Date' => 'Laskun päiväys',
+ 'Invoice Date missing!' => 'Laskun päiväys puuttuu!',
+ 'Invoice Number' => 'Laskun numero',
+ 'Invoice Number missing!' => 'Laskun numero puuttuu!',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Notes' => 'Lisätietoja',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Number' => 'Numero',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'Open' => 'Avoinna',
+ 'Order' => 'Tilaus',
+ 'Order Number' => 'Tilausnumero',
+ 'Paid' => 'Maksettu',
+ 'Payment date missing!' => 'Maksupäivä puuttuu!',
+ 'Payments' => 'Maksut',
+ 'Post' => 'Kirjaa',
+ 'Post as new' => 'Kirjaa uutena',
+ 'Project' => 'Projekti',
+ 'Project not on file!' => 'Projekti ei ole järjestelmässä!',
+ 'Remaining' => 'Jäljellä',
+ 'Sales Invoice' => 'Myyntilasku',
+ 'Select from one of the names below' => 'Valitse yksi nimi alapuolelta',
+ 'Select from one of the projects below' => 'Valitse yksi projekti alapuolelta',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Source' => 'Lähde',
+ 'Subtotal' => 'Välisumma',
+ 'Tax' => 'Vero',
+ 'Tax Included' => 'ALV sisältyy ',
+ 'To' => 'Hetkeen',
+ 'Total' => 'Yhteensä',
+ 'Transaction deleted!' => 'Vienti poistettu!',
+ 'Transaction posted!' => 'Vienti kirjattu!',
+ 'Update' => 'Päivitä',
+ 'Vendor not on file!' => 'Toimittajaa ei järjestelmässä!',
+ 'Yes' => 'Kyllä',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'myyntitapahtuma' => 'ar_transaction',
+ 'jatka' => 'continue',
+ 'poista' => 'delete',
+ 'kirjaa' => 'post',
+ 'kirjaa_uutena' => 'post_as_new',
+ 'myyntilasku' => 'sales_invoice',
+ 'päivitä' => 'update',
+ 'kyllä' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/arap b/sql-ledger/locale/fi/arap
new file mode 100644
index 0000000..8ba26e1
--- /dev/null
+++ b/sql-ledger/locale/fi/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Osoite',
+ 'Continue' => 'Jatka',
+ 'Customer not on file!' => 'Asiakas ei järjestelmässä!',
+ 'Description' => 'Kuvaus',
+ 'Number' => 'Numero',
+ 'Project not on file!' => 'Projekti ei ole järjestelmässä!',
+ 'Select from one of the names below' => 'Valitse yksi nimi alapuolelta',
+ 'Select from one of the projects below' => 'Valitse yksi projekti alapuolelta',
+ 'Vendor not on file!' => 'Toimittajaa ei järjestelmässä!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'jatka' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/ca b/sql-ledger/locale/fi/ca
new file mode 100644
index 0000000..c5f3b37
--- /dev/null
+++ b/sql-ledger/locale/fi/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Tili',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'Balance' => 'Tase',
+ 'Chart of Accounts' => 'Tilikartta',
+ 'Credit' => 'Kredit',
+ 'Date' => 'Päiväys',
+ 'Debit' => 'Debet',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Description' => 'Kuvaus',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'From' => 'Alkaen',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Sisällytä raporttiin',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'List Transactions' => 'Listaa viennit',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'Reference' => 'Viite',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Subtotal' => 'Välisumma',
+ 'To' => 'Hetkeen',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'listaa_viennit' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/cp b/sql-ledger/locale/fi/cp
new file mode 100644
index 0000000..202e8cf
--- /dev/null
+++ b/sql-ledger/locale/fi/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Tili',
+ 'Address' => 'Osoite',
+ 'Amount' => 'Summa',
+ 'Amount does not equal applied!' => 'Määrä eri kuin sovellettu',
+ 'Amount missing!' => 'Määrä puuttuu',
+ 'Applied' => 'Sovellettu',
+ 'Cannot post payment!' => 'Maksua ei voi kirjata!',
+ 'Cannot process payment for a closed period!' => 'Suljetun ajanjakson maksua ei voi käsitellä',
+ 'Check' => 'Sekki',
+ 'Check printed!' => 'Sekki tulostettu!',
+ 'Check printing failed!' => 'Sekin tulostus epäonnistui!',
+ 'Continue' => 'Jatka',
+ 'Currency' => 'Valuutta',
+ 'Customer' => 'Asiakas',
+ 'Customer not on file!' => 'Asiakas ei järjestelmässä!',
+ 'Date' => 'Päiväys',
+ 'Date missing!' => 'Päiväys puuttuu',
+ 'Description' => 'Kuvaus',
+ 'Due' => 'Eräpv',
+ 'Exchangerate' => 'Vaihtokurssi',
+ 'From' => 'Alkaen',
+ 'Invoice' => 'Lasku',
+ 'Invoices' => 'Laskut',
+ 'Nothing applied!' => 'Mitään soveltamatta!',
+ 'Number' => 'Numero',
+ 'Paid in full' => 'Täysin maksettu',
+ 'Payment' => 'Maksu',
+ 'Payment posted!' => 'Maksu kirjattu!',
+ 'Post' => 'Kirjaa',
+ 'Print' => 'Tulosta',
+ 'Printer' => 'Kirjoitin',
+ 'Project not on file!' => 'Projekti ei ole järjestelmässä!',
+ 'Receipt' => 'Kuitti',
+ 'Reference' => 'Viite',
+ 'Screen' => 'Näyttö',
+ 'Select from one of the names below' => 'Valitse yksi nimi alapuolelta',
+ 'Select from one of the projects below' => 'Valitse yksi projekti alapuolelta',
+ 'To' => 'Hetkeen',
+ 'Update' => 'Päivitä',
+ 'Vendor' => 'Toimittaja',
+ 'Vendor not on file!' => 'Toimittajaa ei järjestelmässä!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'jatka' => 'continue',
+ 'kirjaa' => 'post',
+ 'tulosta' => 'print',
+ 'päivitä' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/ct b/sql-ledger/locale/fi/ct
new file mode 100644
index 0000000..186b25d
--- /dev/null
+++ b/sql-ledger/locale/fi/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Lisää',
+ 'Address' => 'Osoite',
+ 'All' => 'Kaikki',
+ 'Bcc' => 'Näkymätön kopio',
+ 'Cannot delete customer!' => 'Asiakasta ei voi poistaa!',
+ 'Cannot delete vendor!' => 'Toimittajaa ei voi poistaa!',
+ 'Cc' => 'Kopio',
+ 'Contact' => 'Yhteyshenkilö',
+ 'Continue' => 'Jatka',
+ 'Credit Limit' => 'Luottoraja',
+ 'Customer deleted!' => 'Asiakas poistettu!',
+ 'Customer saved!' => 'Asiakas tallennettu!',
+ 'Customers' => 'Asiakkaat',
+ 'Delete' => 'Poista',
+ 'Discount' => 'Alennus',
+ 'E-mail' => 'Sähköposti',
+ 'Edit Customer' => 'Muokkaa asiakas',
+ 'Edit Vendor' => 'Muokkaa ',
+ 'Fax' => 'Faksi',
+ 'Include in Report' => 'Sisällytä raporttiin',
+ 'Invoice' => 'Lasku',
+ 'Name' => 'Nimi',
+ 'Name missing!' => 'Nimi puuttuu!',
+ 'Notes' => 'Lisätietoja',
+ 'Number' => 'Numero',
+ 'Order' => 'Tilaus',
+ 'Orphaned' => 'Hylätyt',
+ 'Phone' => 'Puhelin',
+ 'Save' => 'Tallenna',
+ 'Ship to' => 'Toimitusosoite',
+ 'Tax Included' => 'ALV sisältyy ',
+ 'Taxable' => 'Verotettavaa',
+ 'Terms: Net' => 'Maksuehto',
+ 'Transactions exist, cannot delete customer!' => 'Vientejä olemassa. Asiakasta ei voi poistaa!',
+ 'Transactions exist, cannot delete vendor!' => 'Vientejä olemassa. Toimittajaa ei voi poistaa!',
+ 'Vendor deleted!' => 'Toimittaja poistettu!',
+ 'Vendor saved!' => 'Toimittaja tallennettu',
+ 'Vendors' => 'Toimittajat',
+ 'days' => 'päivää',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'lisää' => 'add',
+ 'jatka' => 'continue',
+ 'poista' => 'delete',
+ 'lasku' => 'invoice',
+ 'tilaus' => 'order',
+ 'tallenna' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/gl b/sql-ledger/locale/fi/gl
new file mode 100644
index 0000000..6a07b15
--- /dev/null
+++ b/sql-ledger/locale/fi/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Ostotapahtuma',
+ 'AR Transaction' => 'Myyntitapahtuma',
+ 'Account' => 'Tili',
+ 'Add General Ledger Transaction' => 'Lisää pääkirjatapahtuma',
+ 'Address' => 'Osoite',
+ 'All' => 'Kaikki',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Are you sure you want to delete Transaction' => 'Haluatko poistaa viennin?',
+ 'Asset' => 'Vastaavaa',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'Balance' => 'Tase',
+ 'Cannot delete transaction!' => 'Vientiä ei voi poistaa',
+ 'Cannot have a value in both Debit and Credit!' => 'Arvo sekä Kreditissä että Debetissä kielletty!',
+ 'Cannot post a transaction without a value!' => 'Viennin kirjaus ilman arvoa kielletty!',
+ 'Cannot post transaction for a closed period!' => 'Viennin kirjaus suljetulle ajanjaksolle kielletty',
+ 'Confirm!' => 'Vahvista!',
+ 'Continue' => 'Jatka',
+ 'Credit' => 'Kredit',
+ 'Customer not on file!' => 'Asiakas ei järjestelmässä!',
+ 'Date' => 'Päiväys',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet ja kredit erisuuruiset',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Delete' => 'Poista',
+ 'Description' => 'Kuvaus',
+ 'Edit General Ledger Transaction' => 'Muokkaa pääkirjavientiä',
+ 'Equity' => 'Oma pääoma',
+ 'Expense' => 'Menot',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'From' => 'Alkaen',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'Pääkirjavienti',
+ 'General Ledger' => 'Pääkirja',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Sisällytä raporttiin',
+ 'Income' => 'Tulot',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'Liability' => 'Vastattavaa',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Notes' => 'Lisätietoja',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Number' => 'Numero',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'Post' => 'Kirjaa',
+ 'Post as new' => 'Kirjaa uutena',
+ 'Project' => 'Projekti',
+ 'Project not on file!' => 'Projekti ei ole järjestelmässä!',
+ 'Purchase Invoice' => 'Ostolasku',
+ 'Reference' => 'Viite',
+ 'Reference missing!' => 'Viite puuttuu',
+ 'Reports' => 'Raportit',
+ 'Sales Invoice' => 'Myyntilasku',
+ 'Select from one of the names below' => 'Valitse yksi nimi alapuolelta',
+ 'Select from one of the projects below' => 'Valitse yksi projekti alapuolelta',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Source' => 'Lähde',
+ 'Subtotal' => 'Välisumma',
+ 'To' => 'Hetkeen',
+ 'Transaction Date missing!' => 'Viennin päiväys puuttuu!',
+ 'Transaction deleted!' => 'Vienti poistettu!',
+ 'Transaction posted!' => 'Vienti kirjattu!',
+ 'Update' => 'Päivitä',
+ 'Vendor not on file!' => 'Toimittajaa ei järjestelmässä!',
+ 'Yes' => 'Kyllä',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ostotapahtuma' => 'ap_transaction',
+ 'myyntitapahtuma' => 'ar_transaction',
+ 'jatka' => 'continue',
+ 'poista' => 'delete',
+ 'pääkirjavienti' => 'gl_transaction',
+ 'kirjaa' => 'post',
+ 'kirjaa_uutena' => 'post_as_new',
+ 'ostolasku' => 'purchase_invoice',
+ 'myyntilasku' => 'sales_invoice',
+ 'päivitä' => 'update',
+ 'kyllä' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/ic b/sql-ledger/locale/fi/ic
new file mode 100644
index 0000000..55f37a1
--- /dev/null
+++ b/sql-ledger/locale/fi/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Avoin',
+ 'Add' => 'Lisää',
+ 'Add Assembly' => 'Lisää tuote',
+ 'Add Part' => 'Lisää raaka-aine/tarvike',
+ 'Add Purchase Order' => 'Ostotilaus',
+ 'Add Sales Order' => 'Lisää tilausvahvistus',
+ 'Add Service' => 'Lisää palvelu',
+ 'Address' => 'Osoite',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Assemblies' => 'Tuotteet',
+ 'Assemblies restocked!' => 'Tuotteet viety varastoon',
+ 'Assembly Number missing!' => 'Tuotenumero puuttuu!',
+ 'Attachment' => 'Liite',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'BOM' => 'Materiaalilista',
+ 'Bcc' => 'Näkymätön kopio',
+ 'Bin' => 'Varastopaikka',
+ 'Bought' => 'Ostettu',
+ 'COGS' => 'Myydyn tuotteen kulut',
+ 'Cannot delete item already invoiced!' => 'Laskutettua nimikettä ei voi poistaa!',
+ 'Cannot delete item on order!' => 'Nimikettä tilauksessa ei voi poistaa',
+ 'Cannot delete item which is part of an assembly!' => 'Tuotteen raaka-ainetta/tarviketta ei voi poistaa!',
+ 'Cannot delete item!' => 'Nimikettä ei voi poistaa!',
+ 'Cannot stock assemblies!' => 'Tuotteiden varastointi ei onnistu!',
+ 'Cc' => 'Kopio',
+ 'Contact' => 'Yhteyshenkilö',
+ 'Continue' => 'Jatka',
+ 'Copies' => 'Kopiot',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Delete' => 'Poista',
+ 'Delivery Date' => 'Toimituspäivä',
+ 'Description' => 'Kuvaus',
+ 'Drawing' => 'Piirros',
+ 'E-mail' => 'Sähköposti',
+ 'E-mail address missing!' => 'Sähköpostiosoite puuttuu!',
+ 'Edit Assembly' => 'Muokkaa tuotetta',
+ 'Edit Part' => 'Muokkaa raaka-ainetta/tarviketta',
+ 'Edit Service' => 'Muokkaa palvelua',
+ 'Expense' => 'Menot',
+ 'Extended' => 'Pidennetty',
+ 'Fax' => 'Faksi',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'From' => 'Alkaen',
+ 'Image' => 'Kuva',
+ 'In-line' => 'Linjalla',
+ 'Include in Report' => 'Sisällytä raporttiin',
+ 'Income' => 'Tulot',
+ 'Individual Items' => 'Yksittäiset nimikkeet',
+ 'Inventory' => 'Varasto',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Tuotteen varaston on oltava nolla ennen asettamista epäkurantiksi!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Raaka-aineen/tarvikkeen varaston määrä on oltava nolla ennen asettamista epäkurantiksi!',
+ 'Inventory quantity must be zero!' => 'Varaston määrä on oltava nolla!',
+ 'Invoice' => 'Lasku',
+ 'Invoice Date missing!' => 'Laskun päiväys puuttuu!',
+ 'Invoice Number' => 'Laskun numero',
+ 'Invoice Number missing!' => 'Laskun numero puuttuu!',
+ 'Item deleted!' => 'Nimike poistettu!',
+ 'Item not on file!' => 'Nimikettä ei ole järjestelmässä!',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'Last Cost' => 'Edellinen kustannus',
+ 'Line Total' => 'Rivi yhteensä',
+ 'Link Accounts' => 'Linkkaa tilit',
+ 'List Price' => 'Listaa hinnat',
+ 'Make' => 'Valmistaja',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Message' => 'Viesti',
+ 'Microfiche' => 'Mikrokuva',
+ 'Model' => 'Tuotenimi',
+ 'Name' => 'Nimi',
+ 'No.' => 'no',
+ 'Notes' => 'Lisätietoja',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Numero puuttuu kannan riviltä',
+ 'Obsolete' => 'Epäkurantti',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'On Hand' => 'Varastossa',
+ 'On Order' => 'Tilauksesta',
+ 'Order' => 'Tilaus',
+ 'Order Date missing!' => 'Tilauspäivämäärä puuttuu!',
+ 'Order Number' => 'Tilausnumero',
+ 'Order Number missing!' => 'Tilausnumero puuttuu!',
+ 'Ordered' => 'Tilattu',
+ 'Orphaned' => 'Hylätyt',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakkauslista',
+ 'Packing List Date missing!' => 'Pakkauslistan päiväys puuttuu!',
+ 'Packing List Number missing!' => 'Pakkauslistan numero puuttuu!',
+ 'Part' => 'Raaka-aine/tarvike',
+ 'Part Number missing!' => 'Raaka-aine/tarvikenumero puuttuu!',
+ 'Parts' => 'Raaka-aineet/tarvikkeet',
+ 'Phone' => 'Puhelin',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hinta',
+ 'Printer' => 'Kirjoitin',
+ 'Project' => 'Projekti',
+ 'Purchase Order' => 'Ostotilaus',
+ 'Qty' => 'Määrä',
+ 'ROP' => 'Uudelleentilausraja',
+ 'Recd' => 'Vastaanotettu',
+ 'Required by' => 'Toimituspäivä',
+ 'Sales' => 'Myynti',
+ 'Sales Order' => 'Tilausvahvistus',
+ 'Save' => 'Tallenna',
+ 'Screen' => 'Näyttö',
+ 'Select from one of the items below' => 'Valitse yksi nimike alapuolelta',
+ 'Select postscript or PDF!' => 'Valitse postscript tai PDF',
+ 'Sell Price' => 'Myyntihinta',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Service' => 'Palvelu',
+ 'Service Number missing!' => 'Palvelun numero puuttuu',
+ 'Services' => 'Palvelut',
+ 'Ship' => 'Lähetä',
+ 'Ship to' => 'Toimitusosoite',
+ 'Short' => 'Lyhytaikaiset',
+ 'Sold' => 'Myyty',
+ 'Stock Assembly' => 'Varastoi tuote',
+ 'Subject' => 'Aihe',
+ 'Subtotal' => 'Välisumma',
+ 'Tax' => 'Vero',
+ 'To' => 'Hetkeen',
+ 'Top Level' => 'Ylin taso',
+ 'Total' => 'Yhteensä',
+ 'Unit' => 'Yksikkö',
+ 'Unit of measure' => 'mittayksikkö',
+ 'Update' => 'Päivitä',
+ 'Updated' => 'Päivitetty',
+ 'Weight' => 'Paino',
+ 'What type of item is this?' => 'Minkä tyyppinen nimike tämä on?',
+ 'ea' => 'kpl',
+ 'emailed to' => 'lähetetty sähköpostilla',
+ 'hr' => 't',
+ 'sent to printer' => 'lähetetty tulostimelle',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'lisää' => 'add',
+ 'lisää_tuote' => 'add_assembly',
+ 'lisää_raaka_aine/tarvike' => 'add_part',
+ 'lisää_palvelu' => 'add_service',
+ 'jatka' => 'continue',
+ 'poista' => 'delete',
+ 'muokkaa_tuotetta' => 'edit_assembly',
+ 'muokkaa_raaka_ainetta/tarviketta' => 'edit_part',
+ 'muokkaa_palvelua' => 'edit_service',
+ 'tallenna' => 'save',
+ 'päivitä' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/io b/sql-ledger/locale/fi/io
new file mode 100644
index 0000000..cc147a8
--- /dev/null
+++ b/sql-ledger/locale/fi/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Ostotilaus',
+ 'Add Sales Order' => 'Lisää tilausvahvistus',
+ 'Address' => 'Osoite',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Attachment' => 'Liite',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'Bcc' => 'Näkymätön kopio',
+ 'Bin' => 'Varastopaikka',
+ 'Cc' => 'Kopio',
+ 'Contact' => 'Yhteyshenkilö',
+ 'Continue' => 'Jatka',
+ 'Copies' => 'Kopiot',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Delivery Date' => 'Toimituspäivä',
+ 'Description' => 'Kuvaus',
+ 'E-mail' => 'Sähköposti',
+ 'E-mail address missing!' => 'Sähköpostiosoite puuttuu!',
+ 'Extended' => 'Pidennetty',
+ 'Fax' => 'Faksi',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'In-line' => 'Linjalla',
+ 'Invoice' => 'Lasku',
+ 'Invoice Date missing!' => 'Laskun päiväys puuttuu!',
+ 'Invoice Number missing!' => 'Laskun numero puuttuu!',
+ 'Item not on file!' => 'Nimikettä ei ole järjestelmässä!',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Message' => 'Viesti',
+ 'Name' => 'Nimi',
+ 'No.' => 'no',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Numero puuttuu kannan riviltä',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'Order' => 'Tilaus',
+ 'Order Date missing!' => 'Tilauspäivämäärä puuttuu!',
+ 'Order Number missing!' => 'Tilausnumero puuttuu!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakkauslista',
+ 'Packing List Date missing!' => 'Pakkauslistan päiväys puuttuu!',
+ 'Packing List Number missing!' => 'Pakkauslistan numero puuttuu!',
+ 'Part' => 'Raaka-aine/tarvike',
+ 'Phone' => 'Puhelin',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hinta',
+ 'Printer' => 'Kirjoitin',
+ 'Project' => 'Projekti',
+ 'Purchase Order' => 'Ostotilaus',
+ 'Qty' => 'Määrä',
+ 'Recd' => 'Vastaanotettu',
+ 'Required by' => 'Toimituspäivä',
+ 'Sales Order' => 'Tilausvahvistus',
+ 'Screen' => 'Näyttö',
+ 'Select from one of the items below' => 'Valitse yksi nimike alapuolelta',
+ 'Select postscript or PDF!' => 'Valitse postscript tai PDF',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Service' => 'Palvelu',
+ 'Ship' => 'Lähetä',
+ 'Ship to' => 'Toimitusosoite',
+ 'Subject' => 'Aihe',
+ 'To' => 'Hetkeen',
+ 'Unit' => 'Yksikkö',
+ 'What type of item is this?' => 'Minkä tyyppinen nimike tämä on?',
+ 'emailed to' => 'lähetetty sähköpostilla',
+ 'sent to printer' => 'lähetetty tulostimelle',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'jatka' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/ir b/sql-ledger/locale/fi/ir
new file mode 100644
index 0000000..1070f99
--- /dev/null
+++ b/sql-ledger/locale/fi/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Tili',
+ 'Add Purchase Invoice' => 'Lisää ostolasku',
+ 'Add Purchase Order' => 'Ostotilaus',
+ 'Add Sales Order' => 'Lisää tilausvahvistus',
+ 'Address' => 'Osoite',
+ 'Amount' => 'Summa',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Are you sure you want to delete Invoice Number' => 'Haluatko poistaa laskun numero?',
+ 'Attachment' => 'Liite',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'Bcc' => 'Näkymätön kopio',
+ 'Bin' => 'Varastopaikka',
+ 'Cannot delete invoice!' => 'Laskua ei voi poistaa!',
+ 'Cannot post invoice for a closed period!' => 'Laskun kirjaus suljetulle ajanjaksolle kielletty!',
+ 'Cannot post invoice!' => 'Laskua ei voi kirjata!',
+ 'Cannot post payment for a closed period!' => 'Maksun kirjaus suljetulle ajanjaksolle kielletty ',
+ 'Cc' => 'Kopio',
+ 'Confirm!' => 'Vahvista!',
+ 'Contact' => 'Yhteyshenkilö',
+ 'Continue' => 'Jatka',
+ 'Copies' => 'Kopiot',
+ 'Currency' => 'Valuutta',
+ 'Customer not on file!' => 'Asiakas ei järjestelmässä!',
+ 'Date' => 'Päiväys',
+ 'Date Due' => 'Eräpäivä',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Delete' => 'Poista',
+ 'Delivery Date' => 'Toimituspäivä',
+ 'Description' => 'Kuvaus',
+ 'E-mail' => 'Sähköposti',
+ 'E-mail address missing!' => 'Sähköpostiosoite puuttuu!',
+ 'Edit Purchase Invoice' => 'Muokkaa ostolaskua',
+ 'Exch' => 'Vaihtokurssi',
+ 'Exchangerate' => 'Vaihtokurssi',
+ 'Exchangerate for payment missing!' => 'Maksun vaihtokurssi puuttuu',
+ 'Exchangerate missing!' => 'Vaihtokurssi puuttuu',
+ 'Extended' => 'Pidennetty',
+ 'Fax' => 'Faksi',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'In-line' => 'Linjalla',
+ 'Invoice' => 'Lasku',
+ 'Invoice Date' => 'Laskun päiväys',
+ 'Invoice Date missing!' => 'Laskun päiväys puuttuu!',
+ 'Invoice Number' => 'Laskun numero',
+ 'Invoice Number missing!' => 'Laskun numero puuttuu!',
+ 'Invoice deleted!' => 'Lasku poistettu!',
+ 'Invoice posted!' => 'Lasku kirjattu!',
+ 'Item not on file!' => 'Nimikettä ei ole järjestelmässä!',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Message' => 'Viesti',
+ 'Name' => 'Nimi',
+ 'No.' => 'no',
+ 'Notes' => 'Lisätietoja',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Numero puuttuu kannan riviltä',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'Order' => 'Tilaus',
+ 'Order Date missing!' => 'Tilauspäivämäärä puuttuu!',
+ 'Order Number' => 'Tilausnumero',
+ 'Order Number missing!' => 'Tilausnumero puuttuu!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakkauslista',
+ 'Packing List Date missing!' => 'Pakkauslistan päiväys puuttuu!',
+ 'Packing List Number missing!' => 'Pakkauslistan numero puuttuu!',
+ 'Part' => 'Raaka-aine/tarvike',
+ 'Payment date missing!' => 'Maksupäivä puuttuu!',
+ 'Payments' => 'Maksut',
+ 'Phone' => 'Puhelin',
+ 'Post' => 'Kirjaa',
+ 'Post as new' => 'Kirjaa uutena',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hinta',
+ 'Printer' => 'Kirjoitin',
+ 'Project' => 'Projekti',
+ 'Project not on file!' => 'Projekti ei ole järjestelmässä!',
+ 'Purchase Order' => 'Ostotilaus',
+ 'Qty' => 'Määrä',
+ 'Recd' => 'Vastaanotettu',
+ 'Record in' => 'Talleta tilille',
+ 'Required by' => 'Toimituspäivä',
+ 'Sales Order' => 'Tilausvahvistus',
+ 'Screen' => 'Näyttö',
+ 'Select from one of the items below' => 'Valitse yksi nimike alapuolelta',
+ 'Select from one of the names below' => 'Valitse yksi nimi alapuolelta',
+ 'Select from one of the projects below' => 'Valitse yksi projekti alapuolelta',
+ 'Select postscript or PDF!' => 'Valitse postscript tai PDF',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Service' => 'Palvelu',
+ 'Ship' => 'Lähetä',
+ 'Ship to' => 'Toimitusosoite',
+ 'Source' => 'Lähde',
+ 'Subject' => 'Aihe',
+ 'Subtotal' => 'Välisumma',
+ 'Tax Included' => 'ALV sisältyy ',
+ 'To' => 'Hetkeen',
+ 'Total' => 'Yhteensä',
+ 'Unit' => 'Yksikkö',
+ 'Update' => 'Päivitä',
+ 'Vendor' => 'Toimittaja',
+ 'Vendor missing!' => 'Toimittaja puuttuu!',
+ 'Vendor not on file!' => 'Toimittajaa ei järjestelmässä!',
+ 'What type of item is this?' => 'Minkä tyyppinen nimike tämä on?',
+ 'Yes' => 'Kyllä',
+ 'ea' => 'kpl',
+ 'emailed to' => 'lähetetty sähköpostilla',
+ 'sent to printer' => 'lähetetty tulostimelle',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'jatka' => 'continue',
+ 'poista' => 'delete',
+ 'tilaus' => 'order',
+ 'kirjaa' => 'post',
+ 'kirjaa_uutena' => 'post_as_new',
+ 'päivitä' => 'update',
+ 'kyllä' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/is b/sql-ledger/locale/fi/is
new file mode 100644
index 0000000..da492f9
--- /dev/null
+++ b/sql-ledger/locale/fi/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Tili',
+ 'Add Purchase Order' => 'Ostotilaus',
+ 'Add Sales Invoice' => 'Lisää myyntilasku',
+ 'Add Sales Order' => 'Lisää tilausvahvistus',
+ 'Address' => 'Osoite',
+ 'Amount' => 'Summa',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Are you sure you want to delete Invoice Number' => 'Haluatko poistaa laskun numero?',
+ 'Attachment' => 'Liite',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'Bcc' => 'Näkymätön kopio',
+ 'Bin' => 'Varastopaikka',
+ 'Cannot delete invoice!' => 'Laskua ei voi poistaa!',
+ 'Cannot post invoice for a closed period!' => 'Laskun kirjaus suljetulle ajanjaksolle kielletty!',
+ 'Cannot post invoice!' => 'Laskua ei voi kirjata!',
+ 'Cannot post payment for a closed period!' => 'Maksun kirjaus suljetulle ajanjaksolle kielletty ',
+ 'Cc' => 'Kopio',
+ 'Confirm!' => 'Vahvista!',
+ 'Contact' => 'Yhteyshenkilö',
+ 'Continue' => 'Jatka',
+ 'Copies' => 'Kopiot',
+ 'Credit Limit' => 'Luottoraja',
+ 'Currency' => 'Valuutta',
+ 'Customer' => 'Asiakas',
+ 'Customer missing!' => 'Asiakas puuttuu!',
+ 'Customer not on file!' => 'Asiakas ei järjestelmässä!',
+ 'Date' => 'Päiväys',
+ 'Date Due' => 'Eräpäivä',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Delete' => 'Poista',
+ 'Delivery Date' => 'Toimituspäivä',
+ 'Description' => 'Kuvaus',
+ 'E-mail' => 'Sähköposti',
+ 'E-mail address missing!' => 'Sähköpostiosoite puuttuu!',
+ 'Edit Sales Invoice' => 'Muokkaa myyntilaskua',
+ 'Exch' => 'Vaihtokurssi',
+ 'Exchangerate' => 'Vaihtokurssi',
+ 'Exchangerate for payment missing!' => 'Maksun vaihtokurssi puuttuu',
+ 'Exchangerate missing!' => 'Vaihtokurssi puuttuu',
+ 'Extended' => 'Pidennetty',
+ 'Fax' => 'Faksi',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'In-line' => 'Linjalla',
+ 'Invoice' => 'Lasku',
+ 'Invoice Date' => 'Laskun päiväys',
+ 'Invoice Date missing!' => 'Laskun päiväys puuttuu!',
+ 'Invoice Number' => 'Laskun numero',
+ 'Invoice Number missing!' => 'Laskun numero puuttuu!',
+ 'Invoice deleted!' => 'Lasku poistettu!',
+ 'Invoice posted!' => 'Lasku kirjattu!',
+ 'Item not on file!' => 'Nimikettä ei ole järjestelmässä!',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Message' => 'Viesti',
+ 'Name' => 'Nimi',
+ 'No.' => 'no',
+ 'Notes' => 'Lisätietoja',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Numero puuttuu kannan riviltä',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'Order' => 'Tilaus',
+ 'Order Date missing!' => 'Tilauspäivämäärä puuttuu!',
+ 'Order Number' => 'Tilausnumero',
+ 'Order Number missing!' => 'Tilausnumero puuttuu!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakkauslista',
+ 'Packing List Date missing!' => 'Pakkauslistan päiväys puuttuu!',
+ 'Packing List Number missing!' => 'Pakkauslistan numero puuttuu!',
+ 'Part' => 'Raaka-aine/tarvike',
+ 'Payment date missing!' => 'Maksupäivä puuttuu!',
+ 'Payments' => 'Maksut',
+ 'Phone' => 'Puhelin',
+ 'Post' => 'Kirjaa',
+ 'Post as new' => 'Kirjaa uutena',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hinta',
+ 'Print' => 'Tulosta',
+ 'Printer' => 'Kirjoitin',
+ 'Project' => 'Projekti',
+ 'Project not on file!' => 'Projekti ei ole järjestelmässä!',
+ 'Purchase Order' => 'Ostotilaus',
+ 'Qty' => 'Määrä',
+ 'Recd' => 'Vastaanotettu',
+ 'Record in' => 'Talleta tilille',
+ 'Remaining' => 'Jäljellä',
+ 'Required by' => 'Toimituspäivä',
+ 'Sales Order' => 'Tilausvahvistus',
+ 'Screen' => 'Näyttö',
+ 'Select from one of the items below' => 'Valitse yksi nimike alapuolelta',
+ 'Select from one of the names below' => 'Valitse yksi nimi alapuolelta',
+ 'Select from one of the projects below' => 'Valitse yksi projekti alapuolelta',
+ 'Select postscript or PDF!' => 'Valitse postscript tai PDF',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Service' => 'Palvelu',
+ 'Ship' => 'Lähetä',
+ 'Ship to' => 'Toimitusosoite',
+ 'Ship via' => 'Lähetä kautta',
+ 'Source' => 'Lähde',
+ 'Subject' => 'Aihe',
+ 'Subtotal' => 'Välisumma',
+ 'Tax Included' => 'ALV sisältyy ',
+ 'To' => 'Hetkeen',
+ 'Total' => 'Yhteensä',
+ 'Unit' => 'Yksikkö',
+ 'Update' => 'Päivitä',
+ 'Vendor not on file!' => 'Toimittajaa ei järjestelmässä!',
+ 'What type of item is this?' => 'Minkä tyyppinen nimike tämä on?',
+ 'Yes' => 'Kyllä',
+ 'ea' => 'kpl',
+ 'emailed to' => 'lähetetty sähköpostilla',
+ 'sent to printer' => 'lähetetty tulostimelle',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'jatka' => 'continue',
+ 'poista' => 'delete',
+ 'sähköposti' => 'e_mail',
+ 'tilaus' => 'order',
+ 'kirjaa' => 'post',
+ 'kirjaa_uutena' => 'post_as_new',
+ 'tulosta' => 'print',
+ 'toimitusosoite' => 'ship_to',
+ 'päivitä' => 'update',
+ 'kyllä' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/login b/sql-ledger/locale/fi/login
new file mode 100644
index 0000000..783ae05
--- /dev/null
+++ b/sql-ledger/locale/fi/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Lisätietoja',
+ 'Database Host' => 'Tietokannan isäntä',
+ 'Dataset' => 'Tietolähde',
+ 'Incorrect Dataset version!' => 'Väärä tietolähdeversio!',
+ 'Incorrect Password!' => 'Väärä salasana!',
+ 'Licensed to' => 'Lisenssin omistaja',
+ 'Login' => 'Kirjaudu',
+ 'Name' => 'Nimi',
+ 'Password' => 'Salasana',
+ 'User' => 'Käyttäjä',
+ 'Version' => 'Versio',
+ 'You are logged out!' => 'Olet poistunut järjestelmästä',
+ 'You did not enter a name!' => 'Et kirjoittanut nimeä',
+ 'is not a member!' => 'ei ole käyttäjä',
+ 'localhost' => 'paikallinen tietokone',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'kirjaudu' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/menu b/sql-ledger/locale/fi/menu
new file mode 100644
index 0000000..c3cde8b
--- /dev/null
+++ b/sql-ledger/locale/fi/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Ostot',
+ 'AP Aging' => 'Erääntyvät ostolaskut',
+ 'AR' => 'Myynnit',
+ 'AR Aging' => 'Erääntyvät myyntilaskut',
+ 'Accounting Menu' => 'Kirjanpitovalikko',
+ 'Add Account' => 'Lisää tili',
+ 'Add Assembly' => 'Lisää tuote',
+ 'Add Customer' => 'Lisää asiakas',
+ 'Add GIFI' => 'Lisää GIFI',
+ 'Add Part' => 'Lisää raaka-aine/tarvike',
+ 'Add Project' => 'Lisää projekti',
+ 'Add Service' => 'Lisää palvelu',
+ 'Add Transaction' => 'Lisää tapahtuma',
+ 'Add Vendor' => 'Lisää toimittaja',
+ 'Assemblies' => 'Tuotteet',
+ 'Audit Control' => 'Tilien tarkistus',
+ 'Backup' => 'Varmuuskopio',
+ 'Balance Sheet' => 'Taselaskelma',
+ 'Cash' => 'Käteiskauppa',
+ 'Chart of Accounts' => 'Tilikartta',
+ 'Check' => 'Sekki',
+ 'Customers' => 'Asiakkaat',
+ 'General Ledger' => 'Pääkirja',
+ 'Goods & Services' => 'Hyödykkeet ja palvelut',
+ 'HTML Templates' => 'HTML mallit',
+ 'Income Statement' => 'Tuloslaskelma',
+ 'Invoice' => 'Lasku',
+ 'LaTeX Templates' => 'LaTeX mallit',
+ 'List Accounts' => 'Listaa tilit',
+ 'List GIFI' => 'Listaa GIFI',
+ 'Logout' => 'Kirjaudu ulos',
+ 'Order Entry' => 'Tilauksen kirjaus',
+ 'Packing List' => 'Pakkauslista',
+ 'Parts' => 'Raaka-aineet/tarvikkeet',
+ 'Payment' => 'Maksu',
+ 'Payments' => 'Maksut',
+ 'Preferences' => 'Asetukset',
+ 'Projects' => 'Projektit',
+ 'Purchase Invoice' => 'Ostolasku',
+ 'Purchase Order' => 'Ostotilaus',
+ 'Purchase Orders' => 'Ostotilaukset',
+ 'Receipt' => 'Kuitti',
+ 'Receipts' => 'Kuitit',
+ 'Reconciliation' => 'Sovitus',
+ 'Reports' => 'Raportit',
+ 'Sales Invoice' => 'Myyntilasku',
+ 'Sales Order' => 'Tilausvahvistus',
+ 'Sales Orders' => 'Tilausvahvistukset',
+ 'Save to File' => 'Tallenna tiedostoon',
+ 'Send by E-Mail' => 'Lähetä sähköpostilla',
+ 'Services' => 'Palvelut',
+ 'Statement' => 'Tiliote',
+ 'Stock Assembly' => 'Varastoi tuote',
+ 'Stylesheet' => 'Tyylimalli',
+ 'System' => 'Järjestelmä',
+ 'Tax collected' => 'Veroa kerätty',
+ 'Tax paid' => 'Veroa maksettu ',
+ 'Transactions' => 'Tapahtumat',
+ 'Trial Balance' => 'Saldolista',
+ 'Vendors' => 'Toimittajat',
+ 'Version' => 'Versio',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/oe b/sql-ledger/locale/fi/oe
new file mode 100644
index 0000000..bf1f726
--- /dev/null
+++ b/sql-ledger/locale/fi/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Lisää',
+ 'Add Purchase Invoice' => 'Lisää ostolasku',
+ 'Add Purchase Order' => 'Ostotilaus',
+ 'Add Sales Invoice' => 'Lisää myyntilasku',
+ 'Add Sales Order' => 'Lisää tilausvahvistus',
+ 'Address' => 'Osoite',
+ 'Amount' => 'Summa',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Are you sure you want to delete Order Number' => 'Haluatko poistaa tilauksen numero',
+ 'Attachment' => 'Liite',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'Bcc' => 'Näkymätön kopio',
+ 'Bin' => 'Varastopaikka',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Tilausta ei voi poistaa!',
+ 'Cannot save order!' => 'Tilauksen tallennus ei onnistu!',
+ 'Cc' => 'Kopio',
+ 'Closed' => 'Suljettu',
+ 'Confirm!' => 'Vahvista!',
+ 'Contact' => 'Yhteyshenkilö',
+ 'Continue' => 'Jatka',
+ 'Copies' => 'Kopiot',
+ 'Credit Limit' => 'Luottoraja',
+ 'Curr' => 'Valuutta',
+ 'Currency' => 'Valuutta',
+ 'Customer' => 'Asiakas',
+ 'Customer missing!' => 'Asiakas puuttuu!',
+ 'Customer not on file!' => 'Asiakas ei järjestelmässä!',
+ 'Date' => 'Päiväys',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Delete' => 'Poista',
+ 'Delivery Date' => 'Toimituspäivä',
+ 'Description' => 'Kuvaus',
+ 'E-mail' => 'Sähköposti',
+ 'E-mail address missing!' => 'Sähköpostiosoite puuttuu!',
+ 'Edit Purchase Order' => 'Muokkaa ostotilausta',
+ 'Edit Sales Order' => 'Muokkaa myyntitilausta',
+ 'Exchangerate' => 'Vaihtokurssi',
+ 'Exchangerate missing!' => 'Vaihtokurssi puuttuu',
+ 'Extended' => 'Pidennetty',
+ 'Fax' => 'Faksi',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'From' => 'Alkaen',
+ 'ID' => 'ID',
+ 'In-line' => 'Linjalla',
+ 'Include in Report' => 'Sisällytä raporttiin',
+ 'Invoice' => 'Lasku',
+ 'Invoice Date missing!' => 'Laskun päiväys puuttuu!',
+ 'Invoice Number missing!' => 'Laskun numero puuttuu!',
+ 'Item not on file!' => 'Nimikettä ei ole järjestelmässä!',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Message' => 'Viesti',
+ 'Name' => 'Nimi',
+ 'No.' => 'no',
+ 'Notes' => 'Lisätietoja',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Numero puuttuu kannan riviltä',
+ 'O' => 'O',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'Open' => 'Avoinna',
+ 'Order' => 'Tilaus',
+ 'Order Date' => 'Tilauspäivämäärä',
+ 'Order Date missing!' => 'Tilauspäivämäärä puuttuu!',
+ 'Order Number' => 'Tilausnumero',
+ 'Order Number missing!' => 'Tilausnumero puuttuu!',
+ 'Order deleted!' => 'Tilaus poistettu!',
+ 'Order saved!' => 'Tilaus tallennettu!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakkauslista',
+ 'Packing List Date missing!' => 'Pakkauslistan päiväys puuttuu!',
+ 'Packing List Number missing!' => 'Pakkauslistan numero puuttuu!',
+ 'Part' => 'Raaka-aine/tarvike',
+ 'Phone' => 'Puhelin',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Hinta',
+ 'Print' => 'Tulosta',
+ 'Printer' => 'Kirjoitin',
+ 'Project' => 'Projekti',
+ 'Project not on file!' => 'Projekti ei ole järjestelmässä!',
+ 'Purchase Order' => 'Ostotilaus',
+ 'Purchase Orders' => 'Ostotilaukset',
+ 'Qty' => 'Määrä',
+ 'Recd' => 'Vastaanotettu',
+ 'Remaining' => 'Jäljellä',
+ 'Required by' => 'Toimituspäivä',
+ 'Sales Order' => 'Tilausvahvistus',
+ 'Sales Orders' => 'Tilausvahvistukset',
+ 'Save' => 'Tallenna',
+ 'Save as new' => 'Tallenna uutena',
+ 'Screen' => 'Näyttö',
+ 'Select from one of the items below' => 'Valitse yksi nimike alapuolelta',
+ 'Select from one of the names below' => 'Valitse yksi nimi alapuolelta',
+ 'Select from one of the projects below' => 'Valitse yksi projekti alapuolelta',
+ 'Select postscript or PDF!' => 'Valitse postscript tai PDF',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Service' => 'Palvelu',
+ 'Ship' => 'Lähetä',
+ 'Ship to' => 'Toimitusosoite',
+ 'Ship via' => 'Lähetä kautta',
+ 'Subject' => 'Aihe',
+ 'Subtotal' => 'Välisumma',
+ 'Tax' => 'Vero',
+ 'Tax Included' => 'ALV sisältyy ',
+ 'Terms: Net' => 'Maksuehto',
+ 'To' => 'Hetkeen',
+ 'Total' => 'Yhteensä',
+ 'Unit' => 'Yksikkö',
+ 'Update' => 'Päivitä',
+ 'Vendor' => 'Toimittaja',
+ 'Vendor missing!' => 'Toimittaja puuttuu!',
+ 'Vendor not on file!' => 'Toimittajaa ei järjestelmässä!',
+ 'What type of item is this?' => 'Minkä tyyppinen nimike tämä on?',
+ 'Yes' => 'Kyllä',
+ 'days' => 'päivää',
+ 'ea' => 'kpl',
+ 'emailed to' => 'lähetetty sähköpostilla',
+ 'sent to printer' => 'lähetetty tulostimelle',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'lisää' => 'add',
+ 'jatka' => 'continue',
+ 'poista' => 'delete',
+ 'sähköposti' => 'e_mail',
+ 'lasku' => 'invoice',
+ 'tulosta' => 'print',
+ 'tallenna' => 'save',
+ 'tallenna_uutena' => 'save_as_new',
+ 'toimitusosoite' => 'ship_to',
+ 'päivitä' => 'update',
+ 'kyllä' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/pe b/sql-ledger/locale/fi/pe
new file mode 100644
index 0000000..c9fe2c1
--- /dev/null
+++ b/sql-ledger/locale/fi/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Lisää',
+ 'Add Project' => 'Lisää projekti',
+ 'All' => 'Kaikki',
+ 'Continue' => 'Jatka',
+ 'Delete' => 'Poista',
+ 'Description' => 'Kuvaus',
+ 'Edit Project' => 'Muokkaa projektia',
+ 'Number' => 'Numero',
+ 'Orphaned' => 'Hylätyt',
+ 'Project' => 'Projekti',
+ 'Project Number missing!' => 'Projektinumero puuttuu!',
+ 'Project deleted!' => 'Projekti poistettu!',
+ 'Project saved!' => 'Projekti tallennettu!',
+ 'Projects' => 'Projektit',
+ 'Save' => 'Tallenna',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'lisää' => 'add',
+ 'jatka' => 'continue',
+ 'poista' => 'delete',
+ 'tallenna' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/rc b/sql-ledger/locale/fi/rc
new file mode 100644
index 0000000..57ea0da
--- /dev/null
+++ b/sql-ledger/locale/fi/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Tili',
+ 'Balance' => 'Tase',
+ 'Cleared Balance' => 'Tarkistettu tase',
+ 'Continue' => 'Jatka',
+ 'Date' => 'Päiväys',
+ 'Deposit' => 'Rahatallennus',
+ 'Description' => 'Kuvaus',
+ 'Difference' => 'Ero',
+ 'Done' => 'Suoritettu!',
+ 'Exchangerate Difference' => 'Vaihtokurssin ero',
+ 'From' => 'Alkaen',
+ 'Out of balance!' => 'Ei tasapainossa',
+ 'Payment' => 'Maksu',
+ 'Reconciliation' => 'Sovitus',
+ 'Select all' => 'Valitse kaikki',
+ 'Source' => 'Lähde',
+ 'Statement Balance' => 'Tiliotteen tase',
+ 'To' => 'Hetkeen',
+ 'Update' => 'Päivitä',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'jatka' => 'continue',
+ 'suoritettu!' => 'done',
+ 'valitse_kaikki' => 'select_all',
+ 'päivitä' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/fi/rp b/sql-ledger/locale/fi/rp
new file mode 100644
index 0000000..cbc572f
--- /dev/null
+++ b/sql-ledger/locale/fi/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Erääntyvät ostolaskut',
+ 'AR Aging' => 'Erääntyvät myyntilaskut',
+ 'Account' => 'Tili',
+ 'Accounts' => 'Tilit',
+ 'Amount' => 'Summa',
+ 'Apr' => 'Huh',
+ 'April' => 'Huhtikuu',
+ 'Attachment' => 'Liite',
+ 'Aug' => 'Elo',
+ 'August' => 'Elokuu',
+ 'Balance Sheet' => 'Taselaskelma',
+ 'Bcc' => 'Näkymätön kopio',
+ 'Cash based' => 'Käteiseen perustuva',
+ 'Cc' => 'Kopio',
+ 'Compare to' => 'verrattuna',
+ 'Continue' => 'Jatka',
+ 'Copies' => 'Kopiot',
+ 'Credit' => 'Kredit',
+ 'Current' => 'Erääntyy',
+ 'Customer' => 'Asiakas',
+ 'Date' => 'Päiväys',
+ 'Debit' => 'Debet',
+ 'Dec' => 'Jou',
+ 'December' => 'Joulukuu',
+ 'Decimalplaces' => 'Desimaalipaikkoja',
+ 'Description' => 'Kuvaus',
+ 'Due' => 'Eräpv',
+ 'E-mail' => 'Sähköposti',
+ 'E-mail Statement to' => 'Sähköpostilla tiliote kenelle',
+ 'Feb' => 'Hel',
+ 'February' => 'Helmikuu',
+ 'From' => 'Alkaen',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Otsikko',
+ 'ID' => 'ID',
+ 'In-line' => 'Linjalla',
+ 'Include in Report' => 'Sisällytä raporttiin',
+ 'Income Statement' => 'Tuloslaskelma',
+ 'Invoice' => 'Lasku',
+ 'Jan' => 'Tam',
+ 'January' => 'Tammikuu',
+ 'Jul' => 'Hei',
+ 'July' => 'Heinäkuu',
+ 'Jun' => 'Kes',
+ 'June' => 'Kesäkuu',
+ 'Mar' => 'Maa',
+ 'March' => 'Maaliskuu',
+ 'May' => 'Tou',
+ 'May ' => 'Toukokuu',
+ 'Message' => 'Viesti',
+ 'N/A' => 'Ei saatavilla',
+ 'Nothing selected!' => 'Mitään valitsematta!',
+ 'Nov' => 'Mar',
+ 'November' => 'Marraskuu',
+ 'Oct' => 'Lok',
+ 'October' => 'Lokakuu',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Maksut',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Tulosta',
+ 'Printer' => 'Kirjoitin',
+ 'Receipts' => 'Kuitit',
+ 'Report for' => 'Raportti',
+ 'Retained Earnings' => 'Käyttörahasto\jakamaton voitto',
+ 'Screen' => 'Näyttö',
+ 'Select all' => 'Valitse kaikki',
+ 'Select postscript or PDF!' => 'Valitse postscript tai PDF',
+ 'Sep' => 'Syy',
+ 'September' => 'Syyskuu',
+ 'Source' => 'Lähde',
+ 'Standard' => 'Vakio',
+ 'Statement' => 'Tiliote',
+ 'Statement sent to' => 'Tiliote lähetetty',
+ 'Statements sent to printer!' => 'Tiliotteet lähetetty tulostimelle!',
+ 'Subject' => 'Aihe',
+ 'Subtotal' => 'Välisumma',
+ 'Tax' => 'Vero',
+ 'Tax collected' => 'Veroa kerätty',
+ 'Tax paid' => 'Veroa maksettu ',
+ 'To' => 'Hetkeen',
+ 'Total' => 'Yhteensä',
+ 'Trial Balance' => 'Saldolista',
+ 'Vendor' => 'Toimittaja',
+ 'as at' => 'päivänä ',
+ 'collected on sales' => 'Kerätty myynneistä',
+ 'for Period' => 'jaksolta',
+ 'paid on purchases' => 'maksettu ostoista',
+ 'to' => 'Kenelle',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'jatka' => 'continue',
+ 'sähköposti' => 'e_mail',
+ 'tulosta' => 'print',
+ 'valitse_kaikki' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/COPYING b/sql-ledger/locale/fr/COPYING
new file mode 100644
index 0000000..2010dcc
--- /dev/null
+++ b/sql-ledger/locale/fr/COPYING
@@ -0,0 +1,27 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2003
+#
+# French texts:
+#
+# Author: Sèbastien Brassard <sbrassar.cgocable.ca>
+# Oscar Buijten <oscar@elbie.com>
+# Wolfgang Sourdeau <wolfgang@contre.com>
+# Aguibou KONE <aguibou.kone@rocketmail.com>
+# Jens-Ingo Brodesser <jens-ingo@all2all.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/fr/LANGUAGE b/sql-ledger/locale/fr/LANGUAGE
new file mode 100644
index 0000000..744b2c3
--- /dev/null
+++ b/sql-ledger/locale/fr/LANGUAGE
@@ -0,0 +1 @@
+French
diff --git a/sql-ledger/locale/fr/admin b/sql-ledger/locale/fr/admin
new file mode 100644
index 0000000..38498b1
--- /dev/null
+++ b/sql-ledger/locale/fr/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Contrôle d\'accès',
+ 'Accounting' => 'Comptabilité',
+ 'Add User' => 'Ajouter utilisateur',
+ 'Address' => 'Adresse',
+ 'Administration' => 'Administration',
+ 'Administrator' => 'Administrateur',
+ 'All Datasets up to date!' => 'Tous les fichiers de données sont à jour!',
+ 'Change Admin Password' => 'Changement de mot de passe administrateur',
+ 'Change Password' => 'Changement de mot de passe',
+ 'Character Set' => 'Encodage des caractères',
+ 'Click on login name to edit!' => 'Cliquer sur votre identifiant pour editer',
+ 'Company' => 'Société',
+ 'Connect to' => 'Connecter à',
+ 'Continue' => 'Continuer',
+ 'Create Chart of Accounts' => 'Créer le Plan Comptable',
+ 'Create Dataset' => 'Créer fichier de données',
+ 'DBI not installed!' => 'DBI non installée!',
+ 'Database' => 'Base de données',
+ 'Database Administration' => 'Gérer base de données',
+ 'Database Driver not checked!' => 'Pilotes de base de données pas verifiés!',
+ 'Database User missing!' => 'Utilisateur base de données manquante!',
+ 'Dataset' => 'Fichier de données',
+ 'Dataset missing!' => 'Fichier de données manquant!',
+ 'Dataset updated!' => 'Base de données mise à jour!',
+ 'Date Format' => 'Format de Date',
+ 'Delete' => 'Supprimer',
+ 'Delete Dataset' => 'Supprimer fichier de données',
+ 'Directory' => 'Répertoire',
+ 'Driver' => 'Pilote',
+ 'Dropdown Limit' => 'Limit de déroulement',
+ 'E-mail' => 'Email',
+ 'Edit User' => 'Modifier utilisateur',
+ 'Existing Datasets' => 'Fichiers de données existants',
+ 'Fax' => 'Fax',
+ 'Host' => 'Hôte',
+ 'Hostname missing!' => 'Nom de l\'hôte manquant',
+ 'Incorrect Password!' => 'Mot de passe incorrect!',
+ 'Language' => 'Langue',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Laisser "port" et "hôte" vide, sauf si vous voulez vous connecter à distance (par réseau)',
+ 'Login' => 'Login',
+ 'Multibyte Encoding' => 'Encodage multibyte',
+ 'Name' => 'Nom',
+ 'New Templates' => 'Nouveaux modèles',
+ 'No Database Drivers available!' => 'Pas de pilotes de base de données disponibles!',
+ 'No Dataset selected!' => 'Pas de fichier de données sélectioné!',
+ 'Nothing to delete!' => 'Rien à supprimer',
+ 'Number Format' => 'Format des numéros',
+ 'Oracle Database Administration' => 'Administration de base de données Oracle',
+ 'Password' => 'Mot de Passe',
+ 'Password changed!' => 'Mot de passe changé!',
+ 'Pg Database Administration' => 'Administration base de données PostgreSQL',
+ 'Phone' => 'Tél.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port manquant!',
+ 'Printer' => 'Imprimante',
+ 'Save' => 'Enregistrer',
+ 'Select a Dataset to delete and press "Continue"' => 'Sélectionner la base de données à supprimer et cliquer sur "Continuer"',
+ 'Setup Templates' => 'Configuration des Gabarits',
+ 'Ship via' => 'Expédier via',
+ 'Signature' => 'Signature',
+ 'Stylesheet' => 'Feuille de style',
+ 'Templates' => 'Gabarits',
+ 'The following Datasets are not in use and can be deleted' => 'Les fichiers de données suivants ne sont pas utilisés et peuvent être supprimés.',
+ 'The following Datasets need to be updated' => 'Les fichiers de données suivants doivent être mis a jour',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Ceci est un test préliminaire des sources existante. Aucune modification à ce stade!!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Pour ajouter un utilisateur à un groupe, editer un "nom", changer le "login" et enregistrer. Un nouveau utilisateur avec les mêmes données sera enregistré avec le nouveau "login".',
+ 'Update Dataset' => 'Mis à jour de la base de données',
+ 'Use Templates' => 'Utiliser les modèles',
+ 'User' => 'Utilisateur',
+ 'User deleted!' => 'Utilisateur supprimé!',
+ 'User saved!' => 'Utilisateur enregistré!',
+ 'Version' => 'Version',
+ 'You must enter a host and port for local and remote connections!' => 'Vous devez saisir un "hôte" et un "port" pour les connexions distantes!',
+ 'does not exist' => 'n\'existe pas!',
+ 'is already a member!' => 'est déjà un membre!',
+ 'localhost' => 'hôte local',
+ 'locked!' => 'verrouillé!',
+ 'successfully created!' => 'créé avec succès',
+ 'successfully deleted!' => 'supprimé avec succès',
+ 'website' => 'site web',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'ajouter_utilisateur' => 'add_user',
+ 'changement_de_mot_de_passe_administrateur' => 'change_admin_password',
+ 'changement_de_mot_de_passe' => 'change_password',
+ 'continuer' => 'continue',
+ 'créer_fichier_de_données' => 'create_dataset',
+ 'supprimer' => 'delete',
+ 'supprimer_fichier_de_données' => 'delete_dataset',
+ 'login' => 'login',
+ 'administration_de_base_de_données_oracle' => 'oracle_database_administration',
+ 'administration_base_de_données_postgresql' => 'pg_database_administration',
+ 'enregistrer' => 'save',
+ 'mis_à_jour_de_la_base_de_données' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/all b/sql-ledger/locale/fr/all
new file mode 100644
index 0000000..3d514c3
--- /dev/null
+++ b/sql-ledger/locale/fr/all
@@ -0,0 +1,495 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Dépenses',
+ 'AP Aging' => 'Dépenses exigibles',
+ 'AP Transaction' => 'Ecriture Dépense',
+ 'AP Transactions' => 'Mouvements - Dépenses',
+ 'AR' => 'Recettes',
+ 'AR Aging' => 'Recettes exigibles',
+ 'AR Transaction' => 'Ecriture Recette',
+ 'AR Transactions' => 'Mouvements - Recettes',
+ 'About' => 'A propos',
+ 'Access Control' => 'Contrôle d\'accès',
+ 'Account' => 'Compte',
+ 'Account Number' => 'Numéro de compte',
+ 'Account Number missing!' => 'Numéro de compte manquant!',
+ 'Account Type' => 'Type de compte',
+ 'Account Type missing!' => 'Type de compte manquant!',
+ 'Account deleted!' => 'Compte supprimé',
+ 'Account saved!' => 'Compte enregistré',
+ 'Accounting' => 'Comptabilité',
+ 'Accounting Menu' => 'Menu de comptabilité',
+ 'Accounts' => 'Comptes',
+ 'Active' => 'Actif',
+ 'Add' => 'Ajouter',
+ 'Add Account' => 'Ajouter compte',
+ 'Add Accounts Payables Transaction' => 'Saisie d\'écriture - Dépenses',
+ 'Add Accounts Receivables Transaction' => 'Saisie d\'écriture - Recettes',
+ 'Add Assembly' => 'Ajouter produit',
+ 'Add Customer' => 'Ajouter client',
+ 'Add GIFI' => 'Ajouter Code d\'Identification Comptable ou Fiscale',
+ 'Add General Ledger Transaction' => 'Ajouter une écriture au Grand Livre',
+ 'Add Part' => 'Ajouter marchandise',
+ 'Add Project' => 'Ajouter projet',
+ 'Add Purchase Invoice' => 'Etablir facture d\'achat',
+ 'Add Purchase Order' => 'Etablir commande d\'achat',
+ 'Add Sales Invoice' => 'Etablir facture de vente',
+ 'Add Sales Order' => 'Etablir commande de vente',
+ 'Add Service' => 'Ajouter service',
+ 'Add Transaction' => 'Saisie d\'écriture',
+ 'Add User' => 'Ajouter utilisateur',
+ 'Add Vendor' => 'Ajouter fournisseur',
+ 'Address' => 'Adresse',
+ 'Administration' => 'Administration',
+ 'Administrator' => 'Administrateur',
+ 'All' => 'Tous',
+ 'All Datasets up to date!' => 'Tous les fichiers de données sont à jour!',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Montant dû',
+ 'Amount does not equal applied!' => 'Le montant n\'est égal à celui appliqué!',
+ 'Amount missing!' => 'Montant manquant',
+ 'Applied' => 'Appliquer',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Are you sure you want to delete Invoice Number' => 'Êtes-vous sûr de vouloir supprimer la Facture No.:',
+ 'Are you sure you want to delete Order Number' => 'Êtes vous sûr de vouloir supprimer Commande N°',
+ 'Are you sure you want to delete Transaction' => 'Êtes vous sûr de vouloir effacer la saisie?',
+ 'Assemblies' => 'Produits finis',
+ 'Assemblies restocked!' => 'Renvoyer produits vers stock!',
+ 'Assembly Number missing!' => 'Numéro de produit manquant',
+ 'Asset' => 'Actif',
+ 'Attachment' => 'Pièce jointe',
+ 'Audit Control' => 'Clôture périodique',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'BOM' => 'Nomenclature composantes',
+ 'Backup' => 'Sauvegarder',
+ 'Backup sent to' => 'Sauvegarde envoyée à',
+ 'Balance' => 'Solde',
+ 'Balance Sheet' => 'Bilan',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Localisation',
+ 'Books are open' => 'Début exercice',
+ 'Bought' => 'Acheté',
+ 'Business Number' => 'Numéro d\'enregistrement société',
+ 'C' => 'C',
+ 'COGS' => 'CMV',
+ 'Cannot delete account!' => 'Impossible de supprimer le compte!',
+ 'Cannot delete customer!' => 'Impossible de supprimer le client!',
+ 'Cannot delete default account!' => 'Ne peut pas supprimer le compte par defaut!',
+ 'Cannot delete invoice!' => 'Impossible de supprimer la facture',
+ 'Cannot delete item already invoiced!' => 'Ne peut pas effacer un élément qui est déjà facturé!',
+ 'Cannot delete item on order!' => 'Impossible de supprimer un élément faisant partie d\'une commande',
+ 'Cannot delete item which is part of an assembly!' => 'Ne peut pas supprimer une marchandise qui est intégrée dans un produit fini!',
+ 'Cannot delete item!' => 'Impossible de supprimer ce poste!',
+ 'Cannot delete order!' => 'Impossible de supprimer la commande!',
+ 'Cannot delete transaction!' => 'Impossible de supprimer la saisie!',
+ 'Cannot delete vendor!' => 'Impossible de supprimer le fournisseur!',
+ 'Cannot have a value in both Debit and Credit!' => 'Impossible d\'avoir des valeurs dans Crédit et Débit en même temps!',
+ 'Cannot post a transaction without a value!' => 'Impossible d\'effectuer une écriture sans valeur!',
+ 'Cannot post invoice for a closed period!' => 'Impossible d\'enregistrer la facture sur un exercice clos!',
+ 'Cannot post invoice!' => 'Impossible d\'enregistrer la facture!',
+ 'Cannot post payment for a closed period!' => 'Impossible d\'enregistrer le paiement sur un exercice clos!',
+ 'Cannot post payment!' => 'Impossible d\'enregistrer le paiement!',
+ 'Cannot post transaction for a closed period!' => 'Impossible d\'enregistrer l\'écriture sur un exercice clos!',
+ 'Cannot post transaction!' => 'Impossible d\'enregistrer l\'écriture!',
+ 'Cannot process payment for a closed period!' => 'Impossible de faire un paiement sur un exercice clos!',
+ 'Cannot save account!' => 'Impossible d\'enregistrer le compte!',
+ 'Cannot save order!' => 'Impossible d\'enregistrer la commande!',
+ 'Cannot save preferences!' => 'Impossible d\'enregistrer les préférences',
+ 'Cannot stock assemblies!' => 'Impossible de stocker l\'assemblage!',
+ 'Cash' => 'Caisse',
+ 'Cash based' => 'En liquide',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => 'Changement de mot de passe administrateur',
+ 'Change Password' => 'Changement de mot de passe',
+ 'Character Set' => 'Encodage des caractères',
+ 'Chart of Accounts' => 'Plan Comptable',
+ 'Check' => 'Chèque',
+ 'Check printed!' => 'Chèque imprimé!',
+ 'Check printing failed!' => 'Impression du chèque échoué!',
+ 'Cleared Balance' => 'Solde rapproché',
+ 'Click on login name to edit!' => 'Cliquer sur votre identifiant pour editer',
+ 'Close Books up to' => 'Clôturer l\'exercice jusqu\'au',
+ 'Closed' => 'Clôturé',
+ 'Company' => 'Société',
+ 'Compare to' => 'Comparer à',
+ 'Confirm!' => 'Confirmez!',
+ 'Connect to' => 'Connecter à',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continuer',
+ 'Copies' => 'Copies',
+ 'Copy to COA' => 'Copier dans le Plan Comptable',
+ 'Create Chart of Accounts' => 'Créer le Plan Comptable',
+ 'Create Dataset' => 'Créer fichier de données',
+ 'Credit' => 'Crédit',
+ 'Credit Limit' => 'Encours autorisé',
+ 'Curr' => 'En cours',
+ 'Currency' => 'Devise',
+ 'Current' => 'En cours',
+ 'Customer' => 'Client',
+ 'Customer deleted!' => 'Client supprimé!',
+ 'Customer missing!' => 'Client manquant!',
+ 'Customer not on file!' => 'Client absent du fichier!',
+ 'Customer saved!' => 'Client enregistré!',
+ 'Customers' => 'Clients',
+ 'DBI not installed!' => 'DBI non installée!',
+ 'Database' => 'Base de données',
+ 'Database Administration' => 'Gérer base de données',
+ 'Database Driver not checked!' => 'Pilotes de base de données pas verifiés!',
+ 'Database Host' => 'Hôte de base de données',
+ 'Database User missing!' => 'Utilisateur base de données manquante!',
+ 'Dataset' => 'Fichier de données',
+ 'Dataset missing!' => 'Fichier de données manquant!',
+ 'Dataset updated!' => 'Base de données mise à jour!',
+ 'Date' => 'Date',
+ 'Date Due' => 'Date d\'échéance',
+ 'Date Format' => 'Format de Date',
+ 'Date Paid' => 'Date de paiement',
+ 'Date missing!' => 'Date manquante!',
+ 'Debit' => 'Débit',
+ 'Debit and credit out of balance!' => 'Le débit et le crédit ne sont pas équilibrés!',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Decimalplaces' => 'Décimales',
+ 'Delete' => 'Supprimer',
+ 'Delete Account' => 'Supprimer compte',
+ 'Delete Dataset' => 'Supprimer fichier de données',
+ 'Delivery Date' => 'Date de livraison',
+ 'Department' => '',
+ 'Deposit' => 'Dépôt',
+ 'Description' => 'Description',
+ 'Difference' => 'Différence',
+ 'Directory' => 'Répertoire',
+ 'Discount' => 'Remise',
+ 'Done' => 'Fait!',
+ 'Drawing' => 'Dessin',
+ 'Driver' => 'Pilote',
+ 'Dropdown Limit' => 'Limit de déroulement',
+ 'Due' => 'Echéance',
+ 'Due Date' => 'Date d\'échéance',
+ 'Due Date missing!' => 'Date d\'échéance manquante!',
+ 'E-mail' => 'Email',
+ 'E-mail Statement to' => 'Message éléctronique à',
+ 'E-mail address missing!' => 'Adresse email manquante!',
+ 'Edit' => 'Modifier',
+ 'Edit Account' => 'Modifier le compte',
+ 'Edit Accounts Payables Transaction' => 'Modifier Mouvements - Dépenses',
+ 'Edit Accounts Receivables Transaction' => 'Modifier Mouvements - Recettes',
+ 'Edit Assembly' => 'Modifier produit fini / transformé',
+ 'Edit Customer' => 'Modifier client',
+ 'Edit GIFI' => 'Modifier Code d\'Identification Comptable ou Fiscale',
+ 'Edit General Ledger Transaction' => 'Modifier écriture Grand Livre',
+ 'Edit Part' => 'Modifier marchandise',
+ 'Edit Preferences for' => 'Modifier les préférences pour',
+ 'Edit Project' => 'Modifier projet',
+ 'Edit Purchase Invoice' => 'Modifier facture d\'achat',
+ 'Edit Purchase Order' => 'Modifier commande d\'achat',
+ 'Edit Sales Invoice' => 'Modifier facture de vente',
+ 'Edit Sales Order' => 'Modifier commande de vente',
+ 'Edit Service' => 'Modifier service',
+ 'Edit Template' => 'Modifier modèle',
+ 'Edit User' => 'Modifier utilisateur',
+ 'Edit Vendor' => 'Modifier fournisseur',
+ 'Employee' => 'Employé',
+ 'Enforce transaction reversal for all dates' => 'Appliquer l\'inversion des écritures pour toutes les dates',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Entrer le nom de la monnaie nationale et des monnaies étrangères en 3 lettres séparées par (:) (Ex: EUR:USD:CAD)',
+ 'Equity' => 'Capital',
+ 'Exch' => 'Change',
+ 'Exchangerate' => 'Taux de change',
+ 'Exchangerate Difference' => 'Différence de taux de change',
+ 'Exchangerate for payment missing!' => 'Taux de change manquant pour le paiement!',
+ 'Exchangerate missing!' => 'Taux de change manquant!',
+ 'Existing Datasets' => 'Fichiers de données existants',
+ 'Expense' => 'Dépense',
+ 'Expense Account' => 'Compte Dépenses',
+ 'Expense/Asset' => 'Dépense/Actif',
+ 'Extended' => 'Prix Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'Foreign Exchange Gain' => 'Produit conversion devises',
+ 'Foreign Exchange Loss' => 'Perte conversion devises',
+ 'From' => 'De',
+ 'GIFI' => 'Code d\'Identification Comptable ou Fiscale',
+ 'GIFI deleted!' => 'Code d\'Identification Comptable ou Fiscale supprimé!',
+ 'GIFI missing!' => 'Code d\'Identification Comptable ou Fiscale manquant!',
+ 'GIFI saved!' => 'Code d\'Identification Comptable ou Fiscale enregistré!',
+ 'GL Transaction' => 'Transaction Grand Livre',
+ 'General Ledger' => 'Grand Livre',
+ 'Goods & Services' => 'Articles & Services',
+ 'HTML Templates' => 'Gabarits HTML',
+ 'Heading' => 'En-tête',
+ 'Host' => 'Hôte',
+ 'Hostname missing!' => 'Nom de l\'hôte manquant',
+ 'ID' => 'ID',
+ 'Image' => 'Image',
+ 'In-line' => 'En ligne',
+ 'Include in Report' => 'Inclure dans l\'état',
+ 'Include in drop-down menus' => 'Inclure dans les menus deroulants',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Afficher ce compte sur les formulaires de client/fournisseur pour le marquer comme imposable?',
+ 'Income' => 'Recettes',
+ 'Income Account' => 'Compte Recettes',
+ 'Income Statement' => 'Compte de Résultat',
+ 'Incorrect Dataset version!' => 'Fichier de données incorrect!',
+ 'Incorrect Password!' => 'Mot de passe incorrect!',
+ 'Individual Items' => 'Composition en marchandises individuelles',
+ 'Inventory' => 'Inventaire',
+ 'Inventory Account' => 'Compte d\'Inventaire',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La quantité en stock doit être à zéro avant de pouvoir indiquer cet assemblage comme obsolète!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La quantité en stock devrait être zero avant de pouvoir indiquer cette pièce comme obsolète!',
+ 'Inventory quantity must be zero!' => 'La quantité en stock doit être zero!',
+ 'Invoice' => 'Facture',
+ 'Invoice Date' => 'Date de facturation',
+ 'Invoice Date missing!' => 'Date de facture manquante!',
+ 'Invoice Number' => 'Numéro de facture',
+ 'Invoice Number missing!' => 'Numéro de facture manquant!',
+ 'Invoice deleted!' => 'Facture supprimé!',
+ 'Invoice posted!' => 'Facture enregistré!',
+ 'Invoices' => 'Factures',
+ 'Is this a summary account to record' => 'Est-ce que c\'est un compte sommaire à enregistrer?',
+ 'Item deleted!' => 'Objet supprimé!',
+ 'Item not on file!' => 'Objet non-listé!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'LaTeX Templates' => 'Gabarits LaTeX',
+ 'Language' => 'Langue',
+ 'Last Cost' => 'Dernier prix',
+ 'Last Invoice Number' => 'Dernier numéro de facture',
+ 'Last Numbers & Default Accounts' => 'Derniers numéros et comptes par défauts',
+ 'Last Purchase Order Number' => 'Dernier numéro de commande d\'achat',
+ 'Last Sales Order Number' => 'Numéro de la dernière commande de vente',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Laisser "port" et "hôte" vide, sauf si vous voulez vous connecter à distance (par réseau)',
+ 'Liability' => 'Passif',
+ 'Licensed to' => 'Licence à',
+ 'Line Total' => 'Total ligne',
+ 'Link' => 'Liens',
+ 'Link Accounts' => 'Lier Comptes',
+ 'List Accounts' => 'Liste des comptes',
+ 'List GIFI' => 'Afficher la liste des Codes d\'Identification Comptable ou Fiscale',
+ 'List Price' => 'Prix d\'achat',
+ 'List Transactions' => 'Afficher écritures',
+ 'Login' => 'Login',
+ 'Logout' => 'Déconnexion',
+ 'Make' => 'Marque',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Message',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modèle',
+ 'Multibyte Encoding' => 'Encodage multibyte',
+ 'N/A' => 'Non Applicable',
+ 'Name' => 'Nom',
+ 'Name missing!' => 'Nom manquant!',
+ 'New Templates' => 'Nouveaux modèles',
+ 'No' => 'Non',
+ 'No Database Drivers available!' => 'Pas de pilotes de base de données disponibles!',
+ 'No Dataset selected!' => 'Pas de fichier de données sélectioné!',
+ 'No email address for' => 'Pas d\'adresse email pour',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nothing applied!' => 'Rien n\'a été appliqué!',
+ 'Nothing selected!' => 'Pas de sélection!',
+ 'Nothing to delete!' => 'Rien à supprimer',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Number' => 'Numéro',
+ 'Number Format' => 'Format des numéros',
+ 'Number missing in Row' => 'Numéro manquant dans ligne',
+ 'O' => 'O',
+ 'Obsolete' => 'Obsolète',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'On Hand' => 'En Stock / Disponible',
+ 'On Order' => 'Sur Commande',
+ 'Open' => 'Ouvert',
+ 'Oracle Database Administration' => 'Administration de base de données Oracle',
+ 'Order' => 'Commande',
+ 'Order Date' => 'Date commande',
+ 'Order Date missing!' => 'Date de commande manquante!',
+ 'Order Entry' => 'Bons de Commandes',
+ 'Order Number' => 'Numéro de commande',
+ 'Order Number missing!' => 'Numéro de commande manquant!',
+ 'Order deleted!' => 'Commande supprimé!',
+ 'Order saved!' => 'Commande enregistré!',
+ 'Ordered' => 'Commandé',
+ 'Orphaned' => 'Orphelin',
+ 'Out of balance!' => 'Solde non équilibré!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Liste d\'envoi',
+ 'Packing List Date missing!' => 'La date est manquante sur la liste d\'envoi!',
+ 'Packing List Number missing!' => 'Le numéro de liste d\'envoi est manquant!',
+ 'Paid' => 'Total Payé',
+ 'Paid in full' => 'Complètement payé',
+ 'Part' => 'Marchandise',
+ 'Part Number missing!' => 'Numéro de marchandise manquant!',
+ 'Parts' => 'Marchandises',
+ 'Parts Inventory' => 'Inventaire marchandises',
+ 'Password' => 'Mot de Passe',
+ 'Password changed!' => 'Mot de passe changé!',
+ 'Payables' => 'À Payer',
+ 'Payment' => 'Paiement',
+ 'Payment date missing!' => 'Date de paiement manquant!',
+ 'Payment posted!' => 'Paiement enregistré!',
+ 'Payments' => 'Paiements',
+ 'Pg Database Administration' => 'Administration base de données PostgreSQL',
+ 'Phone' => 'Tél.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port manquant!',
+ 'Post' => 'Enregistrer',
+ 'Post as new' => 'Enregistrer comme nouveau',
+ 'Postscript' => 'Postcript',
+ 'Preferences' => 'Préférences',
+ 'Preferences saved!' => 'Préférences enregistrées!',
+ 'Price' => 'Prix',
+ 'Print' => 'Imprimer',
+ 'Printer' => 'Imprimante',
+ 'Project' => 'Projet',
+ 'Project Number' => '',
+ 'Project Number missing!' => 'Numéro du projet manquant!',
+ 'Project deleted!' => 'Projet supprimé!',
+ 'Project not on file!' => 'Projet absent du fichier!',
+ 'Project saved!' => 'Projet enregistré!',
+ 'Projects' => 'Projets',
+ 'Purchase Invoice' => 'Facture d\'Achat',
+ 'Purchase Order' => 'Commande d\'Achat',
+ 'Purchase Orders' => 'Commandes d\'Achats',
+ 'Qty' => 'Qté',
+ 'ROP' => 'Niveau de commande',
+ 'Rate' => 'Cadence',
+ 'Recd' => 'Reçu',
+ 'Receipt' => 'Reçu',
+ 'Receipt printed!' => '',
+ 'Receipt printing failed!' => '',
+ 'Receipts' => 'Reçus',
+ 'Receivables' => 'À recevoir',
+ 'Reconciliation' => 'Rapprochement',
+ 'Record in' => 'Enregistrer dans',
+ 'Reference' => 'Référence',
+ 'Reference missing!' => 'Référence manquant!',
+ 'Remaining' => 'Restant',
+ 'Report for' => 'Rapport de',
+ 'Reports' => 'Rapports',
+ 'Required by' => 'Requis pour',
+ 'Retained Earnings' => 'Éxcédents non distribués',
+ 'Sales' => 'Ventes',
+ 'Sales Invoice' => 'Facture de Vente',
+ 'Sales Order' => 'Commande de Vente',
+ 'Sales Orders' => 'Commandes de Vente',
+ 'Save' => 'Enregistrer',
+ 'Save as new' => 'Enregistrer comme nouveau',
+ 'Save to File' => 'Enregistrer comme fichier',
+ 'Screen' => 'Écran',
+ 'Select a Dataset to delete and press "Continue"' => 'Sélectionner la base de données à supprimer et cliquer sur "Continuer"',
+ 'Select all' => 'Sélectionner tout',
+ 'Select from one of the items below' => 'Sélectionner un des postes ci-dessous',
+ 'Select from one of the names below' => 'Sélectionner un des noms ci-dessous',
+ 'Select from one of the projects below' => 'Sélectionner un des projets ci-dessous',
+ 'Select postscript or PDF!' => 'Sélectionner Postscript ou PDF',
+ 'Sell Price' => 'Prix de vente',
+ 'Send by E-Mail' => 'Envoyer par email',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Service' => 'Service',
+ 'Service Items' => 'Services',
+ 'Service Number missing!' => 'Numéro de service manquant!',
+ 'Services' => 'Services',
+ 'Setup Templates' => 'Configuration des Gabarits',
+ 'Ship' => 'Expédier',
+ 'Ship to' => 'Expédier à',
+ 'Ship via' => 'Expédier via',
+ 'Short' => 'Court',
+ 'Signature' => 'Signature',
+ 'Sold' => 'Vendu',
+ 'Source' => 'Source',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Relevé',
+ 'Statement Balance' => 'Relevé de compte',
+ 'Statement sent to' => 'Relevé envoyé à',
+ 'Statements sent to printer!' => 'Relevés envoyés à l\'imprimante!',
+ 'Stock Assembly' => 'Stock de produits',
+ 'Stylesheet' => 'Feuille de style',
+ 'Subject' => 'Objet',
+ 'Subtotal' => 'Sous Total',
+ 'System' => 'Système',
+ 'Tax' => 'Taxe',
+ 'Tax Accounts' => 'Comptes de taxe',
+ 'Tax Included' => 'Taxe incluse',
+ 'Tax collected' => 'Taxe collectée',
+ 'Tax paid' => 'Taxe payée',
+ 'Taxable' => 'Imposable',
+ 'Template saved!' => 'Gabarit enregistré!',
+ 'Templates' => 'Gabarits',
+ 'Terms: Net' => 'Crédit limité à',
+ 'The following Datasets are not in use and can be deleted' => 'Les fichiers de données suivants ne sont pas utilisés et peuvent être supprimés.',
+ 'The following Datasets need to be updated' => 'Les fichiers de données suivants doivent être mis a jour',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Ceci est un test préliminaire des sources existante. Aucune modification à ce stade!!',
+ 'To' => 'à ',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Pour ajouter un utilisateur à un groupe, editer un "nom", changer le "login" et enregistrer. Un nouveau utilisateur avec les mêmes données sera enregistré avec le nouveau "login".',
+ 'Top Level' => 'Description principale',
+ 'Total' => 'Total',
+ 'Transaction Date missing!' => 'Date d\'écriture manquante!',
+ 'Transaction deleted!' => 'Ecriture supprimée!',
+ 'Transaction posted!' => 'Ecriture enregistrée!',
+ 'Transaction reversal enforced for all dates' => 'Inversion des écritures exécuté pour toutes les dates',
+ 'Transaction reversal enforced up to' => 'Inversion des écritures exécuté jusqu\'au',
+ 'Transactions' => 'Mouvements',
+ 'Transactions exist, cannot delete customer!' => 'Des écritures existent, impossible d\'effacer le client!',
+ 'Transactions exist, cannot delete vendor!' => 'Des écritures existent, impossible d\'effacer le fournisseur!',
+ 'Transactions exist; cannot delete account!' => 'Des écritures existent, impossible d\'effacer le compte!',
+ 'Trial Balance' => 'Balance Globale',
+ 'Unit' => 'Unité',
+ 'Unit of measure' => 'Unité de mesure',
+ 'Update' => 'Mettre à jour',
+ 'Update Dataset' => 'Mis à jour de la base de données',
+ 'Updated' => 'Mis à jour',
+ 'Use Templates' => 'Utiliser les modèles',
+ 'User' => 'Utilisateur',
+ 'User deleted!' => 'Utilisateur supprimé!',
+ 'User saved!' => 'Utilisateur enregistré!',
+ 'Vendor' => 'Fournisseur',
+ 'Vendor deleted!' => 'Fournisseur supprimé!',
+ 'Vendor missing!' => 'Fournisseur manquant!',
+ 'Vendor not on file!' => 'Fournisseur absent du fichier!',
+ 'Vendor saved!' => 'Fournisseur enregistré!',
+ 'Vendors' => 'Fournisseurs',
+ 'Version' => 'Version',
+ 'Weight' => 'Poids',
+ 'Weight Unit' => 'Unité de poids',
+ 'What type of item is this?' => 'De quel type est ce poste?',
+ 'Year End' => 'Fin d\'année',
+ 'Yes' => 'Oui',
+ 'You are logged out!' => 'Vous êtes déconnecté!',
+ 'You did not enter a name!' => 'Vous n\'avez pas saisi de nom!',
+ 'You must enter a host and port for local and remote connections!' => 'Vous devez saisir un "hôte" et un "port" pour les connexions distantes!',
+ 'as at' => 'au',
+ 'collected on sales' => 'collectées sur les ventes',
+ 'days' => 'jours',
+ 'does not exist' => 'n\'existe pas!',
+ 'ea' => 'ch',
+ 'emailed to' => 'envoyé par email à',
+ 'for Period' => 'pour la période',
+ 'hr' => 'h',
+ 'is already a member!' => 'est déjà un membre!',
+ 'is not a member!' => 'n\'est pas un membre',
+ 'localhost' => 'hôte local',
+ 'locked!' => 'verrouillé!',
+ 'paid on purchases' => 'payées sur les achats',
+ 'sent to printer' => 'envoyé à l\'imprimante',
+ 'successfully created!' => 'créé avec succès',
+ 'successfully deleted!' => 'supprimé avec succès',
+ 'to' => 'jusqu\'au',
+ 'website' => 'site web',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/am b/sql-ledger/locale/fr/am
new file mode 100644
index 0000000..2c61263
--- /dev/null
+++ b/sql-ledger/locale/fr/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Dépenses',
+ 'AR' => 'Recettes',
+ 'Account' => 'Compte',
+ 'Account Number' => 'Numéro de compte',
+ 'Account Number missing!' => 'Numéro de compte manquant!',
+ 'Account Type' => 'Type de compte',
+ 'Account Type missing!' => 'Type de compte manquant!',
+ 'Account deleted!' => 'Compte supprimé',
+ 'Account saved!' => 'Compte enregistré',
+ 'Add Account' => 'Ajouter compte',
+ 'Add GIFI' => 'Ajouter Code d\'Identification Comptable ou Fiscale',
+ 'Address' => 'Adresse',
+ 'Asset' => 'Actif',
+ 'Audit Control' => 'Clôture périodique',
+ 'Backup sent to' => 'Sauvegarde envoyée à',
+ 'Books are open' => 'Début exercice',
+ 'Business Number' => 'Numéro d\'enregistrement société',
+ 'COGS' => 'CMV',
+ 'Cannot delete account!' => 'Impossible de supprimer le compte!',
+ 'Cannot delete default account!' => 'Ne peut pas supprimer le compte par defaut!',
+ 'Cannot save account!' => 'Impossible d\'enregistrer le compte!',
+ 'Cannot save preferences!' => 'Impossible d\'enregistrer les préférences',
+ 'Character Set' => 'Encodage des caractères',
+ 'Chart of Accounts' => 'Plan Comptable',
+ 'Close Books up to' => 'Clôturer l\'exercice jusqu\'au',
+ 'Company' => 'Société',
+ 'Continue' => 'Continuer',
+ 'Copy to COA' => 'Copier dans le Plan Comptable',
+ 'Credit' => 'Crédit',
+ 'Date Format' => 'Format de Date',
+ 'Debit' => 'Débit',
+ 'Delete' => 'Supprimer',
+ 'Delete Account' => 'Supprimer compte',
+ 'Description' => 'Description',
+ 'Dropdown Limit' => 'Limit de déroulement',
+ 'E-mail' => 'Email',
+ 'Edit' => 'Modifier',
+ 'Edit Account' => 'Modifier le compte',
+ 'Edit GIFI' => 'Modifier Code d\'Identification Comptable ou Fiscale',
+ 'Edit Preferences for' => 'Modifier les préférences pour',
+ 'Edit Template' => 'Modifier modèle',
+ 'Enforce transaction reversal for all dates' => 'Appliquer l\'inversion des écritures pour toutes les dates',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Entrer le nom de la monnaie nationale et des monnaies étrangères en 3 lettres séparées par (:) (Ex: EUR:USD:CAD)',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Dépense',
+ 'Expense Account' => 'Compte Dépenses',
+ 'Expense/Asset' => 'Dépense/Actif',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Produit conversion devises',
+ 'Foreign Exchange Loss' => 'Perte conversion devises',
+ 'GIFI' => 'Code d\'Identification Comptable ou Fiscale',
+ 'GIFI deleted!' => 'Code d\'Identification Comptable ou Fiscale supprimé!',
+ 'GIFI missing!' => 'Code d\'Identification Comptable ou Fiscale manquant!',
+ 'GIFI saved!' => 'Code d\'Identification Comptable ou Fiscale enregistré!',
+ 'Heading' => 'En-tête',
+ 'Include in drop-down menus' => 'Inclure dans les menus deroulants',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Afficher ce compte sur les formulaires de client/fournisseur pour le marquer comme imposable?',
+ 'Income' => 'Recettes',
+ 'Income Account' => 'Compte Recettes',
+ 'Inventory' => 'Inventaire',
+ 'Inventory Account' => 'Compte d\'Inventaire',
+ 'Is this a summary account to record' => 'Est-ce que c\'est un compte sommaire à enregistrer?',
+ 'Language' => 'Langue',
+ 'Last Invoice Number' => 'Dernier numéro de facture',
+ 'Last Numbers & Default Accounts' => 'Derniers numéros et comptes par défauts',
+ 'Last Purchase Order Number' => 'Dernier numéro de commande d\'achat',
+ 'Last Sales Order Number' => 'Numéro de la dernière commande de vente',
+ 'Liability' => 'Passif',
+ 'Link' => 'Liens',
+ 'Name' => 'Nom',
+ 'No' => 'Non',
+ 'No email address for' => 'Pas d\'adresse email pour',
+ 'Number' => 'Numéro',
+ 'Number Format' => 'Format des numéros',
+ 'Parts Inventory' => 'Inventaire marchandises',
+ 'Password' => 'Mot de Passe',
+ 'Payables' => 'À Payer',
+ 'Payment' => 'Paiement',
+ 'Phone' => 'Tél.',
+ 'Preferences saved!' => 'Préférences enregistrées!',
+ 'Rate' => 'Cadence',
+ 'Receivables' => 'À recevoir',
+ 'Sales' => 'Ventes',
+ 'Save' => 'Enregistrer',
+ 'Service Items' => 'Services',
+ 'Ship via' => 'Expédier via',
+ 'Signature' => 'Signature',
+ 'Stylesheet' => 'Feuille de style',
+ 'Tax' => 'Taxe',
+ 'Tax Accounts' => 'Comptes de taxe',
+ 'Template saved!' => 'Gabarit enregistré!',
+ 'Transaction reversal enforced for all dates' => 'Inversion des écritures exécuté pour toutes les dates',
+ 'Transaction reversal enforced up to' => 'Inversion des écritures exécuté jusqu\'au',
+ 'Transactions exist; cannot delete account!' => 'Des écritures existent, impossible d\'effacer le compte!',
+ 'Weight Unit' => 'Unité de poids',
+ 'Year End' => 'Fin d\'année',
+ 'Yes' => 'Oui',
+ 'does not exist' => 'n\'existe pas!',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'ajouter_compte' => 'add_account',
+ 'continuer' => 'continue',
+ 'copier_dans_le_plan_comptable' => 'copy_to_coa',
+ 'supprimer' => 'delete',
+ 'modifier' => 'edit',
+ 'modifier_le_compte' => 'edit_account',
+ 'enregistrer' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/ap b/sql-ledger/locale/fr/ap
new file mode 100644
index 0000000..ac20a09
--- /dev/null
+++ b/sql-ledger/locale/fr/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Ecriture Dépense',
+ 'AP Transactions' => 'Mouvements - Dépenses',
+ 'Account' => 'Compte',
+ 'Add Accounts Payables Transaction' => 'Saisie d\'écriture - Dépenses',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Montant dû',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Are you sure you want to delete Transaction' => 'Êtes vous sûr de vouloir effacer la saisie?',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'Cannot delete transaction!' => 'Impossible de supprimer la saisie!',
+ 'Cannot post payment for a closed period!' => 'Impossible d\'enregistrer le paiement sur un exercice clos!',
+ 'Cannot post transaction for a closed period!' => 'Impossible d\'enregistrer l\'écriture sur un exercice clos!',
+ 'Cannot post transaction!' => 'Impossible d\'enregistrer l\'écriture!',
+ 'Closed' => 'Clôturé',
+ 'Confirm!' => 'Confirmez!',
+ 'Continue' => 'Continuer',
+ 'Currency' => 'Devise',
+ 'Customer not on file!' => 'Client absent du fichier!',
+ 'Date' => 'Date',
+ 'Date Paid' => 'Date de paiement',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Delete' => 'Supprimer',
+ 'Description' => 'Description',
+ 'Due Date' => 'Date d\'échéance',
+ 'Due Date missing!' => 'Date d\'échéance manquante!',
+ 'Edit Accounts Payables Transaction' => 'Modifier Mouvements - Dépenses',
+ 'Employee' => 'Employé',
+ 'Exch' => 'Change',
+ 'Exchangerate' => 'Taux de change',
+ 'Exchangerate for payment missing!' => 'Taux de change manquant pour le paiement!',
+ 'Exchangerate missing!' => 'Taux de change manquant!',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inclure dans l\'état',
+ 'Invoice' => 'Facture',
+ 'Invoice Date' => 'Date de facturation',
+ 'Invoice Date missing!' => 'Date de facture manquante!',
+ 'Invoice Number' => 'Numéro de facture',
+ 'Invoice Number missing!' => 'Numéro de facture manquant!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Number' => 'Numéro',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'Open' => 'Ouvert',
+ 'Order' => 'Commande',
+ 'Order Number' => 'Numéro de commande',
+ 'Paid' => 'Total Payé',
+ 'Payment date missing!' => 'Date de paiement manquant!',
+ 'Payments' => 'Paiements',
+ 'Post' => 'Enregistrer',
+ 'Post as new' => 'Enregistrer comme nouveau',
+ 'Project' => 'Projet',
+ 'Project not on file!' => 'Projet absent du fichier!',
+ 'Purchase Invoice' => 'Facture d\'Achat',
+ 'Select from one of the names below' => 'Sélectionner un des noms ci-dessous',
+ 'Select from one of the projects below' => 'Sélectionner un des projets ci-dessous',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Source' => 'Source',
+ 'Subtotal' => 'Sous Total',
+ 'Tax' => 'Taxe',
+ 'Tax Included' => 'Taxe incluse',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Ecriture supprimée!',
+ 'Transaction posted!' => 'Ecriture enregistrée!',
+ 'Update' => 'Mettre à jour',
+ 'Vendor' => 'Fournisseur',
+ 'Vendor missing!' => 'Fournisseur manquant!',
+ 'Vendor not on file!' => 'Fournisseur absent du fichier!',
+ 'Yes' => 'Oui',
+ 'to' => 'jusqu\'au',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ecriture_dépense' => 'ap_transaction',
+ 'saisie_d\'écriture___dépenses' => 'add_accounts_payables_transaction',
+ 'continuer' => 'continue',
+ 'supprimer' => 'delete',
+ 'modifier_mouvements___dépenses' => 'edit_accounts_payables_transaction',
+ 'enregistrer' => 'post',
+ 'enregistrer_comme_nouveau' => 'post_as_new',
+ 'facture_d\'achat' => 'purchase_invoice',
+ 'mettre_à_jour' => 'update',
+ 'oui' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/ar b/sql-ledger/locale/fr/ar
new file mode 100644
index 0000000..49f2828
--- /dev/null
+++ b/sql-ledger/locale/fr/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Ecriture Recette',
+ 'AR Transactions' => 'Mouvements - Recettes',
+ 'Account' => 'Compte',
+ 'Add Accounts Receivables Transaction' => 'Saisie d\'écriture - Recettes',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Montant dû',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Are you sure you want to delete Transaction' => 'Êtes vous sûr de vouloir effacer la saisie?',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'Cannot delete transaction!' => 'Impossible de supprimer la saisie!',
+ 'Cannot post payment for a closed period!' => 'Impossible d\'enregistrer le paiement sur un exercice clos!',
+ 'Cannot post transaction for a closed period!' => 'Impossible d\'enregistrer l\'écriture sur un exercice clos!',
+ 'Cannot post transaction!' => 'Impossible d\'enregistrer l\'écriture!',
+ 'Closed' => 'Clôturé',
+ 'Confirm!' => 'Confirmez!',
+ 'Continue' => 'Continuer',
+ 'Credit Limit' => 'Encours autorisé',
+ 'Currency' => 'Devise',
+ 'Customer' => 'Client',
+ 'Customer missing!' => 'Client manquant!',
+ 'Customer not on file!' => 'Client absent du fichier!',
+ 'Date' => 'Date',
+ 'Date Paid' => 'Date de paiement',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Delete' => 'Supprimer',
+ 'Description' => 'Description',
+ 'Due Date' => 'Date d\'échéance',
+ 'Due Date missing!' => 'Date d\'échéance manquante!',
+ 'Edit Accounts Receivables Transaction' => 'Modifier Mouvements - Recettes',
+ 'Employee' => 'Employé',
+ 'Exch' => 'Change',
+ 'Exchangerate' => 'Taux de change',
+ 'Exchangerate for payment missing!' => 'Taux de change manquant pour le paiement!',
+ 'Exchangerate missing!' => 'Taux de change manquant!',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inclure dans l\'état',
+ 'Invoice' => 'Facture',
+ 'Invoice Date' => 'Date de facturation',
+ 'Invoice Date missing!' => 'Date de facture manquante!',
+ 'Invoice Number' => 'Numéro de facture',
+ 'Invoice Number missing!' => 'Numéro de facture manquant!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Number' => 'Numéro',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'Open' => 'Ouvert',
+ 'Order' => 'Commande',
+ 'Order Number' => 'Numéro de commande',
+ 'Paid' => 'Total Payé',
+ 'Payment date missing!' => 'Date de paiement manquant!',
+ 'Payments' => 'Paiements',
+ 'Post' => 'Enregistrer',
+ 'Post as new' => 'Enregistrer comme nouveau',
+ 'Project' => 'Projet',
+ 'Project not on file!' => 'Projet absent du fichier!',
+ 'Remaining' => 'Restant',
+ 'Sales Invoice' => 'Facture de Vente',
+ 'Select from one of the names below' => 'Sélectionner un des noms ci-dessous',
+ 'Select from one of the projects below' => 'Sélectionner un des projets ci-dessous',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Source' => 'Source',
+ 'Subtotal' => 'Sous Total',
+ 'Tax' => 'Taxe',
+ 'Tax Included' => 'Taxe incluse',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Ecriture supprimée!',
+ 'Transaction posted!' => 'Ecriture enregistrée!',
+ 'Update' => 'Mettre à jour',
+ 'Vendor not on file!' => 'Fournisseur absent du fichier!',
+ 'Yes' => 'Oui',
+ 'to' => 'jusqu\'au',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ecriture_recette' => 'ar_transaction',
+ 'continuer' => 'continue',
+ 'supprimer' => 'delete',
+ 'enregistrer' => 'post',
+ 'enregistrer_comme_nouveau' => 'post_as_new',
+ 'facture_de_vente' => 'sales_invoice',
+ 'mettre_à_jour' => 'update',
+ 'oui' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/arap b/sql-ledger/locale/fr/arap
new file mode 100644
index 0000000..369913f
--- /dev/null
+++ b/sql-ledger/locale/fr/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adresse',
+ 'Continue' => 'Continuer',
+ 'Customer not on file!' => 'Client absent du fichier!',
+ 'Description' => 'Description',
+ 'Number' => 'Numéro',
+ 'Project not on file!' => 'Projet absent du fichier!',
+ 'Select from one of the names below' => 'Sélectionner un des noms ci-dessous',
+ 'Select from one of the projects below' => 'Sélectionner un des projets ci-dessous',
+ 'Vendor not on file!' => 'Fournisseur absent du fichier!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'continuer' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/ca b/sql-ledger/locale/fr/ca
new file mode 100644
index 0000000..1e011ac
--- /dev/null
+++ b/sql-ledger/locale/fr/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Compte',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'Balance' => 'Solde',
+ 'Chart of Accounts' => 'Plan Comptable',
+ 'Credit' => 'Crédit',
+ 'Date' => 'Date',
+ 'Debit' => 'Débit',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Description' => 'Description',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'From' => 'De',
+ 'GIFI' => 'Code d\'Identification Comptable ou Fiscale',
+ 'Include in Report' => 'Inclure dans l\'état',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'List Transactions' => 'Afficher écritures',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'Reference' => 'Référence',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Subtotal' => 'Sous Total',
+ 'to' => 'jusqu\'au',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'afficher_écritures' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/cp b/sql-ledger/locale/fr/cp
new file mode 100644
index 0000000..b769513
--- /dev/null
+++ b/sql-ledger/locale/fr/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'Compte',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Total',
+ 'Amount does not equal applied!' => 'Le montant n\'est égal à celui appliqué!',
+ 'Amount missing!' => 'Montant manquant',
+ 'Applied' => 'Appliquer',
+ 'Cannot post payment!' => 'Impossible d\'enregistrer le paiement!',
+ 'Cannot process payment for a closed period!' => 'Impossible de faire un paiement sur un exercice clos!',
+ 'Check' => 'Chèque',
+ 'Check printed!' => 'Chèque imprimé!',
+ 'Check printing failed!' => 'Impression du chèque échoué!',
+ 'Continue' => 'Continuer',
+ 'Currency' => 'Devise',
+ 'Customer' => 'Client',
+ 'Customer not on file!' => 'Client absent du fichier!',
+ 'Date' => 'Date',
+ 'Date missing!' => 'Date manquante!',
+ 'Description' => 'Description',
+ 'Due' => 'Echéance',
+ 'Exchangerate' => 'Taux de change',
+ 'From' => 'De',
+ 'Invoice' => 'Facture',
+ 'Invoices' => 'Factures',
+ 'Nothing applied!' => 'Rien n\'a été appliqué!',
+ 'Number' => 'Numéro',
+ 'Paid in full' => 'Complètement payé',
+ 'Payment' => 'Paiement',
+ 'Payment posted!' => 'Paiement enregistré!',
+ 'Post' => 'Enregistrer',
+ 'Print' => 'Imprimer',
+ 'Printer' => 'Imprimante',
+ 'Project not on file!' => 'Projet absent du fichier!',
+ 'Receipt' => 'Reçu',
+ 'Receipt printed!' => 'Receipt printed!',
+ 'Receipt printing failed!' => 'Receipt printing failed!',
+ 'Reference' => 'Référence',
+ 'Screen' => 'Écran',
+ 'Select from one of the names below' => 'Sélectionner un des noms ci-dessous',
+ 'Select from one of the projects below' => 'Sélectionner un des projets ci-dessous',
+ 'Update' => 'Mettre à jour',
+ 'Vendor' => 'Fournisseur',
+ 'Vendor not on file!' => 'Fournisseur absent du fichier!',
+ 'to' => 'jusqu\'au',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'continuer' => 'continue',
+ 'enregistrer' => 'post',
+ 'imprimer' => 'print',
+ 'mettre_à_jour' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/ct b/sql-ledger/locale/fr/ct
new file mode 100644
index 0000000..21be5e2
--- /dev/null
+++ b/sql-ledger/locale/fr/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Ajouter',
+ 'Address' => 'Adresse',
+ 'All' => 'Tous',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Impossible de supprimer le client!',
+ 'Cannot delete vendor!' => 'Impossible de supprimer le fournisseur!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continuer',
+ 'Credit Limit' => 'Encours autorisé',
+ 'Customer deleted!' => 'Client supprimé!',
+ 'Customer saved!' => 'Client enregistré!',
+ 'Customers' => 'Clients',
+ 'Delete' => 'Supprimer',
+ 'Discount' => 'Remise',
+ 'E-mail' => 'Email',
+ 'Edit Customer' => 'Modifier client',
+ 'Edit Vendor' => 'Modifier fournisseur',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Inclure dans l\'état',
+ 'Invoice' => 'Facture',
+ 'Name' => 'Nom',
+ 'Name missing!' => 'Nom manquant!',
+ 'Notes' => 'Notes',
+ 'Number' => 'Numéro',
+ 'Order' => 'Commande',
+ 'Orphaned' => 'Orphelin',
+ 'Phone' => 'Tél.',
+ 'Save' => 'Enregistrer',
+ 'Ship to' => 'Expédier à',
+ 'Tax Included' => 'Taxe incluse',
+ 'Taxable' => 'Imposable',
+ 'Terms: Net' => 'Crédit limité à',
+ 'Transactions exist, cannot delete customer!' => 'Des écritures existent, impossible d\'effacer le client!',
+ 'Transactions exist, cannot delete vendor!' => 'Des écritures existent, impossible d\'effacer le fournisseur!',
+ 'Vendor deleted!' => 'Fournisseur supprimé!',
+ 'Vendor saved!' => 'Fournisseur enregistré!',
+ 'Vendors' => 'Fournisseurs',
+ 'days' => 'jours',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'ajouter' => 'add',
+ 'continuer' => 'continue',
+ 'supprimer' => 'delete',
+ 'facture' => 'invoice',
+ 'commande' => 'order',
+ 'enregistrer' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/gl b/sql-ledger/locale/fr/gl
new file mode 100644
index 0000000..da2e0ce
--- /dev/null
+++ b/sql-ledger/locale/fr/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Ecriture Dépense',
+ 'AR Transaction' => 'Ecriture Recette',
+ 'Account' => 'Compte',
+ 'Add General Ledger Transaction' => 'Ajouter une écriture au Grand Livre',
+ 'Address' => 'Adresse',
+ 'All' => 'Tous',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Are you sure you want to delete Transaction' => 'Êtes vous sûr de vouloir effacer la saisie?',
+ 'Asset' => 'Actif',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'Balance' => 'Solde',
+ 'Cannot delete transaction!' => 'Impossible de supprimer la saisie!',
+ 'Cannot have a value in both Debit and Credit!' => 'Impossible d\'avoir des valeurs dans Crédit et Débit en même temps!',
+ 'Cannot post a transaction without a value!' => 'Impossible d\'effectuer une écriture sans valeur!',
+ 'Cannot post transaction for a closed period!' => 'Impossible d\'enregistrer l\'écriture sur un exercice clos!',
+ 'Confirm!' => 'Confirmez!',
+ 'Continue' => 'Continuer',
+ 'Credit' => 'Crédit',
+ 'Customer not on file!' => 'Client absent du fichier!',
+ 'Date' => 'Date',
+ 'Debit' => 'Débit',
+ 'Debit and credit out of balance!' => 'Le débit et le crédit ne sont pas équilibrés!',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Delete' => 'Supprimer',
+ 'Description' => 'Description',
+ 'Edit General Ledger Transaction' => 'Modifier écriture Grand Livre',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Dépense',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'From' => 'De',
+ 'GIFI' => 'Code d\'Identification Comptable ou Fiscale',
+ 'GL Transaction' => 'Transaction Grand Livre',
+ 'General Ledger' => 'Grand Livre',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inclure dans l\'état',
+ 'Income' => 'Recettes',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'Liability' => 'Passif',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Number' => 'Numéro',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'Post' => 'Enregistrer',
+ 'Post as new' => 'Enregistrer comme nouveau',
+ 'Project' => 'Projet',
+ 'Project not on file!' => 'Projet absent du fichier!',
+ 'Purchase Invoice' => 'Facture d\'Achat',
+ 'Reference' => 'Référence',
+ 'Reference missing!' => 'Référence manquant!',
+ 'Reports' => 'Rapports',
+ 'Sales Invoice' => 'Facture de Vente',
+ 'Select from one of the names below' => 'Sélectionner un des noms ci-dessous',
+ 'Select from one of the projects below' => 'Sélectionner un des projets ci-dessous',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Source' => 'Source',
+ 'Subtotal' => 'Sous Total',
+ 'Transaction Date missing!' => 'Date d\'écriture manquante!',
+ 'Transaction deleted!' => 'Ecriture supprimée!',
+ 'Transaction posted!' => 'Ecriture enregistrée!',
+ 'Update' => 'Mettre à jour',
+ 'Vendor not on file!' => 'Fournisseur absent du fichier!',
+ 'Yes' => 'Oui',
+ 'to' => 'jusqu\'au',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ecriture_dépense' => 'ap_transaction',
+ 'ecriture_recette' => 'ar_transaction',
+ 'continuer' => 'continue',
+ 'supprimer' => 'delete',
+ 'transaction_grand_livre' => 'gl_transaction',
+ 'enregistrer' => 'post',
+ 'enregistrer_comme_nouveau' => 'post_as_new',
+ 'facture_d\'achat' => 'purchase_invoice',
+ 'facture_de_vente' => 'sales_invoice',
+ 'mettre_à_jour' => 'update',
+ 'oui' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/ic b/sql-ledger/locale/fr/ic
new file mode 100644
index 0000000..58ffab7
--- /dev/null
+++ b/sql-ledger/locale/fr/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => 'Actif',
+ 'Add' => 'Ajouter',
+ 'Add Assembly' => 'Ajouter produit',
+ 'Add Part' => 'Ajouter marchandise',
+ 'Add Purchase Order' => 'Etablir commande d\'achat',
+ 'Add Sales Order' => 'Etablir commande de vente',
+ 'Add Service' => 'Ajouter service',
+ 'Address' => 'Adresse',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Assemblies' => 'Produits finis',
+ 'Assemblies restocked!' => 'Renvoyer produits vers stock!',
+ 'Assembly Number missing!' => 'Numéro de produit manquant',
+ 'Attachment' => 'Pièce jointe',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'BOM' => 'Nomenclature composantes',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Localisation',
+ 'Bought' => 'Acheté',
+ 'COGS' => 'CMV',
+ 'Cannot delete item already invoiced!' => 'Ne peut pas effacer un élément qui est déjà facturé!',
+ 'Cannot delete item on order!' => 'Impossible de supprimer un élément faisant partie d\'une commande',
+ 'Cannot delete item which is part of an assembly!' => 'Ne peut pas supprimer une marchandise qui est intégrée dans un produit fini!',
+ 'Cannot delete item!' => 'Impossible de supprimer ce poste!',
+ 'Cannot stock assemblies!' => 'Impossible de stocker l\'assemblage!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continuer',
+ 'Copies' => 'Copies',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Delete' => 'Supprimer',
+ 'Delivery Date' => 'Date de livraison',
+ 'Description' => 'Description',
+ 'Drawing' => 'Dessin',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Adresse email manquante!',
+ 'Edit Assembly' => 'Modifier produit fini / transformé',
+ 'Edit Part' => 'Modifier marchandise',
+ 'Edit Service' => 'Modifier service',
+ 'Expense' => 'Dépense',
+ 'Extended' => 'Prix Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'From' => 'De',
+ 'Image' => 'Image',
+ 'In-line' => 'En ligne',
+ 'Include in Report' => 'Inclure dans l\'état',
+ 'Income' => 'Recettes',
+ 'Individual Items' => 'Composition en marchandises individuelles',
+ 'Inventory' => 'Inventaire',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La quantité en stock doit être à zéro avant de pouvoir indiquer cet assemblage comme obsolète!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La quantité en stock devrait être zero avant de pouvoir indiquer cette pièce comme obsolète!',
+ 'Inventory quantity must be zero!' => 'La quantité en stock doit être zero!',
+ 'Invoice' => 'Facture',
+ 'Invoice Date missing!' => 'Date de facture manquante!',
+ 'Invoice Number' => 'Numéro de facture',
+ 'Invoice Number missing!' => 'Numéro de facture manquant!',
+ 'Item deleted!' => 'Objet supprimé!',
+ 'Item not on file!' => 'Objet non-listé!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'Last Cost' => 'Dernier prix',
+ 'Line Total' => 'Total ligne',
+ 'Link Accounts' => 'Lier Comptes',
+ 'List Price' => 'Prix d\'achat',
+ 'Make' => 'Marque',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Message',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modèle',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Number' => 'Numéro',
+ 'Number missing in Row' => 'Numéro manquant dans ligne',
+ 'Obsolete' => 'Obsolète',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'On Hand' => 'En Stock / Disponible',
+ 'On Order' => 'Sur Commande',
+ 'Order' => 'Commande',
+ 'Order Date missing!' => 'Date de commande manquante!',
+ 'Order Number' => 'Numéro de commande',
+ 'Order Number missing!' => 'Numéro de commande manquant!',
+ 'Ordered' => 'Commandé',
+ 'Orphaned' => 'Orphelin',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Liste d\'envoi',
+ 'Packing List Date missing!' => 'La date est manquante sur la liste d\'envoi!',
+ 'Packing List Number missing!' => 'Le numéro de liste d\'envoi est manquant!',
+ 'Part' => 'Marchandise',
+ 'Part Number missing!' => 'Numéro de marchandise manquant!',
+ 'Parts' => 'Marchandises',
+ 'Phone' => 'Tél.',
+ 'Postscript' => 'Postcript',
+ 'Price' => 'Prix',
+ 'Printer' => 'Imprimante',
+ 'Project' => 'Projet',
+ 'Purchase Order' => 'Commande d\'Achat',
+ 'Qty' => 'Qté',
+ 'ROP' => 'Niveau de commande',
+ 'Recd' => 'Reçu',
+ 'Required by' => 'Requis pour',
+ 'Sales' => 'Ventes',
+ 'Sales Order' => 'Commande de Vente',
+ 'Save' => 'Enregistrer',
+ 'Screen' => 'Écran',
+ 'Select from one of the items below' => 'Sélectionner un des postes ci-dessous',
+ 'Select postscript or PDF!' => 'Sélectionner Postscript ou PDF',
+ 'Sell Price' => 'Prix de vente',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Service' => 'Service',
+ 'Service Number missing!' => 'Numéro de service manquant!',
+ 'Services' => 'Services',
+ 'Ship' => 'Expédier',
+ 'Ship to' => 'Expédier à',
+ 'Short' => 'Court',
+ 'Sold' => 'Vendu',
+ 'Stock Assembly' => 'Stock de produits',
+ 'Subject' => 'Objet',
+ 'Subtotal' => 'Sous Total',
+ 'Tax' => 'Taxe',
+ 'To' => 'à ',
+ 'Top Level' => 'Description principale',
+ 'Total' => 'Total',
+ 'Unit' => 'Unité',
+ 'Unit of measure' => 'Unité de mesure',
+ 'Update' => 'Mettre à jour',
+ 'Updated' => 'Mis à jour',
+ 'Weight' => 'Poids',
+ 'What type of item is this?' => 'De quel type est ce poste?',
+ 'ea' => 'ch',
+ 'emailed to' => 'envoyé par email à',
+ 'hr' => 'h',
+ 'sent to printer' => 'envoyé à l\'imprimante',
+ 'to' => 'jusqu\'au',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'ajouter' => 'add',
+ 'ajouter_produit' => 'add_assembly',
+ 'ajouter_marchandise' => 'add_part',
+ 'ajouter_service' => 'add_service',
+ 'continuer' => 'continue',
+ 'supprimer' => 'delete',
+ 'modifier_produit_fini_/_transformé' => 'edit_assembly',
+ 'modifier_marchandise' => 'edit_part',
+ 'modifier_service' => 'edit_service',
+ 'enregistrer' => 'save',
+ 'mettre_à_jour' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/io b/sql-ledger/locale/fr/io
new file mode 100644
index 0000000..2ad48bc
--- /dev/null
+++ b/sql-ledger/locale/fr/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Etablir commande d\'achat',
+ 'Add Sales Order' => 'Etablir commande de vente',
+ 'Address' => 'Adresse',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Attachment' => 'Pièce jointe',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Localisation',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continuer',
+ 'Copies' => 'Copies',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Delivery Date' => 'Date de livraison',
+ 'Description' => 'Description',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Adresse email manquante!',
+ 'Extended' => 'Prix Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'In-line' => 'En ligne',
+ 'Invoice' => 'Facture',
+ 'Invoice Date missing!' => 'Date de facture manquante!',
+ 'Invoice Number missing!' => 'Numéro de facture manquant!',
+ 'Item not on file!' => 'Objet non-listé!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Message',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Number' => 'Numéro',
+ 'Number missing in Row' => 'Numéro manquant dans ligne',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'Order' => 'Commande',
+ 'Order Date missing!' => 'Date de commande manquante!',
+ 'Order Number missing!' => 'Numéro de commande manquant!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Liste d\'envoi',
+ 'Packing List Date missing!' => 'La date est manquante sur la liste d\'envoi!',
+ 'Packing List Number missing!' => 'Le numéro de liste d\'envoi est manquant!',
+ 'Part' => 'Marchandise',
+ 'Phone' => 'Tél.',
+ 'Postscript' => 'Postcript',
+ 'Price' => 'Prix',
+ 'Printer' => 'Imprimante',
+ 'Project' => 'Projet',
+ 'Purchase Order' => 'Commande d\'Achat',
+ 'Qty' => 'Qté',
+ 'Recd' => 'Reçu',
+ 'Required by' => 'Requis pour',
+ 'Sales Order' => 'Commande de Vente',
+ 'Screen' => 'Écran',
+ 'Select from one of the items below' => 'Sélectionner un des postes ci-dessous',
+ 'Select postscript or PDF!' => 'Sélectionner Postscript ou PDF',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Service' => 'Service',
+ 'Ship' => 'Expédier',
+ 'Ship to' => 'Expédier à',
+ 'Subject' => 'Objet',
+ 'To' => 'à ',
+ 'Unit' => 'Unité',
+ 'What type of item is this?' => 'De quel type est ce poste?',
+ 'emailed to' => 'envoyé par email à',
+ 'sent to printer' => 'envoyé à l\'imprimante',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continuer' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/ir b/sql-ledger/locale/fr/ir
new file mode 100644
index 0000000..edeec1f
--- /dev/null
+++ b/sql-ledger/locale/fr/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Compte',
+ 'Add Purchase Invoice' => 'Etablir facture d\'achat',
+ 'Add Purchase Order' => 'Etablir commande d\'achat',
+ 'Add Sales Order' => 'Etablir commande de vente',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Total',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Are you sure you want to delete Invoice Number' => 'Êtes-vous sûr de vouloir supprimer la Facture No.:',
+ 'Attachment' => 'Pièce jointe',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Localisation',
+ 'Cannot delete invoice!' => 'Impossible de supprimer la facture',
+ 'Cannot post invoice for a closed period!' => 'Impossible d\'enregistrer la facture sur un exercice clos!',
+ 'Cannot post invoice!' => 'Impossible d\'enregistrer la facture!',
+ 'Cannot post payment for a closed period!' => 'Impossible d\'enregistrer le paiement sur un exercice clos!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmez!',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continuer',
+ 'Copies' => 'Copies',
+ 'Currency' => 'Devise',
+ 'Customer not on file!' => 'Client absent du fichier!',
+ 'Date' => 'Date',
+ 'Date Due' => 'Date d\'échéance',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Delete' => 'Supprimer',
+ 'Delivery Date' => 'Date de livraison',
+ 'Description' => 'Description',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Adresse email manquante!',
+ 'Edit Purchase Invoice' => 'Modifier facture d\'achat',
+ 'Exch' => 'Change',
+ 'Exchangerate' => 'Taux de change',
+ 'Exchangerate for payment missing!' => 'Taux de change manquant pour le paiement!',
+ 'Exchangerate missing!' => 'Taux de change manquant!',
+ 'Extended' => 'Prix Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'In-line' => 'En ligne',
+ 'Invoice' => 'Facture',
+ 'Invoice Date' => 'Date de facturation',
+ 'Invoice Date missing!' => 'Date de facture manquante!',
+ 'Invoice Number' => 'Numéro de facture',
+ 'Invoice Number missing!' => 'Numéro de facture manquant!',
+ 'Invoice deleted!' => 'Facture supprimé!',
+ 'Invoice posted!' => 'Facture enregistré!',
+ 'Item not on file!' => 'Objet non-listé!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Message',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Number' => 'Numéro',
+ 'Number missing in Row' => 'Numéro manquant dans ligne',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'Order' => 'Commande',
+ 'Order Date missing!' => 'Date de commande manquante!',
+ 'Order Number' => 'Numéro de commande',
+ 'Order Number missing!' => 'Numéro de commande manquant!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Liste d\'envoi',
+ 'Packing List Date missing!' => 'La date est manquante sur la liste d\'envoi!',
+ 'Packing List Number missing!' => 'Le numéro de liste d\'envoi est manquant!',
+ 'Part' => 'Marchandise',
+ 'Payment date missing!' => 'Date de paiement manquant!',
+ 'Payments' => 'Paiements',
+ 'Phone' => 'Tél.',
+ 'Post' => 'Enregistrer',
+ 'Post as new' => 'Enregistrer comme nouveau',
+ 'Postscript' => 'Postcript',
+ 'Price' => 'Prix',
+ 'Printer' => 'Imprimante',
+ 'Project' => 'Projet',
+ 'Project not on file!' => 'Projet absent du fichier!',
+ 'Purchase Order' => 'Commande d\'Achat',
+ 'Qty' => 'Qté',
+ 'Recd' => 'Reçu',
+ 'Record in' => 'Enregistrer dans',
+ 'Required by' => 'Requis pour',
+ 'Sales Order' => 'Commande de Vente',
+ 'Screen' => 'Écran',
+ 'Select from one of the items below' => 'Sélectionner un des postes ci-dessous',
+ 'Select from one of the names below' => 'Sélectionner un des noms ci-dessous',
+ 'Select from one of the projects below' => 'Sélectionner un des projets ci-dessous',
+ 'Select postscript or PDF!' => 'Sélectionner Postscript ou PDF',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Service' => 'Service',
+ 'Ship' => 'Expédier',
+ 'Ship to' => 'Expédier à',
+ 'Source' => 'Source',
+ 'Subject' => 'Objet',
+ 'Subtotal' => 'Sous Total',
+ 'Tax Included' => 'Taxe incluse',
+ 'To' => 'à ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unité',
+ 'Update' => 'Mettre à jour',
+ 'Vendor' => 'Fournisseur',
+ 'Vendor missing!' => 'Fournisseur manquant!',
+ 'Vendor not on file!' => 'Fournisseur absent du fichier!',
+ 'What type of item is this?' => 'De quel type est ce poste?',
+ 'Yes' => 'Oui',
+ 'ea' => 'ch',
+ 'emailed to' => 'envoyé par email à',
+ 'sent to printer' => 'envoyé à l\'imprimante',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuer' => 'continue',
+ 'supprimer' => 'delete',
+ 'commande' => 'order',
+ 'enregistrer' => 'post',
+ 'enregistrer_comme_nouveau' => 'post_as_new',
+ 'mettre_à_jour' => 'update',
+ 'oui' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/is b/sql-ledger/locale/fr/is
new file mode 100644
index 0000000..583e627
--- /dev/null
+++ b/sql-ledger/locale/fr/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Compte',
+ 'Add Purchase Order' => 'Etablir commande d\'achat',
+ 'Add Sales Invoice' => 'Etablir facture de vente',
+ 'Add Sales Order' => 'Etablir commande de vente',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Total',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Are you sure you want to delete Invoice Number' => 'Êtes-vous sûr de vouloir supprimer la Facture No.:',
+ 'Attachment' => 'Pièce jointe',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Localisation',
+ 'Cannot delete invoice!' => 'Impossible de supprimer la facture',
+ 'Cannot post invoice for a closed period!' => 'Impossible d\'enregistrer la facture sur un exercice clos!',
+ 'Cannot post invoice!' => 'Impossible d\'enregistrer la facture!',
+ 'Cannot post payment for a closed period!' => 'Impossible d\'enregistrer le paiement sur un exercice clos!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmez!',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continuer',
+ 'Copies' => 'Copies',
+ 'Credit Limit' => 'Encours autorisé',
+ 'Currency' => 'Devise',
+ 'Customer' => 'Client',
+ 'Customer missing!' => 'Client manquant!',
+ 'Customer not on file!' => 'Client absent du fichier!',
+ 'Date' => 'Date',
+ 'Date Due' => 'Date d\'échéance',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Delete' => 'Supprimer',
+ 'Delivery Date' => 'Date de livraison',
+ 'Description' => 'Description',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Adresse email manquante!',
+ 'Edit Sales Invoice' => 'Modifier facture de vente',
+ 'Exch' => 'Change',
+ 'Exchangerate' => 'Taux de change',
+ 'Exchangerate for payment missing!' => 'Taux de change manquant pour le paiement!',
+ 'Exchangerate missing!' => 'Taux de change manquant!',
+ 'Extended' => 'Prix Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'In-line' => 'En ligne',
+ 'Invoice' => 'Facture',
+ 'Invoice Date' => 'Date de facturation',
+ 'Invoice Date missing!' => 'Date de facture manquante!',
+ 'Invoice Number' => 'Numéro de facture',
+ 'Invoice Number missing!' => 'Numéro de facture manquant!',
+ 'Invoice deleted!' => 'Facture supprimé!',
+ 'Invoice posted!' => 'Facture enregistré!',
+ 'Item not on file!' => 'Objet non-listé!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Message',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Number' => 'Numéro',
+ 'Number missing in Row' => 'Numéro manquant dans ligne',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'Order' => 'Commande',
+ 'Order Date missing!' => 'Date de commande manquante!',
+ 'Order Number' => 'Numéro de commande',
+ 'Order Number missing!' => 'Numéro de commande manquant!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Liste d\'envoi',
+ 'Packing List Date missing!' => 'La date est manquante sur la liste d\'envoi!',
+ 'Packing List Number missing!' => 'Le numéro de liste d\'envoi est manquant!',
+ 'Part' => 'Marchandise',
+ 'Payment date missing!' => 'Date de paiement manquant!',
+ 'Payments' => 'Paiements',
+ 'Phone' => 'Tél.',
+ 'Post' => 'Enregistrer',
+ 'Post as new' => 'Enregistrer comme nouveau',
+ 'Postscript' => 'Postcript',
+ 'Price' => 'Prix',
+ 'Print' => 'Imprimer',
+ 'Printer' => 'Imprimante',
+ 'Project' => 'Projet',
+ 'Project not on file!' => 'Projet absent du fichier!',
+ 'Purchase Order' => 'Commande d\'Achat',
+ 'Qty' => 'Qté',
+ 'Recd' => 'Reçu',
+ 'Record in' => 'Enregistrer dans',
+ 'Remaining' => 'Restant',
+ 'Required by' => 'Requis pour',
+ 'Sales Order' => 'Commande de Vente',
+ 'Screen' => 'Écran',
+ 'Select from one of the items below' => 'Sélectionner un des postes ci-dessous',
+ 'Select from one of the names below' => 'Sélectionner un des noms ci-dessous',
+ 'Select from one of the projects below' => 'Sélectionner un des projets ci-dessous',
+ 'Select postscript or PDF!' => 'Sélectionner Postscript ou PDF',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Service' => 'Service',
+ 'Ship' => 'Expédier',
+ 'Ship to' => 'Expédier à',
+ 'Ship via' => 'Expédier via',
+ 'Source' => 'Source',
+ 'Subject' => 'Objet',
+ 'Subtotal' => 'Sous Total',
+ 'Tax Included' => 'Taxe incluse',
+ 'To' => 'à ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unité',
+ 'Update' => 'Mettre à jour',
+ 'Vendor not on file!' => 'Fournisseur absent du fichier!',
+ 'What type of item is this?' => 'De quel type est ce poste?',
+ 'Yes' => 'Oui',
+ 'ea' => 'ch',
+ 'emailed to' => 'envoyé par email à',
+ 'sent to printer' => 'envoyé à l\'imprimante',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuer' => 'continue',
+ 'supprimer' => 'delete',
+ 'email' => 'e_mail',
+ 'commande' => 'order',
+ 'enregistrer' => 'post',
+ 'enregistrer_comme_nouveau' => 'post_as_new',
+ 'imprimer' => 'print',
+ 'expédier_à' => 'ship_to',
+ 'mettre_à_jour' => 'update',
+ 'oui' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/login b/sql-ledger/locale/fr/login
new file mode 100644
index 0000000..1020ac2
--- /dev/null
+++ b/sql-ledger/locale/fr/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'A propos',
+ 'Database Host' => 'Hôte de base de données',
+ 'Dataset' => 'Fichier de données',
+ 'Incorrect Dataset version!' => 'Fichier de données incorrect!',
+ 'Incorrect Password!' => 'Mot de passe incorrect!',
+ 'Licensed to' => 'Licence à',
+ 'Login' => 'Login',
+ 'Name' => 'Nom',
+ 'Password' => 'Mot de Passe',
+ 'User' => 'Utilisateur',
+ 'Version' => 'Version',
+ 'You are logged out!' => 'Vous êtes déconnecté!',
+ 'You did not enter a name!' => 'Vous n\'avez pas saisi de nom!',
+ 'is not a member!' => 'n\'est pas un membre',
+ 'localhost' => 'hôte local',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/menu b/sql-ledger/locale/fr/menu
new file mode 100644
index 0000000..102a1c2
--- /dev/null
+++ b/sql-ledger/locale/fr/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Dépenses',
+ 'AP Aging' => 'Dépenses exigibles',
+ 'AR' => 'Recettes',
+ 'AR Aging' => 'Recettes exigibles',
+ 'Accounting Menu' => 'Menu de comptabilité',
+ 'Add Account' => 'Ajouter compte',
+ 'Add Assembly' => 'Ajouter produit',
+ 'Add Customer' => 'Ajouter client',
+ 'Add GIFI' => 'Ajouter Code d\'Identification Comptable ou Fiscale',
+ 'Add Part' => 'Ajouter marchandise',
+ 'Add Project' => 'Ajouter projet',
+ 'Add Service' => 'Ajouter service',
+ 'Add Transaction' => 'Saisie d\'écriture',
+ 'Add Vendor' => 'Ajouter fournisseur',
+ 'Assemblies' => 'Produits finis',
+ 'Audit Control' => 'Clôture périodique',
+ 'Backup' => 'Sauvegarder',
+ 'Balance Sheet' => 'Bilan',
+ 'Cash' => 'Caisse',
+ 'Chart of Accounts' => 'Plan Comptable',
+ 'Check' => 'Chèque',
+ 'Customers' => 'Clients',
+ 'General Ledger' => 'Grand Livre',
+ 'Goods & Services' => 'Articles & Services',
+ 'HTML Templates' => 'Gabarits HTML',
+ 'Income Statement' => 'Compte de Résultat',
+ 'Invoice' => 'Facture',
+ 'LaTeX Templates' => 'Gabarits LaTeX',
+ 'List Accounts' => 'Liste des comptes',
+ 'List GIFI' => 'Afficher la liste des Codes d\'Identification Comptable ou Fiscale',
+ 'Logout' => 'Déconnexion',
+ 'Order Entry' => 'Bons de Commandes',
+ 'Packing List' => 'Liste d\'envoi',
+ 'Parts' => 'Marchandises',
+ 'Payment' => 'Paiement',
+ 'Payments' => 'Paiements',
+ 'Preferences' => 'Préférences',
+ 'Projects' => 'Projets',
+ 'Purchase Invoice' => 'Facture d\'Achat',
+ 'Purchase Order' => 'Commande d\'Achat',
+ 'Purchase Orders' => 'Commandes d\'Achats',
+ 'Receipt' => 'Reçu',
+ 'Receipts' => 'Reçus',
+ 'Reconciliation' => 'Rapprochement',
+ 'Reports' => 'Rapports',
+ 'Sales Invoice' => 'Facture de Vente',
+ 'Sales Order' => 'Commande de Vente',
+ 'Sales Orders' => 'Commandes de Vente',
+ 'Save to File' => 'Enregistrer comme fichier',
+ 'Send by E-Mail' => 'Envoyer par email',
+ 'Services' => 'Services',
+ 'Statement' => 'Relevé',
+ 'Stock Assembly' => 'Stock de produits',
+ 'Stylesheet' => 'Feuille de style',
+ 'System' => 'Système',
+ 'Tax collected' => 'Taxe collectée',
+ 'Tax paid' => 'Taxe payée',
+ 'Transactions' => 'Mouvements',
+ 'Trial Balance' => 'Balance Globale',
+ 'Vendors' => 'Fournisseurs',
+ 'Version' => 'Version',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/oe b/sql-ledger/locale/fr/oe
new file mode 100644
index 0000000..d1c2b74
--- /dev/null
+++ b/sql-ledger/locale/fr/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'Ajouter',
+ 'Add Purchase Invoice' => 'Etablir facture d\'achat',
+ 'Add Purchase Order' => 'Etablir commande d\'achat',
+ 'Add Sales Invoice' => 'Etablir facture de vente',
+ 'Add Sales Order' => 'Etablir commande de vente',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Total',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Are you sure you want to delete Order Number' => 'Êtes vous sûr de vouloir supprimer Commande N°',
+ 'Attachment' => 'Pièce jointe',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Localisation',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Impossible de supprimer la commande!',
+ 'Cannot save order!' => 'Impossible d\'enregistrer la commande!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Clôturé',
+ 'Confirm!' => 'Confirmez!',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Continuer',
+ 'Copies' => 'Copies',
+ 'Credit Limit' => 'Encours autorisé',
+ 'Curr' => 'En cours',
+ 'Currency' => 'Devise',
+ 'Customer' => 'Client',
+ 'Customer missing!' => 'Client manquant!',
+ 'Customer not on file!' => 'Client absent du fichier!',
+ 'Date' => 'Date',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Delete' => 'Supprimer',
+ 'Delivery Date' => 'Date de livraison',
+ 'Description' => 'Description',
+ 'E-mail' => 'Email',
+ 'E-mail address missing!' => 'Adresse email manquante!',
+ 'Edit Purchase Order' => 'Modifier commande d\'achat',
+ 'Edit Sales Order' => 'Modifier commande de vente',
+ 'Exchangerate' => 'Taux de change',
+ 'Exchangerate missing!' => 'Taux de change manquant!',
+ 'Extended' => 'Prix Total',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'In-line' => 'En ligne',
+ 'Include in Report' => 'Inclure dans l\'état',
+ 'Invoice' => 'Facture',
+ 'Invoice Date missing!' => 'Date de facture manquante!',
+ 'Invoice Number missing!' => 'Numéro de facture manquant!',
+ 'Item not on file!' => 'Objet non-listé!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Message',
+ 'Name' => 'Nom',
+ 'No.' => 'No.',
+ 'Notes' => 'Notes',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Number' => 'Numéro',
+ 'Number missing in Row' => 'Numéro manquant dans ligne',
+ 'O' => 'O',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'Open' => 'Ouvert',
+ 'Order' => 'Commande',
+ 'Order Date' => 'Date commande',
+ 'Order Date missing!' => 'Date de commande manquante!',
+ 'Order Number' => 'Numéro de commande',
+ 'Order Number missing!' => 'Numéro de commande manquant!',
+ 'Order deleted!' => 'Commande supprimé!',
+ 'Order saved!' => 'Commande enregistré!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Liste d\'envoi',
+ 'Packing List Date missing!' => 'La date est manquante sur la liste d\'envoi!',
+ 'Packing List Number missing!' => 'Le numéro de liste d\'envoi est manquant!',
+ 'Part' => 'Marchandise',
+ 'Phone' => 'Tél.',
+ 'Postscript' => 'Postcript',
+ 'Price' => 'Prix',
+ 'Print' => 'Imprimer',
+ 'Printer' => 'Imprimante',
+ 'Project' => 'Projet',
+ 'Project not on file!' => 'Projet absent du fichier!',
+ 'Purchase Order' => 'Commande d\'Achat',
+ 'Purchase Orders' => 'Commandes d\'Achats',
+ 'Qty' => 'Qté',
+ 'Recd' => 'Reçu',
+ 'Remaining' => 'Restant',
+ 'Required by' => 'Requis pour',
+ 'Sales Order' => 'Commande de Vente',
+ 'Sales Orders' => 'Commandes de Vente',
+ 'Save' => 'Enregistrer',
+ 'Save as new' => 'Enregistrer comme nouveau',
+ 'Screen' => 'Écran',
+ 'Select from one of the items below' => 'Sélectionner un des postes ci-dessous',
+ 'Select from one of the names below' => 'Sélectionner un des noms ci-dessous',
+ 'Select from one of the projects below' => 'Sélectionner un des projets ci-dessous',
+ 'Select postscript or PDF!' => 'Sélectionner Postscript ou PDF',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Service' => 'Service',
+ 'Ship' => 'Expédier',
+ 'Ship to' => 'Expédier à',
+ 'Ship via' => 'Expédier via',
+ 'Subject' => 'Objet',
+ 'Subtotal' => 'Sous Total',
+ 'Tax' => 'Taxe',
+ 'Tax Included' => 'Taxe incluse',
+ 'Terms: Net' => 'Crédit limité à',
+ 'To' => 'à ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unité',
+ 'Update' => 'Mettre à jour',
+ 'Vendor' => 'Fournisseur',
+ 'Vendor missing!' => 'Fournisseur manquant!',
+ 'Vendor not on file!' => 'Fournisseur absent du fichier!',
+ 'What type of item is this?' => 'De quel type est ce poste?',
+ 'Yes' => 'Oui',
+ 'days' => 'jours',
+ 'ea' => 'ch',
+ 'emailed to' => 'envoyé par email à',
+ 'sent to printer' => 'envoyé à l\'imprimante',
+ 'to' => 'jusqu\'au',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'ajouter' => 'add',
+ 'continuer' => 'continue',
+ 'supprimer' => 'delete',
+ 'email' => 'e_mail',
+ 'facture' => 'invoice',
+ 'imprimer' => 'print',
+ 'enregistrer' => 'save',
+ 'enregistrer_comme_nouveau' => 'save_as_new',
+ 'expédier_à' => 'ship_to',
+ 'mettre_à_jour' => 'update',
+ 'oui' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/pe b/sql-ledger/locale/fr/pe
new file mode 100644
index 0000000..84127de
--- /dev/null
+++ b/sql-ledger/locale/fr/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Ajouter',
+ 'Add Project' => 'Ajouter projet',
+ 'All' => 'Tous',
+ 'Continue' => 'Continuer',
+ 'Delete' => 'Supprimer',
+ 'Description' => 'Description',
+ 'Edit Project' => 'Modifier projet',
+ 'Number' => 'Numéro',
+ 'Orphaned' => 'Orphelin',
+ 'Project' => 'Projet',
+ 'Project Number missing!' => 'Numéro du projet manquant!',
+ 'Project deleted!' => 'Projet supprimé!',
+ 'Project saved!' => 'Projet enregistré!',
+ 'Projects' => 'Projets',
+ 'Save' => 'Enregistrer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'ajouter' => 'add',
+ 'continuer' => 'continue',
+ 'supprimer' => 'delete',
+ 'enregistrer' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/rc b/sql-ledger/locale/fr/rc
new file mode 100644
index 0000000..092aabe
--- /dev/null
+++ b/sql-ledger/locale/fr/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Compte',
+ 'Balance' => 'Solde',
+ 'Cleared Balance' => 'Solde rapproché',
+ 'Continue' => 'Continuer',
+ 'Date' => 'Date',
+ 'Deposit' => 'Dépôt',
+ 'Description' => 'Description',
+ 'Difference' => 'Différence',
+ 'Done' => 'Fait!',
+ 'Exchangerate Difference' => 'Différence de taux de change',
+ 'From' => 'De',
+ 'Out of balance!' => 'Solde non équilibré!',
+ 'Payment' => 'Paiement',
+ 'Reconciliation' => 'Rapprochement',
+ 'Select all' => 'Sélectionner tout',
+ 'Source' => 'Source',
+ 'Statement Balance' => 'Relevé de compte',
+ 'Update' => 'Mettre à jour',
+ 'to' => 'jusqu\'au',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continuer' => 'continue',
+ 'fait!' => 'done',
+ 'sélectionner_tout' => 'select_all',
+ 'mettre_à_jour' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/fr/rp b/sql-ledger/locale/fr/rp
new file mode 100644
index 0000000..dad49de
--- /dev/null
+++ b/sql-ledger/locale/fr/rp
@@ -0,0 +1,120 @@
+$self{texts} = {
+ 'AP Aging' => 'Dépenses exigibles',
+ 'AR Aging' => 'Recettes exigibles',
+ 'Account' => 'Compte',
+ 'Accounts' => 'Comptes',
+ 'Amount' => 'Total',
+ 'Apr' => 'Avril',
+ 'April' => 'Avril',
+ 'Attachment' => 'Pièce jointe',
+ 'Aug' => 'Août',
+ 'August' => 'Août',
+ 'Balance' => 'Solde',
+ 'Balance Sheet' => 'Bilan',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'En liquide',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Comparer à',
+ 'Continue' => 'Continuer',
+ 'Copies' => 'Copies',
+ 'Credit' => 'Crédit',
+ 'Current' => 'En cours',
+ 'Customer' => 'Client',
+ 'Date' => 'Date',
+ 'Debit' => 'Débit',
+ 'Dec' => 'Déc.',
+ 'December' => 'Décembre',
+ 'Decimalplaces' => 'Décimales',
+ 'Department' => 'Department',
+ 'Description' => 'Description',
+ 'Due' => 'Echéance',
+ 'E-mail' => 'Email',
+ 'E-mail Statement to' => 'Message éléctronique à',
+ 'Feb' => 'Fév.',
+ 'February' => 'Février',
+ 'From' => 'De',
+ 'GIFI' => 'Code d\'Identification Comptable ou Fiscale',
+ 'Heading' => 'En-tête',
+ 'ID' => 'ID',
+ 'In-line' => 'En ligne',
+ 'Include in Report' => 'Inclure dans l\'état',
+ 'Income Statement' => 'Compte de Résultat',
+ 'Invoice' => 'Facture',
+ 'Jan' => 'Jan.',
+ 'January' => 'Janvier',
+ 'Jul' => 'Juil.',
+ 'July' => 'Juillet',
+ 'Jun' => 'Juin',
+ 'June' => 'Juin',
+ 'Mar' => 'Mars',
+ 'March' => 'Mars',
+ 'May' => 'Mai',
+ 'May ' => 'Mai ',
+ 'Message' => 'Message',
+ 'N/A' => 'Non Applicable',
+ 'Nothing selected!' => 'Pas de sélection!',
+ 'Nov' => 'Nov.',
+ 'November' => 'Novembre',
+ 'Oct' => 'Oct.',
+ 'October' => 'Octobre',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Paiements',
+ 'Postscript' => 'Postcript',
+ 'Print' => 'Imprimer',
+ 'Printer' => 'Imprimante',
+ 'Project Number' => 'Project Number',
+ 'Receipts' => 'Reçus',
+ 'Report for' => 'Rapport de',
+ 'Retained Earnings' => 'Éxcédents non distribués',
+ 'Screen' => 'Écran',
+ 'Select all' => 'Sélectionner tout',
+ 'Select postscript or PDF!' => 'Sélectionner Postscript ou PDF',
+ 'Sep' => 'Sept.',
+ 'September' => 'Septembre',
+ 'Source' => 'Source',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Relevé',
+ 'Statement sent to' => 'Relevé envoyé à',
+ 'Statements sent to printer!' => 'Relevés envoyés à l\'imprimante!',
+ 'Subject' => 'Objet',
+ 'Subtotal' => 'Sous Total',
+ 'Tax' => 'Taxe',
+ 'Tax collected' => 'Taxe collectée',
+ 'Tax paid' => 'Taxe payée',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Balance Globale',
+ 'Vendor' => 'Fournisseur',
+ 'as at' => 'au',
+ 'collected on sales' => 'collectées sur les ventes',
+ 'for Period' => 'pour la période',
+ 'paid on purchases' => 'payées sur les achats',
+ 'to' => 'jusqu\'au',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continuer' => 'continue',
+ 'email' => 'e_mail',
+ 'imprimer' => 'print',
+ 'sélectionner_tout' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/COPYING b/sql-ledger/locale/hu/COPYING
new file mode 100644
index 0000000..890d2e8
--- /dev/null
+++ b/sql-ledger/locale/hu/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2003
+#
+# Hungarian texts:
+#
+# Author: Kabai József <kabai@investor.hu>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/hu/LANGUAGE b/sql-ledger/locale/hu/LANGUAGE
new file mode 100644
index 0000000..3459bb2
--- /dev/null
+++ b/sql-ledger/locale/hu/LANGUAGE
@@ -0,0 +1 @@
+Hungarian
diff --git a/sql-ledger/locale/hu/admin b/sql-ledger/locale/hu/admin
new file mode 100644
index 0000000..3aca70a
--- /dev/null
+++ b/sql-ledger/locale/hu/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Hozzáférési jogok',
+ 'Accounting' => 'Könyvelés',
+ 'Add User' => 'Új felhasználó',
+ 'Address' => 'Cím',
+ 'Administration' => 'Rendszerfelügyelet',
+ 'Administrator' => 'Rendszergazda',
+ 'All Datasets up to date!' => 'Összes ügyféladatbázis frissítve!',
+ 'Change Admin Password' => 'Rendszergazda jelszavának megváltoztatása',
+ 'Change Password' => 'Jelszó megváltoztatása',
+ 'Character Set' => 'Betû kódlap',
+ 'Click on login name to edit!' => 'Módosításhoz klikkeljen a felhasználó nevére!',
+ 'Company' => 'Társaság',
+ 'Connect to' => 'Csatlakozva ehhez:',
+ 'Continue' => 'Folytatás',
+ 'Create Chart of Accounts' => 'Számlatükör készítése',
+ 'Create Dataset' => 'Új cégadatbázis',
+ 'DBI not installed!' => 'DBI program nincs installálva!',
+ 'Database' => 'Adatbázis',
+ 'Database Administration' => 'Adatbázis felügyelet',
+ 'Database Driver not checked!' => 'Nincs kijelölve az adatbázismotor típusa!',
+ 'Database User missing!' => 'Adatbázis felhasználója hiányzik!',
+ 'Dataset' => 'Cégadatbázis',
+ 'Dataset missing!' => 'Cégadatbázis hiányzik!',
+ 'Dataset updated!' => 'Cégadatbázis frissítve!',
+ 'Date Format' => 'Dátumformátum',
+ 'Delete' => 'Törlés',
+ 'Delete Dataset' => 'Cégadatbázis törlése',
+ 'Directory' => 'Könyvtár',
+ 'Driver' => 'Meghajtó',
+ 'Dropdown Limit' => 'Lenyíló ablak limit',
+ 'E-mail' => 'E-mail',
+ 'Edit User' => 'Felhasználó módosítása',
+ 'Existing Datasets' => 'Létezõ cégadatbázisok',
+ 'Fax' => 'Fax',
+ 'Host' => 'Adatbázis helye:',
+ 'Hostname missing!' => 'Adatbázis helye hiányzik!',
+ 'Incorrect Password!' => 'Érvénytelen jelszó!',
+ 'Language' => 'Nyelv',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Hagyja üresen a Hely és a Port mezõket, hacsak nem akar távoli kapcsolatot létesíteni',
+ 'Login' => 'Belépés',
+ 'Multibyte Encoding' => 'Multibyte kódolás',
+ 'Name' => 'Név',
+ 'New Templates' => 'Új sablonok',
+ 'No Database Drivers available!' => 'Nincs elérhetõ adatbázismeghajtó!',
+ 'No Dataset selected!' => 'Nincs kiválasztott cégadatbázis!',
+ 'Nothing to delete!' => 'Nincs mit törölni!',
+ 'Number Format' => 'Számformátum',
+ 'Oracle Database Administration' => 'Oracle adatbázis felügyelet',
+ 'Password' => 'Jelszó',
+ 'Password changed!' => 'Jelszó megváltozott!',
+ 'Pg Database Administration' => 'Postgresql adatbázis felügyelet',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port száma',
+ 'Port missing!' => 'Port száma hiányzik!',
+ 'Printer' => 'Nyomtató',
+ 'Save' => 'Mentés',
+ 'Select a Dataset to delete and press "Continue"' => 'Válassza ki a törölni kívánt cégadatbázist, és klikkeljen a "Folytatás"-ra',
+ 'Setup Templates' => 'Sablonok beállítása',
+ 'Ship via' => 'Szállítás innen:',
+ 'Signature' => 'Aláírás',
+ 'Stylesheet' => 'Stíluslap',
+ 'Templates' => 'Sablonok',
+ 'The following Datasets are not in use and can be deleted' => 'Az alábbi cégadatbázisok üresek, és törölhetõk',
+ 'The following Datasets need to be updated' => 'Az alábbi cégadatbázisokat frissíteni kell',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'A meglévõ adatbázisok elõzetes ellenõrzése. A program itt még nem töröl és nem hoz létre semmit!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Új felhasználót úgy hozhat létre egy meglévõ cégadatbázishoz, hogy egy létezõ felhasználóra kattint, és a belépési nevet és a jelszót megváltoztatja és elmenti. Az új felhasználó örökli a beállításokat.',
+ 'Update Dataset' => 'Cégadatbázis frissítése',
+ 'Use Templates' => 'Sablon használata',
+ 'User' => 'Felhasználó',
+ 'User deleted!' => 'Felhasználó törölve!',
+ 'User saved!' => 'Felhasználó elmentve!',
+ 'Version' => 'Verzió',
+ 'You must enter a host and port for local and remote connections!' => 'A helyi és távoli kapcsolat eléréséhez írjon be helyet, és portszámot!',
+ 'does not exist' => 'nem létezik',
+ 'is already a member!' => 'már tag!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'zárolva',
+ 'successfully created!' => 'sikeresen létrehozva!',
+ 'successfully deleted!' => 'sikeresen törölve!',
+ 'website' => 'honlap',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'Új_felhasználó' => 'add_user',
+ 'rendszergazda_jelszavának_megváltoztatása' => 'change_admin_password',
+ 'jelszó_megváltoztatása' => 'change_password',
+ 'folytatás' => 'continue',
+ 'Új_cégadatbázis' => 'create_dataset',
+ 'törlés' => 'delete',
+ 'cégadatbázis_törlése' => 'delete_dataset',
+ 'belépés' => 'login',
+ 'oracle_adatbázis_felügyelet' => 'oracle_database_administration',
+ 'postgresql_adatbázis_felügyelet' => 'pg_database_administration',
+ 'mentés' => 'save',
+ 'cégadatbázis_frissítése' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/all b/sql-ledger/locale/hu/all
new file mode 100644
index 0000000..823f366
--- /dev/null
+++ b/sql-ledger/locale/hu/all
@@ -0,0 +1,499 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Szállítók',
+ 'AP Aging' => 'Szállító lejárati lista',
+ 'AP Transaction' => 'Szállító tranzakció',
+ 'AP Transactions' => 'Szállító tranzakciók',
+ 'AR' => 'Vevõk',
+ 'AR Aging' => 'Vevõ lejárati lista',
+ 'AR Transaction' => 'Vevõ tranzakció',
+ 'AR Transactions' => 'Vevõ tranzakciók',
+ 'About' => ' ',
+ 'Access Control' => 'Hozzáférési jogok',
+ 'Account' => 'Számla',
+ 'Account Number' => 'Számlaszám',
+ 'Account Number missing!' => 'Számlaszám hiányzik!',
+ 'Account Type' => 'Számlatípus',
+ 'Account Type missing!' => 'Számlatípus hiányzik!',
+ 'Account deleted!' => 'Számla törölve!',
+ 'Account saved!' => 'Számla elmentve!',
+ 'Accounting' => 'Könyvelés',
+ 'Accounting Menu' => 'Menü',
+ 'Accounts' => 'Számlák',
+ 'Active' => 'Aktív',
+ 'Add' => 'Új',
+ 'Add Account' => 'Új számla',
+ 'Add Accounts Payables Transaction' => 'Új szállító tranzakció',
+ 'Add Accounts Receivables Transaction' => 'Új vevõ tranzakció',
+ 'Add Assembly' => 'Új saját termék',
+ 'Add Customer' => 'Új vevõ',
+ 'Add GIFI' => 'Új gyûjtõkód',
+ 'Add General Ledger Transaction' => 'Új fõkönyvi könyvelés',
+ 'Add Group' => '',
+ 'Add Part' => 'Új cikk',
+ 'Add Project' => 'Új munkaszám',
+ 'Add Purchase Order' => 'Új beszerzési rendelés',
+ 'Add Sales Invoice' => 'Új vevõszámla',
+ 'Add Sales Order' => 'Új vevõrendelés',
+ 'Add Service' => 'Új szolgáltatás',
+ 'Add Transaction' => 'Új tranzakció',
+ 'Add User' => 'Új felhasználó',
+ 'Add Vendor' => 'Új szállító',
+ 'Add Vendor Invoice' => '',
+ 'Address' => 'Cím',
+ 'Administration' => 'Rendszerfelügyelet',
+ 'Administrator' => 'Rendszergazda',
+ 'All' => 'Összes',
+ 'All Datasets up to date!' => 'Összes ügyféladatbázis frissítve!',
+ 'Amount' => 'Összeg',
+ 'Amount Due' => 'Esedékes összeg',
+ 'Amount does not equal applied!' => 'Az összeg nem egyezik a kitöltött szám(ok) összegével',
+ 'Amount missing!' => 'Összeg hiányzik!',
+ 'Applied' => 'Kitöltés',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Are you sure you want to delete Invoice Number' => 'Biztos, hogy törölni akarja? Számlaszám:',
+ 'Are you sure you want to delete Order Number' => 'Biztos, hogy törölni akarja? Megrendelésszám:',
+ 'Are you sure you want to delete Transaction' => 'Biztos, hogy törölni akarja? Tranzakció:',
+ 'Assemblies' => 'Saját termékek',
+ 'Assemblies restocked!' => 'Saját termékek készletre véve',
+ 'Assembly Number missing!' => 'Saját termékszám hiányzik!',
+ 'Asset' => 'Eszköz',
+ 'Attachment' => 'Csatolás',
+ 'Audit Control' => 'Audit Kontroll',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'BOM' => '',
+ 'Backup' => 'Biztonsági másolat',
+ 'Backup sent to' => 'Biztonsági másolat elküldve:',
+ 'Balance' => 'Egyenleg',
+ 'Balance Sheet' => 'Mérleg',
+ 'Bcc' => 'Titkos másolat',
+ 'Bin' => 'Bin',
+ 'Books are open' => 'Az ügyféladatbázisban lehet könyvelni',
+ 'Bought' => 'Vásárolt',
+ 'Business Number' => 'Cégszám',
+ 'C' => 'C',
+ 'COGS' => 'ELÁBÉ',
+ 'Cannot delete account!' => 'A számlát nem lehet törölni',
+ 'Cannot delete customer!' => 'A vevõt nem lehet törölni!',
+ 'Cannot delete default account!' => 'Az alapbeállítású számlát nem lehet törölni!',
+ 'Cannot delete invoice!' => 'A partnerszámlát nem lehet törölni!',
+ 'Cannot delete item!' => 'A tételt nem lehet törölni!',
+ 'Cannot delete order!' => 'A rendelést nem lehet törölni!',
+ 'Cannot delete transaction!' => 'A tranzakciót nem lehet törölni!',
+ 'Cannot delete vendor!' => 'Szállítót nem lehet törölni!',
+ 'Cannot have a value in both Debit and Credit!' => 'A Tartozik és Követel oldal is tartalmaz értéket!',
+ 'Cannot post a transaction without a value!' => 'Az összeg megadása nélkül nem lehet a tranzakciót rögzíteni!',
+ 'Cannot post invoice for a closed period!' => 'A lezárt idõszakban nem lehet számlát kiállítani!',
+ 'Cannot post invoice!' => 'A partnerszámlát nem lehet kiállítani',
+ 'Cannot post payment for a closed period!' => 'A lezárt idõszakban nem lehet fizetést rögzíteni!',
+ 'Cannot post payment!' => 'A pénzmozgást nem lehet rögzíteni',
+ 'Cannot post transaction for a closed period!' => 'A lezárt idõszakban nem lehet tranzakciót rögzíteni!!',
+ 'Cannot post transaction!' => 'A tranzakciót nem lehet rögzíteni!',
+ 'Cannot process payment for a closed period!' => 'A pénzmozgást nem lehet lezárt idõszakban rögzíteni!',
+ 'Cannot save account!' => 'A számlát nem lehet elmenteni!',
+ 'Cannot save order!' => 'A rendelést nem lehet elmenteni!',
+ 'Cannot save preferences!' => 'A beállításokat nem lehet elmenteni',
+ 'Cannot stock assemblies!' => 'A saját terméket nem lehet készletre venni!',
+ 'Cash' => 'Pénzmozgások',
+ 'Cash based' => 'Pénzmozgás alapján',
+ 'Cc' => 'Másolat',
+ 'Change Admin Password' => 'Rendszergazda jelszavának megváltoztatása',
+ 'Change Password' => 'Jelszó megváltoztatása',
+ 'Character Set' => 'Betû kódlap',
+ 'Chart of Accounts' => 'Számlatükör',
+ 'Check' => 'Csekk',
+ 'Check printed!' => 'Csekk kinyomtatva!',
+ 'Check printing failed!' => 'A csekk nyomtatása nem sikerült!',
+ 'Cleared Balance' => 'Egyeztetett egyenleg',
+ 'Click on login name to edit!' => 'Módosításhoz klikkeljen a felhasználó nevére!',
+ 'Close Books up to' => 'Könyvelés lezárása eddig az idõpontig:',
+ 'Closed' => 'Lezárt',
+ 'Company' => 'Társaság',
+ 'Compare to' => 'Összehasonlítva:',
+ 'Confirm!' => 'Megerõsítés:',
+ 'Connect to' => 'Csatlakozva ehhez:',
+ 'Contact' => 'Kapcsolat',
+ 'Continue' => 'Folytatás',
+ 'Copies' => 'Másolatok',
+ 'Copy to COA' => 'Másolás a számlatükörbe',
+ 'Create Chart of Accounts' => 'Számlatükör készítése',
+ 'Create Dataset' => 'Új cégadatbázis',
+ 'Credit' => 'Követel',
+ 'Credit Limit' => 'Hitelkeret',
+ 'Curr' => 'Dev',
+ 'Currency' => 'Deviza',
+ 'Current' => 'Nem lejárt',
+ 'Customer' => 'Vevõ',
+ 'Customer deleted!' => 'Vevõ törölve!',
+ 'Customer missing!' => 'Vevõ hiányzik!',
+ 'Customer not on file!' => 'A vevõ hiányzik az adatbázisból!',
+ 'Customer saved!' => 'Vevõ elmentve!',
+ 'Customers' => 'Vevõadatok',
+ 'DBI not installed!' => 'DBI program nincs installálva!',
+ 'Database' => 'Adatbázis',
+ 'Database Administration' => 'Adatbázis felügyelet',
+ 'Database Driver not checked!' => 'Nincs kijelölve az adatbázismotor típusa!',
+ 'Database Host' => 'Adatbázis helye',
+ 'Database User missing!' => 'Adatbázis felhasználója hiányzik!',
+ 'Dataset' => 'Cégadatbázis',
+ 'Dataset missing!' => 'Cégadatbázis hiányzik!',
+ 'Dataset updated!' => 'Cégadatbázis frissítve!',
+ 'Date' => 'Dátum',
+ 'Date Format' => 'Dátumformátum',
+ 'Date Paid' => 'Fizetés napja',
+ 'Date missing!' => 'Dátum hiányzik',
+ 'Debit' => 'Tartozik',
+ 'Debit and credit out of balance!' => 'Tartozik Követel összege nem egyezik!',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Decimalplaces' => 'Tizedeshelyek',
+ 'Delete' => 'Törlés',
+ 'Delete Account' => 'Számla törlése',
+ 'Delete Dataset' => 'Cégadatbázis törlése',
+ 'Delivery Date' => 'Szállítás dátuma',
+ 'Deposit' => 'Betét',
+ 'Description' => 'Szöveges leírás',
+ 'Difference' => 'Eltérés',
+ 'Directory' => 'Könyvtár',
+ 'Discount' => 'Engedmény',
+ 'Done' => 'Elvégezve',
+ 'Drawing' => 'Rajz',
+ 'Driver' => 'Meghajtó',
+ 'Dropdown Limit' => 'Lenyíló ablak limit',
+ 'Due' => 'Esedékes',
+ 'Due Date' => 'Esedékesség',
+ 'Due Date missing!' => 'Esedékesség hiányzik!',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'Kimutatás küldése e-mail-ben:',
+ 'E-mail address missing!' => 'E-mail cím hiányzik!',
+ 'Edit' => 'Módosítás',
+ 'Edit Account' => 'Számlaszám módosítása',
+ 'Edit Accounts Payables Transaction' => 'Szállító tranzakció módosítása',
+ 'Edit Accounts Receivables Transaction' => 'Vevõ tranzakció módosítása',
+ 'Edit Assembly' => 'Saját termék módosítása',
+ 'Edit Customer' => 'Vevõ módosítása',
+ 'Edit GIFI' => 'Gyûjtõkód módosítása',
+ 'Edit General Ledger Transaction' => 'Vegyes könyvelési tétel módosítása',
+ 'Edit Group' => '',
+ 'Edit Part' => 'Cikk módosítása',
+ 'Edit Preferences for' => 'Felhasználói paraméterek módosítása:',
+ 'Edit Project' => 'Projekt módosítása',
+ 'Edit Purchase Order' => 'Beszerzési rendelés módosítása',
+ 'Edit Sales Invoice' => 'Vevõszámla módosítása',
+ 'Edit Sales Order' => 'Vevõrendelés módosítása',
+ 'Edit Service' => 'Szolgáltatás módosítása',
+ 'Edit Template' => 'Sablon módosítása',
+ 'Edit User' => 'Felhasználó módosítása',
+ 'Edit Vendor' => 'Szállító módosítása',
+ 'Edit Vendor Invoice' => '',
+ 'Employee' => 'Alkalmazott',
+ 'Enforce transaction reversal for all dates' => 'Minden dátum esetében visszautasítsa a tranzakció rögzítését?',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'A saját és külföldi devizákat jelölje 3 betûvel kettõsponttal elválasztva! (pl. HUF:EUR:USD)',
+ 'Equity' => 'Tõke',
+ 'Exch' => 'Árf',
+ 'Exchangerate' => 'Átváltási árfolyam',
+ 'Exchangerate Difference' => 'Árfolyamkülönbség',
+ 'Exchangerate for payment missing!' => 'A fizetett összeg átváltási árfolyama hiányzik!',
+ 'Exchangerate missing!' => 'Átváltási árfolyam hiányzik!',
+ 'Existing Datasets' => 'Létezõ cégadatbázisok',
+ 'Expense' => 'Költség',
+ 'Expense Account' => 'Költségszámla',
+ 'Expense/Asset' => 'Költség/Eszköz',
+ 'Extended' => 'Összeg',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'Foreign Exchange Gain' => 'Árfolyamnyereség',
+ 'Foreign Exchange Loss' => 'Árfolyamveszteség',
+ 'From' => 'Mikortól:',
+ 'GIFI' => 'Gyûjtõkód',
+ 'GIFI deleted!' => 'Gyûjtõkód törölve!',
+ 'GIFI missing!' => 'Gyûjtõkód hiányzik!',
+ 'GIFI saved!' => 'Gyûjtõkód elmentve!',
+ 'GL Transaction' => 'Fõkönyvi tranzakció!',
+ 'General Ledger' => 'Fõkönyvi könyvelés',
+ 'Goods & Services' => 'Áruk & Szolgáltatások',
+ 'Group' => '',
+ 'Group Items' => '',
+ 'Group deleted!' => '',
+ 'Group missing!' => '',
+ 'Group saved!' => '',
+ 'Groups' => '',
+ 'HTML Templates' => 'HTML sablonok',
+ 'Heading' => 'Fejléc',
+ 'Host' => 'Adatbázis helye:',
+ 'Hostname missing!' => 'Adatbázis helye hiányzik!',
+ 'ID' => 'Azonosító',
+ 'Image' => 'Kép',
+ 'In-line' => 'Beágyazva',
+ 'Include in Report' => 'Oszlopok:',
+ 'Include in drop-down menus' => 'Mely tranzakció(k)-nál lehessen kiválasztani?:',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Kiválasztható legyen a vevõ/szállító ûrlapokon, mint adószámla?',
+ 'Income' => 'Árbevétel',
+ 'Income Account' => 'Árbevételszámla',
+ 'Income Statement' => 'Eredménykimutatás',
+ 'Incorrect Dataset version!' => 'Érvénytelen adatbázisverzió!',
+ 'Incorrect Password!' => 'Érvénytelen jelszó!',
+ 'Individual Items' => 'Összetevõk',
+ 'Inventory' => 'Készlet',
+ 'Inventory Account' => 'Készletszámla',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Mielõtt ezt a saját terméket elévültnek nyilvánítja,a mennyiségnek nullának kell lennie!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Mielõtt ezt az anyagot/árut elévültnek nyilvánítja,a mennyiségnek nullának kell lennie!!',
+ 'Invoice' => 'Számla',
+ 'Invoice Date' => 'Teljesítés dátuma',
+ 'Invoice Date missing!' => 'Teljesítés dátuma hiányzik!',
+ 'Invoice Number' => 'Számlaszám',
+ 'Invoice Number missing!' => 'Számlaszám hiányzik!',
+ 'Invoice deleted!' => 'Számla törölve!',
+ 'Invoice posted!' => 'Számla rögzítve!',
+ 'Invoices' => 'Számlák',
+ 'Is this a summary account to record' => 'Gyûjtõszámlaként szerepeljen ezeknél a tranzakcióknál:',
+ 'Item deleted!' => 'Tétel törölve!',
+ 'Item not on file!' => 'A tétel nincs az adatbázisban!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'LaTeX Templates' => 'LaTeX sablonok',
+ 'Language' => 'Nyelv',
+ 'Last Cost' => 'Utolsó beszerzési ár',
+ 'Last Invoice Number' => 'Utolsó számlaszám',
+ 'Last Numbers & Default Accounts' => 'Legutolsó számok & Alapszámlák',
+ 'Last Purchase Order Number' => 'Utolsó beszerzési rendelésszám',
+ 'Last Sales Order Number' => 'Utolsó vevõ rendelésszám',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Hagyja üresen a Hely és a Port mezõket, hacsak nem akar távoli kapcsolatot létesíteni',
+ 'Liability' => 'Kötelezettség',
+ 'Licensed to' => 'Cég:',
+ 'Line Total' => 'Sor összesen',
+ 'Link' => 'Kapcsolat',
+ 'Link Accounts' => 'Számlakapcsolatok',
+ 'List Accounts' => 'Számlák listázása',
+ 'List GIFI' => 'Gyûjtõkódok listázása',
+ 'List Price' => 'Listaár',
+ 'List Transactions' => 'Tranzakciók listázása',
+ 'Login' => 'Belépés',
+ 'Logout' => 'Kilépés',
+ 'Make' => 'Gyártmány',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Message' => 'Üzenet',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modell',
+ 'Multibyte Encoding' => 'Multibyte kódolás',
+ 'N/A' => 'N/A',
+ 'Name' => 'Név',
+ 'Name missing!' => 'Név hiányzik',
+ 'New Templates' => 'Új sablonok',
+ 'No' => 'Nem',
+ 'No Database Drivers available!' => 'Nincs elérhetõ adatbázismeghajtó!',
+ 'No Dataset selected!' => 'Nincs kiválasztott cégadatbázis!',
+ 'No email address for' => 'Nincs e-mail címe:',
+ 'No.' => 'Sz.',
+ 'Notes' => 'Megjegyzés',
+ 'Nothing applied!' => 'Nincs semmi kitöltve!',
+ 'Nothing selected!' => 'Nincs semmi kiválasztva!',
+ 'Nothing to delete!' => 'Nincs mit törölni!',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Number' => 'Szám',
+ 'Number Format' => 'Számformátum',
+ 'Number missing in Row' => 'Ebbõl a sorból hiányzik a szám:',
+ 'O' => 'Ny.',
+ 'Obsolete' => 'Elévült',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'On Hand' => 'Készleten',
+ 'On Order' => 'Beszerzési rendelések',
+ 'Open' => 'Nyitott',
+ 'Oracle Database Administration' => 'Oracle adatbázis felügyelet',
+ 'Order' => 'Rendelés',
+ 'Order Date' => 'Rendelés dátuma',
+ 'Order Date missing!' => 'Rendelés dátuma hiányzik!',
+ 'Order Entry' => 'Rendelések',
+ 'Order Number' => 'Rendelés száma',
+ 'Order Number missing!' => 'Rendelés száma hiányzik!',
+ 'Order deleted!' => 'Rendelés törölve!',
+ 'Order saved!' => 'Rendelés elmentve!',
+ 'Ordered' => 'Vevõrendelések',
+ 'Orphaned' => 'Tranzakció nélküli',
+ 'Out of balance!' => 'Az egyenleg nem stimmel!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Szállítólevél',
+ 'Packing List Date missing!' => 'Szállítólevél dátuma hiányzik!',
+ 'Packing List Number missing!' => 'Szállítólevél száma hiányzik!',
+ 'Paid' => 'Fizetve',
+ 'Paid in full' => 'Teljesen fizetve',
+ 'Part' => 'Cikk',
+ 'Part Number missing!' => 'Cikk száma hiányzik!',
+ 'Parts' => 'Cikkek',
+ 'Parts Inventory' => 'Cikkek készlete',
+ 'Password' => 'Jelszó',
+ 'Password changed!' => 'Jelszó megváltozott!',
+ 'Payables' => 'Szállítók',
+ 'Payment' => 'Kifizetés',
+ 'Payment date missing!' => 'Pénzmozgás dátuma hiányzik!',
+ 'Payment posted!' => 'Pénzmozgás rögzítve',
+ 'Payments' => 'Kifizetések',
+ 'Pg Database Administration' => 'Postgresql adatbázis felügyelet',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port száma',
+ 'Port missing!' => 'Port száma hiányzik!',
+ 'Post' => 'Rögzítés',
+ 'Post as new' => 'Rögzítés új tranzakcióként',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Beállítások',
+ 'Preferences saved!' => 'Beállítások elmentve!',
+ 'Price' => 'Ár',
+ 'Print' => 'Nyomtatás',
+ 'Printer' => 'Nyomtató',
+ 'Project' => 'Munkaszám',
+ 'Project Number' => 'Munkaszám',
+ 'Project Number missing!' => 'Munkaszám száma hiányzik!',
+ 'Project deleted!' => 'Munkaszám törölve!',
+ 'Project not on file!' => 'Munkaszám hiányzik az adatbázisból!',
+ 'Project saved!' => 'Munkaszám elmentve!',
+ 'Projects' => 'Munkaszámok',
+ 'Purchase Order' => 'Beszerzési rendelés',
+ 'Purchase Orders' => 'Beszerzési rendelések',
+ 'Qty' => 'Menny.',
+ 'ROP' => 'Rendelési pont',
+ 'Rate' => 'Árfolyam',
+ 'Recd' => 'Kapott',
+ 'Receipt' => 'Bevétel',
+ 'Receipt printed!' => 'Nyugta nyomtatva!',
+ 'Receipt printing failed!' => 'A nyugta nyomtatása nem sikerült!',
+ 'Receipts' => 'Bevételek',
+ 'Receivables' => 'Vevõk',
+ 'Reconciliation' => 'Egyeztetés',
+ 'Record in' => 'Feladás:',
+ 'Reference' => 'Hivatkozás',
+ 'Reference missing!' => 'Hivatkozás hiányzik',
+ 'Remaining' => 'Maradék',
+ 'Report for' => 'Jelentés:',
+ 'Reports' => 'Jelentések',
+ 'Required by' => 'Leszállítás',
+ 'Retained Earnings' => 'Adózás elõtti eredmény',
+ 'Sales' => 'Eladás',
+ 'Sales Invoice' => 'Számlázás',
+ 'Sales Order' => 'Vevõrendelés',
+ 'Sales Orders' => 'Vevõrendelések',
+ 'Salesperson' => '',
+ 'Save' => 'Mentés',
+ 'Save as new' => 'Mentés újként',
+ 'Save to File' => 'Másolat File-ba',
+ 'Screen' => 'Képernyõre',
+ 'Select a Dataset to delete and press "Continue"' => 'Válassza ki a törölni kívánt cégadatbázist, és klikkeljen a "Folytatás"-ra',
+ 'Select all' => 'Mindent kijelöl',
+ 'Select from one of the items below' => 'Válasszon ki egyet az alábbi tételek közül',
+ 'Select from one of the names below' => 'Válasszon ki egyet az alábbi nevek közül',
+ 'Select from one of the projects below' => 'Válasszon ki egyet az alábbi munkaszámok közül',
+ 'Select postscript or PDF!' => 'Válassza ki a postscript vagy a PDF formátumot!',
+ 'Sell Price' => 'Eladási ár',
+ 'Send by E-Mail' => 'Másolat E-mail-ben',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Service' => 'Szolgáltatás',
+ 'Service Items' => 'Szolgáltatás tételek',
+ 'Service Number missing!' => 'Szolgáltatás száma hiányzik!',
+ 'Services' => 'Szolgáltatások',
+ 'Setup Templates' => 'Sablonok beállítása',
+ 'Ship' => 'Szállítás',
+ 'Ship to' => 'Szállítási cím',
+ 'Ship via' => 'Szállítás innen:',
+ 'Short' => 'Hiányzó',
+ 'Signature' => 'Aláírás',
+ 'Sold' => 'Eladva',
+ 'Source' => 'Bizonylatszám',
+ 'Standard' => 'Sztenderd',
+ 'Statement' => 'Kimutatás',
+ 'Statement Balance' => 'Kimutatás egyenlege',
+ 'Statement sent to' => 'Kimutatás elküldve:',
+ 'Statements sent to printer!' => 'Kimutatás kinyomtatva!',
+ 'Stock' => '',
+ 'Stock Assembly' => 'Saját termék bevételezése',
+ 'Stylesheet' => 'Stíluslap',
+ 'Subject' => 'Tárgy',
+ 'Subtotal' => 'Részösszeg',
+ 'System' => 'Törzsadatok',
+ 'Tax' => 'Adó',
+ 'Tax Accounts' => 'Adószámlák',
+ 'Tax Included' => 'Adót tartalmazza',
+ 'Tax collected' => 'Fizetendõ ÁFA',
+ 'Tax paid' => 'Levonható ÁFA',
+ 'Taxable' => 'Adó:',
+ 'Template saved!' => 'Sablon elmentve!',
+ 'Templates' => 'Sablonok',
+ 'Terms: Net' => 'Határidõ',
+ 'The following Datasets are not in use and can be deleted' => 'Az alábbi cégadatbázisok üresek, és törölhetõk',
+ 'The following Datasets need to be updated' => 'Az alábbi cégadatbázisokat frissíteni kell',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'A meglévõ adatbázisok elõzetes ellenõrzése. A program itt még nem töröl és nem hoz létre semmit!',
+ 'To' => 'Meddig:',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Új felhasználót úgy hozhat létre egy meglévõ cégadatbázishoz, hogy egy létezõ felhasználóra kattint, és a belépési nevet és a jelszót megváltoztatja és elmenti. Az új felhasználó örökli a beállításokat.',
+ 'Top Level' => 'Legfelsõ szint',
+ 'Total' => 'Végösszeg',
+ 'Transaction Date missing!' => 'Tranzakció dátuma hiányzik!',
+ 'Transaction deleted!' => 'Tranzakció törölve!',
+ 'Transaction posted!' => 'Tranzakció rögzítve!',
+ 'Transaction reversal enforced for all dates' => 'Bármilyen dátumú tranzakciót visszautasít',
+ 'Transaction reversal enforced up to' => 'E dátumig utasítja vissza a tranzakciókat',
+ 'Transactions' => 'Tranzakciók',
+ 'Transactions exist, cannot delete customer!' => 'A vevõhöz tranzakciók tartoznak, nem lehet törölni!',
+ 'Transactions exist, cannot delete vendor!' => 'A szállítóhoz tranzakciók tartoznak, nem lehet törölni!',
+ 'Transactions exist; cannot delete account!' => 'A számlához tranzakciók tartoznak, nem lehet törölni!',
+ 'Trial Balance' => 'Fõkönyvi kivonat',
+ 'Unit' => 'Egység',
+ 'Unit of measure' => 'Mértékegység',
+ 'Update' => 'Frissítés',
+ 'Update Dataset' => 'Cégadatbázis frissítése',
+ 'Updated' => 'Frissítve',
+ 'Use Templates' => 'Sablon használata',
+ 'User' => 'Felhasználó',
+ 'User deleted!' => 'Felhasználó törölve!',
+ 'User saved!' => 'Felhasználó elmentve!',
+ 'Vendor' => 'Szállító',
+ 'Vendor Invoice' => '',
+ 'Vendor deleted!' => 'Szállító törölve!',
+ 'Vendor missing!' => 'Szállító hiányzik!',
+ 'Vendor not on file!' => 'Szállító nincs az adatbázisban!',
+ 'Vendor saved!' => 'Szállító elmentve!',
+ 'Vendors' => 'Szállítók',
+ 'Version' => 'Verzió',
+ 'Weight' => 'Súly',
+ 'Weight Unit' => 'Súlyegység',
+ 'What type of item is this?' => 'Ez milyen típusú tétel?',
+ 'Year End' => 'Évzárás',
+ 'Yes' => 'Igen',
+ 'You are logged out!' => 'Már kijelentkezett!',
+ 'You did not enter a name!' => 'Nem írt be nevet!',
+ 'You must enter a host and port for local and remote connections!' => 'A helyi és távoli kapcsolat eléréséhez írjon be helyet, és portszámot!',
+ 'as at' => 'Fordulónap:',
+ 'collected on sales' => 'vevõszámlák alapján',
+ 'days' => 'nap',
+ 'does not exist' => 'nem létezik',
+ 'ea' => 'db',
+ 'emailed to' => 'e-mail küldve:',
+ 'for Period' => 'Idõszak:',
+ 'hr' => 'óra',
+ 'is already a member!' => 'már tag!',
+ 'is not a member!' => 'nem tag!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'zárolva',
+ 'paid on purchases' => 'szállítószámlák alapján',
+ 'sent to printer' => 'kinyomtatva',
+ 'successfully created!' => 'sikeresen létrehozva!',
+ 'successfully deleted!' => 'sikeresen törölve!',
+ 'to' => 'Meddig:',
+ 'website' => 'honlap',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/am b/sql-ledger/locale/hu/am
new file mode 100644
index 0000000..0bb2b83
--- /dev/null
+++ b/sql-ledger/locale/hu/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Szállítók',
+ 'AR' => 'Vevõk',
+ 'Account' => 'Számla',
+ 'Account Number' => 'Számlaszám',
+ 'Account Number missing!' => 'Számlaszám hiányzik!',
+ 'Account Type' => 'Számlatípus',
+ 'Account Type missing!' => 'Számlatípus hiányzik!',
+ 'Account deleted!' => 'Számla törölve!',
+ 'Account saved!' => 'Számla elmentve!',
+ 'Add Account' => 'Új számla',
+ 'Add GIFI' => 'Új gyûjtõkód',
+ 'Address' => 'Cím',
+ 'Asset' => 'Eszköz',
+ 'Audit Control' => 'Audit Kontroll',
+ 'Backup sent to' => 'Biztonsági másolat elküldve:',
+ 'Books are open' => 'Az ügyféladatbázisban lehet könyvelni',
+ 'Business Number' => 'Cégszám',
+ 'COGS' => 'ELÁBÉ',
+ 'Cannot delete account!' => 'A számlát nem lehet törölni',
+ 'Cannot delete default account!' => 'Az alapbeállítású számlát nem lehet törölni!',
+ 'Cannot save account!' => 'A számlát nem lehet elmenteni!',
+ 'Cannot save preferences!' => 'A beállításokat nem lehet elmenteni',
+ 'Character Set' => 'Betû kódlap',
+ 'Chart of Accounts' => 'Számlatükör',
+ 'Close Books up to' => 'Könyvelés lezárása eddig az idõpontig:',
+ 'Company' => 'Társaság',
+ 'Continue' => 'Folytatás',
+ 'Copy to COA' => 'Másolás a számlatükörbe',
+ 'Credit' => 'Követel',
+ 'Date Format' => 'Dátumformátum',
+ 'Debit' => 'Tartozik',
+ 'Delete' => 'Törlés',
+ 'Delete Account' => 'Számla törlése',
+ 'Description' => 'Szöveges leírás',
+ 'Dropdown Limit' => 'Lenyíló ablak limit',
+ 'E-mail' => 'E-mail',
+ 'Edit' => 'Módosítás',
+ 'Edit Account' => 'Számlaszám módosítása',
+ 'Edit GIFI' => 'Gyûjtõkód módosítása',
+ 'Edit Preferences for' => 'Felhasználói paraméterek módosítása:',
+ 'Edit Template' => 'Sablon módosítása',
+ 'Enforce transaction reversal for all dates' => 'Minden dátum esetében visszautasítsa a tranzakció rögzítését?',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'A saját és külföldi devizákat jelölje 3 betûvel kettõsponttal elválasztva! (pl. HUF:EUR:USD)',
+ 'Equity' => 'Tõke',
+ 'Expense' => 'Költség',
+ 'Expense Account' => 'Költségszámla',
+ 'Expense/Asset' => 'Költség/Eszköz',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Árfolyamnyereség',
+ 'Foreign Exchange Loss' => 'Árfolyamveszteség',
+ 'GIFI' => 'Gyûjtõkód',
+ 'GIFI deleted!' => 'Gyûjtõkód törölve!',
+ 'GIFI missing!' => 'Gyûjtõkód hiányzik!',
+ 'GIFI saved!' => 'Gyûjtõkód elmentve!',
+ 'Heading' => 'Fejléc',
+ 'Include in drop-down menus' => 'Mely tranzakció(k)-nál lehessen kiválasztani?:',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Kiválasztható legyen a vevõ/szállító ûrlapokon, mint adószámla?',
+ 'Income' => 'Árbevétel',
+ 'Income Account' => 'Árbevételszámla',
+ 'Inventory' => 'Készlet',
+ 'Inventory Account' => 'Készletszámla',
+ 'Is this a summary account to record' => 'Gyûjtõszámlaként szerepeljen ezeknél a tranzakcióknál:',
+ 'Language' => 'Nyelv',
+ 'Last Invoice Number' => 'Utolsó számlaszám',
+ 'Last Numbers & Default Accounts' => 'Legutolsó számok & Alapszámlák',
+ 'Last Purchase Order Number' => 'Utolsó beszerzési rendelésszám',
+ 'Last Sales Order Number' => 'Utolsó vevõ rendelésszám',
+ 'Liability' => 'Kötelezettség',
+ 'Link' => 'Kapcsolat',
+ 'Name' => 'Név',
+ 'No' => 'Nem',
+ 'No email address for' => 'Nincs e-mail címe:',
+ 'Number' => 'Szám',
+ 'Number Format' => 'Számformátum',
+ 'Parts Inventory' => 'Cikkek készlete',
+ 'Password' => 'Jelszó',
+ 'Payables' => 'Szállítók',
+ 'Payment' => 'Kifizetés',
+ 'Phone' => 'Telefon',
+ 'Preferences saved!' => 'Beállítások elmentve!',
+ 'Rate' => 'Árfolyam',
+ 'Receivables' => 'Vevõk',
+ 'Sales' => 'Eladás',
+ 'Save' => 'Mentés',
+ 'Service Items' => 'Szolgáltatás tételek',
+ 'Ship via' => 'Szállítás innen:',
+ 'Signature' => 'Aláírás',
+ 'Stylesheet' => 'Stíluslap',
+ 'Tax' => 'Adó',
+ 'Tax Accounts' => 'Adószámlák',
+ 'Template saved!' => 'Sablon elmentve!',
+ 'Transaction reversal enforced for all dates' => 'Bármilyen dátumú tranzakciót visszautasít',
+ 'Transaction reversal enforced up to' => 'E dátumig utasítja vissza a tranzakciókat',
+ 'Transactions exist; cannot delete account!' => 'A számlához tranzakciók tartoznak, nem lehet törölni!',
+ 'Weight Unit' => 'Súlyegység',
+ 'Year End' => 'Évzárás',
+ 'Yes' => 'Igen',
+ 'does not exist' => 'nem létezik',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'Új_számla' => 'add_account',
+ 'folytatás' => 'continue',
+ 'másolás_a_számlatükörbe' => 'copy_to_coa',
+ 'törlés' => 'delete',
+ 'módosítás' => 'edit',
+ 'számlaszám_módosítása' => 'edit_account',
+ 'mentés' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/ap b/sql-ledger/locale/hu/ap
new file mode 100644
index 0000000..e39bd70
--- /dev/null
+++ b/sql-ledger/locale/hu/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Szállító tranzakció',
+ 'AP Transactions' => 'Szállító tranzakciók',
+ 'Account' => 'Számla',
+ 'Add Accounts Payables Transaction' => 'Új szállító tranzakció',
+ 'Address' => 'Cím',
+ 'Amount' => 'Összeg',
+ 'Amount Due' => 'Esedékes összeg',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Are you sure you want to delete Transaction' => 'Biztos, hogy törölni akarja? Tranzakció:',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'Cannot delete transaction!' => 'A tranzakciót nem lehet törölni!',
+ 'Cannot post payment for a closed period!' => 'A lezárt idõszakban nem lehet fizetést rögzíteni!',
+ 'Cannot post transaction for a closed period!' => 'A lezárt idõszakban nem lehet tranzakciót rögzíteni!!',
+ 'Cannot post transaction!' => 'A tranzakciót nem lehet rögzíteni!',
+ 'Closed' => 'Lezárt',
+ 'Confirm!' => 'Megerõsítés:',
+ 'Continue' => 'Folytatás',
+ 'Currency' => 'Deviza',
+ 'Customer not on file!' => 'A vevõ hiányzik az adatbázisból!',
+ 'Date' => 'Dátum',
+ 'Date Paid' => 'Fizetés napja',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Delete' => 'Törlés',
+ 'Description' => 'Szöveges leírás',
+ 'Due Date' => 'Esedékesség',
+ 'Due Date missing!' => 'Esedékesség hiányzik!',
+ 'Edit Accounts Payables Transaction' => 'Szállító tranzakció módosítása',
+ 'Employee' => 'Alkalmazott',
+ 'Exch' => 'Árf',
+ 'Exchangerate' => 'Átváltási árfolyam',
+ 'Exchangerate for payment missing!' => 'A fizetett összeg átváltási árfolyama hiányzik!',
+ 'Exchangerate missing!' => 'Átváltási árfolyam hiányzik!',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'From' => 'Mikortól:',
+ 'ID' => 'Azonosító',
+ 'Include in Report' => 'Oszlopok:',
+ 'Invoice' => 'Számla',
+ 'Invoice Date' => 'Teljesítés dátuma',
+ 'Invoice Date missing!' => 'Teljesítés dátuma hiányzik!',
+ 'Invoice Number' => 'Számlaszám',
+ 'Invoice Number missing!' => 'Számlaszám hiányzik!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Notes' => 'Megjegyzés',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Number' => 'Szám',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'Open' => 'Nyitott',
+ 'Order' => 'Rendelés',
+ 'Order Number' => 'Rendelés száma',
+ 'Paid' => 'Fizetve',
+ 'Payment date missing!' => 'Pénzmozgás dátuma hiányzik!',
+ 'Payments' => 'Kifizetések',
+ 'Post' => 'Rögzítés',
+ 'Post as new' => 'Rögzítés új tranzakcióként',
+ 'Project' => 'Munkaszám',
+ 'Project not on file!' => 'Munkaszám hiányzik az adatbázisból!',
+ 'Select from one of the names below' => 'Válasszon ki egyet az alábbi nevek közül',
+ 'Select from one of the projects below' => 'Válasszon ki egyet az alábbi munkaszámok közül',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Source' => 'Bizonylatszám',
+ 'Subtotal' => 'Részösszeg',
+ 'Tax' => 'Adó',
+ 'Tax Included' => 'Adót tartalmazza',
+ 'Total' => 'Végösszeg',
+ 'Transaction deleted!' => 'Tranzakció törölve!',
+ 'Transaction posted!' => 'Tranzakció rögzítve!',
+ 'Update' => 'Frissítés',
+ 'Vendor' => 'Szállító',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendor missing!' => 'Szállító hiányzik!',
+ 'Vendor not on file!' => 'Szállító nincs az adatbázisban!',
+ 'Yes' => 'Igen',
+ 'to' => 'Meddig:',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'szállító_tranzakció' => 'ap_transaction',
+ 'Új_szállító_tranzakció' => 'add_accounts_payables_transaction',
+ 'folytatás' => 'continue',
+ 'törlés' => 'delete',
+ 'szállító_tranzakció_módosítása' => 'edit_accounts_payables_transaction',
+ 'rögzítés' => 'post',
+ 'rögzítés_új_tranzakcióként' => 'post_as_new',
+ 'frissítés' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'igen' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/ar b/sql-ledger/locale/hu/ar
new file mode 100644
index 0000000..2243070
--- /dev/null
+++ b/sql-ledger/locale/hu/ar
@@ -0,0 +1,134 @@
+$self{texts} = {
+ 'AR Transaction' => 'Vevõ tranzakció',
+ 'AR Transactions' => 'Vevõ tranzakciók',
+ 'Account' => 'Számla',
+ 'Add Accounts Receivables Transaction' => 'Új vevõ tranzakció',
+ 'Address' => 'Cím',
+ 'Amount' => 'Összeg',
+ 'Amount Due' => 'Esedékes összeg',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Are you sure you want to delete Transaction' => 'Biztos, hogy törölni akarja? Tranzakció:',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'Cannot delete transaction!' => 'A tranzakciót nem lehet törölni!',
+ 'Cannot post payment for a closed period!' => 'A lezárt idõszakban nem lehet fizetést rögzíteni!',
+ 'Cannot post transaction for a closed period!' => 'A lezárt idõszakban nem lehet tranzakciót rögzíteni!!',
+ 'Cannot post transaction!' => 'A tranzakciót nem lehet rögzíteni!',
+ 'Closed' => 'Lezárt',
+ 'Confirm!' => 'Megerõsítés:',
+ 'Continue' => 'Folytatás',
+ 'Credit Limit' => 'Hitelkeret',
+ 'Currency' => 'Deviza',
+ 'Customer' => 'Vevõ',
+ 'Customer missing!' => 'Vevõ hiányzik!',
+ 'Customer not on file!' => 'A vevõ hiányzik az adatbázisból!',
+ 'Date' => 'Dátum',
+ 'Date Paid' => 'Fizetés napja',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Delete' => 'Törlés',
+ 'Description' => 'Szöveges leírás',
+ 'Due Date' => 'Esedékesség',
+ 'Due Date missing!' => 'Esedékesség hiányzik!',
+ 'Edit Accounts Receivables Transaction' => 'Vevõ tranzakció módosítása',
+ 'Exch' => 'Árf',
+ 'Exchangerate' => 'Átváltási árfolyam',
+ 'Exchangerate for payment missing!' => 'A fizetett összeg átváltási árfolyama hiányzik!',
+ 'Exchangerate missing!' => 'Átváltási árfolyam hiányzik!',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'From' => 'Mikortól:',
+ 'ID' => 'Azonosító',
+ 'Include in Report' => 'Oszlopok:',
+ 'Invoice' => 'Számla',
+ 'Invoice Date' => 'Teljesítés dátuma',
+ 'Invoice Date missing!' => 'Teljesítés dátuma hiányzik!',
+ 'Invoice Number' => 'Számlaszám',
+ 'Invoice Number missing!' => 'Számlaszám hiányzik!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Notes' => 'Megjegyzés',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Number' => 'Szám',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'Open' => 'Nyitott',
+ 'Order' => 'Rendelés',
+ 'Order Number' => 'Rendelés száma',
+ 'Paid' => 'Fizetve',
+ 'Payment date missing!' => 'Pénzmozgás dátuma hiányzik!',
+ 'Payments' => 'Kifizetések',
+ 'Post' => 'Rögzítés',
+ 'Post as new' => 'Rögzítés új tranzakcióként',
+ 'Project' => 'Munkaszám',
+ 'Project not on file!' => 'Munkaszám hiányzik az adatbázisból!',
+ 'Remaining' => 'Maradék',
+ 'Sales Invoice' => 'Számlázás',
+ 'Salesperson' => 'Salesperson',
+ 'Select from one of the names below' => 'Válasszon ki egyet az alábbi nevek közül',
+ 'Select from one of the projects below' => 'Válasszon ki egyet az alábbi munkaszámok közül',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Ship via' => 'Szállítás innen:',
+ 'Source' => 'Bizonylatszám',
+ 'Subtotal' => 'Részösszeg',
+ 'Tax' => 'Adó',
+ 'Tax Included' => 'Adót tartalmazza',
+ 'Total' => 'Végösszeg',
+ 'Transaction deleted!' => 'Tranzakció törölve!',
+ 'Transaction posted!' => 'Tranzakció rögzítve!',
+ 'Update' => 'Frissítés',
+ 'Vendor not on file!' => 'Szállító nincs az adatbázisban!',
+ 'Yes' => 'Igen',
+ 'to' => 'Meddig:',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'vevõ_tranzakció' => 'ar_transaction',
+ 'folytatás' => 'continue',
+ 'törlés' => 'delete',
+ 'rögzítés' => 'post',
+ 'rögzítés_új_tranzakcióként' => 'post_as_new',
+ 'számlázás' => 'sales_invoice',
+ 'frissítés' => 'update',
+ 'igen' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/arap b/sql-ledger/locale/hu/arap
new file mode 100644
index 0000000..9809e35
--- /dev/null
+++ b/sql-ledger/locale/hu/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Cím',
+ 'Continue' => 'Folytatás',
+ 'Customer not on file!' => 'A vevõ hiányzik az adatbázisból!',
+ 'Description' => 'Szöveges leírás',
+ 'Number' => 'Szám',
+ 'Project not on file!' => 'Munkaszám hiányzik az adatbázisból!',
+ 'Select from one of the names below' => 'Válasszon ki egyet az alábbi nevek közül',
+ 'Select from one of the projects below' => 'Válasszon ki egyet az alábbi munkaszámok közül',
+ 'Vendor not on file!' => 'Szállító nincs az adatbázisban!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'folytatás' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/ca b/sql-ledger/locale/hu/ca
new file mode 100644
index 0000000..df4726c
--- /dev/null
+++ b/sql-ledger/locale/hu/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Számla',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'Balance' => 'Egyenleg',
+ 'Chart of Accounts' => 'Számlatükör',
+ 'Credit' => 'Követel',
+ 'Date' => 'Dátum',
+ 'Debit' => 'Tartozik',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Description' => 'Szöveges leírás',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'From' => 'Mikortól:',
+ 'GIFI' => 'Gyûjtõkód',
+ 'Include in Report' => 'Oszlopok:',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'List Transactions' => 'Tranzakciók listázása',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'Reference' => 'Hivatkozás',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Subtotal' => 'Részösszeg',
+ 'to' => 'Meddig:',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'tranzakciók_listázása' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/cp b/sql-ledger/locale/hu/cp
new file mode 100644
index 0000000..2a2b09a
--- /dev/null
+++ b/sql-ledger/locale/hu/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'Számla',
+ 'Address' => 'Cím',
+ 'Amount' => 'Összeg',
+ 'Amount does not equal applied!' => 'Az összeg nem egyezik a kitöltött szám(ok) összegével',
+ 'Amount missing!' => 'Összeg hiányzik!',
+ 'Applied' => 'Kitöltés',
+ 'Cannot post payment!' => 'A pénzmozgást nem lehet rögzíteni',
+ 'Cannot process payment for a closed period!' => 'A pénzmozgást nem lehet lezárt idõszakban rögzíteni!',
+ 'Check' => 'Csekk',
+ 'Check printed!' => 'Csekk kinyomtatva!',
+ 'Check printing failed!' => 'A csekk nyomtatása nem sikerült!',
+ 'Continue' => 'Folytatás',
+ 'Currency' => 'Deviza',
+ 'Customer' => 'Vevõ',
+ 'Customer not on file!' => 'A vevõ hiányzik az adatbázisból!',
+ 'Date' => 'Dátum',
+ 'Date missing!' => 'Dátum hiányzik',
+ 'Description' => 'Szöveges leírás',
+ 'Due' => 'Esedékes',
+ 'Exchangerate' => 'Átváltási árfolyam',
+ 'From' => 'Mikortól:',
+ 'Invoice' => 'Számla',
+ 'Invoices' => 'Számlák',
+ 'Nothing applied!' => 'Nincs semmi kitöltve!',
+ 'Number' => 'Szám',
+ 'Paid in full' => 'Teljesen fizetve',
+ 'Payment' => 'Kifizetés',
+ 'Payment posted!' => 'Pénzmozgás rögzítve',
+ 'Post' => 'Rögzítés',
+ 'Print' => 'Nyomtatás',
+ 'Printer' => 'Nyomtató',
+ 'Project not on file!' => 'Munkaszám hiányzik az adatbázisból!',
+ 'Receipt' => 'Bevétel',
+ 'Receipt printed!' => 'Nyugta nyomtatva!',
+ 'Receipt printing failed!' => 'A nyugta nyomtatása nem sikerült!',
+ 'Reference' => 'Hivatkozás',
+ 'Screen' => 'Képernyõre',
+ 'Select from one of the names below' => 'Válasszon ki egyet az alábbi nevek közül',
+ 'Select from one of the projects below' => 'Válasszon ki egyet az alábbi munkaszámok közül',
+ 'Update' => 'Frissítés',
+ 'Vendor' => 'Szállító',
+ 'Vendor not on file!' => 'Szállító nincs az adatbázisban!',
+ 'to' => 'Meddig:',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'folytatás' => 'continue',
+ 'rögzítés' => 'post',
+ 'nyomtatás' => 'print',
+ 'frissítés' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/ct b/sql-ledger/locale/hu/ct
new file mode 100644
index 0000000..55680ad
--- /dev/null
+++ b/sql-ledger/locale/hu/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Új',
+ 'Address' => 'Cím',
+ 'All' => 'Összes',
+ 'Bcc' => 'Titkos másolat',
+ 'Cannot delete customer!' => 'A vevõt nem lehet törölni!',
+ 'Cannot delete vendor!' => 'Szállítót nem lehet törölni!',
+ 'Cc' => 'Másolat',
+ 'Contact' => 'Kapcsolat',
+ 'Continue' => 'Folytatás',
+ 'Credit Limit' => 'Hitelkeret',
+ 'Customer deleted!' => 'Vevõ törölve!',
+ 'Customer saved!' => 'Vevõ elmentve!',
+ 'Customers' => 'Vevõadatok',
+ 'Delete' => 'Törlés',
+ 'Discount' => 'Engedmény',
+ 'E-mail' => 'E-mail',
+ 'Edit Customer' => 'Vevõ módosítása',
+ 'Edit Vendor' => 'Szállító módosítása',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Oszlopok:',
+ 'Invoice' => 'Számla',
+ 'Name' => 'Név',
+ 'Name missing!' => 'Név hiányzik',
+ 'Notes' => 'Megjegyzés',
+ 'Number' => 'Szám',
+ 'Order' => 'Rendelés',
+ 'Orphaned' => 'Tranzakció nélküli',
+ 'Phone' => 'Telefon',
+ 'Save' => 'Mentés',
+ 'Ship to' => 'Szállítási cím',
+ 'Tax Included' => 'Adót tartalmazza',
+ 'Taxable' => 'Adó:',
+ 'Terms: Net' => 'Határidõ',
+ 'Transactions exist, cannot delete customer!' => 'A vevõhöz tranzakciók tartoznak, nem lehet törölni!',
+ 'Transactions exist, cannot delete vendor!' => 'A szállítóhoz tranzakciók tartoznak, nem lehet törölni!',
+ 'Vendor deleted!' => 'Szállító törölve!',
+ 'Vendor saved!' => 'Szállító elmentve!',
+ 'Vendors' => 'Szállítók',
+ 'days' => 'nap',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'Új' => 'add',
+ 'folytatás' => 'continue',
+ 'törlés' => 'delete',
+ 'számla' => 'invoice',
+ 'rendelés' => 'order',
+ 'mentés' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/gl b/sql-ledger/locale/hu/gl
new file mode 100644
index 0000000..f62d538
--- /dev/null
+++ b/sql-ledger/locale/hu/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Szállító tranzakció',
+ 'AR Transaction' => 'Vevõ tranzakció',
+ 'Account' => 'Számla',
+ 'Add General Ledger Transaction' => 'Új fõkönyvi könyvelés',
+ 'Address' => 'Cím',
+ 'All' => 'Összes',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Are you sure you want to delete Transaction' => 'Biztos, hogy törölni akarja? Tranzakció:',
+ 'Asset' => 'Eszköz',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'Balance' => 'Egyenleg',
+ 'Cannot delete transaction!' => 'A tranzakciót nem lehet törölni!',
+ 'Cannot have a value in both Debit and Credit!' => 'A Tartozik és Követel oldal is tartalmaz értéket!',
+ 'Cannot post a transaction without a value!' => 'Az összeg megadása nélkül nem lehet a tranzakciót rögzíteni!',
+ 'Cannot post transaction for a closed period!' => 'A lezárt idõszakban nem lehet tranzakciót rögzíteni!!',
+ 'Confirm!' => 'Megerõsítés:',
+ 'Continue' => 'Folytatás',
+ 'Credit' => 'Követel',
+ 'Customer not on file!' => 'A vevõ hiányzik az adatbázisból!',
+ 'Date' => 'Dátum',
+ 'Debit' => 'Tartozik',
+ 'Debit and credit out of balance!' => 'Tartozik Követel összege nem egyezik!',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Delete' => 'Törlés',
+ 'Description' => 'Szöveges leírás',
+ 'Edit General Ledger Transaction' => 'Vegyes könyvelési tétel módosítása',
+ 'Equity' => 'Tõke',
+ 'Expense' => 'Költség',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'From' => 'Mikortól:',
+ 'GIFI' => 'Gyûjtõkód',
+ 'GL Transaction' => 'Fõkönyvi tranzakció!',
+ 'General Ledger' => 'Fõkönyvi könyvelés',
+ 'ID' => 'Azonosító',
+ 'Include in Report' => 'Oszlopok:',
+ 'Income' => 'Árbevétel',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'Liability' => 'Kötelezettség',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Notes' => 'Megjegyzés',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Number' => 'Szám',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'Post' => 'Rögzítés',
+ 'Post as new' => 'Rögzítés új tranzakcióként',
+ 'Project' => 'Munkaszám',
+ 'Project not on file!' => 'Munkaszám hiányzik az adatbázisból!',
+ 'Reference' => 'Hivatkozás',
+ 'Reference missing!' => 'Hivatkozás hiányzik',
+ 'Reports' => 'Jelentések',
+ 'Sales Invoice' => 'Számlázás',
+ 'Select from one of the names below' => 'Válasszon ki egyet az alábbi nevek közül',
+ 'Select from one of the projects below' => 'Válasszon ki egyet az alábbi munkaszámok közül',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Source' => 'Bizonylatszám',
+ 'Subtotal' => 'Részösszeg',
+ 'Transaction Date missing!' => 'Tranzakció dátuma hiányzik!',
+ 'Transaction deleted!' => 'Tranzakció törölve!',
+ 'Transaction posted!' => 'Tranzakció rögzítve!',
+ 'Update' => 'Frissítés',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendor not on file!' => 'Szállító nincs az adatbázisban!',
+ 'Yes' => 'Igen',
+ 'to' => 'Meddig:',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'szállító_tranzakció' => 'ap_transaction',
+ 'vevõ_tranzakció' => 'ar_transaction',
+ 'folytatás' => 'continue',
+ 'törlés' => 'delete',
+ 'fõkönyvi_tranzakció!' => 'gl_transaction',
+ 'rögzítés' => 'post',
+ 'rögzítés_új_tranzakcióként' => 'post_as_new',
+ 'számlázás' => 'sales_invoice',
+ 'frissítés' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'igen' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/ic b/sql-ledger/locale/hu/ic
new file mode 100644
index 0000000..768ba21
--- /dev/null
+++ b/sql-ledger/locale/hu/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Aktív',
+ 'Add' => 'Új',
+ 'Add Assembly' => 'Új saját termék',
+ 'Add Part' => 'Új cikk',
+ 'Add Purchase Order' => 'Új beszerzési rendelés',
+ 'Add Sales Order' => 'Új vevõrendelés',
+ 'Add Service' => 'Új szolgáltatás',
+ 'Address' => 'Cím',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Assemblies' => 'Saját termékek',
+ 'Assemblies restocked!' => 'Saját termékek készletre véve',
+ 'Assembly Number missing!' => 'Saját termékszám hiányzik!',
+ 'Attachment' => 'Csatolás',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Titkos másolat',
+ 'Bin' => 'Bin',
+ 'Bought' => 'Vásárolt',
+ 'COGS' => 'ELÁBÉ',
+ 'Cannot delete item!' => 'A tételt nem lehet törölni!',
+ 'Cannot stock assemblies!' => 'A saját terméket nem lehet készletre venni!',
+ 'Cc' => 'Másolat',
+ 'Closed' => 'Lezárt',
+ 'Contact' => 'Kapcsolat',
+ 'Continue' => 'Folytatás',
+ 'Copies' => 'Másolatok',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Delete' => 'Törlés',
+ 'Delivery Date' => 'Szállítás dátuma',
+ 'Description' => 'Szöveges leírás',
+ 'Drawing' => 'Rajz',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail cím hiányzik!',
+ 'Edit Assembly' => 'Saját termék módosítása',
+ 'Edit Part' => 'Cikk módosítása',
+ 'Edit Service' => 'Szolgáltatás módosítása',
+ 'Expense' => 'Költség',
+ 'Extended' => 'Összeg',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'From' => 'Mikortól:',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'Image' => 'Kép',
+ 'In-line' => 'Beágyazva',
+ 'Include in Report' => 'Oszlopok:',
+ 'Income' => 'Árbevétel',
+ 'Individual Items' => 'Összetevõk',
+ 'Inventory' => 'Készlet',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Mielõtt ezt a saját terméket elévültnek nyilvánítja,a mennyiségnek nullának kell lennie!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Mielõtt ezt az anyagot/árut elévültnek nyilvánítja,a mennyiségnek nullának kell lennie!!',
+ 'Invoice' => 'Számla',
+ 'Invoice Date missing!' => 'Teljesítés dátuma hiányzik!',
+ 'Invoice Number' => 'Számlaszám',
+ 'Invoice Number missing!' => 'Számlaszám hiányzik!',
+ 'Item deleted!' => 'Tétel törölve!',
+ 'Item not on file!' => 'A tétel nincs az adatbázisban!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'Last Cost' => 'Utolsó beszerzési ár',
+ 'Line Total' => 'Sor összesen',
+ 'Link Accounts' => 'Számlakapcsolatok',
+ 'List Price' => 'Listaár',
+ 'Make' => 'Gyártmány',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Message' => 'Üzenet',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modell',
+ 'Name' => 'Név',
+ 'No.' => 'Sz.',
+ 'Notes' => 'Megjegyzés',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Number' => 'Szám',
+ 'Number missing in Row' => 'Ebbõl a sorból hiányzik a szám:',
+ 'Obsolete' => 'Elévült',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'On Hand' => 'Készleten',
+ 'On Order' => 'Beszerzési rendelések',
+ 'Order' => 'Rendelés',
+ 'Order Date missing!' => 'Rendelés dátuma hiányzik!',
+ 'Order Number' => 'Rendelés száma',
+ 'Order Number missing!' => 'Rendelés száma hiányzik!',
+ 'Ordered' => 'Vevõrendelések',
+ 'Orphaned' => 'Tranzakció nélküli',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Szállítólevél',
+ 'Packing List Date missing!' => 'Szállítólevél dátuma hiányzik!',
+ 'Packing List Number missing!' => 'Szállítólevél száma hiányzik!',
+ 'Part' => 'Cikk',
+ 'Part Number missing!' => 'Cikk száma hiányzik!',
+ 'Parts' => 'Cikkek',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Ár',
+ 'Printer' => 'Nyomtató',
+ 'Project' => 'Munkaszám',
+ 'Purchase Order' => 'Beszerzési rendelés',
+ 'Qty' => 'Menny.',
+ 'ROP' => 'Rendelési pont',
+ 'Recd' => 'Kapott',
+ 'Required by' => 'Leszállítás',
+ 'Sales' => 'Eladás',
+ 'Sales Order' => 'Vevõrendelés',
+ 'Save' => 'Mentés',
+ 'Save as new' => 'Mentés újként',
+ 'Screen' => 'Képernyõre',
+ 'Select from one of the items below' => 'Válasszon ki egyet az alábbi tételek közül',
+ 'Select postscript or PDF!' => 'Válassza ki a postscript vagy a PDF formátumot!',
+ 'Sell Price' => 'Eladási ár',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Service' => 'Szolgáltatás',
+ 'Service Number missing!' => 'Szolgáltatás száma hiányzik!',
+ 'Services' => 'Szolgáltatások',
+ 'Ship' => 'Szállítás',
+ 'Ship to' => 'Szállítási cím',
+ 'Short' => 'Hiányzó',
+ 'Sold' => 'Eladva',
+ 'Stock' => 'Stock',
+ 'Stock Assembly' => 'Saját termék bevételezése',
+ 'Subject' => 'Tárgy',
+ 'Subtotal' => 'Részösszeg',
+ 'Tax' => 'Adó',
+ 'To' => 'Meddig:',
+ 'Top Level' => 'Legfelsõ szint',
+ 'Total' => 'Végösszeg',
+ 'Unit' => 'Egység',
+ 'Unit of measure' => 'Mértékegység',
+ 'Update' => 'Frissítés',
+ 'Updated' => 'Frissítve',
+ 'Weight' => 'Súly',
+ 'What type of item is this?' => 'Ez milyen típusú tétel?',
+ 'ea' => 'db',
+ 'emailed to' => 'e-mail küldve:',
+ 'hr' => 'óra',
+ 'sent to printer' => 'kinyomtatva',
+ 'to' => 'Meddig:',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'Új' => 'add',
+ 'Új_saját_termék' => 'add_assembly',
+ 'Új_cikk' => 'add_part',
+ 'Új_szolgáltatás' => 'add_service',
+ 'folytatás' => 'continue',
+ 'törlés' => 'delete',
+ 'saját_termék_módosítása' => 'edit_assembly',
+ 'cikk_módosítása' => 'edit_part',
+ 'szolgáltatás_módosítása' => 'edit_service',
+ 'mentés' => 'save',
+ 'mentés_újként' => 'save_as_new',
+ 'frissítés' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/io b/sql-ledger/locale/hu/io
new file mode 100644
index 0000000..c30d7e9
--- /dev/null
+++ b/sql-ledger/locale/hu/io
@@ -0,0 +1,108 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Új beszerzési rendelés',
+ 'Add Sales Order' => 'Új vevõrendelés',
+ 'Address' => 'Cím',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Attachment' => 'Csatolás',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'Bcc' => 'Titkos másolat',
+ 'Bin' => 'Bin',
+ 'Cc' => 'Másolat',
+ 'Contact' => 'Kapcsolat',
+ 'Continue' => 'Folytatás',
+ 'Copies' => 'Másolatok',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Delivery Date' => 'Szállítás dátuma',
+ 'Description' => 'Szöveges leírás',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail cím hiányzik!',
+ 'Extended' => 'Összeg',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'Beágyazva',
+ 'Invoice' => 'Számla',
+ 'Invoice Date missing!' => 'Teljesítés dátuma hiányzik!',
+ 'Invoice Number missing!' => 'Számlaszám hiányzik!',
+ 'Item not on file!' => 'A tétel nincs az adatbázisban!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Message' => 'Üzenet',
+ 'Name' => 'Név',
+ 'No.' => 'Sz.',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Number' => 'Szám',
+ 'Number missing in Row' => 'Ebbõl a sorból hiányzik a szám:',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'Order' => 'Rendelés',
+ 'Order Date missing!' => 'Rendelés dátuma hiányzik!',
+ 'Order Number missing!' => 'Rendelés száma hiányzik!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Szállítólevél',
+ 'Packing List Date missing!' => 'Szállítólevél dátuma hiányzik!',
+ 'Packing List Number missing!' => 'Szállítólevél száma hiányzik!',
+ 'Part' => 'Cikk',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Ár',
+ 'Printer' => 'Nyomtató',
+ 'Project' => 'Munkaszám',
+ 'Purchase Order' => 'Beszerzési rendelés',
+ 'Qty' => 'Menny.',
+ 'Recd' => 'Kapott',
+ 'Required by' => 'Leszállítás',
+ 'Sales Order' => 'Vevõrendelés',
+ 'Screen' => 'Képernyõre',
+ 'Select from one of the items below' => 'Válasszon ki egyet az alábbi tételek közül',
+ 'Select postscript or PDF!' => 'Válassza ki a postscript vagy a PDF formátumot!',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Service' => 'Szolgáltatás',
+ 'Ship' => 'Szállítás',
+ 'Ship to' => 'Szállítási cím',
+ 'Subject' => 'Tárgy',
+ 'To' => 'Meddig:',
+ 'Unit' => 'Egység',
+ 'What type of item is this?' => 'Ez milyen típusú tétel?',
+ 'emailed to' => 'e-mail küldve:',
+ 'sent to printer' => 'kinyomtatva',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'folytatás' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/ir b/sql-ledger/locale/hu/ir
new file mode 100644
index 0000000..5e81745
--- /dev/null
+++ b/sql-ledger/locale/hu/ir
@@ -0,0 +1,180 @@
+$self{texts} = {
+ 'Account' => 'Számla',
+ 'Add Purchase Order' => 'Új beszerzési rendelés',
+ 'Add Sales Order' => 'Új vevõrendelés',
+ 'Add Vendor Invoice' => 'Add Vendor Invoice',
+ 'Address' => 'Cím',
+ 'Amount' => 'Összeg',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Are you sure you want to delete Invoice Number' => 'Biztos, hogy törölni akarja? Számlaszám:',
+ 'Attachment' => 'Csatolás',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'Bcc' => 'Titkos másolat',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'A partnerszámlát nem lehet törölni!',
+ 'Cannot post invoice for a closed period!' => 'A lezárt idõszakban nem lehet számlát kiállítani!',
+ 'Cannot post invoice!' => 'A partnerszámlát nem lehet kiállítani',
+ 'Cannot post payment for a closed period!' => 'A lezárt idõszakban nem lehet fizetést rögzíteni!',
+ 'Cc' => 'Másolat',
+ 'Confirm!' => 'Megerõsítés:',
+ 'Contact' => 'Kapcsolat',
+ 'Continue' => 'Folytatás',
+ 'Copies' => 'Másolatok',
+ 'Currency' => 'Deviza',
+ 'Customer not on file!' => 'A vevõ hiányzik az adatbázisból!',
+ 'Date' => 'Dátum',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Delete' => 'Törlés',
+ 'Delivery Date' => 'Szállítás dátuma',
+ 'Description' => 'Szöveges leírás',
+ 'Due Date' => 'Esedékesség',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail cím hiányzik!',
+ 'Edit Vendor Invoice' => 'Edit Vendor Invoice',
+ 'Exch' => 'Árf',
+ 'Exchangerate' => 'Átváltási árfolyam',
+ 'Exchangerate for payment missing!' => 'A fizetett összeg átváltási árfolyama hiányzik!',
+ 'Exchangerate missing!' => 'Átváltási árfolyam hiányzik!',
+ 'Extended' => 'Összeg',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'Beágyazva',
+ 'Invoice' => 'Számla',
+ 'Invoice Date' => 'Teljesítés dátuma',
+ 'Invoice Date missing!' => 'Teljesítés dátuma hiányzik!',
+ 'Invoice Number' => 'Számlaszám',
+ 'Invoice Number missing!' => 'Számlaszám hiányzik!',
+ 'Invoice deleted!' => 'Számla törölve!',
+ 'Invoice posted!' => 'Számla rögzítve!',
+ 'Item not on file!' => 'A tétel nincs az adatbázisban!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Message' => 'Üzenet',
+ 'Name' => 'Név',
+ 'No.' => 'Sz.',
+ 'Notes' => 'Megjegyzés',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Number' => 'Szám',
+ 'Number missing in Row' => 'Ebbõl a sorból hiányzik a szám:',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'Order' => 'Rendelés',
+ 'Order Date missing!' => 'Rendelés dátuma hiányzik!',
+ 'Order Number' => 'Rendelés száma',
+ 'Order Number missing!' => 'Rendelés száma hiányzik!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Szállítólevél',
+ 'Packing List Date missing!' => 'Szállítólevél dátuma hiányzik!',
+ 'Packing List Number missing!' => 'Szállítólevél száma hiányzik!',
+ 'Part' => 'Cikk',
+ 'Payment date missing!' => 'Pénzmozgás dátuma hiányzik!',
+ 'Payments' => 'Kifizetések',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Rögzítés',
+ 'Post as new' => 'Rögzítés új tranzakcióként',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Ár',
+ 'Printer' => 'Nyomtató',
+ 'Project' => 'Munkaszám',
+ 'Project not on file!' => 'Munkaszám hiányzik az adatbázisból!',
+ 'Purchase Order' => 'Beszerzési rendelés',
+ 'Qty' => 'Menny.',
+ 'Recd' => 'Kapott',
+ 'Record in' => 'Feladás:',
+ 'Required by' => 'Leszállítás',
+ 'Sales Order' => 'Vevõrendelés',
+ 'Screen' => 'Képernyõre',
+ 'Select from one of the items below' => 'Válasszon ki egyet az alábbi tételek közül',
+ 'Select from one of the names below' => 'Válasszon ki egyet az alábbi nevek közül',
+ 'Select from one of the projects below' => 'Válasszon ki egyet az alábbi munkaszámok közül',
+ 'Select postscript or PDF!' => 'Válassza ki a postscript vagy a PDF formátumot!',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Service' => 'Szolgáltatás',
+ 'Ship' => 'Szállítás',
+ 'Ship to' => 'Szállítási cím',
+ 'Source' => 'Bizonylatszám',
+ 'Subject' => 'Tárgy',
+ 'Subtotal' => 'Részösszeg',
+ 'Tax Included' => 'Adót tartalmazza',
+ 'To' => 'Meddig:',
+ 'Total' => 'Végösszeg',
+ 'Unit' => 'Egység',
+ 'Update' => 'Frissítés',
+ 'Vendor' => 'Szállító',
+ 'Vendor missing!' => 'Szállító hiányzik!',
+ 'Vendor not on file!' => 'Szállító nincs az adatbázisban!',
+ 'What type of item is this?' => 'Ez milyen típusú tétel?',
+ 'Yes' => 'Igen',
+ 'ea' => 'db',
+ 'emailed to' => 'e-mail küldve:',
+ 'sent to printer' => 'kinyomtatva',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'folytatás' => 'continue',
+ 'törlés' => 'delete',
+ 'rendelés' => 'order',
+ 'rögzítés' => 'post',
+ 'rögzítés_új_tranzakcióként' => 'post_as_new',
+ 'frissítés' => 'update',
+ 'igen' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/is b/sql-ledger/locale/hu/is
new file mode 100644
index 0000000..54cc04a
--- /dev/null
+++ b/sql-ledger/locale/hu/is
@@ -0,0 +1,187 @@
+$self{texts} = {
+ 'Account' => 'Számla',
+ 'Add Purchase Order' => 'Új beszerzési rendelés',
+ 'Add Sales Invoice' => 'Új vevõszámla',
+ 'Add Sales Order' => 'Új vevõrendelés',
+ 'Address' => 'Cím',
+ 'Amount' => 'Összeg',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Are you sure you want to delete Invoice Number' => 'Biztos, hogy törölni akarja? Számlaszám:',
+ 'Attachment' => 'Csatolás',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'Bcc' => 'Titkos másolat',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'A partnerszámlát nem lehet törölni!',
+ 'Cannot post invoice for a closed period!' => 'A lezárt idõszakban nem lehet számlát kiállítani!',
+ 'Cannot post invoice!' => 'A partnerszámlát nem lehet kiállítani',
+ 'Cannot post payment for a closed period!' => 'A lezárt idõszakban nem lehet fizetést rögzíteni!',
+ 'Cc' => 'Másolat',
+ 'Confirm!' => 'Megerõsítés:',
+ 'Contact' => 'Kapcsolat',
+ 'Continue' => 'Folytatás',
+ 'Copies' => 'Másolatok',
+ 'Credit Limit' => 'Hitelkeret',
+ 'Currency' => 'Deviza',
+ 'Customer' => 'Vevõ',
+ 'Customer missing!' => 'Vevõ hiányzik!',
+ 'Customer not on file!' => 'A vevõ hiányzik az adatbázisból!',
+ 'Date' => 'Dátum',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Delete' => 'Törlés',
+ 'Delivery Date' => 'Szállítás dátuma',
+ 'Description' => 'Szöveges leírás',
+ 'Due Date' => 'Esedékesség',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail cím hiányzik!',
+ 'Edit Sales Invoice' => 'Vevõszámla módosítása',
+ 'Exch' => 'Árf',
+ 'Exchangerate' => 'Átváltási árfolyam',
+ 'Exchangerate for payment missing!' => 'A fizetett összeg átváltási árfolyama hiányzik!',
+ 'Exchangerate missing!' => 'Átváltási árfolyam hiányzik!',
+ 'Extended' => 'Összeg',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'Beágyazva',
+ 'Invoice' => 'Számla',
+ 'Invoice Date' => 'Teljesítés dátuma',
+ 'Invoice Date missing!' => 'Teljesítés dátuma hiányzik!',
+ 'Invoice Number' => 'Számlaszám',
+ 'Invoice Number missing!' => 'Számlaszám hiányzik!',
+ 'Invoice deleted!' => 'Számla törölve!',
+ 'Invoice posted!' => 'Számla rögzítve!',
+ 'Item not on file!' => 'A tétel nincs az adatbázisban!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Message' => 'Üzenet',
+ 'Name' => 'Név',
+ 'No.' => 'Sz.',
+ 'Notes' => 'Megjegyzés',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Number' => 'Szám',
+ 'Number missing in Row' => 'Ebbõl a sorból hiányzik a szám:',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'Order' => 'Rendelés',
+ 'Order Date missing!' => 'Rendelés dátuma hiányzik!',
+ 'Order Number' => 'Rendelés száma',
+ 'Order Number missing!' => 'Rendelés száma hiányzik!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Szállítólevél',
+ 'Packing List Date missing!' => 'Szállítólevél dátuma hiányzik!',
+ 'Packing List Number missing!' => 'Szállítólevél száma hiányzik!',
+ 'Part' => 'Cikk',
+ 'Payment date missing!' => 'Pénzmozgás dátuma hiányzik!',
+ 'Payments' => 'Kifizetések',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Rögzítés',
+ 'Post as new' => 'Rögzítés új tranzakcióként',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Ár',
+ 'Print' => 'Nyomtatás',
+ 'Printer' => 'Nyomtató',
+ 'Project' => 'Munkaszám',
+ 'Project not on file!' => 'Munkaszám hiányzik az adatbázisból!',
+ 'Purchase Order' => 'Beszerzési rendelés',
+ 'Qty' => 'Menny.',
+ 'Recd' => 'Kapott',
+ 'Record in' => 'Feladás:',
+ 'Remaining' => 'Maradék',
+ 'Required by' => 'Leszállítás',
+ 'Sales Order' => 'Vevõrendelés',
+ 'Screen' => 'Képernyõre',
+ 'Select from one of the items below' => 'Válasszon ki egyet az alábbi tételek közül',
+ 'Select from one of the names below' => 'Válasszon ki egyet az alábbi nevek közül',
+ 'Select from one of the projects below' => 'Válasszon ki egyet az alábbi munkaszámok közül',
+ 'Select postscript or PDF!' => 'Válassza ki a postscript vagy a PDF formátumot!',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Service' => 'Szolgáltatás',
+ 'Ship' => 'Szállítás',
+ 'Ship to' => 'Szállítási cím',
+ 'Ship via' => 'Szállítás innen:',
+ 'Source' => 'Bizonylatszám',
+ 'Subject' => 'Tárgy',
+ 'Subtotal' => 'Részösszeg',
+ 'Tax Included' => 'Adót tartalmazza',
+ 'To' => 'Meddig:',
+ 'Total' => 'Végösszeg',
+ 'Unit' => 'Egység',
+ 'Update' => 'Frissítés',
+ 'Vendor not on file!' => 'Szállító nincs az adatbázisban!',
+ 'What type of item is this?' => 'Ez milyen típusú tétel?',
+ 'Yes' => 'Igen',
+ 'ea' => 'db',
+ 'emailed to' => 'e-mail küldve:',
+ 'sent to printer' => 'kinyomtatva',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'folytatás' => 'continue',
+ 'törlés' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'rendelés' => 'order',
+ 'rögzítés' => 'post',
+ 'rögzítés_új_tranzakcióként' => 'post_as_new',
+ 'nyomtatás' => 'print',
+ 'szállítási_cím' => 'ship_to',
+ 'frissítés' => 'update',
+ 'igen' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/login b/sql-ledger/locale/hu/login
new file mode 100644
index 0000000..1b73088
--- /dev/null
+++ b/sql-ledger/locale/hu/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => ' ',
+ 'Database Host' => 'Adatbázis helye',
+ 'Dataset' => 'Cégadatbázis',
+ 'Incorrect Dataset version!' => 'Érvénytelen adatbázisverzió!',
+ 'Incorrect Password!' => 'Érvénytelen jelszó!',
+ 'Licensed to' => 'Cég:',
+ 'Login' => 'Belépés',
+ 'Name' => 'Név',
+ 'Password' => 'Jelszó',
+ 'User' => 'Felhasználó',
+ 'Version' => 'Verzió',
+ 'You are logged out!' => 'Már kijelentkezett!',
+ 'You did not enter a name!' => 'Nem írt be nevet!',
+ 'is not a member!' => 'nem tag!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'belépés' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/menu b/sql-ledger/locale/hu/menu
new file mode 100644
index 0000000..e1c3682
--- /dev/null
+++ b/sql-ledger/locale/hu/menu
@@ -0,0 +1,73 @@
+$self{texts} = {
+ 'AP' => 'Szállítók',
+ 'AP Aging' => 'Szállító lejárati lista',
+ 'AR' => 'Vevõk',
+ 'AR Aging' => 'Vevõ lejárati lista',
+ 'Accounting Menu' => 'Menü',
+ 'Add Account' => 'Új számla',
+ 'Add Assembly' => 'Új saját termék',
+ 'Add Customer' => 'Új vevõ',
+ 'Add GIFI' => 'Új gyûjtõkód',
+ 'Add Group' => 'Add Group',
+ 'Add Part' => 'Új cikk',
+ 'Add Project' => 'Új munkaszám',
+ 'Add Service' => 'Új szolgáltatás',
+ 'Add Transaction' => 'Új tranzakció',
+ 'Add Vendor' => 'Új szállító',
+ 'Assemblies' => 'Saját termékek',
+ 'Audit Control' => 'Audit Kontroll',
+ 'Backup' => 'Biztonsági másolat',
+ 'Balance Sheet' => 'Mérleg',
+ 'Cash' => 'Pénzmozgások',
+ 'Chart of Accounts' => 'Számlatükör',
+ 'Check' => 'Csekk',
+ 'Customers' => 'Vevõadatok',
+ 'General Ledger' => 'Fõkönyvi könyvelés',
+ 'Goods & Services' => 'Áruk & Szolgáltatások',
+ 'Groups' => 'Groups',
+ 'HTML Templates' => 'HTML sablonok',
+ 'Income Statement' => 'Eredménykimutatás',
+ 'Invoice' => 'Számla',
+ 'LaTeX Templates' => 'LaTeX sablonok',
+ 'List Accounts' => 'Számlák listázása',
+ 'List GIFI' => 'Gyûjtõkódok listázása',
+ 'Logout' => 'Kilépés',
+ 'Order Entry' => 'Rendelések',
+ 'Packing List' => 'Szállítólevél',
+ 'Parts' => 'Cikkek',
+ 'Payment' => 'Kifizetés',
+ 'Payments' => 'Kifizetések',
+ 'Preferences' => 'Beállítások',
+ 'Projects' => 'Munkaszámok',
+ 'Purchase Order' => 'Beszerzési rendelés',
+ 'Purchase Orders' => 'Beszerzési rendelések',
+ 'Receipt' => 'Bevétel',
+ 'Receipts' => 'Bevételek',
+ 'Reconciliation' => 'Egyeztetés',
+ 'Reports' => 'Jelentések',
+ 'Sales Invoice' => 'Számlázás',
+ 'Sales Order' => 'Vevõrendelés',
+ 'Sales Orders' => 'Vevõrendelések',
+ 'Save to File' => 'Másolat File-ba',
+ 'Send by E-Mail' => 'Másolat E-mail-ben',
+ 'Services' => 'Szolgáltatások',
+ 'Statement' => 'Kimutatás',
+ 'Stock Assembly' => 'Saját termék bevételezése',
+ 'Stylesheet' => 'Stíluslap',
+ 'System' => 'Törzsadatok',
+ 'Tax collected' => 'Fizetendõ ÁFA',
+ 'Tax paid' => 'Levonható ÁFA',
+ 'Transactions' => 'Tranzakciók',
+ 'Trial Balance' => 'Fõkönyvi kivonat',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendors' => 'Szállítók',
+ 'Version' => 'Verzió',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/oe b/sql-ledger/locale/hu/oe
new file mode 100644
index 0000000..c182bc6
--- /dev/null
+++ b/sql-ledger/locale/hu/oe
@@ -0,0 +1,202 @@
+$self{texts} = {
+ 'Add' => 'Új',
+ 'Add Purchase Order' => 'Új beszerzési rendelés',
+ 'Add Sales Invoice' => 'Új vevõszámla',
+ 'Add Sales Order' => 'Új vevõrendelés',
+ 'Add Vendor Invoice' => 'Add Vendor Invoice',
+ 'Address' => 'Cím',
+ 'Amount' => 'Összeg',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Are you sure you want to delete Order Number' => 'Biztos, hogy törölni akarja? Megrendelésszám:',
+ 'Attachment' => 'Csatolás',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'Bcc' => 'Titkos másolat',
+ 'Bin' => 'Bin',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'A rendelést nem lehet törölni!',
+ 'Cannot save order!' => 'A rendelést nem lehet elmenteni!',
+ 'Cc' => 'Másolat',
+ 'Closed' => 'Lezárt',
+ 'Confirm!' => 'Megerõsítés:',
+ 'Contact' => 'Kapcsolat',
+ 'Continue' => 'Folytatás',
+ 'Copies' => 'Másolatok',
+ 'Credit Limit' => 'Hitelkeret',
+ 'Curr' => 'Dev',
+ 'Currency' => 'Deviza',
+ 'Customer' => 'Vevõ',
+ 'Customer missing!' => 'Vevõ hiányzik!',
+ 'Customer not on file!' => 'A vevõ hiányzik az adatbázisból!',
+ 'Date' => 'Dátum',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Delete' => 'Törlés',
+ 'Delivery Date' => 'Szállítás dátuma',
+ 'Description' => 'Szöveges leírás',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mail cím hiányzik!',
+ 'Edit Purchase Order' => 'Beszerzési rendelés módosítása',
+ 'Edit Sales Order' => 'Vevõrendelés módosítása',
+ 'Exchangerate' => 'Átváltási árfolyam',
+ 'Exchangerate missing!' => 'Átváltási árfolyam hiányzik!',
+ 'Extended' => 'Összeg',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'From' => 'Mikortól:',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'ID' => 'Azonosító',
+ 'In-line' => 'Beágyazva',
+ 'Include in Report' => 'Oszlopok:',
+ 'Invoice' => 'Számla',
+ 'Invoice Date missing!' => 'Teljesítés dátuma hiányzik!',
+ 'Invoice Number missing!' => 'Számlaszám hiányzik!',
+ 'Item not on file!' => 'A tétel nincs az adatbázisban!',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Message' => 'Üzenet',
+ 'Name' => 'Név',
+ 'No.' => 'Sz.',
+ 'Notes' => 'Megjegyzés',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Number' => 'Szám',
+ 'Number missing in Row' => 'Ebbõl a sorból hiányzik a szám:',
+ 'O' => 'Ny.',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'Open' => 'Nyitott',
+ 'Order' => 'Rendelés',
+ 'Order Date' => 'Rendelés dátuma',
+ 'Order Date missing!' => 'Rendelés dátuma hiányzik!',
+ 'Order Number' => 'Rendelés száma',
+ 'Order Number missing!' => 'Rendelés száma hiányzik!',
+ 'Order deleted!' => 'Rendelés törölve!',
+ 'Order saved!' => 'Rendelés elmentve!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Szállítólevél',
+ 'Packing List Date missing!' => 'Szállítólevél dátuma hiányzik!',
+ 'Packing List Number missing!' => 'Szállítólevél száma hiányzik!',
+ 'Part' => 'Cikk',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Ár',
+ 'Print' => 'Nyomtatás',
+ 'Printer' => 'Nyomtató',
+ 'Project' => 'Munkaszám',
+ 'Project not on file!' => 'Munkaszám hiányzik az adatbázisból!',
+ 'Purchase Order' => 'Beszerzési rendelés',
+ 'Purchase Orders' => 'Beszerzési rendelések',
+ 'Qty' => 'Menny.',
+ 'Recd' => 'Kapott',
+ 'Remaining' => 'Maradék',
+ 'Required by' => 'Leszállítás',
+ 'Sales Order' => 'Vevõrendelés',
+ 'Sales Orders' => 'Vevõrendelések',
+ 'Save' => 'Mentés',
+ 'Save as new' => 'Mentés újként',
+ 'Screen' => 'Képernyõre',
+ 'Select from one of the items below' => 'Válasszon ki egyet az alábbi tételek közül',
+ 'Select from one of the names below' => 'Válasszon ki egyet az alábbi nevek közül',
+ 'Select from one of the projects below' => 'Válasszon ki egyet az alábbi munkaszámok közül',
+ 'Select postscript or PDF!' => 'Válassza ki a postscript vagy a PDF formátumot!',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Service' => 'Szolgáltatás',
+ 'Ship' => 'Szállítás',
+ 'Ship to' => 'Szállítási cím',
+ 'Ship via' => 'Szállítás innen:',
+ 'Subject' => 'Tárgy',
+ 'Subtotal' => 'Részösszeg',
+ 'Tax' => 'Adó',
+ 'Tax Included' => 'Adót tartalmazza',
+ 'Terms: Net' => 'Határidõ',
+ 'To' => 'Meddig:',
+ 'Total' => 'Végösszeg',
+ 'Unit' => 'Egység',
+ 'Update' => 'Frissítés',
+ 'Vendor' => 'Szállító',
+ 'Vendor missing!' => 'Szállító hiányzik!',
+ 'Vendor not on file!' => 'Szállító nincs az adatbázisban!',
+ 'What type of item is this?' => 'Ez milyen típusú tétel?',
+ 'Yes' => 'Igen',
+ 'days' => 'nap',
+ 'ea' => 'db',
+ 'emailed to' => 'e-mail küldve:',
+ 'sent to printer' => 'kinyomtatva',
+ 'to' => 'Meddig:',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'Új' => 'add',
+ 'folytatás' => 'continue',
+ 'törlés' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'számla' => 'invoice',
+ 'nyomtatás' => 'print',
+ 'mentés' => 'save',
+ 'mentés_újként' => 'save_as_new',
+ 'szállítási_cím' => 'ship_to',
+ 'frissítés' => 'update',
+ 'igen' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/pe b/sql-ledger/locale/hu/pe
new file mode 100644
index 0000000..1105848
--- /dev/null
+++ b/sql-ledger/locale/hu/pe
@@ -0,0 +1,45 @@
+$self{texts} = {
+ 'Add' => 'Új',
+ 'Add Group' => 'Add Group',
+ 'Add Project' => 'Új munkaszám',
+ 'All' => 'Összes',
+ 'Continue' => 'Folytatás',
+ 'Delete' => 'Törlés',
+ 'Description' => 'Szöveges leírás',
+ 'Edit Group' => 'Edit Group',
+ 'Edit Project' => 'Projekt módosítása',
+ 'Group' => 'Group',
+ 'Group deleted!' => 'Group deleted!',
+ 'Group missing!' => 'Group missing!',
+ 'Group saved!' => 'Group saved!',
+ 'Groups' => 'Groups',
+ 'Number' => 'Szám',
+ 'Orphaned' => 'Tranzakció nélküli',
+ 'Project' => 'Munkaszám',
+ 'Project Number missing!' => 'Munkaszám száma hiányzik!',
+ 'Project deleted!' => 'Munkaszám törölve!',
+ 'Project saved!' => 'Munkaszám elmentve!',
+ 'Projects' => 'Munkaszámok',
+ 'Save' => 'Mentés',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_partsgroup_footer' => 'form_partsgroup_footer',
+ 'form_partsgroup_header' => 'form_partsgroup_header',
+ 'form_project_footer' => 'form_project_footer',
+ 'form_project_header' => 'form_project_header',
+ 'partsgroup_report' => 'partsgroup_report',
+ 'project_report' => 'project_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'Új' => 'add',
+ 'folytatás' => 'continue',
+ 'törlés' => 'delete',
+ 'mentés' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/rc b/sql-ledger/locale/hu/rc
new file mode 100644
index 0000000..f9fc615
--- /dev/null
+++ b/sql-ledger/locale/hu/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Számla',
+ 'Balance' => 'Egyenleg',
+ 'Cleared Balance' => 'Egyeztetett egyenleg',
+ 'Continue' => 'Folytatás',
+ 'Date' => 'Dátum',
+ 'Deposit' => 'Betét',
+ 'Description' => 'Szöveges leírás',
+ 'Difference' => 'Eltérés',
+ 'Done' => 'Elvégezve',
+ 'Exchangerate Difference' => 'Árfolyamkülönbség',
+ 'From' => 'Mikortól:',
+ 'Out of balance!' => 'Az egyenleg nem stimmel!',
+ 'Payment' => 'Kifizetés',
+ 'Reconciliation' => 'Egyeztetés',
+ 'Select all' => 'Mindent kijelöl',
+ 'Source' => 'Bizonylatszám',
+ 'Statement Balance' => 'Kimutatás egyenlege',
+ 'Update' => 'Frissítés',
+ 'to' => 'Meddig:',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'folytatás' => 'continue',
+ 'elvégezve' => 'done',
+ 'mindent_kijelöl' => 'select_all',
+ 'frissítés' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/hu/rp b/sql-ledger/locale/hu/rp
new file mode 100644
index 0000000..3cdf7d4
--- /dev/null
+++ b/sql-ledger/locale/hu/rp
@@ -0,0 +1,119 @@
+$self{texts} = {
+ 'AP Aging' => 'Szállító lejárati lista',
+ 'AR Aging' => 'Vevõ lejárati lista',
+ 'Account' => 'Számla',
+ 'Accounts' => 'Számlák',
+ 'Amount' => 'Összeg',
+ 'Apr' => 'Ápr.',
+ 'April' => 'Április',
+ 'Attachment' => 'Csatolás',
+ 'Aug' => 'Aug.',
+ 'August' => 'Augusztus',
+ 'Balance' => 'Egyenleg',
+ 'Balance Sheet' => 'Mérleg',
+ 'Bcc' => 'Titkos másolat',
+ 'Cash based' => 'Pénzmozgás alapján',
+ 'Cc' => 'Másolat',
+ 'Compare to' => 'Összehasonlítva:',
+ 'Continue' => 'Folytatás',
+ 'Copies' => 'Másolatok',
+ 'Credit' => 'Követel',
+ 'Current' => 'Nem lejárt',
+ 'Customer' => 'Vevõ',
+ 'Date' => 'Dátum',
+ 'Debit' => 'Tartozik',
+ 'Dec' => 'Dec.',
+ 'December' => 'December',
+ 'Decimalplaces' => 'Tizedeshelyek',
+ 'Description' => 'Szöveges leírás',
+ 'Due' => 'Esedékes',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'Kimutatás küldése e-mail-ben:',
+ 'Feb' => 'Feb.',
+ 'February' => 'Február',
+ 'From' => 'Mikortól:',
+ 'GIFI' => 'Gyûjtõkód',
+ 'Heading' => 'Fejléc',
+ 'ID' => 'Azonosító',
+ 'In-line' => 'Beágyazva',
+ 'Include in Report' => 'Oszlopok:',
+ 'Income Statement' => 'Eredménykimutatás',
+ 'Invoice' => 'Számla',
+ 'Jan' => 'Jan.',
+ 'January' => 'Január',
+ 'Jul' => 'Júl.',
+ 'July' => 'Július',
+ 'Jun' => 'Jún.',
+ 'June' => 'Június',
+ 'Mar' => 'Márc.',
+ 'March' => 'Március',
+ 'May' => 'Máj.',
+ 'May ' => 'Május',
+ 'Message' => 'Üzenet',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Nincs semmi kiválasztva!',
+ 'Nov' => 'Nov.',
+ 'November' => 'November',
+ 'Oct' => 'Okt.',
+ 'October' => 'Október',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Kifizetések',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Nyomtatás',
+ 'Printer' => 'Nyomtató',
+ 'Project Number' => 'Munkaszám',
+ 'Receipts' => 'Bevételek',
+ 'Report for' => 'Jelentés:',
+ 'Retained Earnings' => 'Adózás elõtti eredmény',
+ 'Screen' => 'Képernyõre',
+ 'Select all' => 'Mindent kijelöl',
+ 'Select postscript or PDF!' => 'Válassza ki a postscript vagy a PDF formátumot!',
+ 'Sep' => 'Szept.',
+ 'September' => 'Szeptember',
+ 'Source' => 'Bizonylatszám',
+ 'Standard' => 'Sztenderd',
+ 'Statement' => 'Kimutatás',
+ 'Statement sent to' => 'Kimutatás elküldve:',
+ 'Statements sent to printer!' => 'Kimutatás kinyomtatva!',
+ 'Subject' => 'Tárgy',
+ 'Subtotal' => 'Részösszeg',
+ 'Tax' => 'Adó',
+ 'Tax collected' => 'Fizetendõ ÁFA',
+ 'Tax paid' => 'Levonható ÁFA',
+ 'Total' => 'Végösszeg',
+ 'Trial Balance' => 'Fõkönyvi kivonat',
+ 'Vendor' => 'Szállító',
+ 'as at' => 'Fordulónap:',
+ 'collected on sales' => 'vevõszámlák alapján',
+ 'for Period' => 'Idõszak:',
+ 'paid on purchases' => 'szállítószámlák alapján',
+ 'to' => 'Meddig:',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'folytatás' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'nyomtatás' => 'print',
+ 'mindent_kijelöl' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/is/COPYING b/sql-ledger/locale/is/COPYING
new file mode 100644
index 0000000..1992b50
--- /dev/null
+++ b/sql-ledger/locale/is/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2003
+#
+# Icelandic texts:
+#
+# Author: Margeir Reynisson <margeir@met.is>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/is/LANGUAGE b/sql-ledger/locale/is/LANGUAGE
new file mode 100644
index 0000000..b91caef
--- /dev/null
+++ b/sql-ledger/locale/is/LANGUAGE
@@ -0,0 +1 @@
+Icelandic
diff --git a/sql-ledger/locale/is/admin b/sql-ledger/locale/is/admin
new file mode 100644
index 0000000..ddf4c1a
--- /dev/null
+++ b/sql-ledger/locale/is/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Aðgangsheimildir',
+ 'Accounting' => 'Bókhald',
+ 'Add User' => 'Nýr notandi',
+ 'Address' => 'Heimilisfang',
+ 'Administration' => 'Kerfisstjórnun',
+ 'Administrator' => 'Kerfisstjóri',
+ 'All Datasets up to date!' => 'Öll gagnasöfn uppfærð',
+ 'Change Admin Password' => 'Breyta kerfisstjóra lykilorði',
+ 'Change Password' => 'Breyta lykilorði',
+ 'Character Set' => 'Stafaset',
+ 'Click on login name to edit!' => 'Smellið á notendanafn til þess að breyta',
+ 'Company' => 'Fyritæki',
+ 'Connect to' => 'Tengjast við',
+ 'Continue' => 'Áfram',
+ 'Create Chart of Accounts' => 'Búa til lykklasett',
+ 'Create Dataset' => 'Búa til gagnasafn',
+ 'DBI not installed!' => 'DBI ekki virkt',
+ 'Database' => 'Gagnagrunnur',
+ 'Database Administration' => 'Kerfisstjórn gagnagrunns',
+ 'Database Driver not checked!' => 'Gagnagrunnstengi ekki athugað',
+ 'Database User missing!' => 'Gagnagrunns notanda vantar!',
+ 'Dataset' => 'Gagnasafn',
+ 'Dataset missing!' => 'Gagnasafn vantar!',
+ 'Dataset updated!' => 'gagnasafn uppfært!',
+ 'Date Format' => 'Dagsetningarform',
+ 'Delete' => 'Eyða',
+ 'Delete Dataset' => 'Eyða gagnasafni',
+ 'Directory' => 'Mapa',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Takmörk fyrir valmynd',
+ 'E-mail' => 'R-póstur',
+ 'Edit User' => 'Breyta notanda',
+ 'Existing Datasets' => 'Hætta með gagnasafn',
+ 'Fax' => 'Símbréf',
+ 'Host' => 'Netþjónn',
+ 'Hostname missing!' => 'Nafn netþjóns vantar',
+ 'Incorrect Password!' => 'Rangt lykilorð',
+ 'Language' => 'Túngumál',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Setjið engar upplýsingar í netþjónn og port nema um sé að ræða annan netþjón.',
+ 'Login' => 'Tengjast',
+ 'Multibyte Encoding' => 'Multibyte Encoding',
+ 'Name' => 'Nafn',
+ 'New Templates' => 'Nýtt skabalón',
+ 'No Database Drivers available!' => 'Engin gagnagrunnstengin til',
+ 'No Dataset selected!' => 'Ekkert gagnasafn valið',
+ 'Nothing to delete!' => 'Ekkert til þess að eyða!',
+ 'Number Format' => 'Númera útlit',
+ 'Oracle Database Administration' => 'Oracle kerfisstjórnun á gagnagrunni',
+ 'Password' => 'Aðgangsorð',
+ 'Password changed!' => 'Aðgangsorði breytt',
+ 'Pg Database Administration' => 'Pg kerfisstjórnun gagnarunns',
+ 'Phone' => 'Sími.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port vantar',
+ 'Printer' => 'Prentari',
+ 'Save' => 'Geyma',
+ 'Select a Dataset to delete and press "Continue"' => 'Veljið gagnasafn og ýtið á "Áfram"',
+ 'Setup Templates' => 'Skabalón fyrir uppsetningu',
+ 'Ship via' => 'Senda með',
+ 'Signature' => 'Undirskrift',
+ 'Stylesheet' => 'Stílblað',
+ 'Templates' => 'Skabalón',
+ 'The following Datasets are not in use and can be deleted' => 'Eftirfarandi gagnasöfn eru ekki í notkunn og er því ekki hægt að eyða þeim',
+ 'The following Datasets need to be updated' => 'Eftirfarandi gagnasafn þarfnast uppfærslu',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Engu verður eytt eða breytt með þessu ',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Þú getur notað notanda sem til er til þess að útbúa nýjan notanda með þvi að breyta bara notendanafninu.',
+ 'Update Dataset' => 'Uppfæra gagnasafn',
+ 'Use Templates' => 'Nota skabalón',
+ 'User' => 'Notandi',
+ 'User deleted!' => 'Notanda eytt!',
+ 'User saved!' => 'Notandi geymdur!',
+ 'Version' => 'Útgáfa',
+ 'You must enter a host and port for local and remote connections!' => 'Þú verður að gefa upp netþjón of port til þess að geta tengst!',
+ 'does not exist' => 'er ekki til',
+ 'is already a member!' => 'er þegar meðlimur',
+ 'localhost' => 'lokal',
+ 'locked!' => 'læst',
+ 'successfully created!' => 'uppfært!',
+ 'successfully deleted!' => 'eytt!',
+ 'website' => 'á Internetinu',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'nýr_notandi' => 'add_user',
+ 'breyta_kerfisstjóra_lykilorði' => 'change_admin_password',
+ 'breyta_lykilorði' => 'change_password',
+ 'Áfram' => 'continue',
+ 'búa_til_gagnasafn' => 'create_dataset',
+ 'eyða' => 'delete',
+ 'eyða_gagnasafni' => 'delete_dataset',
+ 'tengjast' => 'login',
+ 'oracle_kerfisstjórnun_á_gagnagrunni' => 'oracle_database_administration',
+ 'pg_kerfisstjórnun_gagnarunns' => 'pg_database_administration',
+ 'geyma' => 'save',
+ 'uppfæra_gagnasafn' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/is/all b/sql-ledger/locale/is/all
new file mode 100644
index 0000000..4fc7b2d
--- /dev/null
+++ b/sql-ledger/locale/is/all
@@ -0,0 +1,496 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Innkaupakerfi',
+ 'AP Aging' => 'Aldursgreining',
+ 'AP Transaction' => 'Innkaupafærsla',
+ 'AP Transactions' => 'Innkaupafærslur',
+ 'AR' => 'Sölukerfi',
+ 'AR Aging' => 'Aldursgreining',
+ 'AR Transaction' => 'Sölufærsla',
+ 'AR Transactions' => 'Sölufærslur',
+ 'About' => 'Um',
+ 'Access Control' => 'Aðgangsheimildir',
+ 'Account' => 'Reikningur',
+ 'Account Number' => 'Reikningsnúmer',
+ 'Account Number missing!' => 'Reikningsnúmer vantar!',
+ 'Account Type' => 'Reikningstegund',
+ 'Account Type missing!' => 'Reikningstegund vantar!',
+ 'Account deleted!' => 'Reikningi eytt!',
+ 'Account saved!' => 'Reikningur geymdur!',
+ 'Accounting' => 'Bókhald',
+ 'Accounting Menu' => 'Bókhalds valmynd',
+ 'Accounts' => 'Reikningar',
+ 'Active' => 'Virkja',
+ 'Add' => 'Nýr',
+ 'Add Account' => 'Nýr reikningur',
+ 'Add Accounts Payables Transaction' => 'Ný kredit færsla',
+ 'Add Accounts Receivables Transaction' => 'Ný debit færsla',
+ 'Add Assembly' => 'Ný samsetning',
+ 'Add Customer' => 'Nýr viðskiptavinur',
+ 'Add GIFI' => 'Ný GIFI',
+ 'Add General Ledger Transaction' => 'Ný höfuðfærsla',
+ 'Add Part' => 'Ný vara',
+ 'Add Project' => 'Nýt verkefni',
+ 'Add Purchase Invoice' => 'Nýr innkaupsreikningur',
+ 'Add Purchase Order' => 'Ný innkaupspöntun',
+ 'Add Sales Invoice' => 'Nýr sölureikningur',
+ 'Add Sales Order' => 'Ný sölupöntun',
+ 'Add Service' => 'Ný þjónusta',
+ 'Add Transaction' => 'Ný bókhaldsfærsla',
+ 'Add User' => 'Nýr notandi',
+ 'Add Vendor' => 'Nýr byrgir',
+ 'Address' => 'Heimilisfang',
+ 'Administration' => 'Kerfisstjórnun',
+ 'Administrator' => 'Kerfisstjóri',
+ 'All' => 'Allt',
+ 'All Datasets up to date!' => 'Öll gagnasöfn uppfærð',
+ 'Amount' => 'Upphæð',
+ 'Amount Due' => 'Eindagi',
+ 'Amount does not equal applied!' => 'Upphæð stemmir ekki!',
+ 'Amount missing!' => 'Reikning vantar!',
+ 'Applied' => 'Uppfært',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Are you sure you want to delete Invoice Number' => 'Ert þú viss um að þú viljir eyða reikningi númer',
+ 'Are you sure you want to delete Order Number' => 'Ert þú viss um að þú viljir eyða pöntun númer',
+ 'Are you sure you want to delete Transaction' => 'Ert þú viss um að þú viljir eyða færslunni',
+ 'Assemblies' => 'Samsetningar',
+ 'Assemblies restocked!' => 'Samsetningar endurunnar',
+ 'Assembly Number missing!' => 'Samsetningar númer vantar',
+ 'Asset' => 'Eignir',
+ 'Attachment' => 'Hjálagt',
+ 'Audit Control' => 'Yfirlit stjórnun',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'BOM' => 'BOM',
+ 'Backup' => 'Afrit',
+ 'Backup sent to' => 'Afrit sendist til',
+ 'Balance' => 'Afstemming',
+ 'Balance Sheet' => 'Staða',
+ 'Bcc' => 'Blint afrit',
+ 'Bin' => 'Vörulager',
+ 'Books are open' => 'Bókhald er opið fyrir leiðréttingar',
+ 'Bought' => 'Keypt',
+ 'Business Number' => 'Viðskiptanúmer',
+ 'C' => 'C',
+ 'COGS' => 'Innkaup',
+ 'Cannot delete account!' => 'Get ekki eytt reikningi!',
+ 'Cannot delete customer!' => 'Get ekki eytt viðskiptavini!',
+ 'Cannot delete default account!' => 'Get ekki eytt grunnreikningi!',
+ 'Cannot delete invoice!' => 'Get ekki eytt sölureikningi!',
+ 'Cannot delete item already invoiced!' => 'Get ekki eytt hlut sem þegar er til á sölureikningi!',
+ 'Cannot delete item on order!' => 'Get ekki eytt hlut sem er í pöntun!',
+ 'Cannot delete item which is part of an assembly!' => 'Get ekki eytt hlut sem er partur af samsetningu!',
+ 'Cannot delete item!' => 'Get ekki eytt hlut!',
+ 'Cannot delete order!' => 'Get ekki eytt pöntun!',
+ 'Cannot delete transaction!' => 'Get ekki eytt færslu!',
+ 'Cannot delete vendor!' => 'Get ekki eytt framleiðanda!',
+ 'Cannot have a value in both Debit and Credit!' => 'Get ekki haft gildi bæði í debit og kredit!',
+ 'Cannot post a transaction without a value!' => 'Get ekki bókað án upphæðar',
+ 'Cannot post invoice for a closed period!' => 'Get ekki bókað á lokað tímabil!',
+ 'Cannot post invoice!' => 'Get ekki bókað sölureikning!',
+ 'Cannot post payment for a closed period!' => 'Get ekki bókað greiðslu á lokað tímabil',
+ 'Cannot post payment!' => 'Get ekki bókað greiðslu',
+ 'Cannot post transaction for a closed period!' => 'Get ekki bókað færslu á lokað tímabil!',
+ 'Cannot post transaction!' => 'Get ekki bókað færslu!',
+ 'Cannot process payment for a closed period!' => 'Get ekki meðhöndlað greiðslu fyrir lokað tímabil!',
+ 'Cannot save account!' => 'Get ekki geymt reikning!',
+ 'Cannot save order!' => 'Get ekki geymt pöntun!',
+ 'Cannot save preferences!' => 'Get ekki geymt uppsetningu!',
+ 'Cannot stock assemblies!' => 'Get ekki fært samsetningar',
+ 'Cash' => 'Reiðufé',
+ 'Cash based' => 'Reiðufétengt',
+ 'Cc' => 'Afrit',
+ 'Change Admin Password' => 'Breyta kerfisstjóra lykilorði',
+ 'Change Password' => 'Breyta lykilorði',
+ 'Character Set' => 'Stafaset',
+ 'Chart of Accounts' => 'Listi yfir lykkla/reikninga',
+ 'Check' => 'Ávísun',
+ 'Check printed!' => 'Ávísun prentuð',
+ 'Check printing failed!' => 'Villa við prentun á ávísun',
+ 'Cleared Balance' => 'Hreynsað jafvægi',
+ 'Click on login name to edit!' => 'Smellið á notendanafn til þess að breyta',
+ 'Close Books up to' => 'Loka bókhaldi til dags',
+ 'Closed' => 'Lokað',
+ 'Company' => 'Fyritæki',
+ 'Compare to' => 'Bera saman við',
+ 'Confirm!' => 'Staðfesta!',
+ 'Connect to' => 'Tengjast við',
+ 'Contact' => 'Talsmaður',
+ 'Continue' => 'Áfram',
+ 'Copies' => 'Afrit',
+ 'Copy to COA' => 'Afrita í COA',
+ 'Create Chart of Accounts' => 'Búa til lykklasett',
+ 'Create Dataset' => 'Búa til gagnasafn',
+ 'Credit' => 'Kredit',
+ 'Credit Limit' => 'Kreditmörk',
+ 'Curr' => 'Gjaldm',
+ 'Currency' => 'Gjaldmiðill',
+ 'Current' => 'Núvirði',
+ 'Customer' => 'Viðskiptavinur',
+ 'Customer deleted!' => 'Viðskiptavini eytt!',
+ 'Customer missing!' => 'Viðskiptavin vantar!',
+ 'Customer not on file!' => 'Viðskiptavinur ekki á skrá!',
+ 'Customer saved!' => 'Viðskiptavinur geymdur!',
+ 'Customers' => 'Viðskiptavinir',
+ 'DBI not installed!' => 'DBI ekki virkt',
+ 'Database' => 'Gagnagrunnur',
+ 'Database Administration' => 'Kerfisstjórn gagnagrunns',
+ 'Database Driver not checked!' => 'Gagnagrunnstengi ekki athugað',
+ 'Database Host' => 'Gagnagrunns-netþjónn',
+ 'Database User missing!' => 'Gagnagrunns notanda vantar!',
+ 'Dataset' => 'Gagnasafn',
+ 'Dataset missing!' => 'Gagnasafn vantar!',
+ 'Dataset updated!' => 'gagnasafn uppfært!',
+ 'Date' => 'Dagsetning',
+ 'Date Due' => 'Eindagi',
+ 'Date Format' => 'Dagsetningarform',
+ 'Date Paid' => 'Greiðsludagur',
+ 'Date missing!' => 'Dagsetningu vantar!',
+ 'Debit' => 'Debit',
+ 'Debit and credit out of balance!' => 'Debit og kredit skulu vera eins!',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Decimalplaces' => 'Aukastafir',
+ 'Delete' => 'Eyða',
+ 'Delete Account' => 'Eyða reikningi',
+ 'Delete Dataset' => 'Eyða gagnasafni',
+ 'Delivery Date' => 'Afgreiðsludags.',
+ 'Department' => '',
+ 'Deposit' => 'Innlagt',
+ 'Description' => 'Skýringar',
+ 'Difference' => 'Mismunur',
+ 'Directory' => 'Mapa',
+ 'Discount' => 'Afsláttur',
+ 'Done' => 'Búið',
+ 'Drawing' => 'Dregið',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Takmörk fyrir valmynd',
+ 'Due' => 'Lokið',
+ 'Due Date' => 'Dags. lokið',
+ 'Due Date missing!' => 'Vantar dags. lokið!',
+ 'E-mail' => 'R-póstur',
+ 'E-mail Statement to' => 'Senda yfirlit til',
+ 'E-mail address missing!' => 'R-póst vantar!',
+ 'Edit' => 'Breyta',
+ 'Edit Account' => 'Breyta reikningi',
+ 'Edit Accounts Payables Transaction' => 'Breyta greiðslufærslum',
+ 'Edit Accounts Receivables Transaction' => 'Breyta inn-færslum',
+ 'Edit Assembly' => 'Breyta samsetningu',
+ 'Edit Customer' => 'Breyta viðskiptavini',
+ 'Edit GIFI' => 'Breyta GIFI',
+ 'Edit General Ledger Transaction' => 'Breyta yfitbókunar færslum',
+ 'Edit Part' => 'Breyta vöru',
+ 'Edit Preferences for' => 'Breyta uppsetningu fyrir',
+ 'Edit Project' => 'Breyta verkefni',
+ 'Edit Purchase Invoice' => 'Breyta innkaupareikningi',
+ 'Edit Purchase Order' => 'Breyta innkaupapöntun',
+ 'Edit Sales Invoice' => 'Breyta sölureikningi',
+ 'Edit Sales Order' => 'Breyta sölupöntun',
+ 'Edit Service' => 'Breyta þjónustu',
+ 'Edit Template' => 'Breyta skabalóni',
+ 'Edit User' => 'Breyta notanda',
+ 'Edit Vendor' => 'Breyta byrgja',
+ 'Employee' => 'Starfsmenn',
+ 'Enforce transaction reversal for all dates' => 'Gennemtving explicitte rettelser af posteringer for alle datoer',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Vinsamlega sláið inn 3 stafa nafn á gjaldeyri sem á að nota setji tvípúnkt á milli.',
+ 'Equity' => 'Eigiðfé',
+ 'Exch' => 'Vx',
+ 'Exchangerate' => 'Vextir',
+ 'Exchangerate Difference' => 'Vaxtamunur',
+ 'Exchangerate for payment missing!' => 'Vextir fyrir greiðslu vantar!',
+ 'Exchangerate missing!' => 'Vantar vexti!',
+ 'Existing Datasets' => 'Hætta með gagnasafn',
+ 'Expense' => 'Kostnaður',
+ 'Expense Account' => 'Kostnaðarreikningur',
+ 'Expense/Asset' => 'Kostnaður/Eignir',
+ 'Extended' => 'Framlengt',
+ 'Fax' => 'Símbréf',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'Foreign Exchange Gain' => 'Gengishagnaður',
+ 'Foreign Exchange Loss' => 'Gengistap',
+ 'From' => 'Frá',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI eytt!',
+ 'GIFI missing!' => 'GIFI vantar!',
+ 'GIFI saved!' => 'GIFI geymt!',
+ 'GL Transaction' => 'Færslur í aðalbók',
+ 'General Ledger' => 'Aðalbók',
+ 'Goods & Services' => 'Vörur og þjónusta',
+ 'HTML Templates' => 'HTML-skabalón',
+ 'Heading' => 'Yfirskriftir',
+ 'Host' => 'Netþjónn',
+ 'Hostname missing!' => 'Nafn netþjóns vantar',
+ 'ID' => 'ID',
+ 'Image' => 'Mynd',
+ 'In-line' => 'Inndregið',
+ 'Include in Report' => 'Innifela í skýrslu',
+ 'Include in drop-down menus' => 'Innifela í fellivalmynd',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Innifela þennan lykil hjá viðskiptavinum til þess að geta gert hann vask skildan',
+ 'Income' => 'Innkoma',
+ 'Income Account' => 'Inn reikningur',
+ 'Income Statement' => 'Inn yfirlýsing',
+ 'Incorrect Dataset version!' => 'Röng útgáfa af gagnasfni!',
+ 'Incorrect Password!' => 'Rangt lykilorð',
+ 'Individual Items' => 'Sjálfstæðir hlutir',
+ 'Inventory' => 'Lager',
+ 'Inventory Account' => 'Lagerlykill',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Lagerbeholdning skal være nul for at du kan forælde denne sammensætning',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Lagerbeholdning skal være nul for at du kan forælde denne enhed',
+ 'Inventory quantity must be zero!' => 'Lagerbeholdning skal være nul',
+ 'Invoice' => 'Sölureikningur',
+ 'Invoice Date' => 'Sölureikningur dags.',
+ 'Invoice Date missing!' => 'Sölureiknings dags. vantar!',
+ 'Invoice Number' => 'Sölureikningur Númer',
+ 'Invoice Number missing!' => 'Sölureikningsnúmer vantar!',
+ 'Invoice deleted!' => 'Sölureikningi eytt!',
+ 'Invoice posted!' => 'Sölureikningur bókfærður!',
+ 'Invoices' => 'Sölureikningar',
+ 'Is this a summary account to record' => 'Söfnunarreikningur fyrir',
+ 'Item deleted!' => 'Hlut eytt!',
+ 'Item not on file!' => 'Hlutur ekki á skrá!',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'LaTeX Templates' => 'LaTeX-skabalón',
+ 'Language' => 'Túngumál',
+ 'Last Cost' => 'Síðasta verð',
+ 'Last Invoice Number' => 'Síðasta sölureiknings númer',
+ 'Last Numbers & Default Accounts' => 'Síðasta númer og sjálfgefin reikningur',
+ 'Last Purchase Order Number' => 'Síðasta innkaupa pöntunar númer´',
+ 'Last Sales Order Number' => 'Síðasta sölupöntunar númer',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Setjið engar upplýsingar í netþjónn og port nema um sé að ræða annan netþjón.',
+ 'Liability' => 'Passiv',
+ 'Licensed to' => 'Skráð á',
+ 'Line Total' => 'Samtals línur',
+ 'Link' => 'Tenglar',
+ 'Link Accounts' => 'Tengja lykla',
+ 'List Accounts' => 'Sýna lykla',
+ 'List GIFI' => 'Sýna GIFI',
+ 'List Price' => 'Sýna verð',
+ 'List Transactions' => 'Sýna færslur',
+ 'Login' => 'Tengjast',
+ 'Logout' => 'Aftengjast',
+ 'Make' => 'Tegund',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Message' => 'Skilaboð',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Model',
+ 'Multibyte Encoding' => '',
+ 'N/A' => '',
+ 'Name' => 'Nafn',
+ 'Name missing!' => 'Nafn vantar!',
+ 'New Templates' => 'Nýtt skabalón',
+ 'No' => 'Nei',
+ 'No Database Drivers available!' => 'Engin gagnagrunnstengin til',
+ 'No Dataset selected!' => 'Ekkert gagnasafn valið',
+ 'No email address for' => 'Ekkert netfang fyrir',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Upplýsinar',
+ 'Nothing applied!' => 'Ekkert bókað!',
+ 'Nothing selected!' => 'Ekkert valið!',
+ 'Nothing to delete!' => 'Ekkert til þess að eyða!',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Number' => 'Númer',
+ 'Number Format' => 'Númera útlit',
+ 'Number missing in Row' => 'Tölu vantar í röð',
+ 'O' => 'O',
+ 'Obsolete' => 'Úrelt',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'On Hand' => 'Á lager',
+ 'On Order' => 'Í pöntun',
+ 'Open' => 'opna',
+ 'Oracle Database Administration' => 'Oracle kerfisstjórnun á gagnagrunni',
+ 'Order' => 'Pöntun',
+ 'Order Date' => 'Pöntunar dags.',
+ 'Order Date missing!' => 'Pöntunar dags. vantar',
+ 'Order Entry' => 'Pöntunarblað',
+ 'Order Number' => 'Pöntun númer',
+ 'Order Number missing!' => 'Númer pöntunar vantar',
+ 'Order deleted!' => 'Pöntun eytt',
+ 'Order saved!' => 'Pöntun geymd',
+ 'Ordered' => 'pantað',
+ 'Orphaned' => 'Sjáfstætt',
+ 'Out of balance!' => 'Ekki jafnvægi!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Fylgiseðill',
+ 'Packing List Date missing!' => 'Dags. fylgiseðils vantar!',
+ 'Packing List Number missing!' => 'Númer fylgiseðils vantar!',
+ 'Paid' => 'Greitt',
+ 'Paid in full' => 'Greitt að fullu',
+ 'Part' => 'Vara',
+ 'Part Number missing!' => 'Vörunúmer vantar!',
+ 'Parts' => 'Vörur',
+ 'Parts Inventory' => 'Vörulisti',
+ 'Password' => 'Aðgangsorð',
+ 'Password changed!' => 'Aðgangsorði breytt',
+ 'Payables' => 'Útistandandi',
+ 'Payment' => 'Greislur',
+ 'Payment date missing!' => 'Greiðsudags. vantar!',
+ 'Payment posted!' => 'Greiðsla bókuð',
+ 'Payments' => 'Greiðslur',
+ 'Pg Database Administration' => 'Pg kerfisstjórnun gagnarunns',
+ 'Phone' => 'Sími.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port vantar',
+ 'Post' => 'Bókfæra',
+ 'Post as new' => 'Bókfæra sem nýjan',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Uppsetningar',
+ 'Preferences saved!' => 'Uppsetningar geymdar!',
+ 'Price' => 'Verð',
+ 'Print' => 'Prenta',
+ 'Printer' => 'Prentari',
+ 'Project' => 'Verkefni',
+ 'Project Number' => '',
+ 'Project Number missing!' => 'Verkefnisnúmer vantar!',
+ 'Project deleted!' => 'Verkefni eytt!',
+ 'Project not on file!' => 'Verkefni ekki á skrá!',
+ 'Project saved!' => 'verkefni geymt!',
+ 'Projects' => 'Verkefni',
+ 'Purchase Invoice' => 'Innkaupsreikningur',
+ 'Purchase Order' => 'Innkaupspöntun',
+ 'Purchase Orders' => 'Innkaupspantanir',
+ 'Qty' => 'Magn',
+ 'ROP' => '',
+ 'Rate' => 'Taxti',
+ 'Recd' => 'Mótt:',
+ 'Receipt' => 'Kvittun',
+ 'Receipt printed!' => '',
+ 'Receipt printing failed!' => '',
+ 'Receipts' => 'Kvittanir',
+ 'Receivables' => 'Innborganir',
+ 'Reconciliation' => 'Afstemingar',
+ 'Record in' => 'Bóka á',
+ 'Reference' => 'Fylgiskjal',
+ 'Reference missing!' => 'Fylgiskjal vantar',
+ 'Remaining' => 'Eftir',
+ 'Report for' => 'Skýrsla fyrir',
+ 'Reports' => 'Skýrslur',
+ 'Required by' => 'Pantað af',
+ 'Retained Earnings' => 'Realiseret overskud',
+ 'Sales' => 'Sala',
+ 'Sales Invoice' => 'Sölureikningur',
+ 'Sales Order' => 'Sölupöntun',
+ 'Sales Orders' => 'Sölupantanir',
+ 'Salesperson' => '',
+ 'Save' => 'Geyma',
+ 'Save as new' => 'Geyma sem nýtt',
+ 'Save to File' => 'Geyma í skrá',
+ 'Screen' => 'Skjá',
+ 'Select a Dataset to delete and press "Continue"' => 'Veljið gagnasafn og ýtið á "Áfram"',
+ 'Select all' => 'Velja allt',
+ 'Select from one of the items below' => 'Veljið einhver að neðangreindum hlutum, og ýtið á "Áfram"',
+ 'Select from one of the names below' => 'Veljið einhvað að neðangreindum nöfnum',
+ 'Select from one of the projects below' => 'Veljið einhvað að neðangreindum verkefnum',
+ 'Select postscript or PDF!' => 'Veljið postscript eða PDF',
+ 'Sell Price' => 'Söluverð',
+ 'Send by E-Mail' => 'Senda með rafpósti',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Þjónusta',
+ 'Service Items' => 'Þjónustu hlutur',
+ 'Service Number missing!' => 'Þjónustunúmer vantar!',
+ 'Services' => 'Þjónustur',
+ 'Setup Templates' => 'Skabalón fyrir uppsetningu',
+ 'Ship' => 'Senda',
+ 'Ship to' => 'Senda til',
+ 'Ship via' => 'Senda með',
+ 'Short' => 'Stutt',
+ 'Signature' => 'Undirskrift',
+ 'Sold' => 'Selt',
+ 'Source' => 'Frálag',
+ 'Standard' => 'Standart',
+ 'Statement' => 'Uppgjör',
+ 'Statement Balance' => 'jöfnunaruppgjör',
+ 'Statement sent to' => 'Uppgjör sendist til',
+ 'Statements sent to printer!' => 'Uppgjör sendist á prentara',
+ 'Stock Assembly' => 'Lager samsetning',
+ 'Stylesheet' => 'Stílblað',
+ 'Subject' => 'Efni',
+ 'Subtotal' => 'Samtala',
+ 'System' => 'Kerfi',
+ 'Tax' => 'Virðisaukaskattur',
+ 'Tax Accounts' => 'VSK lykill',
+ 'Tax Included' => 'Taka með VSK',
+ 'Tax collected' => 'VSK samtals',
+ 'Tax paid' => 'VSK greitt',
+ 'Taxable' => 'Skatskildur',
+ 'Template saved!' => 'Skabalón geymt!',
+ 'Templates' => 'Skabalón',
+ 'Terms: Net' => 'Nettó',
+ 'The following Datasets are not in use and can be deleted' => 'Eftirfarandi gagnasöfn eru ekki í notkunn og er því ekki hægt að eyða þeim',
+ 'The following Datasets need to be updated' => 'Eftirfarandi gagnasafn þarfnast uppfærslu',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Engu verður eytt eða breytt með þessu ',
+ 'To' => 'til',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Þú getur notað notanda sem til er til þess að útbúa nýjan notanda með þvi að breyta bara notendanafninu.',
+ 'Top Level' => 'Efsta þrep',
+ 'Total' => 'Samtals',
+ 'Transaction Date missing!' => 'Dags. vantar!',
+ 'Transaction deleted!' => 'Færslu eytt!',
+ 'Transaction posted!' => 'Færsla bókfærð!',
+ 'Transaction reversal enforced for all dates' => 'Rettelser af posteringer skal altid bogføres explicit',
+ 'Transaction reversal enforced up to' => 'Rettelser af posteringer skal bogføres explicit indtil',
+ 'Transactions' => 'Færslur',
+ 'Transactions exist, cannot delete customer!' => 'Ekki er hægt að eyða viðskipamanni með færslur!',
+ 'Transactions exist, cannot delete vendor!' => 'Ekki er hægt að eyða byrgja með færslur!',
+ 'Transactions exist; cannot delete account!' => 'Ekki hægt að eyða reikningi með færslur!',
+ 'Trial Balance' => 'Prufu staða',
+ 'Unit' => 'Einingar',
+ 'Unit of measure' => 'Mælieining',
+ 'Update' => 'Uppfærsla',
+ 'Update Dataset' => 'Uppfæra gagnasafn',
+ 'Updated' => 'Uppfæra',
+ 'Use Templates' => 'Nota skabalón',
+ 'User' => 'Notandi',
+ 'User deleted!' => 'Notanda eytt!',
+ 'User saved!' => 'Notandi geymdur!',
+ 'Vendor' => 'Byrgir',
+ 'Vendor deleted!' => 'Byrgja eytt!',
+ 'Vendor missing!' => 'Byrgja vantar!',
+ 'Vendor not on file!' => 'Byrgir ekki til í gagnagrunni!',
+ 'Vendor saved!' => 'Byrgir geymdur!',
+ 'Vendors' => 'Byrgjar',
+ 'Version' => 'Útgáfa',
+ 'Weight' => 'Vigt',
+ 'Weight Unit' => 'Vigtareining',
+ 'What type of item is this?' => 'Hvernig hlutur er þetta?',
+ 'Year End' => 'Ársuppgjör',
+ 'Yes' => 'Já',
+ 'You are logged out!' => 'Þú ert loggaður út',
+ 'You did not enter a name!' => 'Þú gafst ekki upp nafn',
+ 'You must enter a host and port for local and remote connections!' => 'Þú verður að gefa upp netþjón of port til þess að geta tengst!',
+ 'as at' => 'líkt og með',
+ 'collected on sales' => 'samanlagt við sölu',
+ 'days' => 'dagar',
+ 'does not exist' => 'er ekki til',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendist með rafpósti',
+ 'for Period' => 'fyrir tímabilið',
+ 'hr' => 'tími',
+ 'is already a member!' => 'er þegar meðlimur',
+ 'is not a member!' => 'er ekki meðlimur!',
+ 'localhost' => 'lokal',
+ 'locked!' => 'læst',
+ 'paid on purchases' => 'greitt við innkaup',
+ 'sent to printer' => 'sendist á prentara',
+ 'successfully created!' => 'uppfært!',
+ 'successfully deleted!' => 'eytt!',
+ 'to' => 'til',
+ 'website' => 'á Internetinu',
+};
+
+1;
diff --git a/sql-ledger/locale/is/am b/sql-ledger/locale/is/am
new file mode 100644
index 0000000..e8d66bf
--- /dev/null
+++ b/sql-ledger/locale/is/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Innkaupakerfi',
+ 'AR' => 'Sölukerfi',
+ 'Account' => 'Reikningur',
+ 'Account Number' => 'Reikningsnúmer',
+ 'Account Number missing!' => 'Reikningsnúmer vantar!',
+ 'Account Type' => 'Reikningstegund',
+ 'Account Type missing!' => 'Reikningstegund vantar!',
+ 'Account deleted!' => 'Reikningi eytt!',
+ 'Account saved!' => 'Reikningur geymdur!',
+ 'Add Account' => 'Nýr reikningur',
+ 'Add GIFI' => 'Ný GIFI',
+ 'Address' => 'Heimilisfang',
+ 'Asset' => 'Eignir',
+ 'Audit Control' => 'Yfirlit stjórnun',
+ 'Backup sent to' => 'Afrit sendist til',
+ 'Books are open' => 'Bókhald er opið fyrir leiðréttingar',
+ 'Business Number' => 'Viðskiptanúmer',
+ 'COGS' => 'Innkaup',
+ 'Cannot delete account!' => 'Get ekki eytt reikningi!',
+ 'Cannot delete default account!' => 'Get ekki eytt grunnreikningi!',
+ 'Cannot save account!' => 'Get ekki geymt reikning!',
+ 'Cannot save preferences!' => 'Get ekki geymt uppsetningu!',
+ 'Character Set' => 'Stafaset',
+ 'Chart of Accounts' => 'Listi yfir lykkla/reikninga',
+ 'Close Books up to' => 'Loka bókhaldi til dags',
+ 'Company' => 'Fyritæki',
+ 'Continue' => 'Áfram',
+ 'Copy to COA' => 'Afrita í COA',
+ 'Credit' => 'Kredit',
+ 'Date Format' => 'Dagsetningarform',
+ 'Debit' => 'Debit',
+ 'Delete' => 'Eyða',
+ 'Delete Account' => 'Eyða reikningi',
+ 'Description' => 'Skýringar',
+ 'Dropdown Limit' => 'Takmörk fyrir valmynd',
+ 'E-mail' => 'R-póstur',
+ 'Edit' => 'Breyta',
+ 'Edit Account' => 'Breyta reikningi',
+ 'Edit GIFI' => 'Breyta GIFI',
+ 'Edit Preferences for' => 'Breyta uppsetningu fyrir',
+ 'Edit Template' => 'Breyta skabalóni',
+ 'Enforce transaction reversal for all dates' => 'Gennemtving explicitte rettelser af posteringer for alle datoer',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Vinsamlega sláið inn 3 stafa nafn á gjaldeyri sem á að nota setji tvípúnkt á milli.',
+ 'Equity' => 'Eigiðfé',
+ 'Expense' => 'Kostnaður',
+ 'Expense Account' => 'Kostnaðarreikningur',
+ 'Expense/Asset' => 'Kostnaður/Eignir',
+ 'Fax' => 'Símbréf',
+ 'Foreign Exchange Gain' => 'Gengishagnaður',
+ 'Foreign Exchange Loss' => 'Gengistap',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI eytt!',
+ 'GIFI missing!' => 'GIFI vantar!',
+ 'GIFI saved!' => 'GIFI geymt!',
+ 'Heading' => 'Yfirskriftir',
+ 'Include in drop-down menus' => 'Innifela í fellivalmynd',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Innifela þennan lykil hjá viðskiptavinum til þess að geta gert hann vask skildan',
+ 'Income' => 'Innkoma',
+ 'Income Account' => 'Inn reikningur',
+ 'Inventory' => 'Lager',
+ 'Inventory Account' => 'Lagerlykill',
+ 'Is this a summary account to record' => 'Söfnunarreikningur fyrir',
+ 'Language' => 'Túngumál',
+ 'Last Invoice Number' => 'Síðasta sölureiknings númer',
+ 'Last Numbers & Default Accounts' => 'Síðasta númer og sjálfgefin reikningur',
+ 'Last Purchase Order Number' => 'Síðasta innkaupa pöntunar númer´',
+ 'Last Sales Order Number' => 'Síðasta sölupöntunar númer',
+ 'Liability' => 'Passiv',
+ 'Link' => 'Tenglar',
+ 'Name' => 'Nafn',
+ 'No' => 'Nei',
+ 'No email address for' => 'Ekkert netfang fyrir',
+ 'Number' => 'Númer',
+ 'Number Format' => 'Númera útlit',
+ 'Parts Inventory' => 'Vörulisti',
+ 'Password' => 'Aðgangsorð',
+ 'Payables' => 'Útistandandi',
+ 'Payment' => 'Greislur',
+ 'Phone' => 'Sími.',
+ 'Preferences saved!' => 'Uppsetningar geymdar!',
+ 'Rate' => 'Taxti',
+ 'Receivables' => 'Innborganir',
+ 'Sales' => 'Sala',
+ 'Save' => 'Geyma',
+ 'Service Items' => 'Þjónustu hlutur',
+ 'Ship via' => 'Senda með',
+ 'Signature' => 'Undirskrift',
+ 'Stylesheet' => 'Stílblað',
+ 'Tax' => 'Virðisaukaskattur',
+ 'Tax Accounts' => 'VSK lykill',
+ 'Template saved!' => 'Skabalón geymt!',
+ 'Transaction reversal enforced for all dates' => 'Rettelser af posteringer skal altid bogføres explicit',
+ 'Transaction reversal enforced up to' => 'Rettelser af posteringer skal bogføres explicit indtil',
+ 'Transactions exist; cannot delete account!' => 'Ekki hægt að eyða reikningi með færslur!',
+ 'Weight Unit' => 'Vigtareining',
+ 'Year End' => 'Ársuppgjör',
+ 'Yes' => 'Já',
+ 'does not exist' => 'er ekki til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'nýr_reikningur' => 'add_account',
+ 'Áfram' => 'continue',
+ 'afrita_í_coa' => 'copy_to_coa',
+ 'eyða' => 'delete',
+ 'breyta' => 'edit',
+ 'breyta_reikningi' => 'edit_account',
+ 'geyma' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/is/ap b/sql-ledger/locale/is/ap
new file mode 100644
index 0000000..ea4afb2
--- /dev/null
+++ b/sql-ledger/locale/is/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Innkaupafærsla',
+ 'AP Transactions' => 'Innkaupafærslur',
+ 'Account' => 'Reikningur',
+ 'Add Accounts Payables Transaction' => 'Ný kredit færsla',
+ 'Address' => 'Heimilisfang',
+ 'Amount' => 'Upphæð',
+ 'Amount Due' => 'Eindagi',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Are you sure you want to delete Transaction' => 'Ert þú viss um að þú viljir eyða færslunni',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'Cannot delete transaction!' => 'Get ekki eytt færslu!',
+ 'Cannot post payment for a closed period!' => 'Get ekki bókað greiðslu á lokað tímabil',
+ 'Cannot post transaction for a closed period!' => 'Get ekki bókað færslu á lokað tímabil!',
+ 'Cannot post transaction!' => 'Get ekki bókað færslu!',
+ 'Closed' => 'Lokað',
+ 'Confirm!' => 'Staðfesta!',
+ 'Continue' => 'Áfram',
+ 'Currency' => 'Gjaldmiðill',
+ 'Customer not on file!' => 'Viðskiptavinur ekki á skrá!',
+ 'Date' => 'Dagsetning',
+ 'Date Paid' => 'Greiðsludagur',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Eyða',
+ 'Description' => 'Skýringar',
+ 'Due Date' => 'Dags. lokið',
+ 'Due Date missing!' => 'Vantar dags. lokið!',
+ 'Edit Accounts Payables Transaction' => 'Breyta greiðslufærslum',
+ 'Employee' => 'Starfsmenn',
+ 'Exch' => 'Vx',
+ 'Exchangerate' => 'Vextir',
+ 'Exchangerate for payment missing!' => 'Vextir fyrir greiðslu vantar!',
+ 'Exchangerate missing!' => 'Vantar vexti!',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'From' => 'Frá',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Innifela í skýrslu',
+ 'Invoice' => 'Sölureikningur',
+ 'Invoice Date' => 'Sölureikningur dags.',
+ 'Invoice Date missing!' => 'Sölureiknings dags. vantar!',
+ 'Invoice Number' => 'Sölureikningur Númer',
+ 'Invoice Number missing!' => 'Sölureikningsnúmer vantar!',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Notes' => 'Upplýsinar',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Number' => 'Númer',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'Open' => 'opna',
+ 'Order' => 'Pöntun',
+ 'Order Number' => 'Pöntun númer',
+ 'Paid' => 'Greitt',
+ 'Payment date missing!' => 'Greiðsudags. vantar!',
+ 'Payments' => 'Greiðslur',
+ 'Post' => 'Bókfæra',
+ 'Post as new' => 'Bókfæra sem nýjan',
+ 'Project' => 'Verkefni',
+ 'Project not on file!' => 'Verkefni ekki á skrá!',
+ 'Purchase Invoice' => 'Innkaupsreikningur',
+ 'Select from one of the names below' => 'Veljið einhvað að neðangreindum nöfnum',
+ 'Select from one of the projects below' => 'Veljið einhvað að neðangreindum verkefnum',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Frálag',
+ 'Subtotal' => 'Samtala',
+ 'Tax' => 'Virðisaukaskattur',
+ 'Tax Included' => 'Taka með VSK',
+ 'Total' => 'Samtals',
+ 'Transaction deleted!' => 'Færslu eytt!',
+ 'Transaction posted!' => 'Færsla bókfærð!',
+ 'Update' => 'Uppfærsla',
+ 'Vendor' => 'Byrgir',
+ 'Vendor missing!' => 'Byrgja vantar!',
+ 'Vendor not on file!' => 'Byrgir ekki til í gagnagrunni!',
+ 'Yes' => 'Já',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'innkaupafærsla' => 'ap_transaction',
+ 'ný_kredit_færsla' => 'add_accounts_payables_transaction',
+ 'Áfram' => 'continue',
+ 'eyða' => 'delete',
+ 'breyta_greiðslufærslum' => 'edit_accounts_payables_transaction',
+ 'bókfæra' => 'post',
+ 'bókfæra_sem_nýjan' => 'post_as_new',
+ 'innkaupsreikningur' => 'purchase_invoice',
+ 'uppfærsla' => 'update',
+ 'já' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/is/ar b/sql-ledger/locale/is/ar
new file mode 100644
index 0000000..6619389
--- /dev/null
+++ b/sql-ledger/locale/is/ar
@@ -0,0 +1,134 @@
+$self{texts} = {
+ 'AR Transaction' => 'Sölufærsla',
+ 'AR Transactions' => 'Sölufærslur',
+ 'Account' => 'Reikningur',
+ 'Add Accounts Receivables Transaction' => 'Ný debit færsla',
+ 'Address' => 'Heimilisfang',
+ 'Amount' => 'Upphæð',
+ 'Amount Due' => 'Eindagi',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Are you sure you want to delete Transaction' => 'Ert þú viss um að þú viljir eyða færslunni',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'Cannot delete transaction!' => 'Get ekki eytt færslu!',
+ 'Cannot post payment for a closed period!' => 'Get ekki bókað greiðslu á lokað tímabil',
+ 'Cannot post transaction for a closed period!' => 'Get ekki bókað færslu á lokað tímabil!',
+ 'Cannot post transaction!' => 'Get ekki bókað færslu!',
+ 'Closed' => 'Lokað',
+ 'Confirm!' => 'Staðfesta!',
+ 'Continue' => 'Áfram',
+ 'Credit Limit' => 'Kreditmörk',
+ 'Currency' => 'Gjaldmiðill',
+ 'Customer' => 'Viðskiptavinur',
+ 'Customer missing!' => 'Viðskiptavin vantar!',
+ 'Customer not on file!' => 'Viðskiptavinur ekki á skrá!',
+ 'Date' => 'Dagsetning',
+ 'Date Paid' => 'Greiðsludagur',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Eyða',
+ 'Description' => 'Skýringar',
+ 'Due Date' => 'Dags. lokið',
+ 'Due Date missing!' => 'Vantar dags. lokið!',
+ 'Edit Accounts Receivables Transaction' => 'Breyta inn-færslum',
+ 'Exch' => 'Vx',
+ 'Exchangerate' => 'Vextir',
+ 'Exchangerate for payment missing!' => 'Vextir fyrir greiðslu vantar!',
+ 'Exchangerate missing!' => 'Vantar vexti!',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'From' => 'Frá',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Innifela í skýrslu',
+ 'Invoice' => 'Sölureikningur',
+ 'Invoice Date' => 'Sölureikningur dags.',
+ 'Invoice Date missing!' => 'Sölureiknings dags. vantar!',
+ 'Invoice Number' => 'Sölureikningur Númer',
+ 'Invoice Number missing!' => 'Sölureikningsnúmer vantar!',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Notes' => 'Upplýsinar',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Number' => 'Númer',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'Open' => 'opna',
+ 'Order' => 'Pöntun',
+ 'Order Number' => 'Pöntun númer',
+ 'Paid' => 'Greitt',
+ 'Payment date missing!' => 'Greiðsudags. vantar!',
+ 'Payments' => 'Greiðslur',
+ 'Post' => 'Bókfæra',
+ 'Post as new' => 'Bókfæra sem nýjan',
+ 'Project' => 'Verkefni',
+ 'Project not on file!' => 'Verkefni ekki á skrá!',
+ 'Remaining' => 'Eftir',
+ 'Sales Invoice' => 'Sölureikningur',
+ 'Salesperson' => 'Salesperson',
+ 'Select from one of the names below' => 'Veljið einhvað að neðangreindum nöfnum',
+ 'Select from one of the projects below' => 'Veljið einhvað að neðangreindum verkefnum',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Ship via' => 'Senda með',
+ 'Source' => 'Frálag',
+ 'Subtotal' => 'Samtala',
+ 'Tax' => 'Virðisaukaskattur',
+ 'Tax Included' => 'Taka með VSK',
+ 'Total' => 'Samtals',
+ 'Transaction deleted!' => 'Færslu eytt!',
+ 'Transaction posted!' => 'Færsla bókfærð!',
+ 'Update' => 'Uppfærsla',
+ 'Vendor not on file!' => 'Byrgir ekki til í gagnagrunni!',
+ 'Yes' => 'Já',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'sölufærsla' => 'ar_transaction',
+ 'Áfram' => 'continue',
+ 'eyða' => 'delete',
+ 'bókfæra' => 'post',
+ 'bókfæra_sem_nýjan' => 'post_as_new',
+ 'sölureikningur' => 'sales_invoice',
+ 'uppfærsla' => 'update',
+ 'já' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/is/arap b/sql-ledger/locale/is/arap
new file mode 100644
index 0000000..3e63011
--- /dev/null
+++ b/sql-ledger/locale/is/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Heimilisfang',
+ 'Continue' => 'Áfram',
+ 'Customer not on file!' => 'Viðskiptavinur ekki á skrá!',
+ 'Description' => 'Skýringar',
+ 'Number' => 'Númer',
+ 'Project not on file!' => 'Verkefni ekki á skrá!',
+ 'Select from one of the names below' => 'Veljið einhvað að neðangreindum nöfnum',
+ 'Select from one of the projects below' => 'Veljið einhvað að neðangreindum verkefnum',
+ 'Vendor not on file!' => 'Byrgir ekki til í gagnagrunni!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'Áfram' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/is/ca b/sql-ledger/locale/is/ca
new file mode 100644
index 0000000..8d3b384
--- /dev/null
+++ b/sql-ledger/locale/is/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Reikningur',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'Balance' => 'Afstemming',
+ 'Chart of Accounts' => 'Listi yfir lykkla/reikninga',
+ 'Credit' => 'Kredit',
+ 'Date' => 'Dagsetning',
+ 'Debit' => 'Debit',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Description' => 'Skýringar',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'From' => 'Frá',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Innifela í skýrslu',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'List Transactions' => 'Sýna færslur',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'Reference' => 'Fylgiskjal',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Subtotal' => 'Samtala',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'sýna_færslur' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/is/cp b/sql-ledger/locale/is/cp
new file mode 100644
index 0000000..d21df27
--- /dev/null
+++ b/sql-ledger/locale/is/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'Reikningur',
+ 'Address' => 'Heimilisfang',
+ 'Amount' => 'Upphæð',
+ 'Amount does not equal applied!' => 'Upphæð stemmir ekki!',
+ 'Amount missing!' => 'Reikning vantar!',
+ 'Applied' => 'Uppfært',
+ 'Cannot post payment!' => 'Get ekki bókað greiðslu',
+ 'Cannot process payment for a closed period!' => 'Get ekki meðhöndlað greiðslu fyrir lokað tímabil!',
+ 'Check' => 'Ávísun',
+ 'Check printed!' => 'Ávísun prentuð',
+ 'Check printing failed!' => 'Villa við prentun á ávísun',
+ 'Continue' => 'Áfram',
+ 'Currency' => 'Gjaldmiðill',
+ 'Customer' => 'Viðskiptavinur',
+ 'Customer not on file!' => 'Viðskiptavinur ekki á skrá!',
+ 'Date' => 'Dagsetning',
+ 'Date missing!' => 'Dagsetningu vantar!',
+ 'Description' => 'Skýringar',
+ 'Due' => 'Lokið',
+ 'Exchangerate' => 'Vextir',
+ 'From' => 'Frá',
+ 'Invoice' => 'Sölureikningur',
+ 'Invoices' => 'Sölureikningar',
+ 'Nothing applied!' => 'Ekkert bókað!',
+ 'Number' => 'Númer',
+ 'Paid in full' => 'Greitt að fullu',
+ 'Payment' => 'Greislur',
+ 'Payment posted!' => 'Greiðsla bókuð',
+ 'Post' => 'Bókfæra',
+ 'Print' => 'Prenta',
+ 'Printer' => 'Prentari',
+ 'Project not on file!' => 'Verkefni ekki á skrá!',
+ 'Receipt' => 'Kvittun',
+ 'Receipt printed!' => 'Receipt printed!',
+ 'Receipt printing failed!' => 'Receipt printing failed!',
+ 'Reference' => 'Fylgiskjal',
+ 'Screen' => 'Skjá',
+ 'Select from one of the names below' => 'Veljið einhvað að neðangreindum nöfnum',
+ 'Select from one of the projects below' => 'Veljið einhvað að neðangreindum verkefnum',
+ 'Update' => 'Uppfærsla',
+ 'Vendor' => 'Byrgir',
+ 'Vendor not on file!' => 'Byrgir ekki til í gagnagrunni!',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'Áfram' => 'continue',
+ 'bókfæra' => 'post',
+ 'prenta' => 'print',
+ 'uppfærsla' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/is/ct b/sql-ledger/locale/is/ct
new file mode 100644
index 0000000..d2be965
--- /dev/null
+++ b/sql-ledger/locale/is/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Nýr',
+ 'Address' => 'Heimilisfang',
+ 'All' => 'Allt',
+ 'Bcc' => 'Blint afrit',
+ 'Cannot delete customer!' => 'Get ekki eytt viðskiptavini!',
+ 'Cannot delete vendor!' => 'Get ekki eytt framleiðanda!',
+ 'Cc' => 'Afrit',
+ 'Contact' => 'Talsmaður',
+ 'Continue' => 'Áfram',
+ 'Credit Limit' => 'Kreditmörk',
+ 'Customer deleted!' => 'Viðskiptavini eytt!',
+ 'Customer saved!' => 'Viðskiptavinur geymdur!',
+ 'Customers' => 'Viðskiptavinir',
+ 'Delete' => 'Eyða',
+ 'Discount' => 'Afsláttur',
+ 'E-mail' => 'R-póstur',
+ 'Edit Customer' => 'Breyta viðskiptavini',
+ 'Edit Vendor' => 'Breyta byrgja',
+ 'Fax' => 'Símbréf',
+ 'Include in Report' => 'Innifela í skýrslu',
+ 'Invoice' => 'Sölureikningur',
+ 'Name' => 'Nafn',
+ 'Name missing!' => 'Nafn vantar!',
+ 'Notes' => 'Upplýsinar',
+ 'Number' => 'Númer',
+ 'Order' => 'Pöntun',
+ 'Orphaned' => 'Sjáfstætt',
+ 'Phone' => 'Sími.',
+ 'Save' => 'Geyma',
+ 'Ship to' => 'Senda til',
+ 'Tax Included' => 'Taka með VSK',
+ 'Taxable' => 'Skatskildur',
+ 'Terms: Net' => 'Nettó',
+ 'Transactions exist, cannot delete customer!' => 'Ekki er hægt að eyða viðskipamanni með færslur!',
+ 'Transactions exist, cannot delete vendor!' => 'Ekki er hægt að eyða byrgja með færslur!',
+ 'Vendor deleted!' => 'Byrgja eytt!',
+ 'Vendor saved!' => 'Byrgir geymdur!',
+ 'Vendors' => 'Byrgjar',
+ 'days' => 'dagar',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'nýr' => 'add',
+ 'Áfram' => 'continue',
+ 'eyða' => 'delete',
+ 'sölureikningur' => 'invoice',
+ 'pöntun' => 'order',
+ 'geyma' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/is/gl b/sql-ledger/locale/is/gl
new file mode 100644
index 0000000..e659b9d
--- /dev/null
+++ b/sql-ledger/locale/is/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Innkaupafærsla',
+ 'AR Transaction' => 'Sölufærsla',
+ 'Account' => 'Reikningur',
+ 'Add General Ledger Transaction' => 'Ný höfuðfærsla',
+ 'Address' => 'Heimilisfang',
+ 'All' => 'Allt',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Are you sure you want to delete Transaction' => 'Ert þú viss um að þú viljir eyða færslunni',
+ 'Asset' => 'Eignir',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'Balance' => 'Afstemming',
+ 'Cannot delete transaction!' => 'Get ekki eytt færslu!',
+ 'Cannot have a value in both Debit and Credit!' => 'Get ekki haft gildi bæði í debit og kredit!',
+ 'Cannot post a transaction without a value!' => 'Get ekki bókað án upphæðar',
+ 'Cannot post transaction for a closed period!' => 'Get ekki bókað færslu á lokað tímabil!',
+ 'Confirm!' => 'Staðfesta!',
+ 'Continue' => 'Áfram',
+ 'Credit' => 'Kredit',
+ 'Customer not on file!' => 'Viðskiptavinur ekki á skrá!',
+ 'Date' => 'Dagsetning',
+ 'Debit' => 'Debit',
+ 'Debit and credit out of balance!' => 'Debit og kredit skulu vera eins!',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Eyða',
+ 'Description' => 'Skýringar',
+ 'Edit General Ledger Transaction' => 'Breyta yfitbókunar færslum',
+ 'Equity' => 'Eigiðfé',
+ 'Expense' => 'Kostnaður',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'From' => 'Frá',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'Færslur í aðalbók',
+ 'General Ledger' => 'Aðalbók',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Innifela í skýrslu',
+ 'Income' => 'Innkoma',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'Liability' => 'Passiv',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Notes' => 'Upplýsinar',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Number' => 'Númer',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'Post' => 'Bókfæra',
+ 'Post as new' => 'Bókfæra sem nýjan',
+ 'Project' => 'Verkefni',
+ 'Project not on file!' => 'Verkefni ekki á skrá!',
+ 'Purchase Invoice' => 'Innkaupsreikningur',
+ 'Reference' => 'Fylgiskjal',
+ 'Reference missing!' => 'Fylgiskjal vantar',
+ 'Reports' => 'Skýrslur',
+ 'Sales Invoice' => 'Sölureikningur',
+ 'Select from one of the names below' => 'Veljið einhvað að neðangreindum nöfnum',
+ 'Select from one of the projects below' => 'Veljið einhvað að neðangreindum verkefnum',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Frálag',
+ 'Subtotal' => 'Samtala',
+ 'Transaction Date missing!' => 'Dags. vantar!',
+ 'Transaction deleted!' => 'Færslu eytt!',
+ 'Transaction posted!' => 'Færsla bókfærð!',
+ 'Update' => 'Uppfærsla',
+ 'Vendor not on file!' => 'Byrgir ekki til í gagnagrunni!',
+ 'Yes' => 'Já',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'innkaupafærsla' => 'ap_transaction',
+ 'sölufærsla' => 'ar_transaction',
+ 'Áfram' => 'continue',
+ 'eyða' => 'delete',
+ 'færslur_í_aðalbók' => 'gl_transaction',
+ 'bókfæra' => 'post',
+ 'bókfæra_sem_nýjan' => 'post_as_new',
+ 'innkaupsreikningur' => 'purchase_invoice',
+ 'sölureikningur' => 'sales_invoice',
+ 'uppfærsla' => 'update',
+ 'já' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/is/ic b/sql-ledger/locale/is/ic
new file mode 100644
index 0000000..7950a0c
--- /dev/null
+++ b/sql-ledger/locale/is/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => 'Virkja',
+ 'Add' => 'Nýr',
+ 'Add Assembly' => 'Ný samsetning',
+ 'Add Part' => 'Ný vara',
+ 'Add Purchase Order' => 'Ný innkaupspöntun',
+ 'Add Sales Order' => 'Ný sölupöntun',
+ 'Add Service' => 'Ný þjónusta',
+ 'Address' => 'Heimilisfang',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Assemblies' => 'Samsetningar',
+ 'Assemblies restocked!' => 'Samsetningar endurunnar',
+ 'Assembly Number missing!' => 'Samsetningar númer vantar',
+ 'Attachment' => 'Hjálagt',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Blint afrit',
+ 'Bin' => 'Vörulager',
+ 'Bought' => 'Keypt',
+ 'COGS' => 'Innkaup',
+ 'Cannot delete item already invoiced!' => 'Get ekki eytt hlut sem þegar er til á sölureikningi!',
+ 'Cannot delete item on order!' => 'Get ekki eytt hlut sem er í pöntun!',
+ 'Cannot delete item which is part of an assembly!' => 'Get ekki eytt hlut sem er partur af samsetningu!',
+ 'Cannot delete item!' => 'Get ekki eytt hlut!',
+ 'Cannot stock assemblies!' => 'Get ekki fært samsetningar',
+ 'Cc' => 'Afrit',
+ 'Contact' => 'Talsmaður',
+ 'Continue' => 'Áfram',
+ 'Copies' => 'Afrit',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Eyða',
+ 'Delivery Date' => 'Afgreiðsludags.',
+ 'Description' => 'Skýringar',
+ 'Drawing' => 'Dregið',
+ 'E-mail' => 'R-póstur',
+ 'E-mail address missing!' => 'R-póst vantar!',
+ 'Edit Assembly' => 'Breyta samsetningu',
+ 'Edit Part' => 'Breyta vöru',
+ 'Edit Service' => 'Breyta þjónustu',
+ 'Expense' => 'Kostnaður',
+ 'Extended' => 'Framlengt',
+ 'Fax' => 'Símbréf',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'From' => 'Frá',
+ 'Image' => 'Mynd',
+ 'In-line' => 'Inndregið',
+ 'Include in Report' => 'Innifela í skýrslu',
+ 'Income' => 'Innkoma',
+ 'Individual Items' => 'Sjálfstæðir hlutir',
+ 'Inventory' => 'Lager',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Lagerbeholdning skal være nul for at du kan forælde denne sammensætning',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Lagerbeholdning skal være nul for at du kan forælde denne enhed',
+ 'Inventory quantity must be zero!' => 'Lagerbeholdning skal være nul',
+ 'Invoice' => 'Sölureikningur',
+ 'Invoice Date missing!' => 'Sölureiknings dags. vantar!',
+ 'Invoice Number' => 'Sölureikningur Númer',
+ 'Invoice Number missing!' => 'Sölureikningsnúmer vantar!',
+ 'Item deleted!' => 'Hlut eytt!',
+ 'Item not on file!' => 'Hlutur ekki á skrá!',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'Last Cost' => 'Síðasta verð',
+ 'Line Total' => 'Samtals línur',
+ 'Link Accounts' => 'Tengja lykla',
+ 'List Price' => 'Sýna verð',
+ 'Make' => 'Tegund',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Message' => 'Skilaboð',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Model',
+ 'Name' => 'Nafn',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Upplýsinar',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Number' => 'Númer',
+ 'Number missing in Row' => 'Tölu vantar í röð',
+ 'Obsolete' => 'Úrelt',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'On Hand' => 'Á lager',
+ 'On Order' => 'Í pöntun',
+ 'Order' => 'Pöntun',
+ 'Order Date missing!' => 'Pöntunar dags. vantar',
+ 'Order Number' => 'Pöntun númer',
+ 'Order Number missing!' => 'Númer pöntunar vantar',
+ 'Ordered' => 'pantað',
+ 'Orphaned' => 'Sjáfstætt',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Fylgiseðill',
+ 'Packing List Date missing!' => 'Dags. fylgiseðils vantar!',
+ 'Packing List Number missing!' => 'Númer fylgiseðils vantar!',
+ 'Part' => 'Vara',
+ 'Part Number missing!' => 'Vörunúmer vantar!',
+ 'Parts' => 'Vörur',
+ 'Phone' => 'Sími.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Verð',
+ 'Printer' => 'Prentari',
+ 'Project' => 'Verkefni',
+ 'Purchase Order' => 'Innkaupspöntun',
+ 'Qty' => 'Magn',
+ 'ROP' => 'ROP',
+ 'Recd' => 'Mótt:',
+ 'Required by' => 'Pantað af',
+ 'Sales' => 'Sala',
+ 'Sales Order' => 'Sölupöntun',
+ 'Save' => 'Geyma',
+ 'Screen' => 'Skjá',
+ 'Select from one of the items below' => 'Veljið einhver að neðangreindum hlutum, og ýtið á "Áfram"',
+ 'Select postscript or PDF!' => 'Veljið postscript eða PDF',
+ 'Sell Price' => 'Söluverð',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Þjónusta',
+ 'Service Number missing!' => 'Þjónustunúmer vantar!',
+ 'Services' => 'Þjónustur',
+ 'Ship' => 'Senda',
+ 'Ship to' => 'Senda til',
+ 'Short' => 'Stutt',
+ 'Sold' => 'Selt',
+ 'Stock Assembly' => 'Lager samsetning',
+ 'Subject' => 'Efni',
+ 'Subtotal' => 'Samtala',
+ 'Tax' => 'Virðisaukaskattur',
+ 'To' => 'til',
+ 'Top Level' => 'Efsta þrep',
+ 'Total' => 'Samtals',
+ 'Unit' => 'Einingar',
+ 'Unit of measure' => 'Mælieining',
+ 'Update' => 'Uppfærsla',
+ 'Updated' => 'Uppfæra',
+ 'Weight' => 'Vigt',
+ 'What type of item is this?' => 'Hvernig hlutur er þetta?',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendist með rafpósti',
+ 'hr' => 'tími',
+ 'sent to printer' => 'sendist á prentara',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'nýr' => 'add',
+ 'ný_samsetning' => 'add_assembly',
+ 'ný_vara' => 'add_part',
+ 'ný_þjónusta' => 'add_service',
+ 'Áfram' => 'continue',
+ 'eyða' => 'delete',
+ 'breyta_samsetningu' => 'edit_assembly',
+ 'breyta_vöru' => 'edit_part',
+ 'breyta_þjónustu' => 'edit_service',
+ 'geyma' => 'save',
+ 'uppfærsla' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/is/io b/sql-ledger/locale/is/io
new file mode 100644
index 0000000..def8209
--- /dev/null
+++ b/sql-ledger/locale/is/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Ný innkaupspöntun',
+ 'Add Sales Order' => 'Ný sölupöntun',
+ 'Address' => 'Heimilisfang',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Attachment' => 'Hjálagt',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'Bcc' => 'Blint afrit',
+ 'Bin' => 'Vörulager',
+ 'Cc' => 'Afrit',
+ 'Contact' => 'Talsmaður',
+ 'Continue' => 'Áfram',
+ 'Copies' => 'Afrit',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delivery Date' => 'Afgreiðsludags.',
+ 'Description' => 'Skýringar',
+ 'E-mail' => 'R-póstur',
+ 'E-mail address missing!' => 'R-póst vantar!',
+ 'Extended' => 'Framlengt',
+ 'Fax' => 'Símbréf',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'In-line' => 'Inndregið',
+ 'Invoice' => 'Sölureikningur',
+ 'Invoice Date missing!' => 'Sölureiknings dags. vantar!',
+ 'Invoice Number missing!' => 'Sölureikningsnúmer vantar!',
+ 'Item not on file!' => 'Hlutur ekki á skrá!',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Message' => 'Skilaboð',
+ 'Name' => 'Nafn',
+ 'No.' => 'Nr.',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Number' => 'Númer',
+ 'Number missing in Row' => 'Tölu vantar í röð',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'Order' => 'Pöntun',
+ 'Order Date missing!' => 'Pöntunar dags. vantar',
+ 'Order Number missing!' => 'Númer pöntunar vantar',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Fylgiseðill',
+ 'Packing List Date missing!' => 'Dags. fylgiseðils vantar!',
+ 'Packing List Number missing!' => 'Númer fylgiseðils vantar!',
+ 'Part' => 'Vara',
+ 'Phone' => 'Sími.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Verð',
+ 'Printer' => 'Prentari',
+ 'Project' => 'Verkefni',
+ 'Purchase Order' => 'Innkaupspöntun',
+ 'Qty' => 'Magn',
+ 'Recd' => 'Mótt:',
+ 'Required by' => 'Pantað af',
+ 'Sales Order' => 'Sölupöntun',
+ 'Screen' => 'Skjá',
+ 'Select from one of the items below' => 'Veljið einhver að neðangreindum hlutum, og ýtið á "Áfram"',
+ 'Select postscript or PDF!' => 'Veljið postscript eða PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Þjónusta',
+ 'Ship' => 'Senda',
+ 'Ship to' => 'Senda til',
+ 'Subject' => 'Efni',
+ 'To' => 'til',
+ 'Unit' => 'Einingar',
+ 'What type of item is this?' => 'Hvernig hlutur er þetta?',
+ 'emailed to' => 'sendist með rafpósti',
+ 'sent to printer' => 'sendist á prentara',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'Áfram' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/is/ir b/sql-ledger/locale/is/ir
new file mode 100644
index 0000000..f941395
--- /dev/null
+++ b/sql-ledger/locale/is/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Reikningur',
+ 'Add Purchase Invoice' => 'Nýr innkaupsreikningur',
+ 'Add Purchase Order' => 'Ný innkaupspöntun',
+ 'Add Sales Order' => 'Ný sölupöntun',
+ 'Address' => 'Heimilisfang',
+ 'Amount' => 'Upphæð',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Are you sure you want to delete Invoice Number' => 'Ert þú viss um að þú viljir eyða reikningi númer',
+ 'Attachment' => 'Hjálagt',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'Bcc' => 'Blint afrit',
+ 'Bin' => 'Vörulager',
+ 'Cannot delete invoice!' => 'Get ekki eytt sölureikningi!',
+ 'Cannot post invoice for a closed period!' => 'Get ekki bókað á lokað tímabil!',
+ 'Cannot post invoice!' => 'Get ekki bókað sölureikning!',
+ 'Cannot post payment for a closed period!' => 'Get ekki bókað greiðslu á lokað tímabil',
+ 'Cc' => 'Afrit',
+ 'Confirm!' => 'Staðfesta!',
+ 'Contact' => 'Talsmaður',
+ 'Continue' => 'Áfram',
+ 'Copies' => 'Afrit',
+ 'Currency' => 'Gjaldmiðill',
+ 'Customer not on file!' => 'Viðskiptavinur ekki á skrá!',
+ 'Date' => 'Dagsetning',
+ 'Date Due' => 'Eindagi',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Eyða',
+ 'Delivery Date' => 'Afgreiðsludags.',
+ 'Description' => 'Skýringar',
+ 'E-mail' => 'R-póstur',
+ 'E-mail address missing!' => 'R-póst vantar!',
+ 'Edit Purchase Invoice' => 'Breyta innkaupareikningi',
+ 'Exch' => 'Vx',
+ 'Exchangerate' => 'Vextir',
+ 'Exchangerate for payment missing!' => 'Vextir fyrir greiðslu vantar!',
+ 'Exchangerate missing!' => 'Vantar vexti!',
+ 'Extended' => 'Framlengt',
+ 'Fax' => 'Símbréf',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'In-line' => 'Inndregið',
+ 'Invoice' => 'Sölureikningur',
+ 'Invoice Date' => 'Sölureikningur dags.',
+ 'Invoice Date missing!' => 'Sölureiknings dags. vantar!',
+ 'Invoice Number' => 'Sölureikningur Númer',
+ 'Invoice Number missing!' => 'Sölureikningsnúmer vantar!',
+ 'Invoice deleted!' => 'Sölureikningi eytt!',
+ 'Invoice posted!' => 'Sölureikningur bókfærður!',
+ 'Item not on file!' => 'Hlutur ekki á skrá!',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Message' => 'Skilaboð',
+ 'Name' => 'Nafn',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Upplýsinar',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Number' => 'Númer',
+ 'Number missing in Row' => 'Tölu vantar í röð',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'Order' => 'Pöntun',
+ 'Order Date missing!' => 'Pöntunar dags. vantar',
+ 'Order Number' => 'Pöntun númer',
+ 'Order Number missing!' => 'Númer pöntunar vantar',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Fylgiseðill',
+ 'Packing List Date missing!' => 'Dags. fylgiseðils vantar!',
+ 'Packing List Number missing!' => 'Númer fylgiseðils vantar!',
+ 'Part' => 'Vara',
+ 'Payment date missing!' => 'Greiðsudags. vantar!',
+ 'Payments' => 'Greiðslur',
+ 'Phone' => 'Sími.',
+ 'Post' => 'Bókfæra',
+ 'Post as new' => 'Bókfæra sem nýjan',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Verð',
+ 'Printer' => 'Prentari',
+ 'Project' => 'Verkefni',
+ 'Project not on file!' => 'Verkefni ekki á skrá!',
+ 'Purchase Order' => 'Innkaupspöntun',
+ 'Qty' => 'Magn',
+ 'Recd' => 'Mótt:',
+ 'Record in' => 'Bóka á',
+ 'Required by' => 'Pantað af',
+ 'Sales Order' => 'Sölupöntun',
+ 'Screen' => 'Skjá',
+ 'Select from one of the items below' => 'Veljið einhver að neðangreindum hlutum, og ýtið á "Áfram"',
+ 'Select from one of the names below' => 'Veljið einhvað að neðangreindum nöfnum',
+ 'Select from one of the projects below' => 'Veljið einhvað að neðangreindum verkefnum',
+ 'Select postscript or PDF!' => 'Veljið postscript eða PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Þjónusta',
+ 'Ship' => 'Senda',
+ 'Ship to' => 'Senda til',
+ 'Source' => 'Frálag',
+ 'Subject' => 'Efni',
+ 'Subtotal' => 'Samtala',
+ 'Tax Included' => 'Taka með VSK',
+ 'To' => 'til',
+ 'Total' => 'Samtals',
+ 'Unit' => 'Einingar',
+ 'Update' => 'Uppfærsla',
+ 'Vendor' => 'Byrgir',
+ 'Vendor missing!' => 'Byrgja vantar!',
+ 'Vendor not on file!' => 'Byrgir ekki til í gagnagrunni!',
+ 'What type of item is this?' => 'Hvernig hlutur er þetta?',
+ 'Yes' => 'Já',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendist með rafpósti',
+ 'sent to printer' => 'sendist á prentara',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'Áfram' => 'continue',
+ 'eyða' => 'delete',
+ 'pöntun' => 'order',
+ 'bókfæra' => 'post',
+ 'bókfæra_sem_nýjan' => 'post_as_new',
+ 'uppfærsla' => 'update',
+ 'já' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/is/is b/sql-ledger/locale/is/is
new file mode 100644
index 0000000..0416418
--- /dev/null
+++ b/sql-ledger/locale/is/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Reikningur',
+ 'Add Purchase Order' => 'Ný innkaupspöntun',
+ 'Add Sales Invoice' => 'Nýr sölureikningur',
+ 'Add Sales Order' => 'Ný sölupöntun',
+ 'Address' => 'Heimilisfang',
+ 'Amount' => 'Upphæð',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Are you sure you want to delete Invoice Number' => 'Ert þú viss um að þú viljir eyða reikningi númer',
+ 'Attachment' => 'Hjálagt',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'Bcc' => 'Blint afrit',
+ 'Bin' => 'Vörulager',
+ 'Cannot delete invoice!' => 'Get ekki eytt sölureikningi!',
+ 'Cannot post invoice for a closed period!' => 'Get ekki bókað á lokað tímabil!',
+ 'Cannot post invoice!' => 'Get ekki bókað sölureikning!',
+ 'Cannot post payment for a closed period!' => 'Get ekki bókað greiðslu á lokað tímabil',
+ 'Cc' => 'Afrit',
+ 'Confirm!' => 'Staðfesta!',
+ 'Contact' => 'Talsmaður',
+ 'Continue' => 'Áfram',
+ 'Copies' => 'Afrit',
+ 'Credit Limit' => 'Kreditmörk',
+ 'Currency' => 'Gjaldmiðill',
+ 'Customer' => 'Viðskiptavinur',
+ 'Customer missing!' => 'Viðskiptavin vantar!',
+ 'Customer not on file!' => 'Viðskiptavinur ekki á skrá!',
+ 'Date' => 'Dagsetning',
+ 'Date Due' => 'Eindagi',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Eyða',
+ 'Delivery Date' => 'Afgreiðsludags.',
+ 'Description' => 'Skýringar',
+ 'E-mail' => 'R-póstur',
+ 'E-mail address missing!' => 'R-póst vantar!',
+ 'Edit Sales Invoice' => 'Breyta sölureikningi',
+ 'Exch' => 'Vx',
+ 'Exchangerate' => 'Vextir',
+ 'Exchangerate for payment missing!' => 'Vextir fyrir greiðslu vantar!',
+ 'Exchangerate missing!' => 'Vantar vexti!',
+ 'Extended' => 'Framlengt',
+ 'Fax' => 'Símbréf',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'In-line' => 'Inndregið',
+ 'Invoice' => 'Sölureikningur',
+ 'Invoice Date' => 'Sölureikningur dags.',
+ 'Invoice Date missing!' => 'Sölureiknings dags. vantar!',
+ 'Invoice Number' => 'Sölureikningur Númer',
+ 'Invoice Number missing!' => 'Sölureikningsnúmer vantar!',
+ 'Invoice deleted!' => 'Sölureikningi eytt!',
+ 'Invoice posted!' => 'Sölureikningur bókfærður!',
+ 'Item not on file!' => 'Hlutur ekki á skrá!',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Message' => 'Skilaboð',
+ 'Name' => 'Nafn',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Upplýsinar',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Number' => 'Númer',
+ 'Number missing in Row' => 'Tölu vantar í röð',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'Order' => 'Pöntun',
+ 'Order Date missing!' => 'Pöntunar dags. vantar',
+ 'Order Number' => 'Pöntun númer',
+ 'Order Number missing!' => 'Númer pöntunar vantar',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Fylgiseðill',
+ 'Packing List Date missing!' => 'Dags. fylgiseðils vantar!',
+ 'Packing List Number missing!' => 'Númer fylgiseðils vantar!',
+ 'Part' => 'Vara',
+ 'Payment date missing!' => 'Greiðsudags. vantar!',
+ 'Payments' => 'Greiðslur',
+ 'Phone' => 'Sími.',
+ 'Post' => 'Bókfæra',
+ 'Post as new' => 'Bókfæra sem nýjan',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Verð',
+ 'Print' => 'Prenta',
+ 'Printer' => 'Prentari',
+ 'Project' => 'Verkefni',
+ 'Project not on file!' => 'Verkefni ekki á skrá!',
+ 'Purchase Order' => 'Innkaupspöntun',
+ 'Qty' => 'Magn',
+ 'Recd' => 'Mótt:',
+ 'Record in' => 'Bóka á',
+ 'Remaining' => 'Eftir',
+ 'Required by' => 'Pantað af',
+ 'Sales Order' => 'Sölupöntun',
+ 'Screen' => 'Skjá',
+ 'Select from one of the items below' => 'Veljið einhver að neðangreindum hlutum, og ýtið á "Áfram"',
+ 'Select from one of the names below' => 'Veljið einhvað að neðangreindum nöfnum',
+ 'Select from one of the projects below' => 'Veljið einhvað að neðangreindum verkefnum',
+ 'Select postscript or PDF!' => 'Veljið postscript eða PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Þjónusta',
+ 'Ship' => 'Senda',
+ 'Ship to' => 'Senda til',
+ 'Ship via' => 'Senda með',
+ 'Source' => 'Frálag',
+ 'Subject' => 'Efni',
+ 'Subtotal' => 'Samtala',
+ 'Tax Included' => 'Taka með VSK',
+ 'To' => 'til',
+ 'Total' => 'Samtals',
+ 'Unit' => 'Einingar',
+ 'Update' => 'Uppfærsla',
+ 'Vendor not on file!' => 'Byrgir ekki til í gagnagrunni!',
+ 'What type of item is this?' => 'Hvernig hlutur er þetta?',
+ 'Yes' => 'Já',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendist með rafpósti',
+ 'sent to printer' => 'sendist á prentara',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'Áfram' => 'continue',
+ 'eyða' => 'delete',
+ 'r_póstur' => 'e_mail',
+ 'pöntun' => 'order',
+ 'bókfæra' => 'post',
+ 'bókfæra_sem_nýjan' => 'post_as_new',
+ 'prenta' => 'print',
+ 'senda_til' => 'ship_to',
+ 'uppfærsla' => 'update',
+ 'já' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/is/login b/sql-ledger/locale/is/login
new file mode 100644
index 0000000..2bb761d
--- /dev/null
+++ b/sql-ledger/locale/is/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Um',
+ 'Database Host' => 'Gagnagrunns-netþjónn',
+ 'Dataset' => 'Gagnasafn',
+ 'Incorrect Dataset version!' => 'Röng útgáfa af gagnasfni!',
+ 'Incorrect Password!' => 'Rangt lykilorð',
+ 'Licensed to' => 'Skráð á',
+ 'Login' => 'Tengjast',
+ 'Name' => 'Nafn',
+ 'Password' => 'Aðgangsorð',
+ 'User' => 'Notandi',
+ 'Version' => 'Útgáfa',
+ 'You are logged out!' => 'Þú ert loggaður út',
+ 'You did not enter a name!' => 'Þú gafst ekki upp nafn',
+ 'is not a member!' => 'er ekki meðlimur!',
+ 'localhost' => 'lokal',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'tengjast' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/is/menu b/sql-ledger/locale/is/menu
new file mode 100644
index 0000000..1bfede9
--- /dev/null
+++ b/sql-ledger/locale/is/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Innkaupakerfi',
+ 'AP Aging' => 'Aldursgreining',
+ 'AR' => 'Sölukerfi',
+ 'AR Aging' => 'Aldursgreining',
+ 'Accounting Menu' => 'Bókhalds valmynd',
+ 'Add Account' => 'Nýr reikningur',
+ 'Add Assembly' => 'Ný samsetning',
+ 'Add Customer' => 'Nýr viðskiptavinur',
+ 'Add GIFI' => 'Ný GIFI',
+ 'Add Part' => 'Ný vara',
+ 'Add Project' => 'Nýt verkefni',
+ 'Add Service' => 'Ný þjónusta',
+ 'Add Transaction' => 'Ný bókhaldsfærsla',
+ 'Add Vendor' => 'Nýr byrgir',
+ 'Assemblies' => 'Samsetningar',
+ 'Audit Control' => 'Yfirlit stjórnun',
+ 'Backup' => 'Afrit',
+ 'Balance Sheet' => 'Staða',
+ 'Cash' => 'Reiðufé',
+ 'Chart of Accounts' => 'Listi yfir lykkla/reikninga',
+ 'Check' => 'Ávísun',
+ 'Customers' => 'Viðskiptavinir',
+ 'General Ledger' => 'Aðalbók',
+ 'Goods & Services' => 'Vörur og þjónusta',
+ 'HTML Templates' => 'HTML-skabalón',
+ 'Income Statement' => 'Inn yfirlýsing',
+ 'Invoice' => 'Sölureikningur',
+ 'LaTeX Templates' => 'LaTeX-skabalón',
+ 'List Accounts' => 'Sýna lykla',
+ 'List GIFI' => 'Sýna GIFI',
+ 'Logout' => 'Aftengjast',
+ 'Order Entry' => 'Pöntunarblað',
+ 'Packing List' => 'Fylgiseðill',
+ 'Parts' => 'Vörur',
+ 'Payment' => 'Greislur',
+ 'Payments' => 'Greiðslur',
+ 'Preferences' => 'Uppsetningar',
+ 'Projects' => 'Verkefni',
+ 'Purchase Invoice' => 'Innkaupsreikningur',
+ 'Purchase Order' => 'Innkaupspöntun',
+ 'Purchase Orders' => 'Innkaupspantanir',
+ 'Receipt' => 'Kvittun',
+ 'Receipts' => 'Kvittanir',
+ 'Reconciliation' => 'Afstemingar',
+ 'Reports' => 'Skýrslur',
+ 'Sales Invoice' => 'Sölureikningur',
+ 'Sales Order' => 'Sölupöntun',
+ 'Sales Orders' => 'Sölupantanir',
+ 'Save to File' => 'Geyma í skrá',
+ 'Send by E-Mail' => 'Senda með rafpósti',
+ 'Services' => 'Þjónustur',
+ 'Statement' => 'Uppgjör',
+ 'Stock Assembly' => 'Lager samsetning',
+ 'Stylesheet' => 'Stílblað',
+ 'System' => 'Kerfi',
+ 'Tax collected' => 'VSK samtals',
+ 'Tax paid' => 'VSK greitt',
+ 'Transactions' => 'Færslur',
+ 'Trial Balance' => 'Prufu staða',
+ 'Vendors' => 'Byrgjar',
+ 'Version' => 'Útgáfa',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/is/oe b/sql-ledger/locale/is/oe
new file mode 100644
index 0000000..9675640
--- /dev/null
+++ b/sql-ledger/locale/is/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'Nýr',
+ 'Add Purchase Invoice' => 'Nýr innkaupsreikningur',
+ 'Add Purchase Order' => 'Ný innkaupspöntun',
+ 'Add Sales Invoice' => 'Nýr sölureikningur',
+ 'Add Sales Order' => 'Ný sölupöntun',
+ 'Address' => 'Heimilisfang',
+ 'Amount' => 'Upphæð',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Are you sure you want to delete Order Number' => 'Ert þú viss um að þú viljir eyða pöntun númer',
+ 'Attachment' => 'Hjálagt',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'Bcc' => 'Blint afrit',
+ 'Bin' => 'Vörulager',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Get ekki eytt pöntun!',
+ 'Cannot save order!' => 'Get ekki geymt pöntun!',
+ 'Cc' => 'Afrit',
+ 'Closed' => 'Lokað',
+ 'Confirm!' => 'Staðfesta!',
+ 'Contact' => 'Talsmaður',
+ 'Continue' => 'Áfram',
+ 'Copies' => 'Afrit',
+ 'Credit Limit' => 'Kreditmörk',
+ 'Curr' => 'Gjaldm',
+ 'Currency' => 'Gjaldmiðill',
+ 'Customer' => 'Viðskiptavinur',
+ 'Customer missing!' => 'Viðskiptavin vantar!',
+ 'Customer not on file!' => 'Viðskiptavinur ekki á skrá!',
+ 'Date' => 'Dagsetning',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Eyða',
+ 'Delivery Date' => 'Afgreiðsludags.',
+ 'Description' => 'Skýringar',
+ 'E-mail' => 'R-póstur',
+ 'E-mail address missing!' => 'R-póst vantar!',
+ 'Edit Purchase Order' => 'Breyta innkaupapöntun',
+ 'Edit Sales Order' => 'Breyta sölupöntun',
+ 'Exchangerate' => 'Vextir',
+ 'Exchangerate missing!' => 'Vantar vexti!',
+ 'Extended' => 'Framlengt',
+ 'Fax' => 'Símbréf',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'From' => 'Frá',
+ 'ID' => 'ID',
+ 'In-line' => 'Inndregið',
+ 'Include in Report' => 'Innifela í skýrslu',
+ 'Invoice' => 'Sölureikningur',
+ 'Invoice Date missing!' => 'Sölureiknings dags. vantar!',
+ 'Invoice Number missing!' => 'Sölureikningsnúmer vantar!',
+ 'Item not on file!' => 'Hlutur ekki á skrá!',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Message' => 'Skilaboð',
+ 'Name' => 'Nafn',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Upplýsinar',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Number' => 'Númer',
+ 'Number missing in Row' => 'Tölu vantar í röð',
+ 'O' => 'O',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'Open' => 'opna',
+ 'Order' => 'Pöntun',
+ 'Order Date' => 'Pöntunar dags.',
+ 'Order Date missing!' => 'Pöntunar dags. vantar',
+ 'Order Number' => 'Pöntun númer',
+ 'Order Number missing!' => 'Númer pöntunar vantar',
+ 'Order deleted!' => 'Pöntun eytt',
+ 'Order saved!' => 'Pöntun geymd',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Fylgiseðill',
+ 'Packing List Date missing!' => 'Dags. fylgiseðils vantar!',
+ 'Packing List Number missing!' => 'Númer fylgiseðils vantar!',
+ 'Part' => 'Vara',
+ 'Phone' => 'Sími.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Verð',
+ 'Print' => 'Prenta',
+ 'Printer' => 'Prentari',
+ 'Project' => 'Verkefni',
+ 'Project not on file!' => 'Verkefni ekki á skrá!',
+ 'Purchase Order' => 'Innkaupspöntun',
+ 'Purchase Orders' => 'Innkaupspantanir',
+ 'Qty' => 'Magn',
+ 'Recd' => 'Mótt:',
+ 'Remaining' => 'Eftir',
+ 'Required by' => 'Pantað af',
+ 'Sales Order' => 'Sölupöntun',
+ 'Sales Orders' => 'Sölupantanir',
+ 'Save' => 'Geyma',
+ 'Save as new' => 'Geyma sem nýtt',
+ 'Screen' => 'Skjá',
+ 'Select from one of the items below' => 'Veljið einhver að neðangreindum hlutum, og ýtið á "Áfram"',
+ 'Select from one of the names below' => 'Veljið einhvað að neðangreindum nöfnum',
+ 'Select from one of the projects below' => 'Veljið einhvað að neðangreindum verkefnum',
+ 'Select postscript or PDF!' => 'Veljið postscript eða PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Þjónusta',
+ 'Ship' => 'Senda',
+ 'Ship to' => 'Senda til',
+ 'Ship via' => 'Senda með',
+ 'Subject' => 'Efni',
+ 'Subtotal' => 'Samtala',
+ 'Tax' => 'Virðisaukaskattur',
+ 'Tax Included' => 'Taka með VSK',
+ 'Terms: Net' => 'Nettó',
+ 'To' => 'til',
+ 'Total' => 'Samtals',
+ 'Unit' => 'Einingar',
+ 'Update' => 'Uppfærsla',
+ 'Vendor' => 'Byrgir',
+ 'Vendor missing!' => 'Byrgja vantar!',
+ 'Vendor not on file!' => 'Byrgir ekki til í gagnagrunni!',
+ 'What type of item is this?' => 'Hvernig hlutur er þetta?',
+ 'Yes' => 'Já',
+ 'days' => 'dagar',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendist með rafpósti',
+ 'sent to printer' => 'sendist á prentara',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'nýr' => 'add',
+ 'Áfram' => 'continue',
+ 'eyða' => 'delete',
+ 'r_póstur' => 'e_mail',
+ 'sölureikningur' => 'invoice',
+ 'prenta' => 'print',
+ 'geyma' => 'save',
+ 'geyma_sem_nýtt' => 'save_as_new',
+ 'senda_til' => 'ship_to',
+ 'uppfærsla' => 'update',
+ 'já' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/is/pe b/sql-ledger/locale/is/pe
new file mode 100644
index 0000000..38b9169
--- /dev/null
+++ b/sql-ledger/locale/is/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Nýr',
+ 'Add Project' => 'Nýt verkefni',
+ 'All' => 'Allt',
+ 'Continue' => 'Áfram',
+ 'Delete' => 'Eyða',
+ 'Description' => 'Skýringar',
+ 'Edit Project' => 'Breyta verkefni',
+ 'Number' => 'Númer',
+ 'Orphaned' => 'Sjáfstætt',
+ 'Project' => 'Verkefni',
+ 'Project Number missing!' => 'Verkefnisnúmer vantar!',
+ 'Project deleted!' => 'Verkefni eytt!',
+ 'Project saved!' => 'verkefni geymt!',
+ 'Projects' => 'Verkefni',
+ 'Save' => 'Geyma',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'nýr' => 'add',
+ 'Áfram' => 'continue',
+ 'eyða' => 'delete',
+ 'geyma' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/is/rc b/sql-ledger/locale/is/rc
new file mode 100644
index 0000000..cdd9c82
--- /dev/null
+++ b/sql-ledger/locale/is/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Reikningur',
+ 'Balance' => 'Afstemming',
+ 'Cleared Balance' => 'Hreynsað jafvægi',
+ 'Continue' => 'Áfram',
+ 'Date' => 'Dagsetning',
+ 'Deposit' => 'Innlagt',
+ 'Description' => 'Skýringar',
+ 'Difference' => 'Mismunur',
+ 'Done' => 'Búið',
+ 'Exchangerate Difference' => 'Vaxtamunur',
+ 'From' => 'Frá',
+ 'Out of balance!' => 'Ekki jafnvægi!',
+ 'Payment' => 'Greislur',
+ 'Reconciliation' => 'Afstemingar',
+ 'Select all' => 'Velja allt',
+ 'Source' => 'Frálag',
+ 'Statement Balance' => 'jöfnunaruppgjör',
+ 'Update' => 'Uppfærsla',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'Áfram' => 'continue',
+ 'búið' => 'done',
+ 'velja_allt' => 'select_all',
+ 'uppfærsla' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/is/rp b/sql-ledger/locale/is/rp
new file mode 100644
index 0000000..ba164d8
--- /dev/null
+++ b/sql-ledger/locale/is/rp
@@ -0,0 +1,120 @@
+$self{texts} = {
+ 'AP Aging' => 'Aldursgreining',
+ 'AR Aging' => 'Aldursgreining',
+ 'Account' => 'Reikningur',
+ 'Accounts' => 'Reikningar',
+ 'Amount' => 'Upphæð',
+ 'Apr' => 'apr',
+ 'April' => 'apríl',
+ 'Attachment' => 'Hjálagt',
+ 'Aug' => 'ágú',
+ 'August' => 'ágúst',
+ 'Balance' => 'Afstemming',
+ 'Balance Sheet' => 'Staða',
+ 'Bcc' => 'Blint afrit',
+ 'Cash based' => 'Reiðufétengt',
+ 'Cc' => 'Afrit',
+ 'Compare to' => 'Bera saman við',
+ 'Continue' => 'Áfram',
+ 'Copies' => 'Afrit',
+ 'Credit' => 'Kredit',
+ 'Current' => 'Núvirði',
+ 'Customer' => 'Viðskiptavinur',
+ 'Date' => 'Dagsetning',
+ 'Debit' => 'Debit',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Decimalplaces' => 'Aukastafir',
+ 'Department' => 'Department',
+ 'Description' => 'Skýringar',
+ 'Due' => 'Lokið',
+ 'E-mail' => 'R-póstur',
+ 'E-mail Statement to' => 'Senda yfirlit til',
+ 'Feb' => 'feb',
+ 'February' => 'febrúar',
+ 'From' => 'Frá',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Yfirskriftir',
+ 'ID' => 'ID',
+ 'In-line' => 'Inndregið',
+ 'Include in Report' => 'Innifela í skýrslu',
+ 'Income Statement' => 'Inn yfirlýsing',
+ 'Invoice' => 'Sölureikningur',
+ 'Jan' => 'jan',
+ 'January' => 'janúar',
+ 'Jul' => 'júl',
+ 'July' => 'júlí',
+ 'Jun' => 'jún',
+ 'June' => 'júní',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'maí',
+ 'May ' => 'maí',
+ 'Message' => 'Skilaboð',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Ekkert valið!',
+ 'Nov' => 'nóv',
+ 'November' => 'nóvember',
+ 'Oct' => 'ókt',
+ 'October' => 'óktóber',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Greiðslur',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Prenta',
+ 'Printer' => 'Prentari',
+ 'Project Number' => 'Project Number',
+ 'Receipts' => 'Kvittanir',
+ 'Report for' => 'Skýrsla fyrir',
+ 'Retained Earnings' => 'Realiseret overskud',
+ 'Screen' => 'Skjá',
+ 'Select all' => 'Velja allt',
+ 'Select postscript or PDF!' => 'Veljið postscript eða PDF',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Frálag',
+ 'Standard' => 'Standart',
+ 'Statement' => 'Uppgjör',
+ 'Statement sent to' => 'Uppgjör sendist til',
+ 'Statements sent to printer!' => 'Uppgjör sendist á prentara',
+ 'Subject' => 'Efni',
+ 'Subtotal' => 'Samtala',
+ 'Tax' => 'Virðisaukaskattur',
+ 'Tax collected' => 'VSK samtals',
+ 'Tax paid' => 'VSK greitt',
+ 'Total' => 'Samtals',
+ 'Trial Balance' => 'Prufu staða',
+ 'Vendor' => 'Byrgir',
+ 'as at' => 'líkt og með',
+ 'collected on sales' => 'samanlagt við sölu',
+ 'for Period' => 'fyrir tímabilið',
+ 'paid on purchases' => 'greitt við innkaup',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'Áfram' => 'continue',
+ 'r_póstur' => 'e_mail',
+ 'prenta' => 'print',
+ 'velja_allt' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/it/COPYING b/sql-ledger/locale/it/COPYING
new file mode 100644
index 0000000..55c8de3
--- /dev/null
+++ b/sql-ledger/locale/it/COPYING
@@ -0,0 +1,25 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Italien texts:
+#
+# Author: Paolo Bizzarri <p.bizzarri@icube.it>
+# Luca Venturini <luca@yepa.com>
+# Alessandro Pasotti <apasotti@isoleborromee.it>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/it/LANGUAGE b/sql-ledger/locale/it/LANGUAGE
new file mode 100644
index 0000000..4e07e7e
--- /dev/null
+++ b/sql-ledger/locale/it/LANGUAGE
@@ -0,0 +1 @@
+Italian
diff --git a/sql-ledger/locale/it/Num2text b/sql-ledger/locale/it/Num2text
new file mode 100644
index 0000000..fccc1d4
--- /dev/null
+++ b/sql-ledger/locale/it/Num2text
@@ -0,0 +1,163 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors: Luca Venturini <luca@yepa.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# this is a variation of the Lingua package
+# written for check and receipt printing
+# it returns a properly formatted text string
+# for a number up to 10**12
+
+sub init {
+ my $self = shift;
+
+ %{ $self->{numbername} } =
+ (0 => 'Zero',
+ 1 => 'uno',
+ 2 => 'due',
+ 3 => 'tre',
+ 4 => 'quattro',
+ 5 => 'cinque',
+ 6 => 'sei',
+ 7 => 'sette',
+ 8 => 'otto',
+ 9 => 'nove',
+ 10 => 'dieci',
+ 11 => 'undici',
+ 12 => 'dodici',
+ 13 => 'tredici',
+ 14 => 'quattrodici',
+ 15 => 'quindici',
+ 16 => 'sedici',
+ 17 => 'diciassette',
+ 18 => 'diciotto',
+ 19 => 'diciannove',
+ 20 => 'venti',
+ 30 => 'trenta',
+ 40 => 'quaranta',
+ 50 => 'cinquanta',
+ 60 => 'sessanta',
+ 70 => 'settanta',
+ 80 => 'ottanta',
+ 90 => 'novanta',
+ 10**2 => 'cento',
+ 10**3 => 'mille',
+ 10**6 => 'milione',
+ 10**9 => 'miliardo',
+ 10**12 => 'mille miliardi'
+ );
+
+}
+
+
+sub num2text {
+ my ($self, $amount) = @_;
+
+ return $self->{numbername}{0} unless $amount;
+
+ my @textnumber = ();
+
+ # split amount into chunks of 3
+ my @num = reverse split //, $amount;
+ my @numblock = ();
+ my ($i, $appendn);
+ my @a = ();
+
+ while (@num) {
+ @a = ();
+ for (1 .. 3) {
+ push @a, shift @num;
+ }
+ push @numblock, join / /, reverse @a;
+ }
+
+ while (@numblock) {
+
+ $i = $#numblock;
+ @num = split //, $numblock[$i];
+
+ $numblock[$i] *= 1;
+
+ if ($numblock[$i] == 0) {
+ pop @numblock;
+ next;
+ }
+
+ if ($numblock[$i] > 99) {
+ # the one from hundreds
+ push @textnumber, $self->{numbername}{$num[0]};
+
+ # add hundred designation
+ push @textnumber, $self->{numbername}{10**2};
+
+ # reduce numblock
+ $numblock[$i] -= $num[0] * 100;
+ }
+
+ if ($numblock[$i] > 9) {
+ # tens
+ push @textnumber, $self->format_ten($numblock[$i]);
+ } elsif ($numblock[$i] > 1) {
+ # ones
+ push @textnumber, $self->{numbername}{$numblock[$i]};
+ }
+
+ # add thousand, million
+ if ($i) {
+ $amount = 10**($i * 3);
+ push @textnumber, $self->{numbername}{$amount};
+ }
+
+ pop @numblock;
+
+ }
+
+ join '', @textnumber;
+
+}
+
+
+sub format_ten {
+ my ($self, $amount) = @_;
+
+ my $textnumber = "";
+ my @num = split //, $amount;
+
+ if ($amount > 20) {
+ if ($num[1] == 0) {
+ $textnumber = $self->{numbername}{$amount};
+ } else {
+ $amount = $num[0] * 10;
+ $textnumber = $self->{numbername}{$amount}.$self->{numbername}{$num[1]};
+ }
+ }
+ } else {
+ $textnumber = $self->{numbername}{$amount};
+ }
+
+ $textnumber;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/locale/it/admin b/sql-ledger/locale/it/admin
new file mode 100644
index 0000000..2294823
--- /dev/null
+++ b/sql-ledger/locale/it/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Controllo degli accessi',
+ 'Accounting' => 'Contabilit&agrave;',
+ 'Add User' => 'Aggiungi Utente',
+ 'Address' => 'Indirizzo',
+ 'Administration' => 'Amministrazione',
+ 'Administrator' => 'Amministratore',
+ 'All Datasets up to date!' => 'Tutti i Dataset sono aggiornati!',
+ 'Change Admin Password' => 'Cambia password dell\'amministratore',
+ 'Change Password' => 'Cambia password',
+ 'Character Set' => 'Set di Caratteri',
+ 'Click on login name to edit!' => 'Clicca sul nome per effettuare modifiche',
+ 'Company' => 'Ragione Sociale',
+ 'Connect to' => 'Connetti a',
+ 'Continue' => 'Continua',
+ 'Create Chart of Accounts' => 'Crea Piano dei Conti',
+ 'Create Dataset' => 'Crea Dataset',
+ 'DBI not installed!' => 'Modulo DBI non installato',
+ 'Database' => 'Database',
+ 'Database Administration' => 'Amministratore del Database',
+ 'Database Driver not checked!' => 'Il driver del database non e\' stato controllato!',
+ 'Database User missing!' => 'Manca l\'utente del Database!',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Dataset mancante!',
+ 'Dataset updated!' => 'Dataset aggiornato!',
+ 'Date Format' => 'Formato della data',
+ 'Delete' => 'Cancella',
+ 'Delete Dataset' => 'Cancella Dataset',
+ 'Directory' => 'Directory',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Limite per i menu a discesa',
+ 'E-mail' => 'E-mail',
+ 'Edit User' => 'Modifica Utente',
+ 'Existing Datasets' => 'Datasets esistenti',
+ 'Fax' => 'Fax',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Manca il nome del server',
+ 'Incorrect Password!' => 'Password sbagliata!',
+ 'Language' => 'Lingua',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Lascia in bianco il server e la porta a meno che tu non voglia fare una connessione remota',
+ 'Login' => 'Login',
+ 'Multibyte Encoding' => 'Multibyte Encoding',
+ 'Name' => 'Nome',
+ 'New Templates' => 'Nuovi Modelli',
+ 'No Database Drivers available!' => 'Nessun Database Driver disponibile!',
+ 'No Dataset selected!' => 'Nessun Dataset selezionato!',
+ 'Nothing to delete!' => 'Nulla da cancellare!',
+ 'Number Format' => 'Formato Numerico',
+ 'Oracle Database Administration' => 'Amministratore del Database Oracle',
+ 'Password' => 'Password',
+ 'Password changed!' => 'Password cambiata!',
+ 'Pg Database Administration' => 'Amministratore del Database Pg',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Porta',
+ 'Port missing!' => 'Manca la Porta',
+ 'Printer' => 'Stampante',
+ 'Save' => 'Salva',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleziona un dataset da cancellare e premi "Continua"',
+ 'Setup Templates' => 'Configurazione dei modelli',
+ 'Ship via' => 'Porto',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Foglio di Stile',
+ 'Templates' => 'Modelli',
+ 'The following Datasets are not in use and can be deleted' => 'I seguenti datasets non sono in uso e possono essere cancellati',
+ 'The following Datasets need to be updated' => 'I seguenti datasets devono essere aggiornati',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Questo &egrave; un controllo preliminare per verificare le risorse esistenti. Nulla verr&agrave; creato o cancellato in questa fase!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Per aggiungere un utente ad un gruppo, modifica i dati dell\'utente, cambia lo username e salva. Un nuovo utente con gli stessi dati verr&agrave; salvato con il nuovo username.',
+ 'Update Dataset' => 'Aggiorna il Dataset',
+ 'Use Templates' => 'Usa Modelli',
+ 'User' => 'Utente',
+ 'User deleted!' => 'Utente cancellato!',
+ 'User saved!' => 'Utente salvato!',
+ 'Version' => 'Versione',
+ 'You must enter a host and port for local and remote connections!' => 'Devi inserire un server ed una porta per le connessioni locali e remote!',
+ 'does not exist' => 'non esiste',
+ 'is already a member!' => '&egrave; gi&agrave; utente!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'locked!',
+ 'successfully created!' => 'creato!',
+ 'successfully deleted!' => 'cancellato!',
+ 'website' => 'sito web',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'aggiungi_utente' => 'add_user',
+ 'cambia_password_dell\'amministratore' => 'change_admin_password',
+ 'cambia_password' => 'change_password',
+ 'continua' => 'continue',
+ 'crea_dataset' => 'create_dataset',
+ 'cancella' => 'delete',
+ 'cancella_dataset' => 'delete_dataset',
+ 'login' => 'login',
+ 'amministratore_del_database_oracle' => 'oracle_database_administration',
+ 'amministratore_del_database_pg' => 'pg_database_administration',
+ 'salva' => 'save',
+ 'aggiorna_il_dataset' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/it/all b/sql-ledger/locale/it/all
new file mode 100644
index 0000000..8f47e6c
--- /dev/null
+++ b/sql-ledger/locale/it/all
@@ -0,0 +1,495 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Debiti Fornitori',
+ 'AP Aging' => 'Partite Aperte',
+ 'AP Transaction' => 'Transazione Fornitore',
+ 'AP Transactions' => 'Transazioni Fornitori',
+ 'AR' => 'Crediti Clienti',
+ 'AR Aging' => 'Partite Aperte',
+ 'AR Transaction' => 'Transazione Cliente',
+ 'AR Transactions' => 'Transazioni Clienti',
+ 'About' => 'Informazioni',
+ 'Access Control' => 'Controllo degli accessi',
+ 'Account' => 'Conto',
+ 'Account Number' => 'Numero di conto',
+ 'Account Number missing!' => 'Manca il numero di conto!',
+ 'Account Type' => 'Tipo di conto',
+ 'Account Type missing!' => 'Manca il tipo del conto!',
+ 'Account deleted!' => 'Conto cancellato!',
+ 'Account saved!' => 'Conto salvato!',
+ 'Accounting' => 'Contabilit&agrave;',
+ 'Accounting Menu' => 'Menu Contabilit&agrave;',
+ 'Accounts' => 'Conti',
+ 'Active' => 'Attivo',
+ 'Add' => 'Aggiungi',
+ 'Add Account' => 'Aggiungi conto',
+ 'Add Accounts Payables Transaction' => 'Aggiungi Transazione Fornitori',
+ 'Add Accounts Receivables Transaction' => 'Aggiungi Transazione Clienti',
+ 'Add Assembly' => 'Aggiungi Assemblato',
+ 'Add Customer' => 'Aggiungi Cliente',
+ 'Add GIFI' => 'Aggiungi codice GIFI',
+ 'Add General Ledger Transaction' => 'Aggiungi Transazione di Contabilità Generale',
+ 'Add Part' => 'Aggiungi Articolo',
+ 'Add Project' => 'Aggiungi Progetto',
+ 'Add Purchase Invoice' => 'Aggiungi Fattura di acquisto',
+ 'Add Purchase Order' => 'Aggiungi Ordine di acquisto',
+ 'Add Sales Invoice' => 'Aggiungi Fattura di vendita',
+ 'Add Sales Order' => 'Aggiungi Ordine di vendita',
+ 'Add Service' => 'Aggiungi Servizio',
+ 'Add Transaction' => 'Aggiungi Transazione',
+ 'Add User' => 'Aggiungi Utente',
+ 'Add Vendor' => 'Aggiungi Fornitore',
+ 'Address' => 'Indirizzo',
+ 'Administration' => 'Amministrazione',
+ 'Administrator' => 'Amministratore',
+ 'All' => 'Tutti',
+ 'All Datasets up to date!' => 'Tutti i Dataset sono aggiornati!',
+ 'Amount' => 'Importo',
+ 'Amount Due' => 'Importo Dovuto',
+ 'Amount does not equal applied!' => 'L\'importo non &egrave; uguale a quanto applicato alle diverse fatture!',
+ 'Amount missing!' => 'Manca l\'importo',
+ 'Applied' => 'Applicato a',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Are you sure you want to delete Invoice Number' => 'Sei sicuro di voler cancellare la Fattura numero',
+ 'Are you sure you want to delete Order Number' => 'Sei sicuro di voler cancellare l\'ordine numero',
+ 'Are you sure you want to delete Transaction' => 'Sei sicuro di voler cancellare la Transazione',
+ 'Assemblies' => 'Assemblati',
+ 'Assemblies restocked!' => 'Assemblati ricaricati!',
+ 'Assembly Number missing!' => 'Manca il codice dell\'assemblato',
+ 'Asset' => 'Attivit&agrave;',
+ 'Attachment' => 'Allegato',
+ 'Audit Control' => 'Controllo accessi',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'BOM',
+ 'Backup' => 'Backup',
+ 'Backup sent to' => 'Backup inviato a',
+ 'Balance' => 'Saldo',
+ 'Balance Sheet' => 'Stato Patrimoniale',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Codice BIN',
+ 'Books are open' => 'I conti sono aperti',
+ 'Bought' => 'Comprato',
+ 'Business Number' => 'Partita IVA',
+ 'C' => 'C',
+ 'COGS' => 'Costo dei Beni Venduti',
+ 'Cannot delete account!' => 'Non puoi cancellare il conto!',
+ 'Cannot delete customer!' => 'Non puoi cancellare il cliente!',
+ 'Cannot delete default account!' => 'Non puoi cancellare il conto predefinito!',
+ 'Cannot delete invoice!' => 'Non puoi cancellare la fattura!',
+ 'Cannot delete item already invoiced!' => 'Non puoi cancellare un articolo gi&agrave; fatturato!',
+ 'Cannot delete item on order!' => 'Non puoi cancellare un articolo ordinato!',
+ 'Cannot delete item which is part of an assembly!' => 'Non puoi cancellare un articolo che fa parte di un assemblato!',
+ 'Cannot delete item!' => 'Non puoi cancellare l\'articolo',
+ 'Cannot delete order!' => 'Non puoi cancellare l\'ordine',
+ 'Cannot delete transaction!' => 'Non puoi cancellare la transazione',
+ 'Cannot delete vendor!' => 'Non puoi cancellare il fornitore',
+ 'Cannot have a value in both Debit and Credit!' => 'Non pu&ograve; esserci un valore sia in Dare che in Avere!',
+ 'Cannot post a transaction without a value!' => 'Non puoi salvare una transazione senza un valore!',
+ 'Cannot post invoice for a closed period!' => 'Non puoi salvare una transazione per un periodo chiuso!',
+ 'Cannot post invoice!' => 'Non puoi salvare la fattura!',
+ 'Cannot post payment for a closed period!' => 'Non puoi salvare pagamenti per un periodo chiuso!',
+ 'Cannot post payment!' => 'Non puoi salvare il pagamento!',
+ 'Cannot post transaction for a closed period!' => 'Non puoi salvare una transazione per un periodo chiuso!',
+ 'Cannot post transaction!' => 'Non puoi salvare la transazione!',
+ 'Cannot process payment for a closed period!' => 'Non puoi processare un pagamento per un periodo chiuso!',
+ 'Cannot save account!' => 'Non puoi salvare il conto!',
+ 'Cannot save order!' => 'Non puoi salvare l\'ordine!',
+ 'Cannot save preferences!' => 'Non puoi salvare le preferenze!',
+ 'Cannot stock assemblies!' => 'Non puoi caricare gli assemblati!',
+ 'Cash' => 'Cassa',
+ 'Cash based' => 'Basato sulla cassa',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => 'Cambia password dell\'amministratore',
+ 'Change Password' => 'Cambia password',
+ 'Character Set' => 'Set di Caratteri',
+ 'Chart of Accounts' => 'Piano dei Conti',
+ 'Check' => 'Assegno',
+ 'Check printed!' => 'Assegno stampato!',
+ 'Check printing failed!' => 'Stampa dell\'assegno fallita!',
+ 'Cleared Balance' => 'Saldo gi&agrave; Conciliato',
+ 'Click on login name to edit!' => 'Clicca sul nome per effettuare modifiche',
+ 'Close Books up to' => 'Chiudi i conti fino a',
+ 'Closed' => 'Chiuso',
+ 'Company' => 'Ragione Sociale',
+ 'Compare to' => 'Confronta con',
+ 'Confirm!' => 'Conferma!',
+ 'Connect to' => 'Connetti a',
+ 'Contact' => 'Contatto',
+ 'Continue' => 'Continua',
+ 'Copies' => 'Copie',
+ 'Copy to COA' => 'Inserisci come Conto',
+ 'Create Chart of Accounts' => 'Crea Piano dei Conti',
+ 'Create Dataset' => 'Crea Dataset',
+ 'Credit' => 'Avere',
+ 'Credit Limit' => 'Fido',
+ 'Curr' => 'Valuta',
+ 'Currency' => 'Valuta',
+ 'Current' => 'Corrente',
+ 'Customer' => 'Cliente',
+ 'Customer deleted!' => 'Cliente cancellato!',
+ 'Customer missing!' => 'Cliente mancante!',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Customer saved!' => 'Cliente salvato!',
+ 'Customers' => 'Clienti',
+ 'DBI not installed!' => 'Modulo DBI non installato',
+ 'Database' => 'Database',
+ 'Database Administration' => 'Amministratore del Database',
+ 'Database Driver not checked!' => 'Il driver del database non e\' stato controllato!',
+ 'Database Host' => 'Server',
+ 'Database User missing!' => 'Manca l\'utente del Database!',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Dataset mancante!',
+ 'Dataset updated!' => 'Dataset aggiornato!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data di Scadenza',
+ 'Date Format' => 'Formato della data',
+ 'Date Paid' => 'Data di pagamento',
+ 'Date missing!' => 'Manca la data!',
+ 'Debit' => 'Dare',
+ 'Debit and credit out of balance!' => 'Dare e Avere non concordano!.',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Decimalplaces' => 'Numero di decimali',
+ 'Delete' => 'Cancella',
+ 'Delete Account' => 'Cancella Conto',
+ 'Delete Dataset' => 'Cancella Dataset',
+ 'Delivery Date' => 'Data di spedizione',
+ 'Department' => '',
+ 'Deposit' => 'Deposito',
+ 'Description' => 'Descrizione',
+ 'Difference' => 'Differenza',
+ 'Directory' => 'Directory',
+ 'Discount' => 'Sconto',
+ 'Done' => 'Fatto',
+ 'Drawing' => 'Disegno',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Limite per i menu a discesa',
+ 'Due' => 'Dovuto',
+ 'Due Date' => 'Scadenza Fattura',
+ 'Due Date missing!' => 'Data di Scadenza mancante!',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'Manda il sollecito via e-mail a',
+ 'E-mail address missing!' => 'Indirizzo e-mail mancante!',
+ 'Edit' => 'Modifica',
+ 'Edit Account' => 'Modifica Conto',
+ 'Edit Accounts Payables Transaction' => 'Modifica Transazione Fornitori',
+ 'Edit Accounts Receivables Transaction' => 'Modifica Transazione Clienti',
+ 'Edit Assembly' => 'Modifica Assemblato',
+ 'Edit Customer' => '',
+ 'Edit GIFI' => 'Modifica codice GIFI',
+ 'Edit General Ledger Transaction' => 'Modifica Transazione di Contabilit&agrave; Generale',
+ 'Edit Part' => 'Modifica Articolo',
+ 'Edit Preferences for' => 'Modifica Preferenze di',
+ 'Edit Project' => 'Modifica Progetto',
+ 'Edit Purchase Invoice' => 'Modifica Fattura di acquisto',
+ 'Edit Purchase Order' => 'Modifica Ordine di acquisto',
+ 'Edit Sales Invoice' => 'Modifica Fattura di Vendita',
+ 'Edit Sales Order' => 'Modifica Ordine di vendita',
+ 'Edit Service' => 'Modifica Servizio',
+ 'Edit Template' => 'Modifica Modello',
+ 'Edit User' => 'Modifica Utente',
+ 'Edit Vendor' => '',
+ 'Employee' => 'Dipendente',
+ 'Enforce transaction reversal for all dates' => 'Forza l\'uso delle transazioni inverse per tutte le date',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Inserisci fino a 3 valute separate da ":" (es.: EUR:USD:CAD) per la valuta locale e quelle straniere',
+ 'Equity' => 'Capitale',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasso di Cambio',
+ 'Exchangerate Difference' => 'Differenza sul Tasso di Cambio',
+ 'Exchangerate for payment missing!' => 'Manca il Tasso di Cambio per il pagamento!',
+ 'Exchangerate missing!' => 'Manca il Tasso di Cambio!',
+ 'Existing Datasets' => 'Datasets esistenti',
+ 'Expense' => 'Uscite',
+ 'Expense Account' => 'Conto Acquisti',
+ 'Expense/Asset' => 'Acquisti/Attivit&agrave;',
+ 'Extended' => 'Esteso',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'Foreign Exchange Gain' => 'Guadagno da cambio valuta',
+ 'Foreign Exchange Loss' => 'Perdita da cambio valuta',
+ 'From' => 'Dal',
+ 'GIFI' => 'Codice GIFI',
+ 'GIFI deleted!' => 'Codice GIFI cancellato!',
+ 'GIFI missing!' => 'Codice GIFI mancante!',
+ 'GIFI saved!' => 'Codice GIFI salvato!',
+ 'GL Transaction' => 'Transazione di Contabilit&agrave; generale',
+ 'General Ledger' => 'Contabilit&agrave; generale',
+ 'Goods & Services' => 'Beni e Servizi',
+ 'HTML Templates' => 'Modelli HTML',
+ 'Heading' => 'Intestazione',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Manca il nome del server',
+ 'ID' => 'ID',
+ 'Image' => 'Immagine',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Include in drop-down menus' => 'Da includere nei menu a discesa dei seguenti moduli',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Includere questo conto nei moduli fornitore/cliente per identificare il soggetto come tassabile?',
+ 'Income' => 'Entrate',
+ 'Income Account' => 'Vendite',
+ 'Income Statement' => 'Conto Economico',
+ 'Incorrect Dataset version!' => 'Versione del Dataset non corretta!',
+ 'Incorrect Password!' => 'Password sbagliata!',
+ 'Individual Items' => 'Articoli Individuali',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Conto Inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La quantit&agrave; in inventario deve essere zero per poter mettere l\'assemblato come obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La quantit&agrave; in inventario deve essere zero per poter mettere l\'articolo come obsoleto!',
+ 'Inventory quantity must be zero!' => 'La quantit&agrave; in inventario deve essere zero!',
+ 'Invoice' => 'Fattura',
+ 'Invoice Date' => 'Data Fattura',
+ 'Invoice Date missing!' => 'Manca la data della Fattura!',
+ 'Invoice Number' => 'Fattura Numero',
+ 'Invoice Number missing!' => 'Manca il numero della Fattura!',
+ 'Invoice deleted!' => 'Fattura Cancellata!',
+ 'Invoice posted!' => 'Fattura Salvata!',
+ 'Invoices' => 'Fatture',
+ 'Is this a summary account to record' => 'Conto di riferimento del modulo:',
+ 'Item deleted!' => 'Articolo Cancellato!',
+ 'Item not on file!' => 'Articolo non in archivio!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'LaTeX Templates' => 'Modelli LaTeX',
+ 'Language' => 'Lingua',
+ 'Last Cost' => 'Ultimo Costo',
+ 'Last Invoice Number' => 'Ultimo Numero di Fattura',
+ 'Last Numbers & Default Accounts' => 'Ultimi numeri e Conti di Default',
+ 'Last Purchase Order Number' => 'Ultimo numero d\'ordine di acquisto',
+ 'Last Sales Order Number' => 'Ultimo numero d\'ordine di vendita',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Lascia in bianco il server e la porta a meno che tu non voglia fare una connessione remota',
+ 'Liability' => 'Passivit&agrave;',
+ 'Licensed to' => 'Dato in Licenza a',
+ 'Line Total' => 'Totale Linea',
+ 'Link' => 'Collegamenti',
+ 'Link Accounts' => 'Collegamenti tra Conti',
+ 'List Accounts' => 'Lista Conti',
+ 'List GIFI' => 'Lista codici GIFI',
+ 'List Price' => 'Prezzo di Listino',
+ 'List Transactions' => 'Lista Transazioni',
+ 'Login' => 'Login',
+ 'Logout' => 'Logout',
+ 'Make' => 'Produttore',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Message' => 'Messaggio',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modello',
+ 'Multibyte Encoding' => '',
+ 'N/A' => 'N/A',
+ 'Name' => 'Nome',
+ 'Name missing!' => 'Manca il Nome!',
+ 'New Templates' => 'Nuovi Modelli',
+ 'No' => 'No',
+ 'No Database Drivers available!' => 'Nessun Database Driver disponibile!',
+ 'No Dataset selected!' => 'Nessun Dataset selezionato!',
+ 'No email address for' => 'Manca l\'indirizzo e-mail per',
+ 'No.' => 'No.',
+ 'Notes' => 'Note',
+ 'Nothing applied!' => 'Nulla di applicato!',
+ 'Nothing selected!' => 'Non hai selezionato nulla!',
+ 'Nothing to delete!' => 'Nulla da cancellare!',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Numero',
+ 'Number Format' => 'Formato Numerico',
+ 'Number missing in Row' => 'Manca il codice nella riga',
+ 'O' => 'O',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'On Hand' => 'Disponibilit&agrave;',
+ 'On Order' => 'Mandato ordine fornitore',
+ 'Open' => 'Aperto',
+ 'Oracle Database Administration' => 'Amministratore del Database Oracle',
+ 'Order' => 'Ordine',
+ 'Order Date' => 'Data dell\'ordine',
+ 'Order Date missing!' => 'Manca la data dell\'ordine',
+ 'Order Entry' => 'Ordini',
+ 'Order Number' => 'Ordine Numero',
+ 'Order Number missing!' => 'Manca il numero dell\'ordine!',
+ 'Order deleted!' => 'Ordine Cancellato!',
+ 'Order saved!' => 'Ordine Salvato!',
+ 'Ordered' => 'Ricevuto ordine da cliente',
+ 'Orphaned' => 'Orfano',
+ 'Out of balance!' => 'Non conciliato!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista Etichette',
+ 'Packing List Date missing!' => 'Manca la data della Packing List!',
+ 'Packing List Number missing!' => 'Manca il codice della Packing List!',
+ 'Paid' => 'Importo Pagato',
+ 'Paid in full' => 'Pagato completamente',
+ 'Part' => 'Articolo',
+ 'Part Number missing!' => 'Manca il Codice dell\'articolo!',
+ 'Parts' => 'Articoli',
+ 'Parts Inventory' => 'Inventario degli articoli',
+ 'Password' => 'Password',
+ 'Password changed!' => 'Password cambiata!',
+ 'Payables' => 'Debiti Fornitori',
+ 'Payment' => 'Pagamento',
+ 'Payment date missing!' => 'Manca la data del pagamento!',
+ 'Payment posted!' => 'Pagamento Salvato',
+ 'Payments' => 'Pagamenti',
+ 'Pg Database Administration' => 'Amministratore del Database Pg',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Porta',
+ 'Port missing!' => 'Manca la Porta',
+ 'Post' => 'Salva',
+ 'Post as new' => 'Salva come nuovo',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Preferenze',
+ 'Preferences saved!' => 'Preferenze Salvate!',
+ 'Price' => 'Prezzo',
+ 'Print' => 'Stampa',
+ 'Printer' => 'Stampante',
+ 'Project' => 'Progetto',
+ 'Project Number' => '',
+ 'Project Number missing!' => 'Manca il codice del progetto!',
+ 'Project deleted!' => 'Progetto cancellato!',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Project saved!' => 'Progetto salvato!',
+ 'Projects' => 'Progetti',
+ 'Purchase Invoice' => 'Fattura di acquisto',
+ 'Purchase Order' => 'Ordine di acquisto',
+ 'Purchase Orders' => 'Ordini di acquisto',
+ 'Qty' => 'Q.t&agrave;',
+ 'ROP' => 'Soglia di Riordino',
+ 'Rate' => 'Tasso',
+ 'Recd' => 'Ricevuto',
+ 'Receipt' => 'Incasso',
+ 'Receipt printed!' => '',
+ 'Receipt printing failed!' => '',
+ 'Receipts' => 'Incassi',
+ 'Receivables' => 'Crediti Clienti',
+ 'Reconciliation' => 'Conciliazione',
+ 'Record in' => 'Registra in',
+ 'Reference' => 'Riferimento',
+ 'Reference missing!' => 'Manca il riferimento!',
+ 'Remaining' => 'Rimanente',
+ 'Report for' => 'Prospetto per',
+ 'Reports' => 'Prospetti',
+ 'Required by' => 'Necessario dal',
+ 'Retained Earnings' => 'Guadagni',
+ 'Sales' => 'Vendite',
+ 'Sales Invoice' => 'Fattura di vendita',
+ 'Sales Order' => 'Ordine di vendita',
+ 'Sales Orders' => 'Ordini di vendita',
+ 'Save' => 'Salva',
+ 'Save as new' => 'Salva come nuovo',
+ 'Save to File' => 'Salva su file',
+ 'Screen' => 'Schermo',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleziona un dataset da cancellare e premi "Continua"',
+ 'Select all' => 'Seleziona tutto',
+ 'Select from one of the items below' => 'Seleziona uno dei seguenti Articoli',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Select postscript or PDF!' => 'Scegli tra postscript e PDF!',
+ 'Sell Price' => 'Prezzo di Vendita',
+ 'Send by E-Mail' => 'Spedisci via e-mail',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Service' => 'Servizio',
+ 'Service Items' => 'Inventario (Servizi)',
+ 'Service Number missing!' => 'Manca il codice del servizio',
+ 'Services' => 'Servizi',
+ 'Setup Templates' => 'Configurazione dei modelli',
+ 'Ship' => 'Invio',
+ 'Ship to' => 'Spedire a',
+ 'Ship via' => 'Porto',
+ 'Short' => 'Corto',
+ 'Signature' => 'Firma',
+ 'Sold' => 'Venduto',
+ 'Source' => 'Sorgente',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Sollecito',
+ 'Statement Balance' => 'Saldo',
+ 'Statement sent to' => 'Sollecito mandato a',
+ 'Statements sent to printer!' => 'Solleciti mandati in stampa!',
+ 'Stock Assembly' => 'Magazzino Assemblati',
+ 'Stylesheet' => 'Foglio di Stile',
+ 'Subject' => 'Oggetto',
+ 'Subtotal' => 'Totale Parziale',
+ 'System' => 'Sistema',
+ 'Tax' => 'Tassa',
+ 'Tax Accounts' => 'Conti relativi a tasse',
+ 'Tax Included' => 'Tasse Incluse',
+ 'Tax collected' => 'Debito IVA',
+ 'Tax paid' => 'Credito IVA',
+ 'Taxable' => 'Tassabile',
+ 'Template saved!' => 'Modello salvato!',
+ 'Templates' => 'Modelli',
+ 'Terms: Net' => 'Termini: Netto',
+ 'The following Datasets are not in use and can be deleted' => 'I seguenti datasets non sono in uso e possono essere cancellati',
+ 'The following Datasets need to be updated' => 'I seguenti datasets devono essere aggiornati',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Questo &egrave; un controllo preliminare per verificare le risorse esistenti. Nulla verr&agrave; creato o cancellato in questa fase!',
+ 'To' => 'Al',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Per aggiungere un utente ad un gruppo, modifica i dati dell\'utente, cambia lo username e salva. Un nuovo utente con gli stessi dati verr&agrave; salvato con il nuovo username.',
+ 'Top Level' => 'Livello Top',
+ 'Total' => 'Totale',
+ 'Transaction Date missing!' => 'Manca la data della transazione!',
+ 'Transaction deleted!' => 'Transazione cancellata!',
+ 'Transaction posted!' => 'Transazione salvata!',
+ 'Transaction reversal enforced for all dates' => 'Uso delle transazioni inverse forzato per tutte le date',
+ 'Transaction reversal enforced up to' => 'Uso delle transazioni inverse forzato fino a',
+ 'Transactions' => 'Transazioni',
+ 'Transactions exist, cannot delete customer!' => 'Impossibile cancellare il Cliente: ci sono transazioni a suo nome!',
+ 'Transactions exist, cannot delete vendor!' => 'Impossibile cancellare il Fornitore: ci sono transazioni a suo nome!',
+ 'Transactions exist; cannot delete account!' => 'Impossibile cancellare il Conto: ci sono transazioni!',
+ 'Trial Balance' => 'Bilancio di Verifica',
+ 'Unit' => 'Unit&agrave;',
+ 'Unit of measure' => 'Unit&agrave; di misura',
+ 'Update' => 'Aggiorna',
+ 'Update Dataset' => 'Aggiorna il Dataset',
+ 'Updated' => 'Aggiornato',
+ 'Use Templates' => 'Usa Modelli',
+ 'User' => 'Utente',
+ 'User deleted!' => 'Utente cancellato!',
+ 'User saved!' => 'Utente salvato!',
+ 'Vendor' => 'Fornitore',
+ 'Vendor deleted!' => 'Fornitore cancellato!',
+ 'Vendor missing!' => 'Manca il fornitore!',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+ 'Vendor saved!' => 'Fornitore salvato!',
+ 'Vendors' => 'Fornitori',
+ 'Version' => 'Versione',
+ 'Weight' => 'Peso',
+ 'Weight Unit' => 'Unit&agrave; di misura',
+ 'What type of item is this?' => 'Che tipo di Articolo &egrave; questo?',
+ 'Year End' => 'Fine anno',
+ 'Yes' => 'Si',
+ 'You are logged out!' => 'Sei disconnesso!',
+ 'You did not enter a name!' => 'Non hai inserito il nome!',
+ 'You must enter a host and port for local and remote connections!' => 'Devi inserire un server ed una porta per le connessioni locali e remote!',
+ 'as at' => 'Al',
+ 'collected on sales' => 'incassate su vendite',
+ 'days' => 'giorni',
+ 'does not exist' => 'non esiste',
+ 'ea' => 'ci',
+ 'emailed to' => 'Mandato via e-mail a',
+ 'for Period' => 'per il Periodo',
+ 'hr' => 'ore',
+ 'is already a member!' => '&egrave; gi&agrave; utente!',
+ 'is not a member!' => 'non &eacute; un utente!',
+ 'localhost' => 'localhost',
+ 'locked!' => '',
+ 'paid on purchases' => 'pagato sugli acquisti',
+ 'sent to printer' => 'mandato in stampa',
+ 'successfully created!' => 'creato!',
+ 'successfully deleted!' => 'cancellato!',
+ 'to' => 'al',
+ 'website' => 'sito web',
+};
+
+1;
diff --git a/sql-ledger/locale/it/am b/sql-ledger/locale/it/am
new file mode 100644
index 0000000..285fa50
--- /dev/null
+++ b/sql-ledger/locale/it/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Debiti Fornitori',
+ 'AR' => 'Crediti Clienti',
+ 'Account' => 'Conto',
+ 'Account Number' => 'Numero di conto',
+ 'Account Number missing!' => 'Manca il numero di conto!',
+ 'Account Type' => 'Tipo di conto',
+ 'Account Type missing!' => 'Manca il tipo del conto!',
+ 'Account deleted!' => 'Conto cancellato!',
+ 'Account saved!' => 'Conto salvato!',
+ 'Add Account' => 'Aggiungi conto',
+ 'Add GIFI' => 'Aggiungi codice GIFI',
+ 'Address' => 'Indirizzo',
+ 'Asset' => 'Attivit&agrave;',
+ 'Audit Control' => 'Controllo accessi',
+ 'Backup sent to' => 'Backup inviato a',
+ 'Books are open' => 'I conti sono aperti',
+ 'Business Number' => 'Partita IVA',
+ 'COGS' => 'Costo dei Beni Venduti',
+ 'Cannot delete account!' => 'Non puoi cancellare il conto!',
+ 'Cannot delete default account!' => 'Non puoi cancellare il conto predefinito!',
+ 'Cannot save account!' => 'Non puoi salvare il conto!',
+ 'Cannot save preferences!' => 'Non puoi salvare le preferenze!',
+ 'Character Set' => 'Set di Caratteri',
+ 'Chart of Accounts' => 'Piano dei Conti',
+ 'Close Books up to' => 'Chiudi i conti fino a',
+ 'Company' => 'Ragione Sociale',
+ 'Continue' => 'Continua',
+ 'Copy to COA' => 'Inserisci come Conto',
+ 'Credit' => 'Avere',
+ 'Date Format' => 'Formato della data',
+ 'Debit' => 'Dare',
+ 'Delete' => 'Cancella',
+ 'Delete Account' => 'Cancella Conto',
+ 'Description' => 'Descrizione',
+ 'Dropdown Limit' => 'Limite per i menu a discesa',
+ 'E-mail' => 'E-mail',
+ 'Edit' => 'Modifica',
+ 'Edit Account' => 'Modifica Conto',
+ 'Edit GIFI' => 'Modifica codice GIFI',
+ 'Edit Preferences for' => 'Modifica Preferenze di',
+ 'Edit Template' => 'Modifica Modello',
+ 'Enforce transaction reversal for all dates' => 'Forza l\'uso delle transazioni inverse per tutte le date',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Inserisci fino a 3 valute separate da ":" (es.: EUR:USD:CAD) per la valuta locale e quelle straniere',
+ 'Equity' => 'Capitale',
+ 'Expense' => 'Uscite',
+ 'Expense Account' => 'Conto Acquisti',
+ 'Expense/Asset' => 'Acquisti/Attivit&agrave;',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Guadagno da cambio valuta',
+ 'Foreign Exchange Loss' => 'Perdita da cambio valuta',
+ 'GIFI' => 'Codice GIFI',
+ 'GIFI deleted!' => 'Codice GIFI cancellato!',
+ 'GIFI missing!' => 'Codice GIFI mancante!',
+ 'GIFI saved!' => 'Codice GIFI salvato!',
+ 'Heading' => 'Intestazione',
+ 'Include in drop-down menus' => 'Da includere nei menu a discesa dei seguenti moduli',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Includere questo conto nei moduli fornitore/cliente per identificare il soggetto come tassabile?',
+ 'Income' => 'Entrate',
+ 'Income Account' => 'Vendite',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Conto Inventario',
+ 'Is this a summary account to record' => 'Conto di riferimento del modulo:',
+ 'Language' => 'Lingua',
+ 'Last Invoice Number' => 'Ultimo Numero di Fattura',
+ 'Last Numbers & Default Accounts' => 'Ultimi numeri e Conti di Default',
+ 'Last Purchase Order Number' => 'Ultimo numero d\'ordine di acquisto',
+ 'Last Sales Order Number' => 'Ultimo numero d\'ordine di vendita',
+ 'Liability' => 'Passivit&agrave;',
+ 'Link' => 'Collegamenti',
+ 'Name' => 'Nome',
+ 'No' => 'No',
+ 'No email address for' => 'Manca l\'indirizzo e-mail per',
+ 'Number' => 'Numero',
+ 'Number Format' => 'Formato Numerico',
+ 'Parts Inventory' => 'Inventario degli articoli',
+ 'Password' => 'Password',
+ 'Payables' => 'Debiti Fornitori',
+ 'Payment' => 'Pagamento',
+ 'Phone' => 'Tel.',
+ 'Preferences saved!' => 'Preferenze Salvate!',
+ 'Rate' => 'Tasso',
+ 'Receivables' => 'Crediti Clienti',
+ 'Sales' => 'Vendite',
+ 'Save' => 'Salva',
+ 'Service Items' => 'Inventario (Servizi)',
+ 'Ship via' => 'Porto',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Foglio di Stile',
+ 'Tax' => 'Tassa',
+ 'Tax Accounts' => 'Conti relativi a tasse',
+ 'Template saved!' => 'Modello salvato!',
+ 'Transaction reversal enforced for all dates' => 'Uso delle transazioni inverse forzato per tutte le date',
+ 'Transaction reversal enforced up to' => 'Uso delle transazioni inverse forzato fino a',
+ 'Transactions exist; cannot delete account!' => 'Impossibile cancellare il Conto: ci sono transazioni!',
+ 'Weight Unit' => 'Unit&agrave; di misura',
+ 'Year End' => 'Fine anno',
+ 'Yes' => 'Si',
+ 'does not exist' => 'non esiste',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'aggiungi_conto' => 'add_account',
+ 'continua' => 'continue',
+ 'inserisci_come_conto' => 'copy_to_coa',
+ 'cancella' => 'delete',
+ 'modifica' => 'edit',
+ 'modifica_conto' => 'edit_account',
+ 'salva' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/it/ap b/sql-ledger/locale/it/ap
new file mode 100644
index 0000000..3b57b5c
--- /dev/null
+++ b/sql-ledger/locale/it/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Transazione Fornitore',
+ 'AP Transactions' => 'Transazioni Fornitori',
+ 'Account' => 'Conto',
+ 'Add Accounts Payables Transaction' => 'Aggiungi Transazione Fornitori',
+ 'Address' => 'Indirizzo',
+ 'Amount' => 'Importo',
+ 'Amount Due' => 'Importo Dovuto',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Are you sure you want to delete Transaction' => 'Sei sicuro di voler cancellare la Transazione',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Non puoi cancellare la transazione',
+ 'Cannot post payment for a closed period!' => 'Non puoi salvare pagamenti per un periodo chiuso!',
+ 'Cannot post transaction for a closed period!' => 'Non puoi salvare una transazione per un periodo chiuso!',
+ 'Cannot post transaction!' => 'Non puoi salvare la transazione!',
+ 'Closed' => 'Chiuso',
+ 'Confirm!' => 'Conferma!',
+ 'Continue' => 'Continua',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data di pagamento',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Delete' => 'Cancella',
+ 'Description' => 'Descrizione',
+ 'Due Date' => 'Scadenza Fattura',
+ 'Due Date missing!' => 'Data di Scadenza mancante!',
+ 'Edit Accounts Payables Transaction' => 'Modifica Transazione Fornitori',
+ 'Employee' => 'Dipendente',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasso di Cambio',
+ 'Exchangerate for payment missing!' => 'Manca il Tasso di Cambio per il pagamento!',
+ 'Exchangerate missing!' => 'Manca il Tasso di Cambio!',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'From' => 'Dal',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Invoice' => 'Fattura',
+ 'Invoice Date' => 'Data Fattura',
+ 'Invoice Date missing!' => 'Manca la data della Fattura!',
+ 'Invoice Number' => 'Fattura Numero',
+ 'Invoice Number missing!' => 'Manca il numero della Fattura!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Notes' => 'Note',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Numero',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'Open' => 'Aperto',
+ 'Order' => 'Ordine',
+ 'Order Number' => 'Ordine Numero',
+ 'Paid' => 'Importo Pagato',
+ 'Payment date missing!' => 'Manca la data del pagamento!',
+ 'Payments' => 'Pagamenti',
+ 'Post' => 'Salva',
+ 'Post as new' => 'Salva come nuovo',
+ 'Project' => 'Progetto',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Purchase Invoice' => 'Fattura di acquisto',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Source' => 'Sorgente',
+ 'Subtotal' => 'Totale Parziale',
+ 'Tax' => 'Tassa',
+ 'Tax Included' => 'Tasse Incluse',
+ 'Total' => 'Totale',
+ 'Transaction deleted!' => 'Transazione cancellata!',
+ 'Transaction posted!' => 'Transazione salvata!',
+ 'Update' => 'Aggiorna',
+ 'Vendor' => 'Fornitore',
+ 'Vendor missing!' => 'Manca il fornitore!',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+ 'Yes' => 'Si',
+ 'to' => 'al',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transazione_fornitore' => 'ap_transaction',
+ 'aggiungi_transazione_fornitori' => 'add_accounts_payables_transaction',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'modifica_transazione_fornitori' => 'edit_accounts_payables_transaction',
+ 'salva' => 'post',
+ 'salva_come_nuovo' => 'post_as_new',
+ 'fattura_di_acquisto' => 'purchase_invoice',
+ 'aggiorna' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/it/ar b/sql-ledger/locale/it/ar
new file mode 100644
index 0000000..301d421
--- /dev/null
+++ b/sql-ledger/locale/it/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Transazione Cliente',
+ 'AR Transactions' => 'Transazioni Clienti',
+ 'Account' => 'Conto',
+ 'Add Accounts Receivables Transaction' => 'Aggiungi Transazione Clienti',
+ 'Address' => 'Indirizzo',
+ 'Amount' => 'Importo',
+ 'Amount Due' => 'Importo Dovuto',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Are you sure you want to delete Transaction' => 'Sei sicuro di voler cancellare la Transazione',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Non puoi cancellare la transazione',
+ 'Cannot post payment for a closed period!' => 'Non puoi salvare pagamenti per un periodo chiuso!',
+ 'Cannot post transaction for a closed period!' => 'Non puoi salvare una transazione per un periodo chiuso!',
+ 'Cannot post transaction!' => 'Non puoi salvare la transazione!',
+ 'Closed' => 'Chiuso',
+ 'Confirm!' => 'Conferma!',
+ 'Continue' => 'Continua',
+ 'Credit Limit' => 'Fido',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Cliente mancante!',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data di pagamento',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Delete' => 'Cancella',
+ 'Description' => 'Descrizione',
+ 'Due Date' => 'Scadenza Fattura',
+ 'Due Date missing!' => 'Data di Scadenza mancante!',
+ 'Edit Accounts Receivables Transaction' => 'Modifica Transazione Clienti',
+ 'Employee' => 'Dipendente',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasso di Cambio',
+ 'Exchangerate for payment missing!' => 'Manca il Tasso di Cambio per il pagamento!',
+ 'Exchangerate missing!' => 'Manca il Tasso di Cambio!',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'From' => 'Dal',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Invoice' => 'Fattura',
+ 'Invoice Date' => 'Data Fattura',
+ 'Invoice Date missing!' => 'Manca la data della Fattura!',
+ 'Invoice Number' => 'Fattura Numero',
+ 'Invoice Number missing!' => 'Manca il numero della Fattura!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Notes' => 'Note',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Numero',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'Open' => 'Aperto',
+ 'Order' => 'Ordine',
+ 'Order Number' => 'Ordine Numero',
+ 'Paid' => 'Importo Pagato',
+ 'Payment date missing!' => 'Manca la data del pagamento!',
+ 'Payments' => 'Pagamenti',
+ 'Post' => 'Salva',
+ 'Post as new' => 'Salva come nuovo',
+ 'Project' => 'Progetto',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Remaining' => 'Rimanente',
+ 'Sales Invoice' => 'Fattura di vendita',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Source' => 'Sorgente',
+ 'Subtotal' => 'Totale Parziale',
+ 'Tax' => 'Tassa',
+ 'Tax Included' => 'Tasse Incluse',
+ 'Total' => 'Totale',
+ 'Transaction deleted!' => 'Transazione cancellata!',
+ 'Transaction posted!' => 'Transazione salvata!',
+ 'Update' => 'Aggiorna',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+ 'Yes' => 'Si',
+ 'to' => 'al',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transazione_cliente' => 'ar_transaction',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'salva' => 'post',
+ 'salva_come_nuovo' => 'post_as_new',
+ 'fattura_di_vendita' => 'sales_invoice',
+ 'aggiorna' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/it/arap b/sql-ledger/locale/it/arap
new file mode 100644
index 0000000..57651a9
--- /dev/null
+++ b/sql-ledger/locale/it/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Indirizzo',
+ 'Continue' => 'Continua',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Description' => 'Descrizione',
+ 'Number' => 'Numero',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'continua' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/it/ca b/sql-ledger/locale/it/ca
new file mode 100644
index 0000000..1fdc01d
--- /dev/null
+++ b/sql-ledger/locale/it/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Conto',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Saldo',
+ 'Chart of Accounts' => 'Piano dei Conti',
+ 'Credit' => 'Avere',
+ 'Date' => 'Data',
+ 'Debit' => 'Dare',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Description' => 'Descrizione',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'From' => 'Dal',
+ 'GIFI' => 'Codice GIFI',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'List Transactions' => 'Lista Transazioni',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'Reference' => 'Riferimento',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Subtotal' => 'Totale Parziale',
+ 'to' => 'al',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'lista_transazioni' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/it/cp b/sql-ledger/locale/it/cp
new file mode 100644
index 0000000..3dacb5f
--- /dev/null
+++ b/sql-ledger/locale/it/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'Conto',
+ 'Address' => 'Indirizzo',
+ 'Amount' => 'Importo',
+ 'Amount does not equal applied!' => 'L\'importo non &egrave; uguale a quanto applicato alle diverse fatture!',
+ 'Amount missing!' => 'Manca l\'importo',
+ 'Applied' => 'Applicato a',
+ 'Cannot post payment!' => 'Non puoi salvare il pagamento!',
+ 'Cannot process payment for a closed period!' => 'Non puoi processare un pagamento per un periodo chiuso!',
+ 'Check' => 'Assegno',
+ 'Check printed!' => 'Assegno stampato!',
+ 'Check printing failed!' => 'Stampa dell\'assegno fallita!',
+ 'Continue' => 'Continua',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Cliente',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Date' => 'Data',
+ 'Date missing!' => 'Manca la data!',
+ 'Description' => 'Descrizione',
+ 'Due' => 'Dovuto',
+ 'Exchangerate' => 'Tasso di Cambio',
+ 'From' => 'Dal',
+ 'Invoice' => 'Fattura',
+ 'Invoices' => 'Fatture',
+ 'Nothing applied!' => 'Nulla di applicato!',
+ 'Number' => 'Numero',
+ 'Paid in full' => 'Pagato completamente',
+ 'Payment' => 'Pagamento',
+ 'Payment posted!' => 'Pagamento Salvato',
+ 'Post' => 'Salva',
+ 'Print' => 'Stampa',
+ 'Printer' => 'Stampante',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Receipt' => 'Incasso',
+ 'Receipt printed!' => 'Receipt printed!',
+ 'Receipt printing failed!' => 'Receipt printing failed!',
+ 'Reference' => 'Riferimento',
+ 'Screen' => 'Schermo',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Update' => 'Aggiorna',
+ 'Vendor' => 'Fornitore',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+ 'to' => 'al',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'continua' => 'continue',
+ 'salva' => 'post',
+ 'stampa' => 'print',
+ 'aggiorna' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/it/ct b/sql-ledger/locale/it/ct
new file mode 100644
index 0000000..12bfa6e
--- /dev/null
+++ b/sql-ledger/locale/it/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Aggiungi',
+ 'Address' => 'Indirizzo',
+ 'All' => 'Tutti',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Non puoi cancellare il cliente!',
+ 'Cannot delete vendor!' => 'Non puoi cancellare il fornitore',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contatto',
+ 'Continue' => 'Continua',
+ 'Credit Limit' => 'Fido',
+ 'Customer deleted!' => 'Cliente cancellato!',
+ 'Customer saved!' => 'Cliente salvato!',
+ 'Customers' => 'Clienti',
+ 'Delete' => 'Cancella',
+ 'Discount' => 'Sconto',
+ 'E-mail' => 'E-mail',
+ 'Edit Customer' => 'Edit Customer',
+ 'Edit Vendor' => 'Edit Vendor',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Invoice' => 'Fattura',
+ 'Name' => 'Nome',
+ 'Name missing!' => 'Manca il Nome!',
+ 'Notes' => 'Note',
+ 'Number' => 'Numero',
+ 'Order' => 'Ordine',
+ 'Orphaned' => 'Orfano',
+ 'Phone' => 'Tel.',
+ 'Save' => 'Salva',
+ 'Ship to' => 'Spedire a',
+ 'Tax Included' => 'Tasse Incluse',
+ 'Taxable' => 'Tassabile',
+ 'Terms: Net' => 'Termini: Netto',
+ 'Transactions exist, cannot delete customer!' => 'Impossibile cancellare il Cliente: ci sono transazioni a suo nome!',
+ 'Transactions exist, cannot delete vendor!' => 'Impossibile cancellare il Fornitore: ci sono transazioni a suo nome!',
+ 'Vendor deleted!' => 'Fornitore cancellato!',
+ 'Vendor saved!' => 'Fornitore salvato!',
+ 'Vendors' => 'Fornitori',
+ 'days' => 'giorni',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'aggiungi' => 'add',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'fattura' => 'invoice',
+ 'ordine' => 'order',
+ 'salva' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/it/gl b/sql-ledger/locale/it/gl
new file mode 100644
index 0000000..087fb3e
--- /dev/null
+++ b/sql-ledger/locale/it/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Transazione Fornitore',
+ 'AR Transaction' => 'Transazione Cliente',
+ 'Account' => 'Conto',
+ 'Add General Ledger Transaction' => 'Aggiungi Transazione di Contabilità Generale',
+ 'Address' => 'Indirizzo',
+ 'All' => 'Tutti',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Are you sure you want to delete Transaction' => 'Sei sicuro di voler cancellare la Transazione',
+ 'Asset' => 'Attivit&agrave;',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Saldo',
+ 'Cannot delete transaction!' => 'Non puoi cancellare la transazione',
+ 'Cannot have a value in both Debit and Credit!' => 'Non pu&ograve; esserci un valore sia in Dare che in Avere!',
+ 'Cannot post a transaction without a value!' => 'Non puoi salvare una transazione senza un valore!',
+ 'Cannot post transaction for a closed period!' => 'Non puoi salvare una transazione per un periodo chiuso!',
+ 'Confirm!' => 'Conferma!',
+ 'Continue' => 'Continua',
+ 'Credit' => 'Avere',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Date' => 'Data',
+ 'Debit' => 'Dare',
+ 'Debit and credit out of balance!' => 'Dare e Avere non concordano!.',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Delete' => 'Cancella',
+ 'Description' => 'Descrizione',
+ 'Edit General Ledger Transaction' => 'Modifica Transazione di Contabilit&agrave; Generale',
+ 'Equity' => 'Capitale',
+ 'Expense' => 'Uscite',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'From' => 'Dal',
+ 'GIFI' => 'Codice GIFI',
+ 'GL Transaction' => 'Transazione di Contabilit&agrave; generale',
+ 'General Ledger' => 'Contabilit&agrave; generale',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Income' => 'Entrate',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Liability' => 'Passivit&agrave;',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Notes' => 'Note',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Numero',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'Post' => 'Salva',
+ 'Post as new' => 'Salva come nuovo',
+ 'Project' => 'Progetto',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Purchase Invoice' => 'Fattura di acquisto',
+ 'Reference' => 'Riferimento',
+ 'Reference missing!' => 'Manca il riferimento!',
+ 'Reports' => 'Prospetti',
+ 'Sales Invoice' => 'Fattura di vendita',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Source' => 'Sorgente',
+ 'Subtotal' => 'Totale Parziale',
+ 'Transaction Date missing!' => 'Manca la data della transazione!',
+ 'Transaction deleted!' => 'Transazione cancellata!',
+ 'Transaction posted!' => 'Transazione salvata!',
+ 'Update' => 'Aggiorna',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+ 'Yes' => 'Si',
+ 'to' => 'al',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transazione_fornitore' => 'ap_transaction',
+ 'transazione_cliente' => 'ar_transaction',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'transazione_di_contabilit&agrave;_generale' => 'gl_transaction',
+ 'salva' => 'post',
+ 'salva_come_nuovo' => 'post_as_new',
+ 'fattura_di_acquisto' => 'purchase_invoice',
+ 'fattura_di_vendita' => 'sales_invoice',
+ 'aggiorna' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/it/ic b/sql-ledger/locale/it/ic
new file mode 100644
index 0000000..2f0dc95
--- /dev/null
+++ b/sql-ledger/locale/it/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => 'Attivo',
+ 'Add' => 'Aggiungi',
+ 'Add Assembly' => 'Aggiungi Assemblato',
+ 'Add Part' => 'Aggiungi Articolo',
+ 'Add Purchase Order' => 'Aggiungi Ordine di acquisto',
+ 'Add Sales Order' => 'Aggiungi Ordine di vendita',
+ 'Add Service' => 'Aggiungi Servizio',
+ 'Address' => 'Indirizzo',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Assemblies' => 'Assemblati',
+ 'Assemblies restocked!' => 'Assemblati ricaricati!',
+ 'Assembly Number missing!' => 'Manca il codice dell\'assemblato',
+ 'Attachment' => 'Allegato',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Codice BIN',
+ 'Bought' => 'Comprato',
+ 'COGS' => 'Costo dei Beni Venduti',
+ 'Cannot delete item already invoiced!' => 'Non puoi cancellare un articolo gi&agrave; fatturato!',
+ 'Cannot delete item on order!' => 'Non puoi cancellare un articolo ordinato!',
+ 'Cannot delete item which is part of an assembly!' => 'Non puoi cancellare un articolo che fa parte di un assemblato!',
+ 'Cannot delete item!' => 'Non puoi cancellare l\'articolo',
+ 'Cannot stock assemblies!' => 'Non puoi caricare gli assemblati!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contatto',
+ 'Continue' => 'Continua',
+ 'Copies' => 'Copie',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Delete' => 'Cancella',
+ 'Delivery Date' => 'Data di spedizione',
+ 'Description' => 'Descrizione',
+ 'Drawing' => 'Disegno',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Indirizzo e-mail mancante!',
+ 'Edit Assembly' => 'Modifica Assemblato',
+ 'Edit Part' => 'Modifica Articolo',
+ 'Edit Service' => 'Modifica Servizio',
+ 'Expense' => 'Uscite',
+ 'Extended' => 'Esteso',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'From' => 'Dal',
+ 'Image' => 'Immagine',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Income' => 'Entrate',
+ 'Individual Items' => 'Articoli Individuali',
+ 'Inventory' => 'Inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La quantit&agrave; in inventario deve essere zero per poter mettere l\'assemblato come obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La quantit&agrave; in inventario deve essere zero per poter mettere l\'articolo come obsoleto!',
+ 'Inventory quantity must be zero!' => 'La quantit&agrave; in inventario deve essere zero!',
+ 'Invoice' => 'Fattura',
+ 'Invoice Date missing!' => 'Manca la data della Fattura!',
+ 'Invoice Number' => 'Fattura Numero',
+ 'Invoice Number missing!' => 'Manca il numero della Fattura!',
+ 'Item deleted!' => 'Articolo Cancellato!',
+ 'Item not on file!' => 'Articolo non in archivio!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Last Cost' => 'Ultimo Costo',
+ 'Line Total' => 'Totale Linea',
+ 'Link Accounts' => 'Collegamenti tra Conti',
+ 'List Price' => 'Prezzo di Listino',
+ 'Make' => 'Produttore',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Message' => 'Messaggio',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modello',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Note',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Manca il codice nella riga',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'On Hand' => 'Disponibilit&agrave;',
+ 'On Order' => 'Mandato ordine fornitore',
+ 'Order' => 'Ordine',
+ 'Order Date missing!' => 'Manca la data dell\'ordine',
+ 'Order Number' => 'Ordine Numero',
+ 'Order Number missing!' => 'Manca il numero dell\'ordine!',
+ 'Ordered' => 'Ricevuto ordine da cliente',
+ 'Orphaned' => 'Orfano',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista Etichette',
+ 'Packing List Date missing!' => 'Manca la data della Packing List!',
+ 'Packing List Number missing!' => 'Manca il codice della Packing List!',
+ 'Part' => 'Articolo',
+ 'Part Number missing!' => 'Manca il Codice dell\'articolo!',
+ 'Parts' => 'Articoli',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prezzo',
+ 'Printer' => 'Stampante',
+ 'Project' => 'Progetto',
+ 'Purchase Order' => 'Ordine di acquisto',
+ 'Qty' => 'Q.t&agrave;',
+ 'ROP' => 'Soglia di Riordino',
+ 'Recd' => 'Ricevuto',
+ 'Required by' => 'Necessario dal',
+ 'Sales' => 'Vendite',
+ 'Sales Order' => 'Ordine di vendita',
+ 'Save' => 'Salva',
+ 'Screen' => 'Schermo',
+ 'Select from one of the items below' => 'Seleziona uno dei seguenti Articoli',
+ 'Select postscript or PDF!' => 'Scegli tra postscript e PDF!',
+ 'Sell Price' => 'Prezzo di Vendita',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Service' => 'Servizio',
+ 'Service Number missing!' => 'Manca il codice del servizio',
+ 'Services' => 'Servizi',
+ 'Ship' => 'Invio',
+ 'Ship to' => 'Spedire a',
+ 'Short' => 'Corto',
+ 'Sold' => 'Venduto',
+ 'Stock Assembly' => 'Magazzino Assemblati',
+ 'Subject' => 'Oggetto',
+ 'Subtotal' => 'Totale Parziale',
+ 'Tax' => 'Tassa',
+ 'To' => 'Al',
+ 'Top Level' => 'Livello Top',
+ 'Total' => 'Totale',
+ 'Unit' => 'Unit&agrave;',
+ 'Unit of measure' => 'Unit&agrave; di misura',
+ 'Update' => 'Aggiorna',
+ 'Updated' => 'Aggiornato',
+ 'Weight' => 'Peso',
+ 'What type of item is this?' => 'Che tipo di Articolo &egrave; questo?',
+ 'ea' => 'ci',
+ 'emailed to' => 'Mandato via e-mail a',
+ 'hr' => 'ore',
+ 'sent to printer' => 'mandato in stampa',
+ 'to' => 'al',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'aggiungi' => 'add',
+ 'aggiungi_assemblato' => 'add_assembly',
+ 'aggiungi_articolo' => 'add_part',
+ 'aggiungi_servizio' => 'add_service',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'modifica_assemblato' => 'edit_assembly',
+ 'modifica_articolo' => 'edit_part',
+ 'modifica_servizio' => 'edit_service',
+ 'salva' => 'save',
+ 'aggiorna' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/it/io b/sql-ledger/locale/it/io
new file mode 100644
index 0000000..2914945
--- /dev/null
+++ b/sql-ledger/locale/it/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Aggiungi Ordine di acquisto',
+ 'Add Sales Order' => 'Aggiungi Ordine di vendita',
+ 'Address' => 'Indirizzo',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Attachment' => 'Allegato',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Codice BIN',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contatto',
+ 'Continue' => 'Continua',
+ 'Copies' => 'Copie',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Delivery Date' => 'Data di spedizione',
+ 'Description' => 'Descrizione',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Indirizzo e-mail mancante!',
+ 'Extended' => 'Esteso',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Fattura',
+ 'Invoice Date missing!' => 'Manca la data della Fattura!',
+ 'Invoice Number missing!' => 'Manca il numero della Fattura!',
+ 'Item not on file!' => 'Articolo non in archivio!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Message' => 'Messaggio',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Manca il codice nella riga',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'Order' => 'Ordine',
+ 'Order Date missing!' => 'Manca la data dell\'ordine',
+ 'Order Number missing!' => 'Manca il numero dell\'ordine!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista Etichette',
+ 'Packing List Date missing!' => 'Manca la data della Packing List!',
+ 'Packing List Number missing!' => 'Manca il codice della Packing List!',
+ 'Part' => 'Articolo',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prezzo',
+ 'Printer' => 'Stampante',
+ 'Project' => 'Progetto',
+ 'Purchase Order' => 'Ordine di acquisto',
+ 'Qty' => 'Q.t&agrave;',
+ 'Recd' => 'Ricevuto',
+ 'Required by' => 'Necessario dal',
+ 'Sales Order' => 'Ordine di vendita',
+ 'Screen' => 'Schermo',
+ 'Select from one of the items below' => 'Seleziona uno dei seguenti Articoli',
+ 'Select postscript or PDF!' => 'Scegli tra postscript e PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Service' => 'Servizio',
+ 'Ship' => 'Invio',
+ 'Ship to' => 'Spedire a',
+ 'Subject' => 'Oggetto',
+ 'To' => 'Al',
+ 'Unit' => 'Unit&agrave;',
+ 'What type of item is this?' => 'Che tipo di Articolo &egrave; questo?',
+ 'emailed to' => 'Mandato via e-mail a',
+ 'sent to printer' => 'mandato in stampa',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continua' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/it/ir b/sql-ledger/locale/it/ir
new file mode 100644
index 0000000..242142e
--- /dev/null
+++ b/sql-ledger/locale/it/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Conto',
+ 'Add Purchase Invoice' => 'Aggiungi Fattura di acquisto',
+ 'Add Purchase Order' => 'Aggiungi Ordine di acquisto',
+ 'Add Sales Order' => 'Aggiungi Ordine di vendita',
+ 'Address' => 'Indirizzo',
+ 'Amount' => 'Importo',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Are you sure you want to delete Invoice Number' => 'Sei sicuro di voler cancellare la Fattura numero',
+ 'Attachment' => 'Allegato',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Codice BIN',
+ 'Cannot delete invoice!' => 'Non puoi cancellare la fattura!',
+ 'Cannot post invoice for a closed period!' => 'Non puoi salvare una transazione per un periodo chiuso!',
+ 'Cannot post invoice!' => 'Non puoi salvare la fattura!',
+ 'Cannot post payment for a closed period!' => 'Non puoi salvare pagamenti per un periodo chiuso!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Conferma!',
+ 'Contact' => 'Contatto',
+ 'Continue' => 'Continua',
+ 'Copies' => 'Copie',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data di Scadenza',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Delete' => 'Cancella',
+ 'Delivery Date' => 'Data di spedizione',
+ 'Description' => 'Descrizione',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Indirizzo e-mail mancante!',
+ 'Edit Purchase Invoice' => 'Modifica Fattura di acquisto',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasso di Cambio',
+ 'Exchangerate for payment missing!' => 'Manca il Tasso di Cambio per il pagamento!',
+ 'Exchangerate missing!' => 'Manca il Tasso di Cambio!',
+ 'Extended' => 'Esteso',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Fattura',
+ 'Invoice Date' => 'Data Fattura',
+ 'Invoice Date missing!' => 'Manca la data della Fattura!',
+ 'Invoice Number' => 'Fattura Numero',
+ 'Invoice Number missing!' => 'Manca il numero della Fattura!',
+ 'Invoice deleted!' => 'Fattura Cancellata!',
+ 'Invoice posted!' => 'Fattura Salvata!',
+ 'Item not on file!' => 'Articolo non in archivio!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Message' => 'Messaggio',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Note',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Manca il codice nella riga',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'Order' => 'Ordine',
+ 'Order Date missing!' => 'Manca la data dell\'ordine',
+ 'Order Number' => 'Ordine Numero',
+ 'Order Number missing!' => 'Manca il numero dell\'ordine!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista Etichette',
+ 'Packing List Date missing!' => 'Manca la data della Packing List!',
+ 'Packing List Number missing!' => 'Manca il codice della Packing List!',
+ 'Part' => 'Articolo',
+ 'Payment date missing!' => 'Manca la data del pagamento!',
+ 'Payments' => 'Pagamenti',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Salva',
+ 'Post as new' => 'Salva come nuovo',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prezzo',
+ 'Printer' => 'Stampante',
+ 'Project' => 'Progetto',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Purchase Order' => 'Ordine di acquisto',
+ 'Qty' => 'Q.t&agrave;',
+ 'Recd' => 'Ricevuto',
+ 'Record in' => 'Registra in',
+ 'Required by' => 'Necessario dal',
+ 'Sales Order' => 'Ordine di vendita',
+ 'Screen' => 'Schermo',
+ 'Select from one of the items below' => 'Seleziona uno dei seguenti Articoli',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Select postscript or PDF!' => 'Scegli tra postscript e PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Service' => 'Servizio',
+ 'Ship' => 'Invio',
+ 'Ship to' => 'Spedire a',
+ 'Source' => 'Sorgente',
+ 'Subject' => 'Oggetto',
+ 'Subtotal' => 'Totale Parziale',
+ 'Tax Included' => 'Tasse Incluse',
+ 'To' => 'Al',
+ 'Total' => 'Totale',
+ 'Unit' => 'Unit&agrave;',
+ 'Update' => 'Aggiorna',
+ 'Vendor' => 'Fornitore',
+ 'Vendor missing!' => 'Manca il fornitore!',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+ 'What type of item is this?' => 'Che tipo di Articolo &egrave; questo?',
+ 'Yes' => 'Si',
+ 'ea' => 'ci',
+ 'emailed to' => 'Mandato via e-mail a',
+ 'sent to printer' => 'mandato in stampa',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'ordine' => 'order',
+ 'salva' => 'post',
+ 'salva_come_nuovo' => 'post_as_new',
+ 'aggiorna' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/it/is b/sql-ledger/locale/it/is
new file mode 100644
index 0000000..beb9593
--- /dev/null
+++ b/sql-ledger/locale/it/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Conto',
+ 'Add Purchase Order' => 'Aggiungi Ordine di acquisto',
+ 'Add Sales Invoice' => 'Aggiungi Fattura di vendita',
+ 'Add Sales Order' => 'Aggiungi Ordine di vendita',
+ 'Address' => 'Indirizzo',
+ 'Amount' => 'Importo',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Are you sure you want to delete Invoice Number' => 'Sei sicuro di voler cancellare la Fattura numero',
+ 'Attachment' => 'Allegato',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Codice BIN',
+ 'Cannot delete invoice!' => 'Non puoi cancellare la fattura!',
+ 'Cannot post invoice for a closed period!' => 'Non puoi salvare una transazione per un periodo chiuso!',
+ 'Cannot post invoice!' => 'Non puoi salvare la fattura!',
+ 'Cannot post payment for a closed period!' => 'Non puoi salvare pagamenti per un periodo chiuso!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Conferma!',
+ 'Contact' => 'Contatto',
+ 'Continue' => 'Continua',
+ 'Copies' => 'Copie',
+ 'Credit Limit' => 'Fido',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Cliente mancante!',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data di Scadenza',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Delete' => 'Cancella',
+ 'Delivery Date' => 'Data di spedizione',
+ 'Description' => 'Descrizione',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Indirizzo e-mail mancante!',
+ 'Edit Sales Invoice' => 'Modifica Fattura di Vendita',
+ 'Exch' => 'Cambio',
+ 'Exchangerate' => 'Tasso di Cambio',
+ 'Exchangerate for payment missing!' => 'Manca il Tasso di Cambio per il pagamento!',
+ 'Exchangerate missing!' => 'Manca il Tasso di Cambio!',
+ 'Extended' => 'Esteso',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Fattura',
+ 'Invoice Date' => 'Data Fattura',
+ 'Invoice Date missing!' => 'Manca la data della Fattura!',
+ 'Invoice Number' => 'Fattura Numero',
+ 'Invoice Number missing!' => 'Manca il numero della Fattura!',
+ 'Invoice deleted!' => 'Fattura Cancellata!',
+ 'Invoice posted!' => 'Fattura Salvata!',
+ 'Item not on file!' => 'Articolo non in archivio!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Message' => 'Messaggio',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Note',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Manca il codice nella riga',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'Order' => 'Ordine',
+ 'Order Date missing!' => 'Manca la data dell\'ordine',
+ 'Order Number' => 'Ordine Numero',
+ 'Order Number missing!' => 'Manca il numero dell\'ordine!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista Etichette',
+ 'Packing List Date missing!' => 'Manca la data della Packing List!',
+ 'Packing List Number missing!' => 'Manca il codice della Packing List!',
+ 'Part' => 'Articolo',
+ 'Payment date missing!' => 'Manca la data del pagamento!',
+ 'Payments' => 'Pagamenti',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Salva',
+ 'Post as new' => 'Salva come nuovo',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prezzo',
+ 'Print' => 'Stampa',
+ 'Printer' => 'Stampante',
+ 'Project' => 'Progetto',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Purchase Order' => 'Ordine di acquisto',
+ 'Qty' => 'Q.t&agrave;',
+ 'Recd' => 'Ricevuto',
+ 'Record in' => 'Registra in',
+ 'Remaining' => 'Rimanente',
+ 'Required by' => 'Necessario dal',
+ 'Sales Order' => 'Ordine di vendita',
+ 'Screen' => 'Schermo',
+ 'Select from one of the items below' => 'Seleziona uno dei seguenti Articoli',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Select postscript or PDF!' => 'Scegli tra postscript e PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Service' => 'Servizio',
+ 'Ship' => 'Invio',
+ 'Ship to' => 'Spedire a',
+ 'Ship via' => 'Porto',
+ 'Source' => 'Sorgente',
+ 'Subject' => 'Oggetto',
+ 'Subtotal' => 'Totale Parziale',
+ 'Tax Included' => 'Tasse Incluse',
+ 'To' => 'Al',
+ 'Total' => 'Totale',
+ 'Unit' => 'Unit&agrave;',
+ 'Update' => 'Aggiorna',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+ 'What type of item is this?' => 'Che tipo di Articolo &egrave; questo?',
+ 'Yes' => 'Si',
+ 'ea' => 'ci',
+ 'emailed to' => 'Mandato via e-mail a',
+ 'sent to printer' => 'mandato in stampa',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'ordine' => 'order',
+ 'salva' => 'post',
+ 'salva_come_nuovo' => 'post_as_new',
+ 'stampa' => 'print',
+ 'spedire_a' => 'ship_to',
+ 'aggiorna' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/it/login b/sql-ledger/locale/it/login
new file mode 100644
index 0000000..aaca32d
--- /dev/null
+++ b/sql-ledger/locale/it/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Informazioni',
+ 'Database Host' => 'Server',
+ 'Dataset' => 'Dataset',
+ 'Incorrect Dataset version!' => 'Versione del Dataset non corretta!',
+ 'Incorrect Password!' => 'Password sbagliata!',
+ 'Licensed to' => 'Dato in Licenza a',
+ 'Login' => 'Login',
+ 'Name' => 'Nome',
+ 'Password' => 'Password',
+ 'User' => 'Utente',
+ 'Version' => 'Versione',
+ 'You are logged out!' => 'Sei disconnesso!',
+ 'You did not enter a name!' => 'Non hai inserito il nome!',
+ 'is not a member!' => 'non &eacute; un utente!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/it/menu b/sql-ledger/locale/it/menu
new file mode 100644
index 0000000..58ed36a
--- /dev/null
+++ b/sql-ledger/locale/it/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Debiti Fornitori',
+ 'AP Aging' => 'Partite Aperte',
+ 'AR' => 'Crediti Clienti',
+ 'AR Aging' => 'Partite Aperte',
+ 'Accounting Menu' => 'Menu Contabilit&agrave;',
+ 'Add Account' => 'Aggiungi conto',
+ 'Add Assembly' => 'Aggiungi Assemblato',
+ 'Add Customer' => 'Aggiungi Cliente',
+ 'Add GIFI' => 'Aggiungi codice GIFI',
+ 'Add Part' => 'Aggiungi Articolo',
+ 'Add Project' => 'Aggiungi Progetto',
+ 'Add Service' => 'Aggiungi Servizio',
+ 'Add Transaction' => 'Aggiungi Transazione',
+ 'Add Vendor' => 'Aggiungi Fornitore',
+ 'Assemblies' => 'Assemblati',
+ 'Audit Control' => 'Controllo accessi',
+ 'Backup' => 'Backup',
+ 'Balance Sheet' => 'Stato Patrimoniale',
+ 'Cash' => 'Cassa',
+ 'Chart of Accounts' => 'Piano dei Conti',
+ 'Check' => 'Assegno',
+ 'Customers' => 'Clienti',
+ 'General Ledger' => 'Contabilit&agrave; generale',
+ 'Goods & Services' => 'Beni e Servizi',
+ 'HTML Templates' => 'Modelli HTML',
+ 'Income Statement' => 'Conto Economico',
+ 'Invoice' => 'Fattura',
+ 'LaTeX Templates' => 'Modelli LaTeX',
+ 'List Accounts' => 'Lista Conti',
+ 'List GIFI' => 'Lista codici GIFI',
+ 'Logout' => 'Logout',
+ 'Order Entry' => 'Ordini',
+ 'Packing List' => 'Lista Etichette',
+ 'Parts' => 'Articoli',
+ 'Payment' => 'Pagamento',
+ 'Payments' => 'Pagamenti',
+ 'Preferences' => 'Preferenze',
+ 'Projects' => 'Progetti',
+ 'Purchase Invoice' => 'Fattura di acquisto',
+ 'Purchase Order' => 'Ordine di acquisto',
+ 'Purchase Orders' => 'Ordini di acquisto',
+ 'Receipt' => 'Incasso',
+ 'Receipts' => 'Incassi',
+ 'Reconciliation' => 'Conciliazione',
+ 'Reports' => 'Prospetti',
+ 'Sales Invoice' => 'Fattura di vendita',
+ 'Sales Order' => 'Ordine di vendita',
+ 'Sales Orders' => 'Ordini di vendita',
+ 'Save to File' => 'Salva su file',
+ 'Send by E-Mail' => 'Spedisci via e-mail',
+ 'Services' => 'Servizi',
+ 'Statement' => 'Sollecito',
+ 'Stock Assembly' => 'Magazzino Assemblati',
+ 'Stylesheet' => 'Foglio di Stile',
+ 'System' => 'Sistema',
+ 'Tax collected' => 'Debito IVA',
+ 'Tax paid' => 'Credito IVA',
+ 'Transactions' => 'Transazioni',
+ 'Trial Balance' => 'Bilancio di Verifica',
+ 'Vendors' => 'Fornitori',
+ 'Version' => 'Versione',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/it/oe b/sql-ledger/locale/it/oe
new file mode 100644
index 0000000..b14d61b
--- /dev/null
+++ b/sql-ledger/locale/it/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'Aggiungi',
+ 'Add Purchase Invoice' => 'Aggiungi Fattura di acquisto',
+ 'Add Purchase Order' => 'Aggiungi Ordine di acquisto',
+ 'Add Sales Invoice' => 'Aggiungi Fattura di vendita',
+ 'Add Sales Order' => 'Aggiungi Ordine di vendita',
+ 'Address' => 'Indirizzo',
+ 'Amount' => 'Importo',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Are you sure you want to delete Order Number' => 'Sei sicuro di voler cancellare l\'ordine numero',
+ 'Attachment' => 'Allegato',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Codice BIN',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Non puoi cancellare l\'ordine',
+ 'Cannot save order!' => 'Non puoi salvare l\'ordine!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Chiuso',
+ 'Confirm!' => 'Conferma!',
+ 'Contact' => 'Contatto',
+ 'Continue' => 'Continua',
+ 'Copies' => 'Copie',
+ 'Credit Limit' => 'Fido',
+ 'Curr' => 'Valuta',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Cliente mancante!',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Date' => 'Data',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Delete' => 'Cancella',
+ 'Delivery Date' => 'Data di spedizione',
+ 'Description' => 'Descrizione',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Indirizzo e-mail mancante!',
+ 'Edit Purchase Order' => 'Modifica Ordine di acquisto',
+ 'Edit Sales Order' => 'Modifica Ordine di vendita',
+ 'Exchangerate' => 'Tasso di Cambio',
+ 'Exchangerate missing!' => 'Manca il Tasso di Cambio!',
+ 'Extended' => 'Esteso',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'From' => 'Dal',
+ 'ID' => 'ID',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Invoice' => 'Fattura',
+ 'Invoice Date missing!' => 'Manca la data della Fattura!',
+ 'Invoice Number missing!' => 'Manca il numero della Fattura!',
+ 'Item not on file!' => 'Articolo non in archivio!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Message' => 'Messaggio',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Note',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Numero',
+ 'Number missing in Row' => 'Manca il codice nella riga',
+ 'O' => 'O',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'Open' => 'Aperto',
+ 'Order' => 'Ordine',
+ 'Order Date' => 'Data dell\'ordine',
+ 'Order Date missing!' => 'Manca la data dell\'ordine',
+ 'Order Number' => 'Ordine Numero',
+ 'Order Number missing!' => 'Manca il numero dell\'ordine!',
+ 'Order deleted!' => 'Ordine Cancellato!',
+ 'Order saved!' => 'Ordine Salvato!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista Etichette',
+ 'Packing List Date missing!' => 'Manca la data della Packing List!',
+ 'Packing List Number missing!' => 'Manca il codice della Packing List!',
+ 'Part' => 'Articolo',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prezzo',
+ 'Print' => 'Stampa',
+ 'Printer' => 'Stampante',
+ 'Project' => 'Progetto',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Purchase Order' => 'Ordine di acquisto',
+ 'Purchase Orders' => 'Ordini di acquisto',
+ 'Qty' => 'Q.t&agrave;',
+ 'Recd' => 'Ricevuto',
+ 'Remaining' => 'Rimanente',
+ 'Required by' => 'Necessario dal',
+ 'Sales Order' => 'Ordine di vendita',
+ 'Sales Orders' => 'Ordini di vendita',
+ 'Save' => 'Salva',
+ 'Save as new' => 'Salva come nuovo',
+ 'Screen' => 'Schermo',
+ 'Select from one of the items below' => 'Seleziona uno dei seguenti Articoli',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Select postscript or PDF!' => 'Scegli tra postscript e PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Service' => 'Servizio',
+ 'Ship' => 'Invio',
+ 'Ship to' => 'Spedire a',
+ 'Ship via' => 'Porto',
+ 'Subject' => 'Oggetto',
+ 'Subtotal' => 'Totale Parziale',
+ 'Tax' => 'Tassa',
+ 'Tax Included' => 'Tasse Incluse',
+ 'Terms: Net' => 'Termini: Netto',
+ 'To' => 'Al',
+ 'Total' => 'Totale',
+ 'Unit' => 'Unit&agrave;',
+ 'Update' => 'Aggiorna',
+ 'Vendor' => 'Fornitore',
+ 'Vendor missing!' => 'Manca il fornitore!',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+ 'What type of item is this?' => 'Che tipo di Articolo &egrave; questo?',
+ 'Yes' => 'Si',
+ 'days' => 'giorni',
+ 'ea' => 'ci',
+ 'emailed to' => 'Mandato via e-mail a',
+ 'sent to printer' => 'mandato in stampa',
+ 'to' => 'al',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'aggiungi' => 'add',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'fattura' => 'invoice',
+ 'stampa' => 'print',
+ 'salva' => 'save',
+ 'salva_come_nuovo' => 'save_as_new',
+ 'spedire_a' => 'ship_to',
+ 'aggiorna' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/it/pe b/sql-ledger/locale/it/pe
new file mode 100644
index 0000000..c37877b
--- /dev/null
+++ b/sql-ledger/locale/it/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Aggiungi',
+ 'Add Project' => 'Aggiungi Progetto',
+ 'All' => 'Tutti',
+ 'Continue' => 'Continua',
+ 'Delete' => 'Cancella',
+ 'Description' => 'Descrizione',
+ 'Edit Project' => 'Modifica Progetto',
+ 'Number' => 'Numero',
+ 'Orphaned' => 'Orfano',
+ 'Project' => 'Progetto',
+ 'Project Number missing!' => 'Manca il codice del progetto!',
+ 'Project deleted!' => 'Progetto cancellato!',
+ 'Project saved!' => 'Progetto salvato!',
+ 'Projects' => 'Progetti',
+ 'Save' => 'Salva',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'aggiungi' => 'add',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'salva' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/it/qe b/sql-ledger/locale/it/qe
new file mode 100644
index 0000000..67da640
--- /dev/null
+++ b/sql-ledger/locale/it/qe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Aggiungi',
+ 'Add Purchase Invoice' => 'Aggiungi Fattura di acquisto',
+ 'Add Purchase Order' => 'Aggiungi Ordine di acquisto',
+ 'Add Sales Invoice' => 'Aggiungi Fattura di vendita',
+ 'Add Sales Order' => 'Aggiungi Ordine di vendita',
+ 'Address' => 'Indirizzo',
+ 'Amount' => 'Importo',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Are you sure you want to delete Order Number' => 'Sei sicuro di volre cancellare l\'ordine numero',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Codice BIN',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Non puoi cancellare l\'ordine',
+ 'Cannot save order!' => 'Non puoi salvare l\'ordine!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Chiuso',
+ 'Confirm!' => 'Conferma!',
+ 'Contact' => 'Contatto',
+ 'Continue' => 'Continua',
+ 'Copies' => 'Copie',
+ 'Credit Limit' => 'Fido',
+ 'Curr' => 'Valuta',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Cliente mancante!',
+ 'Customer not on file!' => 'Cliente non sul file!',
+ 'Date' => 'Data',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Delete' => 'Cancella',
+ 'Delivery Date' => 'Data di spedizione',
+ 'Description' => 'Descrizione',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Indirizzo e-mail mancante!',
+ 'Edit Purchase Order' => 'Modifica Ordine di acquisto',
+ 'Edit Sales Order' => 'Modifica Ordine di vendita',
+ 'Exchangerate' => 'Tasso di Cambio',
+ 'Exchangerate missing!' => 'Manca il Tasso di Cambio!',
+ 'Extended' => 'Esteso',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'From' => 'Dal',
+ 'ID' => 'ID',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Invoice' => 'Fattura',
+ 'Invoice Date missing!' => 'Manca la data della Fattura!',
+ 'Invoice Number missing!' => 'Manca il numero della Fattura!',
+ 'Item not on file!' => 'Articolo non in archivio!',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Message' => 'Messaggio',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Note',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Number' => 'Partita IVA',
+ 'Number missing in Row' => 'Manca il codice nella riga',
+ 'O' => 'O',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'Open' => 'Aperto',
+ 'Order' => 'Ordine',
+ 'Order Date' => 'Data dell\'ordine',
+ 'Order Date missing!' => 'Manca la data dell\'ordine',
+ 'Order Number' => 'Ordine Numero',
+ 'Order Number missing!' => 'Manca il numero dell\'ordine!',
+ 'Order deleted!' => 'Ordine Cancellato!',
+ 'Order saved!' => 'Ordine Salvato!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista Etichette',
+ 'Packing List Date missing!' => 'Manca la data della Packing List!',
+ 'Packing List Number missing!' => 'Manca il codice della Packing List!',
+ 'Part' => 'Articolo',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prezzo',
+ 'Print' => 'Stampa',
+ 'Printer' => 'Stampante',
+ 'Project' => 'Progetto',
+ 'Project not on file!' => 'Progetto non archiviato!',
+ 'Purchase Order' => 'Ordine di acquisto',
+ 'Purchase Orders' => 'Ordini di acquisto',
+ 'Qty' => 'Q.t&agrave;',
+ 'Recd' => 'Ricevuto',
+ 'Remaining' => 'Rimanente',
+ 'Required by' => 'Necessario dal',
+ 'Sales Order' => 'Ordine di vendita',
+ 'Sales Orders' => 'Ordini di vendita',
+ 'Save' => 'Salva',
+ 'Save as new' => 'Salva come nuovo',
+ 'Screen' => 'Schermo',
+ 'Select from one of the items below' => 'Seleziona uno dei seguenti Articoli',
+ 'Select from one of the names below' => 'Seleziona uno dei seguenti nomi',
+ 'Select from one of the projects below' => 'Seleziona uno dei seguenti progetti',
+ 'Select postscript or PDF!' => 'Scegli tra postscript e PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Service' => 'Servizio',
+ 'Ship' => 'Invio',
+ 'Ship to' => 'Spedire a',
+ 'Ship via' => 'Porto',
+ 'Subject' => 'Oggetto',
+ 'Subtotal' => 'Totale Parziale',
+ 'Tax' => 'Tassa',
+ 'Tax Included' => 'Tasse Incluse',
+ 'Terms: Net' => 'Termini: Netto',
+ 'To' => 'Al',
+ 'Total' => 'Totale',
+ 'Unit' => 'Unit&agrave;',
+ 'Update' => 'Aggiorna',
+ 'Vendor' => 'Fornitore',
+ 'Vendor missing!' => 'Manca il fornitore!',
+ 'Vendor not on file!' => 'Fornitore non in archivio!',
+ 'What type of item is this?' => 'Che tipo di Articolo &egrave; questo?',
+ 'Yes' => 'Si',
+ 'days' => 'giorni',
+ 'ea' => 'ci',
+ 'emailed to' => 'Mandato via e-mail a',
+ 'sent to printer' => 'mandato in stampa',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'aggiungi' => 'add',
+ 'continua' => 'continue',
+ 'cancella' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'fattura' => 'invoice',
+ 'stampa' => 'print',
+ 'salva' => 'save',
+ 'salva_come_nuovo' => 'save_as_new',
+ 'spedire_a' => 'ship_to',
+ 'aggiorna' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/it/rc b/sql-ledger/locale/it/rc
new file mode 100644
index 0000000..48aa805
--- /dev/null
+++ b/sql-ledger/locale/it/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Conto',
+ 'Balance' => 'Saldo',
+ 'Cleared Balance' => 'Saldo gi&agrave; Conciliato',
+ 'Continue' => 'Continua',
+ 'Date' => 'Data',
+ 'Deposit' => 'Deposito',
+ 'Description' => 'Descrizione',
+ 'Difference' => 'Differenza',
+ 'Done' => 'Fatto',
+ 'Exchangerate Difference' => 'Differenza sul Tasso di Cambio',
+ 'From' => 'Dal',
+ 'Out of balance!' => 'Non conciliato!',
+ 'Payment' => 'Pagamento',
+ 'Reconciliation' => 'Conciliazione',
+ 'Select all' => 'Seleziona tutto',
+ 'Source' => 'Sorgente',
+ 'Statement Balance' => 'Saldo',
+ 'Update' => 'Aggiorna',
+ 'to' => 'al',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continua' => 'continue',
+ 'fatto' => 'done',
+ 'seleziona_tutto' => 'select_all',
+ 'aggiorna' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/it/rp b/sql-ledger/locale/it/rp
new file mode 100644
index 0000000..3a8c51a
--- /dev/null
+++ b/sql-ledger/locale/it/rp
@@ -0,0 +1,120 @@
+$self{texts} = {
+ 'AP Aging' => 'Partite Aperte',
+ 'AR Aging' => 'Partite Aperte',
+ 'Account' => 'Conto',
+ 'Accounts' => 'Conti',
+ 'Amount' => 'Importo',
+ 'Apr' => 'Apr',
+ 'April' => 'Aprile',
+ 'Attachment' => 'Allegato',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Saldo',
+ 'Balance Sheet' => 'Stato Patrimoniale',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Basato sulla cassa',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Confronta con',
+ 'Continue' => 'Continua',
+ 'Copies' => 'Copie',
+ 'Credit' => 'Avere',
+ 'Current' => 'Corrente',
+ 'Customer' => 'Cliente',
+ 'Date' => 'Data',
+ 'Debit' => 'Dare',
+ 'Dec' => 'Dic',
+ 'December' => 'Dicembre',
+ 'Decimalplaces' => 'Numero di decimali',
+ 'Department' => 'Department',
+ 'Description' => 'Descrizione',
+ 'Due' => 'Dovuto',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'Manda il sollecito via e-mail a',
+ 'Feb' => 'Feb',
+ 'February' => 'Febbraio',
+ 'From' => 'Dal',
+ 'GIFI' => 'Codice GIFI',
+ 'Heading' => 'Intestazione',
+ 'ID' => 'ID',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Includi nel Prospetto',
+ 'Income Statement' => 'Conto Economico',
+ 'Invoice' => 'Fattura',
+ 'Jan' => 'Gen',
+ 'January' => 'Gennaio',
+ 'Jul' => 'Lug',
+ 'July' => 'Luglio',
+ 'Jun' => 'Giu',
+ 'June' => 'Giugno',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'Mag',
+ 'May ' => 'Mag ',
+ 'Message' => 'Messaggio',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Non hai selezionato nulla!',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembre',
+ 'Oct' => 'Ott',
+ 'October' => 'Ottobre',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Pagamenti',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Stampa',
+ 'Printer' => 'Stampante',
+ 'Project Number' => 'Project Number',
+ 'Receipts' => 'Incassi',
+ 'Report for' => 'Prospetto per',
+ 'Retained Earnings' => 'Guadagni',
+ 'Screen' => 'Schermo',
+ 'Select all' => 'Seleziona tutto',
+ 'Select postscript or PDF!' => 'Scegli tra postscript e PDF!',
+ 'Sep' => 'Set',
+ 'September' => 'Settembre',
+ 'Source' => 'Sorgente',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Sollecito',
+ 'Statement sent to' => 'Sollecito mandato a',
+ 'Statements sent to printer!' => 'Solleciti mandati in stampa!',
+ 'Subject' => 'Oggetto',
+ 'Subtotal' => 'Totale Parziale',
+ 'Tax' => 'Tassa',
+ 'Tax collected' => 'Debito IVA',
+ 'Tax paid' => 'Credito IVA',
+ 'Total' => 'Totale',
+ 'Trial Balance' => 'Bilancio di Verifica',
+ 'Vendor' => 'Fornitore',
+ 'as at' => 'Al',
+ 'collected on sales' => 'incassate su vendite',
+ 'for Period' => 'per il Periodo',
+ 'paid on purchases' => 'pagato sugli acquisti',
+ 'to' => 'al',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continua' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'stampa' => 'print',
+ 'seleziona_tutto' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/COPYING b/sql-ledger/locale/lt/COPYING
new file mode 100644
index 0000000..763715b
--- /dev/null
+++ b/sql-ledger/locale/lt/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2003
+#
+# Lithuanian texts:
+#
+# Author:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/lt/LANGUAGE b/sql-ledger/locale/lt/LANGUAGE
new file mode 100644
index 0000000..dc243c5
--- /dev/null
+++ b/sql-ledger/locale/lt/LANGUAGE
@@ -0,0 +1 @@
+Lithuanian
diff --git a/sql-ledger/locale/lt/admin b/sql-ledger/locale/lt/admin
new file mode 100644
index 0000000..83cfc84
--- /dev/null
+++ b/sql-ledger/locale/lt/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Priëjimo kontrolë',
+ 'Accounting' => 'Apskaita',
+ 'Add User' => 'Pridëti Vartotojà',
+ 'Address' => 'Adresas',
+ 'Administration' => 'Administracija',
+ 'Administrator' => 'Administratorius',
+ 'All Datasets up to date!' => 'All Datasets up to date!',
+ 'Change Admin Password' => 'Pakeisti Administratoriaus slaptaþodá',
+ 'Change Password' => 'Pakeisti slaptaþodá',
+ 'Character Set' => 'Simboliø aibë',
+ 'Click on login name to edit!' => 'Paspauskit prisijungimo vardà redagavimui!',
+ 'Company' => 'Firma',
+ 'Connect to' => 'Prisijungti prie',
+ 'Continue' => 'Tæsti',
+ 'Create Chart of Accounts' => 'Sukûrti sàskaitø planà',
+ 'Create Dataset' => 'Sukûrti duomenø aibæ',
+ 'DBI not installed!' => 'DBI ne instaliuotas!',
+ 'Database' => 'Duomenø bazë',
+ 'Database Administration' => 'Duomenø bazës administravimas',
+ 'Database Driver not checked!' => 'Duomenø bazës tvarkiklë nepatikrinta!',
+ 'Database User missing!' => 'Duomenø bazës vartotojo nëra!',
+ 'Dataset' => 'Duomenø aibë',
+ 'Dataset missing!' => 'Duomenø aibës nëra!',
+ 'Dataset updated!' => 'Duomenø aibë atnaujinta!',
+ 'Date Format' => 'Datos Formatas',
+ 'Delete' => 'Iðtrinti',
+ 'Delete Dataset' => 'Iðtrinti Duomenø aibë',
+ 'Directory' => 'Direktorija',
+ 'Driver' => 'Tvarkyklë',
+ 'Dropdown Limit' => 'Iðsiskleidþianèio meniu riba',
+ 'E-mail' => 'E-paðtas',
+ 'Edit User' => 'Redaguoti vartotojà',
+ 'Existing Datasets' => 'Egzistuojanèios duomenø aibës',
+ 'Fax' => 'Faksas',
+ 'Host' => 'Hostas',
+ 'Hostname missing!' => 'Hosto vardo nëra!',
+ 'Incorrect Password!' => 'Neteisingas slaptaþodis!',
+ 'Language' => 'Kalba',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Lokaliam prisijungimui palikite hosto ir porto laukelius tuðèiais',
+ 'Login' => 'Prisijungimas',
+ 'Multibyte Encoding' => 'Multibaitinë kodiruotë',
+ 'Name' => 'Vardas',
+ 'New Templates' => 'Nauji ðablonai',
+ 'No Database Drivers available!' => 'Nëra Duomenø baziø tvarkykliø!',
+ 'No Dataset selected!' => 'Duomenø aibë neiðrinkta!',
+ 'Nothing to delete!' => 'Nëra ko trinti!',
+ 'Number Format' => 'Skaièiaus formatas',
+ 'Oracle Database Administration' => 'Oracle Duomenø bazës Administravimas',
+ 'Password' => 'Slaptaþodis',
+ 'Password changed!' => 'Slaptaþodis pakeistas!',
+ 'Pg Database Administration' => 'Pg Duomenø bazës Administravimas',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Portas',
+ 'Port missing!' => 'Porto numerio nëra!',
+ 'Printer' => 'Spausdintuvas',
+ 'Save' => 'Iðsaugoti',
+ 'Select a Dataset to delete and press "Continue"' => 'Iðrinkite Duomenø aibæ trinimui ir paspauskite "Tæsti"',
+ 'Setup Templates' => 'Nustatyti ðablonus',
+ 'Ship via' => 'Pristatyti per',
+ 'Signature' => 'Paraðas',
+ 'Stylesheet' => 'Stiliø lentelë',
+ 'Templates' => 'Ðablonai',
+ 'The following Datasets are not in use and can be deleted' => 'Ðios duomenø aibës nëra naudojamos ir gali bûti iðtrintos',
+ 'The following Datasets need to be updated' => 'Ðios duomenø aibës turi bûti atnaujintos',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Èia preliminarus egzistuojanèiø ðaltiniø patikrinimas. Niekas negali bûti sukurta arba iðtrinta ðioje stadijoje.',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Kad pridëti vartotojà á grupæ redaguokite vardà, pakeiskite prisijungimo vardà ir iðsaugokite. Bus sukurtas naujas vartotojas su tais paèiais kintamaisiais ir nauju prisijungimo vardu',
+ 'Update Dataset' => 'Atnaujinti Duomenø Aibæ',
+ 'Use Templates' => 'Naudoti ðablonus',
+ 'User' => 'Vartotojas',
+ 'User deleted!' => 'Vartotojas iðtrintas!',
+ 'User saved!' => 'Vartotojas iðsaugotas!',
+ 'Version' => 'Versija',
+ 'You must enter a host and port for local and remote connections!' => 'Turite ávesti hostà ir portà lokalioms ir nuotoliniams prisijungimams!',
+ 'does not exist' => 'ne egzistuoja',
+ 'is already a member!' => 'jau narys',
+ 'localhost' => 'lokalhostas',
+ 'locked!' => 'uþblokuotas',
+ 'successfully created!' => 'sëkmingai sukurta',
+ 'successfully deleted!' => 'sëkmingai iðtrinta',
+ 'website' => 'Websaitas',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'pridëti_vartotojà' => 'add_user',
+ 'pakeisti_administratoriaus_slaptaþodá' => 'change_admin_password',
+ 'pakeisti_slaptaþodá' => 'change_password',
+ 'tæsti' => 'continue',
+ 'sukûrti_duomenø_aibæ' => 'create_dataset',
+ 'iðtrinti' => 'delete',
+ 'iðtrinti_duomenø_aibë' => 'delete_dataset',
+ 'prisijungimas' => 'login',
+ 'oracle_duomenø_bazës_administravimas' => 'oracle_database_administration',
+ 'pg_duomenø_bazës_administravimas' => 'pg_database_administration',
+ 'iðsaugoti' => 'save',
+ 'atnaujinti_duomenø_aibæ' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/all b/sql-ledger/locale/lt/all
new file mode 100644
index 0000000..93a8771
--- /dev/null
+++ b/sql-ledger/locale/lt/all
@@ -0,0 +1,497 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Pirkimai',
+ 'AP Aging' => 'Pirkimo Skolos',
+ 'AP Transaction' => 'Pirkimo Operacijà',
+ 'AP Transactions' => 'Pirkimo Operacijos',
+ 'AR' => 'Pardavimai',
+ 'AR Aging' => 'Pardavimo Skolos',
+ 'AR Transaction' => 'Pardavimo Operacijà',
+ 'AR Transactions' => 'Pardavimo Operacijos',
+ 'About' => 'Apie...',
+ 'Access Control' => 'Priëjimo kontrolë',
+ 'Account' => 'Sàskaita',
+ 'Account Number' => 'Sàskaitos numeris',
+ 'Account Number missing!' => 'Sàskaitos numerio nëra!',
+ 'Account Type' => 'Sàskaitos tipas',
+ 'Account Type missing!' => 'Sàskaitos tipo nëra!',
+ 'Account deleted!' => 'Sàskaitos iðtrintos',
+ 'Account saved!' => 'Sàskaitos iðsaugotos',
+ 'Accounting' => 'Apskaita',
+ 'Accounting Menu' => 'Apskaitos Menu',
+ 'Accounts' => 'Sàskaitos',
+ 'Active' => 'Aktyvus',
+ 'Add' => 'Pridëti',
+ 'Add Account' => 'Pridëti sàskaità',
+ 'Add Accounts Payables Transaction' => 'Pridëti Pirkimo Sàskaitas Operacijà',
+ 'Add Accounts Receivables Transaction' => 'Pridëti Pardavimo Sàskaitas Operacijà',
+ 'Add Assembly' => 'Pridëti rinkiná',
+ 'Add Customer' => 'Pridëti klientà',
+ 'Add GIFI' => 'Pridëti GIFI',
+ 'Add General Ledger Transaction' => 'Pridëti Bendroji Þurnalo Operacijà',
+ 'Add Part' => 'Pridëti prekæ',
+ 'Add Project' => 'Pridëti proektà',
+ 'Add Purchase Order' => 'Pridëti Pirkimo uþsakymà',
+ 'Add Sales Invoice' => 'Pridëti Pardavimo sàskaità-faktûrà',
+ 'Add Sales Order' => 'Pridëti Pardavimo uþsakymà',
+ 'Add Service' => 'Pridëti Paslaugà',
+ 'Add Transaction' => 'Pridëti Operacijà',
+ 'Add User' => 'Pridëti Vartotojà',
+ 'Add Vendor' => 'Pridëti Tiekëja',
+ 'Add Vendor Invoice' => '',
+ 'Address' => 'Adresas',
+ 'Administration' => 'Administracija',
+ 'Administrator' => 'Administratorius',
+ 'All' => 'Visi',
+ 'All Datasets up to date!' => 'All Datasets up to date!',
+ 'Amount' => 'Suma',
+ 'Amount Due' => 'Suma iki',
+ 'Amount does not equal applied!' => 'Suma ne lygi pritaikytai!',
+ 'Amount missing!' => 'Nëra sumos!',
+ 'Applied' => 'Pritaikyta',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Are you sure you want to delete Invoice Number' => 'Ar Jus tikrai norite iðtrinti saskaitu-fakturos numeris:',
+ 'Are you sure you want to delete Order Number' => 'Ar Jus tikrai norite iðtrinti uzsakimas numeris:',
+ 'Are you sure you want to delete Transaction' => 'Ar Jus tikrai norite iðtrinti operacijà?',
+ 'Assemblies' => 'Rinkiniai',
+ 'Assemblies restocked!' => 'Rinkiniai persandeliuoti!',
+ 'Assembly Number missing!' => 'Rinkiniø numeriø nëra!',
+ 'Asset' => 'Turtas',
+ 'Attachment' => 'Prisegta',
+ 'Audit Control' => 'Audito kontrolë',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'BOM' => 'BOM',
+ 'Backup' => 'Reservinë kopija',
+ 'Backup sent to' => 'Reservinë kopija iðsiusta á',
+ 'Balance' => 'Balansas',
+ 'Balance Sheet' => 'Balanso lëntelë',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Dëþë',
+ 'Books are open' => 'Þurnalai atidaryti',
+ 'Bought' => 'Nupirkta',
+ 'Business Number' => 'Ámonës kodas',
+ 'C' => 'C',
+ 'COGS' => 'PPS',
+ 'Cannot delete account!' => 'Neámanoma iðtrinti sàskaitos!',
+ 'Cannot delete customer!' => 'Neámanoma iðtrinti kliento!',
+ 'Cannot delete default account!' => 'Neámanoma iðtrinti sàskaitos pagal nutylejimà!',
+ 'Cannot delete invoice!' => 'Neámanoma iðtrinti sàskaitos-faktûros!',
+ 'Cannot delete item already invoiced!' => 'Negalima iðtrinti prekës, kuriai sukurta sàskaita-faktûra!',
+ 'Cannot delete item on order!' => 'Negalima iðtrinti prekës, kuri yra uþsakyme!',
+ 'Cannot delete item which is part of an assembly!' => 'Negalima iðtrinti prekës, kuri yra rinkinio dalis!',
+ 'Cannot delete item!' => 'Neámanoma iðtrinti prekës!',
+ 'Cannot delete order!' => 'Neámanoma iðtrinti uþsakymo!',
+ 'Cannot delete transaction!' => 'Neámanoma iðtrinti operacijos!',
+ 'Cannot delete vendor!' => 'Neámanoma iðtrinti tiekëjo!',
+ 'Cannot have a value in both Debit and Credit!' => 'Negalima turëti tos paèios reikðmës Debete ir Kredite!',
+ 'Cannot post a transaction without a value!' => 'Neámanoma patvirtinti operacijos be reikðmës!',
+ 'Cannot post invoice for a closed period!' => 'Neámanoma patvirtinti sàskaitos-faktûros uþdarajam periodui!',
+ 'Cannot post invoice!' => 'Neámanoma patvirtinti sàskaitos-faktûros!',
+ 'Cannot post payment for a closed period!' => 'Neámanoma patvirtinti mokëjimo uþdarajam periodui!',
+ 'Cannot post payment!' => 'Neámanoma patvirtinti mokëjimo!',
+ 'Cannot post transaction for a closed period!' => 'Neámanoma patvirtinti operacijos uþdarajam periodui!',
+ 'Cannot post transaction!' => 'Neámanoma patvirtinti operacijos!',
+ 'Cannot process payment for a closed period!' => 'Neámanoma vykdyti mokëjimo uþdarajam periodui!',
+ 'Cannot save account!' => 'Neámanoma iðsaugoti sàskaitos!',
+ 'Cannot save order!' => 'Neámanoma iðsaugoti uþsakymo!',
+ 'Cannot save preferences!' => 'Neámanoma iðsaugoti nuostatø!',
+ 'Cannot stock assemblies!' => 'Neámanoma sandelioti rinkinius!',
+ 'Cash' => 'Kasa',
+ 'Cash based' => 'Grynais',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => 'Pakeisti Administratoriaus slaptaþodá',
+ 'Change Password' => 'Pakeisti slaptaþodá',
+ 'Character Set' => 'Simboliø aibë',
+ 'Chart of Accounts' => 'Sàskaitø planas',
+ 'Check' => 'Èekis',
+ 'Check printed!' => 'Èekis atspausdintas!',
+ 'Check printing failed!' => 'Èekio spausdinimas nepavyko!',
+ 'Cleared Balance' => 'Baigiamasis balansas',
+ 'Click on login name to edit!' => 'Paspauskit prisijungimo vardà redagavimui!',
+ 'Close Books up to' => 'Uþdaryti þurnalus iki',
+ 'Closed' => 'Uþdaryta',
+ 'Company' => 'Firma',
+ 'Compare to' => 'Palyginti su',
+ 'Confirm!' => 'Patvirtinti!',
+ 'Connect to' => 'Prisijungti prie',
+ 'Contact' => 'Kontaktas',
+ 'Continue' => 'Tæsti',
+ 'Copies' => 'Kopijos',
+ 'Copy to COA' => 'Kopijuoti á SP',
+ 'Create Chart of Accounts' => 'Sukûrti sàskaitø planà',
+ 'Create Dataset' => 'Sukûrti duomenø aibæ',
+ 'Credit' => 'Kreditas',
+ 'Credit Limit' => 'Kredito riba',
+ 'Curr' => 'Val.',
+ 'Currency' => 'Valiûta',
+ 'Current' => 'Dabartinis',
+ 'Customer' => 'Klientas',
+ 'Customer deleted!' => 'Klientas iðtrintas!',
+ 'Customer missing!' => 'Kliento vardo nëra!',
+ 'Customer not on file!' => 'Tokio kliento nëra!',
+ 'Customer saved!' => 'Klientas iðsaugotas!',
+ 'Customers' => 'Klientai',
+ 'DBI not installed!' => 'DBI ne instaliuotas!',
+ 'Database' => 'Duomenø bazë',
+ 'Database Administration' => 'Duomenø bazës administravimas',
+ 'Database Driver not checked!' => 'Duomenø bazës tvarkiklë nepatikrinta!',
+ 'Database Host' => 'Duomenø bazës hostas',
+ 'Database User missing!' => 'Duomenø bazës vartotojo nëra!',
+ 'Dataset' => 'Duomenø aibë',
+ 'Dataset missing!' => 'Duomenø aibës nëra!',
+ 'Dataset updated!' => 'Duomenø aibë atnaujinta!',
+ 'Date' => 'Data',
+ 'Date Format' => 'Datos Formatas',
+ 'Date Paid' => 'Mokëjimo Data',
+ 'Date missing!' => 'Datos nëra!',
+ 'Debit' => 'Debetas',
+ 'Debit and credit out of balance!' => 'Debetas ir Kreditas nesubalansuoti!',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Decimalplaces' => 'Skaièiø po taðko',
+ 'Delete' => 'Iðtrinti',
+ 'Delete Account' => 'Iðtrinti sàskaità',
+ 'Delete Dataset' => 'Iðtrinti Duomenø aibë',
+ 'Delivery Date' => 'Prystatimo Data',
+ 'Department' => '',
+ 'Deposit' => 'Depozitas',
+ 'Description' => 'Apraðymas',
+ 'Difference' => 'Skirtumas',
+ 'Directory' => 'Direktorija',
+ 'Discount' => 'Nuolaidos',
+ 'Done' => 'Ávykdyta',
+ 'Drawing' => 'Brieþinys',
+ 'Driver' => 'Tvarkyklë',
+ 'Dropdown Limit' => 'Iðsiskleidþianèio meniu riba',
+ 'Due' => 'Iki',
+ 'Due Date' => 'Iki Data',
+ 'Due Date missing!' => 'Nëra Iki Datos!',
+ 'E-mail' => 'E-paðtas',
+ 'E-mail Statement to' => 'Suvestinæ suisti per e-pastà á',
+ 'E-mail address missing!' => 'E-paðto adreso nëra!',
+ 'Edit' => 'Redaguoti',
+ 'Edit Account' => 'Redaguoti sàskaità',
+ 'Edit Accounts Payables Transaction' => 'Redaguoti pirkimo sàskaitø operacijià',
+ 'Edit Accounts Receivables Transaction' => 'Redaguoti pardavimo sàskaitø operacijià',
+ 'Edit Assembly' => 'Redaguoti rinkiná',
+ 'Edit Customer' => 'Redaguoti Klientà',
+ 'Edit GIFI' => 'Redaguoti GIFI',
+ 'Edit General Ledger Transaction' => 'Redaguoti Bendrojo Þurnalo operacijà',
+ 'Edit Part' => 'Redaguoti prekæ',
+ 'Edit Preferences for' => 'Redaguoti nuostatas...',
+ 'Edit Project' => 'Redaguoti projektà',
+ 'Edit Purchase Order' => 'Redaguoti pirkimo uþsakymà',
+ 'Edit Sales Invoice' => 'Redaguoti pardavimo sàskaità-faktûrà',
+ 'Edit Sales Order' => 'Redaguoti pardavimo uþsakymà',
+ 'Edit Service' => 'Redaguoti paslaugà',
+ 'Edit Template' => 'Redaguoti ðablonà',
+ 'Edit User' => 'Redaguoti vartotojà',
+ 'Edit Vendor' => 'Redaguoti Tiekijà',
+ 'Edit Vendor Invoice' => '',
+ 'Employee' => 'Darbuotojas',
+ 'Enforce transaction reversal for all dates' => 'Reversuoti operacijas visoms datoms',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Áveskite iki 3-jø raidþiø, iðskirtø taðkais (Pvz. LTL:EUR:USD:YEN) savo ir uþsienio valiutoms paþymëti',
+ 'Equity' => 'Turtas/Nuosavybë',
+ 'Exch' => 'Kurs.',
+ 'Exchangerate' => 'Keitimo kursas',
+ 'Exchangerate Difference' => 'Keitimo kurso skirtumas',
+ 'Exchangerate for payment missing!' => 'Mokëjimo keitimo kurso nëra!',
+ 'Exchangerate missing!' => 'Keitimo kurso nëra!',
+ 'Existing Datasets' => 'Egzistuojanèios duomenø aibës',
+ 'Expense' => 'Sànaudos',
+ 'Expense Account' => 'Sànaudø sàskaita',
+ 'Expense/Asset' => 'Sànaudos/Aktyvai',
+ 'Extended' => 'Iðplësta',
+ 'Fax' => 'Faksas',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'Foreign Exchange Gain' => 'Valiûtos keitimo pelnas',
+ 'Foreign Exchange Loss' => 'Valiûtos keitimo nuostolis',
+ 'From' => 'Nuo',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI iðtrintas!',
+ 'GIFI missing!' => 'GIFI nëra!',
+ 'GIFI saved!' => 'GIFI iðsaugotas!',
+ 'GL Transaction' => 'BÞ operacija',
+ 'General Ledger' => 'Bendrasis þurnalas',
+ 'Goods & Services' => 'Prekës ir Paslaugos',
+ 'Group' => '',
+ 'Group Items' => '',
+ 'HTML Templates' => 'HTML ðablonai',
+ 'Heading' => 'Antraðtë',
+ 'Host' => 'Hostas',
+ 'Hostname missing!' => 'Hosto vardo nëra!',
+ 'ID' => 'ID',
+ 'Image' => 'Pieðinys',
+ 'In-line' => 'Vienaeilis',
+ 'Include in Report' => 'Ádëti á ataskaità',
+ 'Include in drop-down menus' => 'Ádëti á iðsáskleidþianèius meniu',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Ádëti ðià sàskaità á kliento/tiekëjo formas, kad paþymëti klientà/tiekëjà kaip apmokestinamà?',
+ 'Income' => 'Pajamos',
+ 'Income Account' => 'Pajamø sàskaita',
+ 'Income Statement' => 'Pelno/nuostolio ataskaita',
+ 'Incorrect Dataset version!' => 'Neteisinga duomenø aibës versija!',
+ 'Incorrect Password!' => 'Neteisingas slaptaþodis!',
+ 'Individual Items' => 'Individualios prekës',
+ 'Inventory' => 'Prekës',
+ 'Inventory Account' => 'Prekës sàskaita',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Prekës kiekis turi bûti lygus nuliui prieð paþymint rinkiná pasenusiu!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Prekës kiekis turi bûti lygus nuliui prieð paþymint ðià dalá pasenusia!',
+ 'Inventory quantity must be zero!' => 'Prekës kiekis turi bûti lygus nuliui!',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Invoice Date' => 'Sàskaitos-faktûros data',
+ 'Invoice Date missing!' => 'Sàskaitos-faktûros datos nëra!',
+ 'Invoice Number' => 'Sàskaitos-faktûros numeris',
+ 'Invoice Number missing!' => 'Sàskaitos-faktûra numerio nëra!',
+ 'Invoice deleted!' => 'Sàskaitos-faktûra iðtrintos!',
+ 'Invoice posted!' => 'Sàskaitos-faktûra patvirtintos!',
+ 'Invoices' => 'Sàskaitos-faktûros',
+ 'Is this a summary account to record' => 'Ar èia apibendrinta áraðo sàskaita',
+ 'Item deleted!' => 'Vienetas iðtrintas!',
+ 'Item not on file!' => 'Vieneto nëra áraðuose!',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'LaTeX Templates' => 'LaTeX ðablonai',
+ 'Language' => 'Kalba',
+ 'Last Cost' => 'Paskutinë kaina',
+ 'Last Invoice Number' => 'Paskutinës sàskaitos-faktûros numeris',
+ 'Last Numbers & Default Accounts' => 'Paskutinieji numeriai ir sàskaitos pagal nutylëjimà',
+ 'Last Purchase Order Number' => 'Paskutinio pirkimo uþsakymo numeris',
+ 'Last Sales Order Number' => 'Paskutinio pardavimo uþsakymo numeris',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Lokaliam prisijungimui palikite hosto ir porto laukelius tuðèiais',
+ 'Liability' => 'Nuosavybë',
+ 'Licensed to' => 'Licenzijuota...',
+ 'Line Total' => 'Viso eilutëje',
+ 'Link' => 'Ryðys',
+ 'Link Accounts' => 'Suriðti sàskaitas',
+ 'List Accounts' => 'Sàskaitø sàraðas',
+ 'List GIFI' => 'GIFI sàraðas',
+ 'List Price' => 'Pirkimo kaina',
+ 'List Transactions' => 'Parodyti operacijas',
+ 'Login' => 'Prisijungimas',
+ 'Logout' => 'Iðsijungti',
+ 'Make' => 'Gamintojas',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Message' => 'Þinutë',
+ 'Microfiche' => 'Mikrofiða',
+ 'Model' => 'Modelis',
+ 'Multibyte Encoding' => 'Multibaitinë kodiruotë',
+ 'N/A' => 'N/A',
+ 'Name' => 'Vardas',
+ 'Name missing!' => 'Pavadinimo nëra',
+ 'New Templates' => 'Nauji ðablonai',
+ 'No' => 'Ne',
+ 'No Database Drivers available!' => 'Nëra Duomenø baziø tvarkykliø!',
+ 'No Dataset selected!' => 'Duomenø aibë neiðrinkta!',
+ 'No email address for' => 'Nëra e-paðto adreso...',
+ 'No.' => 'Num',
+ 'Notes' => 'Pastaba',
+ 'Nothing applied!' => 'Niekas nepanaudota!',
+ 'Nothing selected!' => 'Nieko neiðrinkta!',
+ 'Nothing to delete!' => 'Nëra ko trinti!',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Number' => 'Numeris',
+ 'Number Format' => 'Skaièiaus formatas',
+ 'Number missing in Row' => 'Numerio nëra eilëje',
+ 'O' => 'O',
+ 'Obsolete' => 'Pasenæ',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'On Hand' => 'Likutis',
+ 'On Order' => 'Uþsakyme',
+ 'Open' => 'Atidaryti',
+ 'Oracle Database Administration' => 'Oracle Duomenø bazës Administravimas',
+ 'Order' => 'Uþsakymas',
+ 'Order Date' => 'Uþsakymo data',
+ 'Order Date missing!' => 'Uþsakymo datos nëra!',
+ 'Order Entry' => 'Uþsakymo áraðas',
+ 'Order Number' => 'Uþsakymo numeris',
+ 'Order Number missing!' => 'Uþsakymo numerio nëra!',
+ 'Order deleted!' => 'Uþsakymai iðtrinti!',
+ 'Order saved!' => 'Uþsakymas iðsaugotas!',
+ 'Ordered' => 'Uþsakyta',
+ 'Orphaned' => 'Naðlaitinis',
+ 'Out of balance!' => 'Nesubalansuota!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Ápakavimo sàraðas',
+ 'Packing List Date missing!' => 'Ápakavimo sàraðo datos nëra!',
+ 'Packing List Number missing!' => 'Ápakavimo sàraðo numerio nëra!',
+ 'Paid' => 'Apmokëta',
+ 'Paid in full' => 'Pilnai apmokëta',
+ 'Part' => 'Prekë',
+ 'Part Number missing!' => 'Prekës numerio nëra!',
+ 'Parts' => 'Prekës',
+ 'Parts Inventory' => 'Prekiø saraðas',
+ 'Password' => 'Slaptaþodis',
+ 'Password changed!' => 'Slaptaþodis pakeistas!',
+ 'Payables' => 'Pirkimai',
+ 'Payment' => 'Mokëjimas',
+ 'Payment date missing!' => 'Mokëjimo datos nëra',
+ 'Payment posted!' => 'Mokëjimas patvirtintas!',
+ 'Payments' => 'Mokëjimai',
+ 'Pg Database Administration' => 'Pg Duomenø bazës Administravimas',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Portas',
+ 'Port missing!' => 'Porto numerio nëra!',
+ 'Post' => 'Patvirtinti',
+ 'Post as new' => 'Patvirtinti kaip naujà',
+ 'Postscript' => 'Postscript(TM)',
+ 'Preferences' => 'Nuostatos',
+ 'Preferences saved!' => 'Nuostatos iðsaugotos!',
+ 'Price' => 'Kaina',
+ 'Print' => 'Spausdinti',
+ 'Printer' => 'Spausdintuvas',
+ 'Project' => 'Projektas',
+ 'Project Number' => '',
+ 'Project Number missing!' => 'Projekto numerio nëra!',
+ 'Project deleted!' => 'Projektas iðtrintas!',
+ 'Project not on file!' => 'Nëra tokio projekto!',
+ 'Project saved!' => 'Projektas iðsaugotas!',
+ 'Projects' => 'Projektai',
+ 'Purchase Order' => 'Pirkimo uþsakymas',
+ 'Purchase Orders' => 'Pirkimo uþsakymai',
+ 'Qty' => 'Kks',
+ 'ROP' => 'ROP',
+ 'Rate' => 'Kursas',
+ 'Recd' => 'Gaut',
+ 'Receipt' => 'Kasos orderis',
+ 'Receipt printed!' => '',
+ 'Receipt printing failed!' => '',
+ 'Receipts' => 'Kasos orderiai',
+ 'Receivables' => 'Pardavimai',
+ 'Reconciliation' => 'Sutaikinimas',
+ 'Record in' => 'Áraðyti á',
+ 'Reference' => 'Nuorodos',
+ 'Reference missing!' => 'Nuorodos nëra!',
+ 'Remaining' => 'Likutis',
+ 'Report for' => 'Ataskaita...',
+ 'Reports' => 'Ataskaitos',
+ 'Required by' => 'Iki kada',
+ 'Retained Earnings' => 'Turimi uþdarbiai',
+ 'Sales' => 'Pardavimai',
+ 'Sales Invoice' => 'Pardavimo SF',
+ 'Sales Order' => 'Pardavimø uþsakymas',
+ 'Sales Orders' => 'Pardavimø uþsakymai',
+ 'Salesperson' => '',
+ 'Save' => 'Iðsaugoti',
+ 'Save as new' => 'Iðsaugoti kaip naujà',
+ 'Save to File' => 'Iðsaugoti á failà',
+ 'Screen' => 'Ekranas',
+ 'Select a Dataset to delete and press "Continue"' => 'Iðrinkite Duomenø aibæ trinimui ir paspauskite "Tæsti"',
+ 'Select all' => 'Iðrinkti viskà',
+ 'Select from one of the items below' => 'Iðrinkite vienà ið prekiø apaèioje',
+ 'Select from one of the names below' => 'Iðrinkite vienà ið pavadinimø apaèioje',
+ 'Select from one of the projects below' => 'Iðrinkite vienà ið projektø apaèioje',
+ 'Select postscript or PDF!' => 'Iðrinkite postscript arba PDF!',
+ 'Sell Price' => 'Pardavimo kaina',
+ 'Send by E-Mail' => 'Iðsiûsti e-paðtu',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Service' => 'Paslauga',
+ 'Service Items' => 'Paslaugø sàraðas',
+ 'Service Number missing!' => 'Paslaugos numerio nëra!',
+ 'Services' => 'Paslaugos',
+ 'Setup Templates' => 'Nustatyti ðablonus',
+ 'Ship' => 'Pristatymas',
+ 'Ship to' => 'Pristatyti á',
+ 'Ship via' => 'Pristatyti per',
+ 'Short' => 'Stoka',
+ 'Signature' => 'Paraðas',
+ 'Sold' => 'Parduota',
+ 'Source' => 'Dokumentas',
+ 'Standard' => 'Standartas',
+ 'Statement' => 'Suvestinë',
+ 'Statement Balance' => 'Balanso suvestinë',
+ 'Statement sent to' => 'Siusti suvestinæ á',
+ 'Statements sent to printer!' => 'Siusti suvestinæ á spausdintuvà!',
+ 'Stock Assembly' => 'Rinkiniai sandëlyje',
+ 'Stylesheet' => 'Stiliø lentelë',
+ 'Subject' => 'Dalykas',
+ 'Subtotal' => 'Viso',
+ 'System' => 'Sistema',
+ 'Tax' => 'Mokëstis',
+ 'Tax Accounts' => 'Mokesèiø sàskaitos',
+ 'Tax Included' => 'su mokesèiais',
+ 'Tax collected' => 'Mokesèiai surinkti',
+ 'Tax paid' => 'Mokesèiai sumokëti',
+ 'Taxable' => 'Apmokestinama',
+ 'Template saved!' => 'Ðablonai iðsaugoti!',
+ 'Templates' => 'Ðablonai',
+ 'Terms: Net' => 'Terminas: ',
+ 'The following Datasets are not in use and can be deleted' => 'Ðios duomenø aibës nëra naudojamos ir gali bûti iðtrintos',
+ 'The following Datasets need to be updated' => 'Ðios duomenø aibës turi bûti atnaujintos',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Èia preliminarus egzistuojanèiø ðaltiniø patikrinimas. Niekas negali bûti sukurta arba iðtrinta ðioje stadijoje.',
+ 'To' => 'iki',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Kad pridëti vartotojà á grupæ redaguokite vardà, pakeiskite prisijungimo vardà ir iðsaugokite. Bus sukurtas naujas vartotojas su tais paèiais kintamaisiais ir nauju prisijungimo vardu',
+ 'Top Level' => 'Aukðèiausias lygis',
+ 'Total' => 'Ið viso',
+ 'Transaction Date missing!' => 'Operacijos datos nëra!',
+ 'Transaction deleted!' => 'Operacija iðtrinta!',
+ 'Transaction posted!' => 'Operacija patvirtinta!',
+ 'Transaction reversal enforced for all dates' => 'Operacijos bus reversuojamos visoms datoms',
+ 'Transaction reversal enforced up to' => 'Operacijos bus reversuojamos iki',
+ 'Transactions' => 'Operacijos',
+ 'Transactions exist, cannot delete customer!' => 'Operacijos egzistuoja, negalima iðtrinti kliento!',
+ 'Transactions exist, cannot delete vendor!' => 'Operacijos egzistuoja, negalima iðtrinti tiekëjo!',
+ 'Transactions exist; cannot delete account!' => 'Operacijos egzistuoja, negalima iðtrinti sàskaitos!',
+ 'Trial Balance' => 'Bandomasis balansas',
+ 'Unit' => 'Vienetas',
+ 'Unit of measure' => 'Matavimo vienetas',
+ 'Update' => 'Atnaujinti',
+ 'Update Dataset' => 'Atnaujinti Duomenø Aibæ',
+ 'Updated' => 'Atnaujinta',
+ 'Use Templates' => 'Naudoti ðablonus',
+ 'User' => 'Vartotojas',
+ 'User deleted!' => 'Vartotojas iðtrintas!',
+ 'User saved!' => 'Vartotojas iðsaugotas!',
+ 'Vendor' => 'Tiekëjas',
+ 'Vendor Invoice' => '',
+ 'Vendor deleted!' => 'Tiekëjas iðtrintas!',
+ 'Vendor missing!' => 'Tiekëjo Vardo nëra!',
+ 'Vendor not on file!' => 'Tokio tiekëjo nëra!',
+ 'Vendor saved!' => 'Tiekëjai iðsaugoti',
+ 'Vendors' => 'Tiekëjai',
+ 'Version' => 'Versija',
+ 'Weight' => 'Svoris',
+ 'Weight Unit' => 'Svorio vienetas.',
+ 'What type of item is this?' => 'Koks ðio dalyko tipas?',
+ 'Year End' => 'Metø pabaiga',
+ 'Yes' => 'Taip',
+ 'You are logged out!' => 'Jûs iðsijungëte!',
+ 'You did not enter a name!' => 'Neávedëte vardo!',
+ 'You must enter a host and port for local and remote connections!' => 'Turite ávesti hostà ir portà lokalioms ir nuotoliniams prisijungimams!',
+ 'as at' => 'kaip',
+ 'collected on sales' => 'surinkta per pardavimus',
+ 'days' => 'dienos',
+ 'does not exist' => 'ne egzistuoja',
+ 'ea' => 'kk',
+ 'emailed to' => 'email do',
+ 'for Period' => 'periodui',
+ 'hr' => 'val',
+ 'is already a member!' => 'jau narys',
+ 'is not a member!' => 'nëra narys!',
+ 'localhost' => 'lokalhostas',
+ 'locked!' => 'uþblokuotas',
+ 'paid on purchases' => 'apmokëta per pirkimus',
+ 'sent to printer' => 'pasiûsta á spausdintuvà',
+ 'successfully created!' => 'sëkmingai sukurta',
+ 'successfully deleted!' => 'sëkmingai iðtrinta',
+ 'to' => 'iki',
+ 'website' => 'Websaitas',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/am b/sql-ledger/locale/lt/am
new file mode 100644
index 0000000..4796a2b
--- /dev/null
+++ b/sql-ledger/locale/lt/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Pirkimai',
+ 'AR' => 'Pardavimai',
+ 'Account' => 'Sàskaita',
+ 'Account Number' => 'Sàskaitos numeris',
+ 'Account Number missing!' => 'Sàskaitos numerio nëra!',
+ 'Account Type' => 'Sàskaitos tipas',
+ 'Account Type missing!' => 'Sàskaitos tipo nëra!',
+ 'Account deleted!' => 'Sàskaitos iðtrintos',
+ 'Account saved!' => 'Sàskaitos iðsaugotos',
+ 'Add Account' => 'Pridëti sàskaità',
+ 'Add GIFI' => 'Pridëti GIFI',
+ 'Address' => 'Adresas',
+ 'Asset' => 'Turtas',
+ 'Audit Control' => 'Audito kontrolë',
+ 'Backup sent to' => 'Reservinë kopija iðsiusta á',
+ 'Books are open' => 'Þurnalai atidaryti',
+ 'Business Number' => 'Ámonës kodas',
+ 'COGS' => 'PPS',
+ 'Cannot delete account!' => 'Neámanoma iðtrinti sàskaitos!',
+ 'Cannot delete default account!' => 'Neámanoma iðtrinti sàskaitos pagal nutylejimà!',
+ 'Cannot save account!' => 'Neámanoma iðsaugoti sàskaitos!',
+ 'Cannot save preferences!' => 'Neámanoma iðsaugoti nuostatø!',
+ 'Character Set' => 'Simboliø aibë',
+ 'Chart of Accounts' => 'Sàskaitø planas',
+ 'Close Books up to' => 'Uþdaryti þurnalus iki',
+ 'Company' => 'Firma',
+ 'Continue' => 'Tæsti',
+ 'Copy to COA' => 'Kopijuoti á SP',
+ 'Credit' => 'Kreditas',
+ 'Date Format' => 'Datos Formatas',
+ 'Debit' => 'Debetas',
+ 'Delete' => 'Iðtrinti',
+ 'Delete Account' => 'Iðtrinti sàskaità',
+ 'Description' => 'Apraðymas',
+ 'Dropdown Limit' => 'Iðsiskleidþianèio meniu riba',
+ 'E-mail' => 'E-paðtas',
+ 'Edit' => 'Redaguoti',
+ 'Edit Account' => 'Redaguoti sàskaità',
+ 'Edit GIFI' => 'Redaguoti GIFI',
+ 'Edit Preferences for' => 'Redaguoti nuostatas...',
+ 'Edit Template' => 'Redaguoti ðablonà',
+ 'Enforce transaction reversal for all dates' => 'Reversuoti operacijas visoms datoms',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Áveskite iki 3-jø raidþiø, iðskirtø taðkais (Pvz. LTL:EUR:USD:YEN) savo ir uþsienio valiutoms paþymëti',
+ 'Equity' => 'Turtas/Nuosavybë',
+ 'Expense' => 'Sànaudos',
+ 'Expense Account' => 'Sànaudø sàskaita',
+ 'Expense/Asset' => 'Sànaudos/Aktyvai',
+ 'Fax' => 'Faksas',
+ 'Foreign Exchange Gain' => 'Valiûtos keitimo pelnas',
+ 'Foreign Exchange Loss' => 'Valiûtos keitimo nuostolis',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI iðtrintas!',
+ 'GIFI missing!' => 'GIFI nëra!',
+ 'GIFI saved!' => 'GIFI iðsaugotas!',
+ 'Heading' => 'Antraðtë',
+ 'Include in drop-down menus' => 'Ádëti á iðsáskleidþianèius meniu',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Ádëti ðià sàskaità á kliento/tiekëjo formas, kad paþymëti klientà/tiekëjà kaip apmokestinamà?',
+ 'Income' => 'Pajamos',
+ 'Income Account' => 'Pajamø sàskaita',
+ 'Inventory' => 'Prekës',
+ 'Inventory Account' => 'Prekës sàskaita',
+ 'Is this a summary account to record' => 'Ar èia apibendrinta áraðo sàskaita',
+ 'Language' => 'Kalba',
+ 'Last Invoice Number' => 'Paskutinës sàskaitos-faktûros numeris',
+ 'Last Numbers & Default Accounts' => 'Paskutinieji numeriai ir sàskaitos pagal nutylëjimà',
+ 'Last Purchase Order Number' => 'Paskutinio pirkimo uþsakymo numeris',
+ 'Last Sales Order Number' => 'Paskutinio pardavimo uþsakymo numeris',
+ 'Liability' => 'Nuosavybë',
+ 'Link' => 'Ryðys',
+ 'Name' => 'Vardas',
+ 'No' => 'Ne',
+ 'No email address for' => 'Nëra e-paðto adreso...',
+ 'Number' => 'Numeris',
+ 'Number Format' => 'Skaièiaus formatas',
+ 'Parts Inventory' => 'Prekiø saraðas',
+ 'Password' => 'Slaptaþodis',
+ 'Payables' => 'Pirkimai',
+ 'Payment' => 'Mokëjimas',
+ 'Phone' => 'Tel.',
+ 'Preferences saved!' => 'Nuostatos iðsaugotos!',
+ 'Rate' => 'Kursas',
+ 'Receivables' => 'Pardavimai',
+ 'Sales' => 'Pardavimai',
+ 'Save' => 'Iðsaugoti',
+ 'Service Items' => 'Paslaugø sàraðas',
+ 'Ship via' => 'Pristatyti per',
+ 'Signature' => 'Paraðas',
+ 'Stylesheet' => 'Stiliø lentelë',
+ 'Tax' => 'Mokëstis',
+ 'Tax Accounts' => 'Mokesèiø sàskaitos',
+ 'Template saved!' => 'Ðablonai iðsaugoti!',
+ 'Transaction reversal enforced for all dates' => 'Operacijos bus reversuojamos visoms datoms',
+ 'Transaction reversal enforced up to' => 'Operacijos bus reversuojamos iki',
+ 'Transactions exist; cannot delete account!' => 'Operacijos egzistuoja, negalima iðtrinti sàskaitos!',
+ 'Weight Unit' => 'Svorio vienetas.',
+ 'Year End' => 'Metø pabaiga',
+ 'Yes' => 'Taip',
+ 'does not exist' => 'ne egzistuoja',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'pridëti_sàskaità' => 'add_account',
+ 'tæsti' => 'continue',
+ 'kopijuoti_á_sp' => 'copy_to_coa',
+ 'iðtrinti' => 'delete',
+ 'redaguoti' => 'edit',
+ 'redaguoti_sàskaità' => 'edit_account',
+ 'iðsaugoti' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/ap b/sql-ledger/locale/lt/ap
new file mode 100644
index 0000000..749dbfb
--- /dev/null
+++ b/sql-ledger/locale/lt/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Pirkimo Operacijà',
+ 'AP Transactions' => 'Pirkimo Operacijos',
+ 'Account' => 'Sàskaita',
+ 'Add Accounts Payables Transaction' => 'Pridëti Pirkimo Sàskaitas Operacijà',
+ 'Address' => 'Adresas',
+ 'Amount' => 'Suma',
+ 'Amount Due' => 'Suma iki',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Are you sure you want to delete Transaction' => 'Ar Jus tikrai norite iðtrinti operacijà?',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'Cannot delete transaction!' => 'Neámanoma iðtrinti operacijos!',
+ 'Cannot post payment for a closed period!' => 'Neámanoma patvirtinti mokëjimo uþdarajam periodui!',
+ 'Cannot post transaction for a closed period!' => 'Neámanoma patvirtinti operacijos uþdarajam periodui!',
+ 'Cannot post transaction!' => 'Neámanoma patvirtinti operacijos!',
+ 'Closed' => 'Uþdaryta',
+ 'Confirm!' => 'Patvirtinti!',
+ 'Continue' => 'Tæsti',
+ 'Currency' => 'Valiûta',
+ 'Customer not on file!' => 'Tokio kliento nëra!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Mokëjimo Data',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Delete' => 'Iðtrinti',
+ 'Description' => 'Apraðymas',
+ 'Due Date' => 'Iki Data',
+ 'Due Date missing!' => 'Nëra Iki Datos!',
+ 'Edit Accounts Payables Transaction' => 'Redaguoti pirkimo sàskaitø operacijià',
+ 'Employee' => 'Darbuotojas',
+ 'Exch' => 'Kurs.',
+ 'Exchangerate' => 'Keitimo kursas',
+ 'Exchangerate for payment missing!' => 'Mokëjimo keitimo kurso nëra!',
+ 'Exchangerate missing!' => 'Keitimo kurso nëra!',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'From' => 'Nuo',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Ádëti á ataskaità',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Invoice Date' => 'Sàskaitos-faktûros data',
+ 'Invoice Date missing!' => 'Sàskaitos-faktûros datos nëra!',
+ 'Invoice Number' => 'Sàskaitos-faktûros numeris',
+ 'Invoice Number missing!' => 'Sàskaitos-faktûra numerio nëra!',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Notes' => 'Pastaba',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Number' => 'Numeris',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'Open' => 'Atidaryti',
+ 'Order' => 'Uþsakymas',
+ 'Order Number' => 'Uþsakymo numeris',
+ 'Paid' => 'Apmokëta',
+ 'Payment date missing!' => 'Mokëjimo datos nëra',
+ 'Payments' => 'Mokëjimai',
+ 'Post' => 'Patvirtinti',
+ 'Post as new' => 'Patvirtinti kaip naujà',
+ 'Project' => 'Projektas',
+ 'Project not on file!' => 'Nëra tokio projekto!',
+ 'Select from one of the names below' => 'Iðrinkite vienà ið pavadinimø apaèioje',
+ 'Select from one of the projects below' => 'Iðrinkite vienà ið projektø apaèioje',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Source' => 'Dokumentas',
+ 'Subtotal' => 'Viso',
+ 'Tax' => 'Mokëstis',
+ 'Tax Included' => 'su mokesèiais',
+ 'Total' => 'Ið viso',
+ 'Transaction deleted!' => 'Operacija iðtrinta!',
+ 'Transaction posted!' => 'Operacija patvirtinta!',
+ 'Update' => 'Atnaujinti',
+ 'Vendor' => 'Tiekëjas',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendor missing!' => 'Tiekëjo Vardo nëra!',
+ 'Vendor not on file!' => 'Tokio tiekëjo nëra!',
+ 'Yes' => 'Taip',
+ 'to' => 'iki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'pirkimo_operacijà' => 'ap_transaction',
+ 'pridëti_pirkimo_sàskaitas_operacijà' => 'add_accounts_payables_transaction',
+ 'tæsti' => 'continue',
+ 'iðtrinti' => 'delete',
+ 'redaguoti_pirkimo_sàskaitø_operacijià' => 'edit_accounts_payables_transaction',
+ 'patvirtinti' => 'post',
+ 'patvirtinti_kaip_naujà' => 'post_as_new',
+ 'atnaujinti' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'taip' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/ar b/sql-ledger/locale/lt/ar
new file mode 100644
index 0000000..1b5616d
--- /dev/null
+++ b/sql-ledger/locale/lt/ar
@@ -0,0 +1,134 @@
+$self{texts} = {
+ 'AR Transaction' => 'Pardavimo Operacijà',
+ 'AR Transactions' => 'Pardavimo Operacijos',
+ 'Account' => 'Sàskaita',
+ 'Add Accounts Receivables Transaction' => 'Pridëti Pardavimo Sàskaitas Operacijà',
+ 'Address' => 'Adresas',
+ 'Amount' => 'Suma',
+ 'Amount Due' => 'Suma iki',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Are you sure you want to delete Transaction' => 'Ar Jus tikrai norite iðtrinti operacijà?',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'Cannot delete transaction!' => 'Neámanoma iðtrinti operacijos!',
+ 'Cannot post payment for a closed period!' => 'Neámanoma patvirtinti mokëjimo uþdarajam periodui!',
+ 'Cannot post transaction for a closed period!' => 'Neámanoma patvirtinti operacijos uþdarajam periodui!',
+ 'Cannot post transaction!' => 'Neámanoma patvirtinti operacijos!',
+ 'Closed' => 'Uþdaryta',
+ 'Confirm!' => 'Patvirtinti!',
+ 'Continue' => 'Tæsti',
+ 'Credit Limit' => 'Kredito riba',
+ 'Currency' => 'Valiûta',
+ 'Customer' => 'Klientas',
+ 'Customer missing!' => 'Kliento vardo nëra!',
+ 'Customer not on file!' => 'Tokio kliento nëra!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Mokëjimo Data',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Delete' => 'Iðtrinti',
+ 'Description' => 'Apraðymas',
+ 'Due Date' => 'Iki Data',
+ 'Due Date missing!' => 'Nëra Iki Datos!',
+ 'Edit Accounts Receivables Transaction' => 'Redaguoti pardavimo sàskaitø operacijià',
+ 'Exch' => 'Kurs.',
+ 'Exchangerate' => 'Keitimo kursas',
+ 'Exchangerate for payment missing!' => 'Mokëjimo keitimo kurso nëra!',
+ 'Exchangerate missing!' => 'Keitimo kurso nëra!',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'From' => 'Nuo',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Ádëti á ataskaità',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Invoice Date' => 'Sàskaitos-faktûros data',
+ 'Invoice Date missing!' => 'Sàskaitos-faktûros datos nëra!',
+ 'Invoice Number' => 'Sàskaitos-faktûros numeris',
+ 'Invoice Number missing!' => 'Sàskaitos-faktûra numerio nëra!',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Notes' => 'Pastaba',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Number' => 'Numeris',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'Open' => 'Atidaryti',
+ 'Order' => 'Uþsakymas',
+ 'Order Number' => 'Uþsakymo numeris',
+ 'Paid' => 'Apmokëta',
+ 'Payment date missing!' => 'Mokëjimo datos nëra',
+ 'Payments' => 'Mokëjimai',
+ 'Post' => 'Patvirtinti',
+ 'Post as new' => 'Patvirtinti kaip naujà',
+ 'Project' => 'Projektas',
+ 'Project not on file!' => 'Nëra tokio projekto!',
+ 'Remaining' => 'Likutis',
+ 'Sales Invoice' => 'Pardavimo SF',
+ 'Salesperson' => 'Salesperson',
+ 'Select from one of the names below' => 'Iðrinkite vienà ið pavadinimø apaèioje',
+ 'Select from one of the projects below' => 'Iðrinkite vienà ið projektø apaèioje',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Ship via' => 'Pristatyti per',
+ 'Source' => 'Dokumentas',
+ 'Subtotal' => 'Viso',
+ 'Tax' => 'Mokëstis',
+ 'Tax Included' => 'su mokesèiais',
+ 'Total' => 'Ið viso',
+ 'Transaction deleted!' => 'Operacija iðtrinta!',
+ 'Transaction posted!' => 'Operacija patvirtinta!',
+ 'Update' => 'Atnaujinti',
+ 'Vendor not on file!' => 'Tokio tiekëjo nëra!',
+ 'Yes' => 'Taip',
+ 'to' => 'iki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'pardavimo_operacijà' => 'ar_transaction',
+ 'tæsti' => 'continue',
+ 'iðtrinti' => 'delete',
+ 'patvirtinti' => 'post',
+ 'patvirtinti_kaip_naujà' => 'post_as_new',
+ 'pardavimo_sf' => 'sales_invoice',
+ 'atnaujinti' => 'update',
+ 'taip' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/arap b/sql-ledger/locale/lt/arap
new file mode 100644
index 0000000..0033472
--- /dev/null
+++ b/sql-ledger/locale/lt/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adresas',
+ 'Continue' => 'Tæsti',
+ 'Customer not on file!' => 'Tokio kliento nëra!',
+ 'Description' => 'Apraðymas',
+ 'Number' => 'Numeris',
+ 'Project not on file!' => 'Nëra tokio projekto!',
+ 'Select from one of the names below' => 'Iðrinkite vienà ið pavadinimø apaèioje',
+ 'Select from one of the projects below' => 'Iðrinkite vienà ið projektø apaèioje',
+ 'Vendor not on file!' => 'Tokio tiekëjo nëra!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'tæsti' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/ca b/sql-ledger/locale/lt/ca
new file mode 100644
index 0000000..89d18c3
--- /dev/null
+++ b/sql-ledger/locale/lt/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Sàskaita',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'Balance' => 'Balansas',
+ 'Chart of Accounts' => 'Sàskaitø planas',
+ 'Credit' => 'Kreditas',
+ 'Date' => 'Data',
+ 'Debit' => 'Debetas',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Description' => 'Apraðymas',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'From' => 'Nuo',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Ádëti á ataskaità',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'List Transactions' => 'Parodyti operacijas',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'Reference' => 'Nuorodos',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Subtotal' => 'Viso',
+ 'to' => 'iki',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'parodyti_operacijas' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/cp b/sql-ledger/locale/lt/cp
new file mode 100644
index 0000000..ec73d18
--- /dev/null
+++ b/sql-ledger/locale/lt/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'Sàskaita',
+ 'Address' => 'Adresas',
+ 'Amount' => 'Suma',
+ 'Amount does not equal applied!' => 'Suma ne lygi pritaikytai!',
+ 'Amount missing!' => 'Nëra sumos!',
+ 'Applied' => 'Pritaikyta',
+ 'Cannot post payment!' => 'Neámanoma patvirtinti mokëjimo!',
+ 'Cannot process payment for a closed period!' => 'Neámanoma vykdyti mokëjimo uþdarajam periodui!',
+ 'Check' => 'Èekis',
+ 'Check printed!' => 'Èekis atspausdintas!',
+ 'Check printing failed!' => 'Èekio spausdinimas nepavyko!',
+ 'Continue' => 'Tæsti',
+ 'Currency' => 'Valiûta',
+ 'Customer' => 'Klientas',
+ 'Customer not on file!' => 'Tokio kliento nëra!',
+ 'Date' => 'Data',
+ 'Date missing!' => 'Datos nëra!',
+ 'Description' => 'Apraðymas',
+ 'Due' => 'Iki',
+ 'Exchangerate' => 'Keitimo kursas',
+ 'From' => 'Nuo',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Invoices' => 'Sàskaitos-faktûros',
+ 'Nothing applied!' => 'Niekas nepanaudota!',
+ 'Number' => 'Numeris',
+ 'Paid in full' => 'Pilnai apmokëta',
+ 'Payment' => 'Mokëjimas',
+ 'Payment posted!' => 'Mokëjimas patvirtintas!',
+ 'Post' => 'Patvirtinti',
+ 'Print' => 'Spausdinti',
+ 'Printer' => 'Spausdintuvas',
+ 'Project not on file!' => 'Nëra tokio projekto!',
+ 'Receipt' => 'Kasos orderis',
+ 'Receipt printed!' => 'Receipt printed!',
+ 'Receipt printing failed!' => 'Receipt printing failed!',
+ 'Reference' => 'Nuorodos',
+ 'Screen' => 'Ekranas',
+ 'Select from one of the names below' => 'Iðrinkite vienà ið pavadinimø apaèioje',
+ 'Select from one of the projects below' => 'Iðrinkite vienà ið projektø apaèioje',
+ 'Update' => 'Atnaujinti',
+ 'Vendor' => 'Tiekëjas',
+ 'Vendor not on file!' => 'Tokio tiekëjo nëra!',
+ 'to' => 'iki',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'tæsti' => 'continue',
+ 'patvirtinti' => 'post',
+ 'spausdinti' => 'print',
+ 'atnaujinti' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/ct b/sql-ledger/locale/lt/ct
new file mode 100644
index 0000000..5de12f6
--- /dev/null
+++ b/sql-ledger/locale/lt/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Pridëti',
+ 'Address' => 'Adresas',
+ 'All' => 'Visi',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Neámanoma iðtrinti kliento!',
+ 'Cannot delete vendor!' => 'Neámanoma iðtrinti tiekëjo!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontaktas',
+ 'Continue' => 'Tæsti',
+ 'Credit Limit' => 'Kredito riba',
+ 'Customer deleted!' => 'Klientas iðtrintas!',
+ 'Customer saved!' => 'Klientas iðsaugotas!',
+ 'Customers' => 'Klientai',
+ 'Delete' => 'Iðtrinti',
+ 'Discount' => 'Nuolaidos',
+ 'E-mail' => 'E-paðtas',
+ 'Edit Customer' => 'Redaguoti Klientà',
+ 'Edit Vendor' => 'Redaguoti Tiekijà',
+ 'Fax' => 'Faksas',
+ 'Include in Report' => 'Ádëti á ataskaità',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Name' => 'Vardas',
+ 'Name missing!' => 'Pavadinimo nëra',
+ 'Notes' => 'Pastaba',
+ 'Number' => 'Numeris',
+ 'Order' => 'Uþsakymas',
+ 'Orphaned' => 'Naðlaitinis',
+ 'Phone' => 'Tel.',
+ 'Save' => 'Iðsaugoti',
+ 'Ship to' => 'Pristatyti á',
+ 'Tax Included' => 'su mokesèiais',
+ 'Taxable' => 'Apmokestinama',
+ 'Terms: Net' => 'Terminas: ',
+ 'Transactions exist, cannot delete customer!' => 'Operacijos egzistuoja, negalima iðtrinti kliento!',
+ 'Transactions exist, cannot delete vendor!' => 'Operacijos egzistuoja, negalima iðtrinti tiekëjo!',
+ 'Vendor deleted!' => 'Tiekëjas iðtrintas!',
+ 'Vendor saved!' => 'Tiekëjai iðsaugoti',
+ 'Vendors' => 'Tiekëjai',
+ 'days' => 'dienos',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'pridëti' => 'add',
+ 'tæsti' => 'continue',
+ 'iðtrinti' => 'delete',
+ 'sàskaita_faktûra' => 'invoice',
+ 'uþsakymas' => 'order',
+ 'iðsaugoti' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/gl b/sql-ledger/locale/lt/gl
new file mode 100644
index 0000000..db28f7e
--- /dev/null
+++ b/sql-ledger/locale/lt/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Pirkimo Operacijà',
+ 'AR Transaction' => 'Pardavimo Operacijà',
+ 'Account' => 'Sàskaita',
+ 'Add General Ledger Transaction' => 'Pridëti Bendroji Þurnalo Operacijà',
+ 'Address' => 'Adresas',
+ 'All' => 'Visi',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Are you sure you want to delete Transaction' => 'Ar Jus tikrai norite iðtrinti operacijà?',
+ 'Asset' => 'Turtas',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'Balance' => 'Balansas',
+ 'Cannot delete transaction!' => 'Neámanoma iðtrinti operacijos!',
+ 'Cannot have a value in both Debit and Credit!' => 'Negalima turëti tos paèios reikðmës Debete ir Kredite!',
+ 'Cannot post a transaction without a value!' => 'Neámanoma patvirtinti operacijos be reikðmës!',
+ 'Cannot post transaction for a closed period!' => 'Neámanoma patvirtinti operacijos uþdarajam periodui!',
+ 'Confirm!' => 'Patvirtinti!',
+ 'Continue' => 'Tæsti',
+ 'Credit' => 'Kreditas',
+ 'Customer not on file!' => 'Tokio kliento nëra!',
+ 'Date' => 'Data',
+ 'Debit' => 'Debetas',
+ 'Debit and credit out of balance!' => 'Debetas ir Kreditas nesubalansuoti!',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Delete' => 'Iðtrinti',
+ 'Description' => 'Apraðymas',
+ 'Edit General Ledger Transaction' => 'Redaguoti Bendrojo Þurnalo operacijà',
+ 'Equity' => 'Turtas/Nuosavybë',
+ 'Expense' => 'Sànaudos',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'From' => 'Nuo',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'BÞ operacija',
+ 'General Ledger' => 'Bendrasis þurnalas',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Ádëti á ataskaità',
+ 'Income' => 'Pajamos',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'Liability' => 'Nuosavybë',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Notes' => 'Pastaba',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Number' => 'Numeris',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'Post' => 'Patvirtinti',
+ 'Post as new' => 'Patvirtinti kaip naujà',
+ 'Project' => 'Projektas',
+ 'Project not on file!' => 'Nëra tokio projekto!',
+ 'Reference' => 'Nuorodos',
+ 'Reference missing!' => 'Nuorodos nëra!',
+ 'Reports' => 'Ataskaitos',
+ 'Sales Invoice' => 'Pardavimo SF',
+ 'Select from one of the names below' => 'Iðrinkite vienà ið pavadinimø apaèioje',
+ 'Select from one of the projects below' => 'Iðrinkite vienà ið projektø apaèioje',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Source' => 'Dokumentas',
+ 'Subtotal' => 'Viso',
+ 'Transaction Date missing!' => 'Operacijos datos nëra!',
+ 'Transaction deleted!' => 'Operacija iðtrinta!',
+ 'Transaction posted!' => 'Operacija patvirtinta!',
+ 'Update' => 'Atnaujinti',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendor not on file!' => 'Tokio tiekëjo nëra!',
+ 'Yes' => 'Taip',
+ 'to' => 'iki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'pirkimo_operacijà' => 'ap_transaction',
+ 'pardavimo_operacijà' => 'ar_transaction',
+ 'tæsti' => 'continue',
+ 'iðtrinti' => 'delete',
+ 'bÞ_operacija' => 'gl_transaction',
+ 'patvirtinti' => 'post',
+ 'patvirtinti_kaip_naujà' => 'post_as_new',
+ 'pardavimo_sf' => 'sales_invoice',
+ 'atnaujinti' => 'update',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'taip' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/ic b/sql-ledger/locale/lt/ic
new file mode 100644
index 0000000..e749d21
--- /dev/null
+++ b/sql-ledger/locale/lt/ic
@@ -0,0 +1,208 @@
+$self{texts} = {
+ 'Active' => 'Aktyvus',
+ 'Add' => 'Pridëti',
+ 'Add Assembly' => 'Pridëti rinkiná',
+ 'Add Part' => 'Pridëti prekæ',
+ 'Add Purchase Order' => 'Pridëti Pirkimo uþsakymà',
+ 'Add Sales Order' => 'Pridëti Pardavimo uþsakymà',
+ 'Add Service' => 'Pridëti Paslaugà',
+ 'Address' => 'Adresas',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Assemblies' => 'Rinkiniai',
+ 'Assemblies restocked!' => 'Rinkiniai persandeliuoti!',
+ 'Assembly Number missing!' => 'Rinkiniø numeriø nëra!',
+ 'Attachment' => 'Prisegta',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Dëþë',
+ 'Bought' => 'Nupirkta',
+ 'COGS' => 'PPS',
+ 'Cannot delete item already invoiced!' => 'Negalima iðtrinti prekës, kuriai sukurta sàskaita-faktûra!',
+ 'Cannot delete item on order!' => 'Negalima iðtrinti prekës, kuri yra uþsakyme!',
+ 'Cannot delete item which is part of an assembly!' => 'Negalima iðtrinti prekës, kuri yra rinkinio dalis!',
+ 'Cannot delete item!' => 'Neámanoma iðtrinti prekës!',
+ 'Cannot stock assemblies!' => 'Neámanoma sandelioti rinkinius!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontaktas',
+ 'Continue' => 'Tæsti',
+ 'Copies' => 'Kopijos',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Delete' => 'Iðtrinti',
+ 'Delivery Date' => 'Prystatimo Data',
+ 'Description' => 'Apraðymas',
+ 'Drawing' => 'Brieþinys',
+ 'E-mail' => 'E-paðtas',
+ 'E-mail address missing!' => 'E-paðto adreso nëra!',
+ 'Edit Assembly' => 'Redaguoti rinkiná',
+ 'Edit Part' => 'Redaguoti prekæ',
+ 'Edit Service' => 'Redaguoti paslaugà',
+ 'Expense' => 'Sànaudos',
+ 'Extended' => 'Iðplësta',
+ 'Fax' => 'Faksas',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'From' => 'Nuo',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'Image' => 'Pieðinys',
+ 'In-line' => 'Vienaeilis',
+ 'Include in Report' => 'Ádëti á ataskaità',
+ 'Income' => 'Pajamos',
+ 'Individual Items' => 'Individualios prekës',
+ 'Inventory' => 'Prekës',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Prekës kiekis turi bûti lygus nuliui prieð paþymint rinkiná pasenusiu!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Prekës kiekis turi bûti lygus nuliui prieð paþymint ðià dalá pasenusia!',
+ 'Inventory quantity must be zero!' => 'Prekës kiekis turi bûti lygus nuliui!',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Invoice Date missing!' => 'Sàskaitos-faktûros datos nëra!',
+ 'Invoice Number' => 'Sàskaitos-faktûros numeris',
+ 'Invoice Number missing!' => 'Sàskaitos-faktûra numerio nëra!',
+ 'Item deleted!' => 'Vienetas iðtrintas!',
+ 'Item not on file!' => 'Vieneto nëra áraðuose!',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'Last Cost' => 'Paskutinë kaina',
+ 'Line Total' => 'Viso eilutëje',
+ 'Link Accounts' => 'Suriðti sàskaitas',
+ 'List Price' => 'Pirkimo kaina',
+ 'Make' => 'Gamintojas',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Message' => 'Þinutë',
+ 'Microfiche' => 'Mikrofiða',
+ 'Model' => 'Modelis',
+ 'Name' => 'Vardas',
+ 'No.' => 'Num',
+ 'Notes' => 'Pastaba',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Number' => 'Numeris',
+ 'Number missing in Row' => 'Numerio nëra eilëje',
+ 'Obsolete' => 'Pasenæ',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'On Hand' => 'Likutis',
+ 'On Order' => 'Uþsakyme',
+ 'Order' => 'Uþsakymas',
+ 'Order Date missing!' => 'Uþsakymo datos nëra!',
+ 'Order Number' => 'Uþsakymo numeris',
+ 'Order Number missing!' => 'Uþsakymo numerio nëra!',
+ 'Ordered' => 'Uþsakyta',
+ 'Orphaned' => 'Naðlaitinis',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Ápakavimo sàraðas',
+ 'Packing List Date missing!' => 'Ápakavimo sàraðo datos nëra!',
+ 'Packing List Number missing!' => 'Ápakavimo sàraðo numerio nëra!',
+ 'Part' => 'Prekë',
+ 'Part Number missing!' => 'Prekës numerio nëra!',
+ 'Parts' => 'Prekës',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript(TM)',
+ 'Price' => 'Kaina',
+ 'Printer' => 'Spausdintuvas',
+ 'Project' => 'Projektas',
+ 'Purchase Order' => 'Pirkimo uþsakymas',
+ 'Qty' => 'Kks',
+ 'ROP' => 'ROP',
+ 'Recd' => 'Gaut',
+ 'Required by' => 'Iki kada',
+ 'Sales' => 'Pardavimai',
+ 'Sales Order' => 'Pardavimø uþsakymas',
+ 'Save' => 'Iðsaugoti',
+ 'Screen' => 'Ekranas',
+ 'Select from one of the items below' => 'Iðrinkite vienà ið prekiø apaèioje',
+ 'Select postscript or PDF!' => 'Iðrinkite postscript arba PDF!',
+ 'Sell Price' => 'Pardavimo kaina',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Service' => 'Paslauga',
+ 'Service Number missing!' => 'Paslaugos numerio nëra!',
+ 'Services' => 'Paslaugos',
+ 'Ship' => 'Pristatymas',
+ 'Ship to' => 'Pristatyti á',
+ 'Short' => 'Stoka',
+ 'Sold' => 'Parduota',
+ 'Stock Assembly' => 'Rinkiniai sandëlyje',
+ 'Subject' => 'Dalykas',
+ 'Subtotal' => 'Viso',
+ 'Tax' => 'Mokëstis',
+ 'To' => 'iki',
+ 'Top Level' => 'Aukðèiausias lygis',
+ 'Total' => 'Ið viso',
+ 'Unit' => 'Vienetas',
+ 'Unit of measure' => 'Matavimo vienetas',
+ 'Update' => 'Atnaujinti',
+ 'Updated' => 'Atnaujinta',
+ 'Weight' => 'Svoris',
+ 'What type of item is this?' => 'Koks ðio dalyko tipas?',
+ 'ea' => 'kk',
+ 'emailed to' => 'email do',
+ 'hr' => 'val',
+ 'sent to printer' => 'pasiûsta á spausdintuvà',
+ 'to' => 'iki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'pridëti' => 'add',
+ 'pridëti_rinkiná' => 'add_assembly',
+ 'pridëti_prekæ' => 'add_part',
+ 'pridëti_paslaugà' => 'add_service',
+ 'tæsti' => 'continue',
+ 'iðtrinti' => 'delete',
+ 'redaguoti_rinkiná' => 'edit_assembly',
+ 'redaguoti_prekæ' => 'edit_part',
+ 'redaguoti_paslaugà' => 'edit_service',
+ 'iðsaugoti' => 'save',
+ 'atnaujinti' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/io b/sql-ledger/locale/lt/io
new file mode 100644
index 0000000..3b28ede
--- /dev/null
+++ b/sql-ledger/locale/lt/io
@@ -0,0 +1,108 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Pridëti Pirkimo uþsakymà',
+ 'Add Sales Order' => 'Pridëti Pardavimo uþsakymà',
+ 'Address' => 'Adresas',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Attachment' => 'Prisegta',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Dëþë',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontaktas',
+ 'Continue' => 'Tæsti',
+ 'Copies' => 'Kopijos',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Delivery Date' => 'Prystatimo Data',
+ 'Description' => 'Apraðymas',
+ 'E-mail' => 'E-paðtas',
+ 'E-mail address missing!' => 'E-paðto adreso nëra!',
+ 'Extended' => 'Iðplësta',
+ 'Fax' => 'Faksas',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'Vienaeilis',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Invoice Date missing!' => 'Sàskaitos-faktûros datos nëra!',
+ 'Invoice Number missing!' => 'Sàskaitos-faktûra numerio nëra!',
+ 'Item not on file!' => 'Vieneto nëra áraðuose!',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Message' => 'Þinutë',
+ 'Name' => 'Vardas',
+ 'No.' => 'Num',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Number' => 'Numeris',
+ 'Number missing in Row' => 'Numerio nëra eilëje',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'Order' => 'Uþsakymas',
+ 'Order Date missing!' => 'Uþsakymo datos nëra!',
+ 'Order Number missing!' => 'Uþsakymo numerio nëra!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Ápakavimo sàraðas',
+ 'Packing List Date missing!' => 'Ápakavimo sàraðo datos nëra!',
+ 'Packing List Number missing!' => 'Ápakavimo sàraðo numerio nëra!',
+ 'Part' => 'Prekë',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript(TM)',
+ 'Price' => 'Kaina',
+ 'Printer' => 'Spausdintuvas',
+ 'Project' => 'Projektas',
+ 'Purchase Order' => 'Pirkimo uþsakymas',
+ 'Qty' => 'Kks',
+ 'Recd' => 'Gaut',
+ 'Required by' => 'Iki kada',
+ 'Sales Order' => 'Pardavimø uþsakymas',
+ 'Screen' => 'Ekranas',
+ 'Select from one of the items below' => 'Iðrinkite vienà ið prekiø apaèioje',
+ 'Select postscript or PDF!' => 'Iðrinkite postscript arba PDF!',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Service' => 'Paslauga',
+ 'Ship' => 'Pristatymas',
+ 'Ship to' => 'Pristatyti á',
+ 'Subject' => 'Dalykas',
+ 'To' => 'iki',
+ 'Unit' => 'Vienetas',
+ 'What type of item is this?' => 'Koks ðio dalyko tipas?',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'pasiûsta á spausdintuvà',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'tæsti' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/ir b/sql-ledger/locale/lt/ir
new file mode 100644
index 0000000..003b9a6
--- /dev/null
+++ b/sql-ledger/locale/lt/ir
@@ -0,0 +1,180 @@
+$self{texts} = {
+ 'Account' => 'Sàskaita',
+ 'Add Purchase Order' => 'Pridëti Pirkimo uþsakymà',
+ 'Add Sales Order' => 'Pridëti Pardavimo uþsakymà',
+ 'Add Vendor Invoice' => 'Add Vendor Invoice',
+ 'Address' => 'Adresas',
+ 'Amount' => 'Suma',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Are you sure you want to delete Invoice Number' => 'Ar Jus tikrai norite iðtrinti saskaitu-fakturos numeris:',
+ 'Attachment' => 'Prisegta',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Dëþë',
+ 'Cannot delete invoice!' => 'Neámanoma iðtrinti sàskaitos-faktûros!',
+ 'Cannot post invoice for a closed period!' => 'Neámanoma patvirtinti sàskaitos-faktûros uþdarajam periodui!',
+ 'Cannot post invoice!' => 'Neámanoma patvirtinti sàskaitos-faktûros!',
+ 'Cannot post payment for a closed period!' => 'Neámanoma patvirtinti mokëjimo uþdarajam periodui!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Patvirtinti!',
+ 'Contact' => 'Kontaktas',
+ 'Continue' => 'Tæsti',
+ 'Copies' => 'Kopijos',
+ 'Currency' => 'Valiûta',
+ 'Customer not on file!' => 'Tokio kliento nëra!',
+ 'Date' => 'Data',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Delete' => 'Iðtrinti',
+ 'Delivery Date' => 'Prystatimo Data',
+ 'Description' => 'Apraðymas',
+ 'Due Date' => 'Iki Data',
+ 'E-mail' => 'E-paðtas',
+ 'E-mail address missing!' => 'E-paðto adreso nëra!',
+ 'Edit Vendor Invoice' => 'Edit Vendor Invoice',
+ 'Exch' => 'Kurs.',
+ 'Exchangerate' => 'Keitimo kursas',
+ 'Exchangerate for payment missing!' => 'Mokëjimo keitimo kurso nëra!',
+ 'Exchangerate missing!' => 'Keitimo kurso nëra!',
+ 'Extended' => 'Iðplësta',
+ 'Fax' => 'Faksas',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'Vienaeilis',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Invoice Date' => 'Sàskaitos-faktûros data',
+ 'Invoice Date missing!' => 'Sàskaitos-faktûros datos nëra!',
+ 'Invoice Number' => 'Sàskaitos-faktûros numeris',
+ 'Invoice Number missing!' => 'Sàskaitos-faktûra numerio nëra!',
+ 'Invoice deleted!' => 'Sàskaitos-faktûra iðtrintos!',
+ 'Invoice posted!' => 'Sàskaitos-faktûra patvirtintos!',
+ 'Item not on file!' => 'Vieneto nëra áraðuose!',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Message' => 'Þinutë',
+ 'Name' => 'Vardas',
+ 'No.' => 'Num',
+ 'Notes' => 'Pastaba',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Number' => 'Numeris',
+ 'Number missing in Row' => 'Numerio nëra eilëje',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'Order' => 'Uþsakymas',
+ 'Order Date missing!' => 'Uþsakymo datos nëra!',
+ 'Order Number' => 'Uþsakymo numeris',
+ 'Order Number missing!' => 'Uþsakymo numerio nëra!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Ápakavimo sàraðas',
+ 'Packing List Date missing!' => 'Ápakavimo sàraðo datos nëra!',
+ 'Packing List Number missing!' => 'Ápakavimo sàraðo numerio nëra!',
+ 'Part' => 'Prekë',
+ 'Payment date missing!' => 'Mokëjimo datos nëra',
+ 'Payments' => 'Mokëjimai',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Patvirtinti',
+ 'Post as new' => 'Patvirtinti kaip naujà',
+ 'Postscript' => 'Postscript(TM)',
+ 'Price' => 'Kaina',
+ 'Printer' => 'Spausdintuvas',
+ 'Project' => 'Projektas',
+ 'Project not on file!' => 'Nëra tokio projekto!',
+ 'Purchase Order' => 'Pirkimo uþsakymas',
+ 'Qty' => 'Kks',
+ 'Recd' => 'Gaut',
+ 'Record in' => 'Áraðyti á',
+ 'Required by' => 'Iki kada',
+ 'Sales Order' => 'Pardavimø uþsakymas',
+ 'Screen' => 'Ekranas',
+ 'Select from one of the items below' => 'Iðrinkite vienà ið prekiø apaèioje',
+ 'Select from one of the names below' => 'Iðrinkite vienà ið pavadinimø apaèioje',
+ 'Select from one of the projects below' => 'Iðrinkite vienà ið projektø apaèioje',
+ 'Select postscript or PDF!' => 'Iðrinkite postscript arba PDF!',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Service' => 'Paslauga',
+ 'Ship' => 'Pristatymas',
+ 'Ship to' => 'Pristatyti á',
+ 'Source' => 'Dokumentas',
+ 'Subject' => 'Dalykas',
+ 'Subtotal' => 'Viso',
+ 'Tax Included' => 'su mokesèiais',
+ 'To' => 'iki',
+ 'Total' => 'Ið viso',
+ 'Unit' => 'Vienetas',
+ 'Update' => 'Atnaujinti',
+ 'Vendor' => 'Tiekëjas',
+ 'Vendor missing!' => 'Tiekëjo Vardo nëra!',
+ 'Vendor not on file!' => 'Tokio tiekëjo nëra!',
+ 'What type of item is this?' => 'Koks ðio dalyko tipas?',
+ 'Yes' => 'Taip',
+ 'ea' => 'kk',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'pasiûsta á spausdintuvà',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'tæsti' => 'continue',
+ 'iðtrinti' => 'delete',
+ 'uþsakymas' => 'order',
+ 'patvirtinti' => 'post',
+ 'patvirtinti_kaip_naujà' => 'post_as_new',
+ 'atnaujinti' => 'update',
+ 'taip' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/is b/sql-ledger/locale/lt/is
new file mode 100644
index 0000000..d7b1e50
--- /dev/null
+++ b/sql-ledger/locale/lt/is
@@ -0,0 +1,187 @@
+$self{texts} = {
+ 'Account' => 'Sàskaita',
+ 'Add Purchase Order' => 'Pridëti Pirkimo uþsakymà',
+ 'Add Sales Invoice' => 'Pridëti Pardavimo sàskaità-faktûrà',
+ 'Add Sales Order' => 'Pridëti Pardavimo uþsakymà',
+ 'Address' => 'Adresas',
+ 'Amount' => 'Suma',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Are you sure you want to delete Invoice Number' => 'Ar Jus tikrai norite iðtrinti saskaitu-fakturos numeris:',
+ 'Attachment' => 'Prisegta',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Dëþë',
+ 'Cannot delete invoice!' => 'Neámanoma iðtrinti sàskaitos-faktûros!',
+ 'Cannot post invoice for a closed period!' => 'Neámanoma patvirtinti sàskaitos-faktûros uþdarajam periodui!',
+ 'Cannot post invoice!' => 'Neámanoma patvirtinti sàskaitos-faktûros!',
+ 'Cannot post payment for a closed period!' => 'Neámanoma patvirtinti mokëjimo uþdarajam periodui!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Patvirtinti!',
+ 'Contact' => 'Kontaktas',
+ 'Continue' => 'Tæsti',
+ 'Copies' => 'Kopijos',
+ 'Credit Limit' => 'Kredito riba',
+ 'Currency' => 'Valiûta',
+ 'Customer' => 'Klientas',
+ 'Customer missing!' => 'Kliento vardo nëra!',
+ 'Customer not on file!' => 'Tokio kliento nëra!',
+ 'Date' => 'Data',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Delete' => 'Iðtrinti',
+ 'Delivery Date' => 'Prystatimo Data',
+ 'Description' => 'Apraðymas',
+ 'Due Date' => 'Iki Data',
+ 'E-mail' => 'E-paðtas',
+ 'E-mail address missing!' => 'E-paðto adreso nëra!',
+ 'Edit Sales Invoice' => 'Redaguoti pardavimo sàskaità-faktûrà',
+ 'Exch' => 'Kurs.',
+ 'Exchangerate' => 'Keitimo kursas',
+ 'Exchangerate for payment missing!' => 'Mokëjimo keitimo kurso nëra!',
+ 'Exchangerate missing!' => 'Keitimo kurso nëra!',
+ 'Extended' => 'Iðplësta',
+ 'Fax' => 'Faksas',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'In-line' => 'Vienaeilis',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Invoice Date' => 'Sàskaitos-faktûros data',
+ 'Invoice Date missing!' => 'Sàskaitos-faktûros datos nëra!',
+ 'Invoice Number' => 'Sàskaitos-faktûros numeris',
+ 'Invoice Number missing!' => 'Sàskaitos-faktûra numerio nëra!',
+ 'Invoice deleted!' => 'Sàskaitos-faktûra iðtrintos!',
+ 'Invoice posted!' => 'Sàskaitos-faktûra patvirtintos!',
+ 'Item not on file!' => 'Vieneto nëra áraðuose!',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Message' => 'Þinutë',
+ 'Name' => 'Vardas',
+ 'No.' => 'Num',
+ 'Notes' => 'Pastaba',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Number' => 'Numeris',
+ 'Number missing in Row' => 'Numerio nëra eilëje',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'Order' => 'Uþsakymas',
+ 'Order Date missing!' => 'Uþsakymo datos nëra!',
+ 'Order Number' => 'Uþsakymo numeris',
+ 'Order Number missing!' => 'Uþsakymo numerio nëra!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Ápakavimo sàraðas',
+ 'Packing List Date missing!' => 'Ápakavimo sàraðo datos nëra!',
+ 'Packing List Number missing!' => 'Ápakavimo sàraðo numerio nëra!',
+ 'Part' => 'Prekë',
+ 'Payment date missing!' => 'Mokëjimo datos nëra',
+ 'Payments' => 'Mokëjimai',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Patvirtinti',
+ 'Post as new' => 'Patvirtinti kaip naujà',
+ 'Postscript' => 'Postscript(TM)',
+ 'Price' => 'Kaina',
+ 'Print' => 'Spausdinti',
+ 'Printer' => 'Spausdintuvas',
+ 'Project' => 'Projektas',
+ 'Project not on file!' => 'Nëra tokio projekto!',
+ 'Purchase Order' => 'Pirkimo uþsakymas',
+ 'Qty' => 'Kks',
+ 'Recd' => 'Gaut',
+ 'Record in' => 'Áraðyti á',
+ 'Remaining' => 'Likutis',
+ 'Required by' => 'Iki kada',
+ 'Sales Order' => 'Pardavimø uþsakymas',
+ 'Screen' => 'Ekranas',
+ 'Select from one of the items below' => 'Iðrinkite vienà ið prekiø apaèioje',
+ 'Select from one of the names below' => 'Iðrinkite vienà ið pavadinimø apaèioje',
+ 'Select from one of the projects below' => 'Iðrinkite vienà ið projektø apaèioje',
+ 'Select postscript or PDF!' => 'Iðrinkite postscript arba PDF!',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Service' => 'Paslauga',
+ 'Ship' => 'Pristatymas',
+ 'Ship to' => 'Pristatyti á',
+ 'Ship via' => 'Pristatyti per',
+ 'Source' => 'Dokumentas',
+ 'Subject' => 'Dalykas',
+ 'Subtotal' => 'Viso',
+ 'Tax Included' => 'su mokesèiais',
+ 'To' => 'iki',
+ 'Total' => 'Ið viso',
+ 'Unit' => 'Vienetas',
+ 'Update' => 'Atnaujinti',
+ 'Vendor not on file!' => 'Tokio tiekëjo nëra!',
+ 'What type of item is this?' => 'Koks ðio dalyko tipas?',
+ 'Yes' => 'Taip',
+ 'ea' => 'kk',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'pasiûsta á spausdintuvà',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'tæsti' => 'continue',
+ 'iðtrinti' => 'delete',
+ 'e_paðtas' => 'e_mail',
+ 'uþsakymas' => 'order',
+ 'patvirtinti' => 'post',
+ 'patvirtinti_kaip_naujà' => 'post_as_new',
+ 'spausdinti' => 'print',
+ 'pristatyti_á' => 'ship_to',
+ 'atnaujinti' => 'update',
+ 'taip' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/login b/sql-ledger/locale/lt/login
new file mode 100644
index 0000000..8a42d2a
--- /dev/null
+++ b/sql-ledger/locale/lt/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Apie...',
+ 'Database Host' => 'Duomenø bazës hostas',
+ 'Dataset' => 'Duomenø aibë',
+ 'Incorrect Dataset version!' => 'Neteisinga duomenø aibës versija!',
+ 'Incorrect Password!' => 'Neteisingas slaptaþodis!',
+ 'Licensed to' => 'Licenzijuota...',
+ 'Login' => 'Prisijungimas',
+ 'Name' => 'Vardas',
+ 'Password' => 'Slaptaþodis',
+ 'User' => 'Vartotojas',
+ 'Version' => 'Versija',
+ 'You are logged out!' => 'Jûs iðsijungëte!',
+ 'You did not enter a name!' => 'Neávedëte vardo!',
+ 'is not a member!' => 'nëra narys!',
+ 'localhost' => 'lokalhostas',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'prisijungimas' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/menu b/sql-ledger/locale/lt/menu
new file mode 100644
index 0000000..460ea5b
--- /dev/null
+++ b/sql-ledger/locale/lt/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Pirkimai',
+ 'AP Aging' => 'Pirkimo Skolos',
+ 'AR' => 'Pardavimai',
+ 'AR Aging' => 'Pardavimo Skolos',
+ 'Accounting Menu' => 'Apskaitos Menu',
+ 'Add Account' => 'Pridëti sàskaità',
+ 'Add Assembly' => 'Pridëti rinkiná',
+ 'Add Customer' => 'Pridëti klientà',
+ 'Add GIFI' => 'Pridëti GIFI',
+ 'Add Part' => 'Pridëti prekæ',
+ 'Add Project' => 'Pridëti proektà',
+ 'Add Service' => 'Pridëti Paslaugà',
+ 'Add Transaction' => 'Pridëti Operacijà',
+ 'Add Vendor' => 'Pridëti Tiekëja',
+ 'Assemblies' => 'Rinkiniai',
+ 'Audit Control' => 'Audito kontrolë',
+ 'Backup' => 'Reservinë kopija',
+ 'Balance Sheet' => 'Balanso lëntelë',
+ 'Cash' => 'Kasa',
+ 'Chart of Accounts' => 'Sàskaitø planas',
+ 'Check' => 'Èekis',
+ 'Customers' => 'Klientai',
+ 'General Ledger' => 'Bendrasis þurnalas',
+ 'Goods & Services' => 'Prekës ir Paslaugos',
+ 'HTML Templates' => 'HTML ðablonai',
+ 'Income Statement' => 'Pelno/nuostolio ataskaita',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'LaTeX Templates' => 'LaTeX ðablonai',
+ 'List Accounts' => 'Sàskaitø sàraðas',
+ 'List GIFI' => 'GIFI sàraðas',
+ 'Logout' => 'Iðsijungti',
+ 'Order Entry' => 'Uþsakymo áraðas',
+ 'Packing List' => 'Ápakavimo sàraðas',
+ 'Parts' => 'Prekës',
+ 'Payment' => 'Mokëjimas',
+ 'Payments' => 'Mokëjimai',
+ 'Preferences' => 'Nuostatos',
+ 'Projects' => 'Projektai',
+ 'Purchase Order' => 'Pirkimo uþsakymas',
+ 'Purchase Orders' => 'Pirkimo uþsakymai',
+ 'Receipt' => 'Kasos orderis',
+ 'Receipts' => 'Kasos orderiai',
+ 'Reconciliation' => 'Sutaikinimas',
+ 'Reports' => 'Ataskaitos',
+ 'Sales Invoice' => 'Pardavimo SF',
+ 'Sales Order' => 'Pardavimø uþsakymas',
+ 'Sales Orders' => 'Pardavimø uþsakymai',
+ 'Save to File' => 'Iðsaugoti á failà',
+ 'Send by E-Mail' => 'Iðsiûsti e-paðtu',
+ 'Services' => 'Paslaugos',
+ 'Statement' => 'Suvestinë',
+ 'Stock Assembly' => 'Rinkiniai sandëlyje',
+ 'Stylesheet' => 'Stiliø lentelë',
+ 'System' => 'Sistema',
+ 'Tax collected' => 'Mokesèiai surinkti',
+ 'Tax paid' => 'Mokesèiai sumokëti',
+ 'Transactions' => 'Operacijos',
+ 'Trial Balance' => 'Bandomasis balansas',
+ 'Vendor Invoice' => 'Vendor Invoice',
+ 'Vendors' => 'Tiekëjai',
+ 'Version' => 'Versija',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/oe b/sql-ledger/locale/lt/oe
new file mode 100644
index 0000000..c0786c1
--- /dev/null
+++ b/sql-ledger/locale/lt/oe
@@ -0,0 +1,202 @@
+$self{texts} = {
+ 'Add' => 'Pridëti',
+ 'Add Purchase Order' => 'Pridëti Pirkimo uþsakymà',
+ 'Add Sales Invoice' => 'Pridëti Pardavimo sàskaità-faktûrà',
+ 'Add Sales Order' => 'Pridëti Pardavimo uþsakymà',
+ 'Add Vendor Invoice' => 'Add Vendor Invoice',
+ 'Address' => 'Adresas',
+ 'Amount' => 'Suma',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Are you sure you want to delete Order Number' => 'Ar Jus tikrai norite iðtrinti uzsakimas numeris:',
+ 'Attachment' => 'Prisegta',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Dëþë',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Neámanoma iðtrinti uþsakymo!',
+ 'Cannot save order!' => 'Neámanoma iðsaugoti uþsakymo!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Uþdaryta',
+ 'Confirm!' => 'Patvirtinti!',
+ 'Contact' => 'Kontaktas',
+ 'Continue' => 'Tæsti',
+ 'Copies' => 'Kopijos',
+ 'Credit Limit' => 'Kredito riba',
+ 'Curr' => 'Val.',
+ 'Currency' => 'Valiûta',
+ 'Customer' => 'Klientas',
+ 'Customer missing!' => 'Kliento vardo nëra!',
+ 'Customer not on file!' => 'Tokio kliento nëra!',
+ 'Date' => 'Data',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Delete' => 'Iðtrinti',
+ 'Delivery Date' => 'Prystatimo Data',
+ 'Description' => 'Apraðymas',
+ 'E-mail' => 'E-paðtas',
+ 'E-mail address missing!' => 'E-paðto adreso nëra!',
+ 'Edit Purchase Order' => 'Redaguoti pirkimo uþsakymà',
+ 'Edit Sales Order' => 'Redaguoti pardavimo uþsakymà',
+ 'Exchangerate' => 'Keitimo kursas',
+ 'Exchangerate missing!' => 'Keitimo kurso nëra!',
+ 'Extended' => 'Iðplësta',
+ 'Fax' => 'Faksas',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'From' => 'Nuo',
+ 'Group' => 'Group',
+ 'Group Items' => 'Group Items',
+ 'ID' => 'ID',
+ 'In-line' => 'Vienaeilis',
+ 'Include in Report' => 'Ádëti á ataskaità',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Invoice Date missing!' => 'Sàskaitos-faktûros datos nëra!',
+ 'Invoice Number missing!' => 'Sàskaitos-faktûra numerio nëra!',
+ 'Item not on file!' => 'Vieneto nëra áraðuose!',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Message' => 'Þinutë',
+ 'Name' => 'Vardas',
+ 'No.' => 'Num',
+ 'Notes' => 'Pastaba',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Number' => 'Numeris',
+ 'Number missing in Row' => 'Numerio nëra eilëje',
+ 'O' => 'O',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'Open' => 'Atidaryti',
+ 'Order' => 'Uþsakymas',
+ 'Order Date' => 'Uþsakymo data',
+ 'Order Date missing!' => 'Uþsakymo datos nëra!',
+ 'Order Number' => 'Uþsakymo numeris',
+ 'Order Number missing!' => 'Uþsakymo numerio nëra!',
+ 'Order deleted!' => 'Uþsakymai iðtrinti!',
+ 'Order saved!' => 'Uþsakymas iðsaugotas!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Ápakavimo sàraðas',
+ 'Packing List Date missing!' => 'Ápakavimo sàraðo datos nëra!',
+ 'Packing List Number missing!' => 'Ápakavimo sàraðo numerio nëra!',
+ 'Part' => 'Prekë',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript(TM)',
+ 'Price' => 'Kaina',
+ 'Print' => 'Spausdinti',
+ 'Printer' => 'Spausdintuvas',
+ 'Project' => 'Projektas',
+ 'Project not on file!' => 'Nëra tokio projekto!',
+ 'Purchase Order' => 'Pirkimo uþsakymas',
+ 'Purchase Orders' => 'Pirkimo uþsakymai',
+ 'Qty' => 'Kks',
+ 'Recd' => 'Gaut',
+ 'Remaining' => 'Likutis',
+ 'Required by' => 'Iki kada',
+ 'Sales Order' => 'Pardavimø uþsakymas',
+ 'Sales Orders' => 'Pardavimø uþsakymai',
+ 'Save' => 'Iðsaugoti',
+ 'Save as new' => 'Iðsaugoti kaip naujà',
+ 'Screen' => 'Ekranas',
+ 'Select from one of the items below' => 'Iðrinkite vienà ið prekiø apaèioje',
+ 'Select from one of the names below' => 'Iðrinkite vienà ið pavadinimø apaèioje',
+ 'Select from one of the projects below' => 'Iðrinkite vienà ið projektø apaèioje',
+ 'Select postscript or PDF!' => 'Iðrinkite postscript arba PDF!',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Service' => 'Paslauga',
+ 'Ship' => 'Pristatymas',
+ 'Ship to' => 'Pristatyti á',
+ 'Ship via' => 'Pristatyti per',
+ 'Subject' => 'Dalykas',
+ 'Subtotal' => 'Viso',
+ 'Tax' => 'Mokëstis',
+ 'Tax Included' => 'su mokesèiais',
+ 'Terms: Net' => 'Terminas: ',
+ 'To' => 'iki',
+ 'Total' => 'Ið viso',
+ 'Unit' => 'Vienetas',
+ 'Update' => 'Atnaujinti',
+ 'Vendor' => 'Tiekëjas',
+ 'Vendor missing!' => 'Tiekëjo Vardo nëra!',
+ 'Vendor not on file!' => 'Tokio tiekëjo nëra!',
+ 'What type of item is this?' => 'Koks ðio dalyko tipas?',
+ 'Yes' => 'Taip',
+ 'days' => 'dienos',
+ 'ea' => 'kk',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'pasiûsta á spausdintuvà',
+ 'to' => 'iki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'yes' => 'yes',
+ 'pridëti' => 'add',
+ 'tæsti' => 'continue',
+ 'iðtrinti' => 'delete',
+ 'e_paðtas' => 'e_mail',
+ 'sàskaita_faktûra' => 'invoice',
+ 'spausdinti' => 'print',
+ 'iðsaugoti' => 'save',
+ 'iðsaugoti_kaip_naujà' => 'save_as_new',
+ 'pristatyti_á' => 'ship_to',
+ 'atnaujinti' => 'update',
+ 'taip' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/pe b/sql-ledger/locale/lt/pe
new file mode 100644
index 0000000..fa58e62
--- /dev/null
+++ b/sql-ledger/locale/lt/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Pridëti',
+ 'Add Project' => 'Pridëti proektà',
+ 'All' => 'Visi',
+ 'Continue' => 'Tæsti',
+ 'Delete' => 'Iðtrinti',
+ 'Description' => 'Apraðymas',
+ 'Edit Project' => 'Redaguoti projektà',
+ 'Number' => 'Numeris',
+ 'Orphaned' => 'Naðlaitinis',
+ 'Project' => 'Projektas',
+ 'Project Number missing!' => 'Projekto numerio nëra!',
+ 'Project deleted!' => 'Projektas iðtrintas!',
+ 'Project saved!' => 'Projektas iðsaugotas!',
+ 'Projects' => 'Projektai',
+ 'Save' => 'Iðsaugoti',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'pridëti' => 'add',
+ 'tæsti' => 'continue',
+ 'iðtrinti' => 'delete',
+ 'iðsaugoti' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/rc b/sql-ledger/locale/lt/rc
new file mode 100644
index 0000000..7e57584
--- /dev/null
+++ b/sql-ledger/locale/lt/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Sàskaita',
+ 'Balance' => 'Balansas',
+ 'Cleared Balance' => 'Baigiamasis balansas',
+ 'Continue' => 'Tæsti',
+ 'Date' => 'Data',
+ 'Deposit' => 'Depozitas',
+ 'Description' => 'Apraðymas',
+ 'Difference' => 'Skirtumas',
+ 'Done' => 'Ávykdyta',
+ 'Exchangerate Difference' => 'Keitimo kurso skirtumas',
+ 'From' => 'Nuo',
+ 'Out of balance!' => 'Nesubalansuota!',
+ 'Payment' => 'Mokëjimas',
+ 'Reconciliation' => 'Sutaikinimas',
+ 'Select all' => 'Iðrinkti viskà',
+ 'Source' => 'Dokumentas',
+ 'Statement Balance' => 'Balanso suvestinë',
+ 'Update' => 'Atnaujinti',
+ 'to' => 'iki',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'tæsti' => 'continue',
+ 'Ávykdyta' => 'done',
+ 'iðrinkti_viskà' => 'select_all',
+ 'atnaujinti' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/lt/rp b/sql-ledger/locale/lt/rp
new file mode 100644
index 0000000..83cb9c0
--- /dev/null
+++ b/sql-ledger/locale/lt/rp
@@ -0,0 +1,120 @@
+$self{texts} = {
+ 'AP Aging' => 'Pirkimo Skolos',
+ 'AR Aging' => 'Pardavimo Skolos',
+ 'Account' => 'Sàskaita',
+ 'Accounts' => 'Sàskaitos',
+ 'Amount' => 'Suma',
+ 'Apr' => 'Bal',
+ 'April' => 'Balandis',
+ 'Attachment' => 'Prisegta',
+ 'Aug' => 'Rug',
+ 'August' => 'Rugpjûtis',
+ 'Balance' => 'Balansas',
+ 'Balance Sheet' => 'Balanso lëntelë',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Grynais',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Palyginti su',
+ 'Continue' => 'Tæsti',
+ 'Copies' => 'Kopijos',
+ 'Credit' => 'Kreditas',
+ 'Current' => 'Dabartinis',
+ 'Customer' => 'Klientas',
+ 'Date' => 'Data',
+ 'Debit' => 'Debetas',
+ 'Dec' => 'Grd',
+ 'December' => 'Gruodis',
+ 'Decimalplaces' => 'Skaièiø po taðko',
+ 'Department' => 'Department',
+ 'Description' => 'Apraðymas',
+ 'Due' => 'Iki',
+ 'E-mail' => 'E-paðtas',
+ 'E-mail Statement to' => 'Suvestinæ suisti per e-pastà á',
+ 'Feb' => 'Vas',
+ 'February' => 'Vasaris',
+ 'From' => 'Nuo',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Antraðtë',
+ 'ID' => 'ID',
+ 'In-line' => 'Vienaeilis',
+ 'Include in Report' => 'Ádëti á ataskaità',
+ 'Income Statement' => 'Pelno/nuostolio ataskaita',
+ 'Invoice' => 'Sàskaita-faktûra',
+ 'Jan' => 'Sau',
+ 'January' => 'Sausis',
+ 'Jul' => 'Lie',
+ 'July' => 'Liepa',
+ 'Jun' => 'Bir',
+ 'June' => 'Birþelis',
+ 'Mar' => 'Kov',
+ 'March' => 'Kovas',
+ 'May' => 'Geg',
+ 'May ' => 'Geguþë',
+ 'Message' => 'Þinutë',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Nieko neiðrinkta!',
+ 'Nov' => 'Lap',
+ 'November' => 'Lapkritis',
+ 'Oct' => 'Spa',
+ 'October' => 'Spalis',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Mokëjimai',
+ 'Postscript' => 'Postscript(TM)',
+ 'Print' => 'Spausdinti',
+ 'Printer' => 'Spausdintuvas',
+ 'Project Number' => 'Project Number',
+ 'Receipts' => 'Kasos orderiai',
+ 'Report for' => 'Ataskaita...',
+ 'Retained Earnings' => 'Turimi uþdarbiai',
+ 'Screen' => 'Ekranas',
+ 'Select all' => 'Iðrinkti viskà',
+ 'Select postscript or PDF!' => 'Iðrinkite postscript arba PDF!',
+ 'Sep' => 'Rgs',
+ 'September' => 'Rûgsëjis',
+ 'Source' => 'Dokumentas',
+ 'Standard' => 'Standartas',
+ 'Statement' => 'Suvestinë',
+ 'Statement sent to' => 'Siusti suvestinæ á',
+ 'Statements sent to printer!' => 'Siusti suvestinæ á spausdintuvà!',
+ 'Subject' => 'Dalykas',
+ 'Subtotal' => 'Viso',
+ 'Tax' => 'Mokëstis',
+ 'Tax collected' => 'Mokesèiai surinkti',
+ 'Tax paid' => 'Mokesèiai sumokëti',
+ 'Total' => 'Ið viso',
+ 'Trial Balance' => 'Bandomasis balansas',
+ 'Vendor' => 'Tiekëjas',
+ 'as at' => 'kaip',
+ 'collected on sales' => 'surinkta per pardavimus',
+ 'for Period' => 'periodui',
+ 'paid on purchases' => 'apmokëta per pirkimus',
+ 'to' => 'iki',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'tæsti' => 'continue',
+ 'e_paðtas' => 'e_mail',
+ 'spausdinti' => 'print',
+ 'iðrinkti_viskà' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/COPYING b/sql-ledger/locale/mx/COPYING
new file mode 100644
index 0000000..314fc90
--- /dev/null
+++ b/sql-ledger/locale/mx/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Spanish texts (Mexico):
+#
+# Author: Alberto Ladron <h@grupoh.com.mx>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/mx/LANGUAGE b/sql-ledger/locale/mx/LANGUAGE
new file mode 100644
index 0000000..22549db
--- /dev/null
+++ b/sql-ledger/locale/mx/LANGUAGE
@@ -0,0 +1 @@
+Mexican Spanish
diff --git a/sql-ledger/locale/mx/admin b/sql-ledger/locale/mx/admin
new file mode 100644
index 0000000..707b489
--- /dev/null
+++ b/sql-ledger/locale/mx/admin
@@ -0,0 +1,128 @@
+$self{texts} = {
+ 'Access Control' => 'Control de Acceso',
+ 'Accounting' => 'Contabilidad',
+ 'Add User' => 'Agregar Usuario',
+ 'Address' => 'Dirección',
+ 'Administration' => 'Administración',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => '! Todos los conjuntos de datos estan actualizados !',
+ 'Change Admin Password' => 'Cambiar Contraseña de Administrador',
+ 'Change Password' => 'Cambiar Contraseña',
+ 'Character Set' => 'Tabla de Caracteres',
+ 'Click on login name to edit!' => 'Haga clic en el nombre de entrada a
+editar',
+ 'Company' => 'Compañía',
+ 'Connect to' => 'Conectar a',
+ 'Continue' => 'Continuar',
+ 'Create Chart of Accounts' => 'Crear catálogo de cuentas',
+ 'Create Dataset' => 'Crear set de datos',
+ 'DBI not installed!' => 'DBI no instalado!',
+ 'Database' => 'Base de datos',
+ 'Database Administration' => 'Administración de base de datos',
+ 'Database Driver not checked!' => '!No selecciono driver de base de datos!',
+ 'Database User missing!' => 'No se encuentra usuario de base de datos',
+ 'Dataset' => 'Set de datos',
+ 'Dataset missing!' => 'No se encuentra Set de datos!',
+ 'Dataset updated!' => 'Dataset updated!',
+ 'Date Format' => 'Formato de Fecha',
+ 'Delete' => 'Borrar',
+ 'Delete Dataset' => 'Borrar Set de Datos',
+ 'Directory' => 'Directorio',
+ 'Driver' => 'Manejador',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'Correo Electrónico',
+ 'Edit User' => 'Editar Usuario',
+ 'Existing Datasets' => 'Sets de dato existentes',
+ 'Fax' => 'Fax',
+ 'Host' => 'Servidor base de datos',
+ 'Hostname missing!' => 'No se encuentra servidor de base de datos',
+ 'Incorrect Password!' => 'Contraseña Incorrecta!',
+ 'Language' => 'Lenguaje',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deje los campos de servidor de base de datos y puerto vacíos al menos que quiera hacer una conexión remota',
+ 'Login' => 'Login',
+ 'Name' => 'Nombre',
+ 'New Templates' => 'Nuevas Plantillas',
+ 'No Database Drivers available!' => 'No hay manejador de base de datos
+disponible!',
+ 'No Dataset selected!' => 'No se ha seleccionado el set de datos',
+ 'Nothing to delete!' => '!Nada para borrar!',
+ 'Number Format' => 'Formato de Numero',
+ 'Oracle Database Administration' => 'Oracle Administración de base de datos',
+ 'Password' => 'Contraseña',
+ 'Password changed!' => 'Password changed!',
+ 'Pg Database Administration' => 'Pg Administración de base de datos',
+ 'Phone' => 'Teléfono',
+ 'Port' => 'Puerto',
+ 'Port missing!' => 'No se encuentra el Puerto!',
+ 'Printer' => 'Impresora',
+ 'Save' => 'Salvar',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione un set de
+datos para borrar y presione "Continuar"',
+ 'Setup Templates' => 'Configurar Plantillas',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Estilo de hoja',
+ 'Templates' => 'Plantillas',
+ 'The following Datasets are not in use and can be deleted' => 'Los
+siguientes sets de datos no estan en uso y pueden ser borrados',
+ 'The following Datasets need to be updated' => 'Es necesario actualizar las siguientes bases de datos',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta es una verificacion preliminar de fuentes existentes. Nada será creado o borrado en esta etapa!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para agregar un usuario a un grupo, edite un nombre, cambie el nombre de entrada (login) y guarde los cambios. Un nuevo usuario, con las mismas variables será guardado bajo el nuevo nombre de entrada. (login)',
+ 'Update Dataset' => 'Actualizar conjunto de datos',
+ 'Use Templates' => 'Plantillas de Usuarios',
+ 'User' => 'Usuario',
+ 'User deleted!' => 'User deleted!',
+ 'User saved!' => 'User saved!',
+ 'Version' => 'Versión',
+ 'You must enter a host and port for local and remote connections!' => 'Debe
+introducir un servidor de base de datos y un puerto para conexiones locales y
+remotas!',
+ 'does not exist' => 'No existe',
+ 'is already a member!' => 'ya es miembro!',
+ 'localhost' => 'servidor local',
+ 'successfully created!' => 'creado con éxito!',
+ 'successfully deleted!' => 'creado con éxito!',
+ 'website' => 'sitio web',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'agregar_usuario' => 'add_user',
+ 'cambiar_contraseña_de_administrador' => 'change_admin_password',
+ 'cambiar_contraseña' => 'change_password',
+ 'continuar' => 'continue',
+ 'crear_set_de_datos' => 'create_dataset',
+ 'borrar' => 'delete',
+ 'borrar_set_de_datos' => 'delete_dataset',
+ 'login' => 'login',
+ 'oracle_administración_de_base_de_datos' => 'oracle_database_administration',
+ 'pg_administración_de_base_de_datos' => 'pg_database_administration',
+ 'salvar' => 'save',
+ 'actualizar_conjunto_de_datos' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/all b/sql-ledger/locale/mx/all
new file mode 100644
index 0000000..b3761a7
--- /dev/null
+++ b/sql-ledger/locale/mx/all
@@ -0,0 +1,496 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Ctas X Pagar',
+ 'AP Aging' => 'Envejecimiento - CxP',
+ 'AP Transaction' => '',
+ 'AP Transactions' => 'Transacciones - Cuentas por Pagar',
+ 'AR' => 'Ctas X Cobrar',
+ 'AR Aging' => 'Envejecimiento - CxC ',
+ 'AR Transaction' => '',
+ 'AR Transactions' => 'Transacciones de Cuentas por Cobrar',
+ 'About' => 'Acerca',
+ 'Access Control' => 'Control de Acceso',
+ 'Account' => 'Cuenta',
+ 'Account Number' => 'Número de Cuenta',
+ 'Account Number missing!' => 'No existe el número de cuenta!',
+ 'Account Type' => 'Tipo de Cuenta',
+ 'Account Type missing!' => 'No existe el tipo de la cuenta!',
+ 'Account deleted!' => '',
+ 'Account saved!' => '',
+ 'Accounting' => 'Contabilidad',
+ 'Accounting Menu' => 'Menú de Contabilidad',
+ 'Accounts' => 'Cuentas',
+ 'Active' => '',
+ 'Add' => 'Agregar',
+ 'Add Account' => 'Agregar Cuenta',
+ 'Add Accounts Payables Transaction' => '',
+ 'Add Accounts Receivables Transaction' => '',
+ 'Add Assembly' => 'Agregar Ensamblaje',
+ 'Add Customer' => 'Agregar Cliente',
+ 'Add GIFI' => 'Añadir código GIFI',
+ 'Add General Ledger Transaction' => 'Agregar Transacción - Mayor General',
+ 'Add Part' => 'Agregar Parte',
+ 'Add Project' => '',
+ 'Add Purchase Invoice' => '',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Invoice' => '',
+ 'Add Sales Order' => 'Agregar Nota de Remisión',
+ 'Add Service' => 'Agregar Servicio',
+ 'Add Transaction' => 'Agregar Transaccion',
+ 'Add User' => 'Agregar Usuario',
+ 'Add Vendor' => 'Agregar Proveedor',
+ 'Address' => 'Dirección',
+ 'Administration' => 'Administración',
+ 'Administrator' => '',
+ 'All' => 'Todos',
+ 'All Datasets up to date!' => '! Todos los conjuntos de datos estan actualizados !',
+ 'Amount' => 'Total',
+ 'Amount Due' => '',
+ 'Amount does not equal applied!' => '',
+ 'Amount missing!' => '',
+ 'Applied' => '',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Esta seguro de que desea borrar la Factura No.:',
+ 'Are you sure you want to delete Order Number' => '¿Esta seguro de que desea
+borrar la Orden No.:?',
+ 'Are you sure you want to delete Transaction' => '¿Está usted seguro de que desea suprimir la transacción?',
+ 'Assemblies' => 'Ensamblajes',
+ 'Assemblies restocked!' => '',
+ 'Assembly Number missing!' => 'No existe Numero de Ensamblaje!',
+ 'Asset' => 'Activo',
+ 'Attachment' => 'Adjunto',
+ 'Audit Control' => 'Control de auditoria',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => '',
+ 'Backup' => 'Respaldo',
+ 'Backup sent to' => 'Respaldo enviado a',
+ 'Balance' => '',
+ 'Balance Sheet' => 'Hoja de Balance',
+ 'Bcc' => '',
+ 'Bin' => 'Bin',
+ 'Books are open' => 'Los libros estan abiertos',
+ 'Bought' => 'Comprado',
+ 'Business Number' => 'Numero de Negocio',
+ 'C' => '',
+ 'COGS' => 'Costo de Ventas',
+ 'Cannot delete account!' => '',
+ 'Cannot delete customer!' => '',
+ 'Cannot delete default account!' => 'No se puede borrar cuenta por defecto!',
+ 'Cannot delete invoice!' => '',
+ 'Cannot delete item already invoiced!' => 'No puede suprimir el item ya facturado!',
+ 'Cannot delete item on order!' => 'No se puede eliminar un elemnto presente en una orden',
+ 'Cannot delete item which is part of an assembly!' => 'No puede suprimir un item que es parte de un ensamblaje!',
+ 'Cannot delete item!' => '',
+ 'Cannot delete order!' => '',
+ 'Cannot delete transaction!' => '',
+ 'Cannot delete vendor!' => '',
+ 'Cannot have a value in both Debit and Credit!' => 'No puede tener un valor en Débito y Crédito simultáneamente!',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => 'No se puede registrar factura para un periodo cerrado!',
+ 'Cannot post invoice!' => '',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cannot post payment!' => '',
+ 'Cannot post transaction for a closed period!' => 'No se puede registrar una transacción para un periodo cerrado',
+ 'Cannot post transaction!' => '',
+ 'Cannot process payment for a closed period!' => '',
+ 'Cannot save account!' => '',
+ 'Cannot save order!' => '',
+ 'Cannot save preferences!' => '',
+ 'Cannot stock assemblies!' => '',
+ 'Cash' => '',
+ 'Cash based' => '',
+ 'Cc' => '',
+ 'Change Admin Password' => 'Cambiar Contraseña de Administrador',
+ 'Change Password' => 'Cambiar Contraseña',
+ 'Character Set' => 'Tabla de Caracteres',
+ 'Chart of Accounts' => 'Catálogo Contable',
+ 'Check' => '',
+ 'Check printed!' => '',
+ 'Check printing failed!' => '',
+ 'Cleared Balance' => '',
+ 'Click on login name to edit!' => 'Haga clic en el nombre de entrada a
+editar',
+ 'Close Books up to' => 'Se cerraron los libros hasta',
+ 'Closed' => 'Cerrado',
+ 'Company' => 'Compañía',
+ 'Compare to' => 'Comparar a',
+ 'Confirm!' => 'Confirmar!',
+ 'Connect to' => 'Conectar a',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Copy to COA' => 'Copiar al catálogo de cuentas',
+ 'Create Chart of Accounts' => 'Crear catálogo de cuentas',
+ 'Create Dataset' => 'Crear set de datos',
+ 'Credit' => 'Crédito',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Curr' => 'Mon.',
+ 'Currency' => 'Moneda',
+ 'Current' => '',
+ 'Customer' => 'Cliente',
+ 'Customer deleted!' => '',
+ 'Customer missing!' => '',
+ 'Customer not on file!' => '',
+ 'Customer saved!' => '',
+ 'Customers' => '',
+ 'DBI not installed!' => 'DBI no instalado!',
+ 'Database' => 'Base de datos',
+ 'Database Administration' => 'Administración de base de datos',
+ 'Database Driver not checked!' => '!No selecciono driver de base de datos!',
+ 'Database Host' => 'Servidor de Base de Datos',
+ 'Database User missing!' => 'No se encuentra usuario de base de datos',
+ 'Dataset' => 'Set de datos',
+ 'Dataset missing!' => 'No se encuentra Set de datos!',
+ 'Dataset updated!' => '',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Fecha de Vencimiento',
+ 'Date Format' => 'Formato de Fecha',
+ 'Date Paid' => 'Fecha de pago',
+ 'Date missing!' => '',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito y Crédito fuera de balance.',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Decimalplaces' => '',
+ 'Delete' => 'Borrar',
+ 'Delete Account' => 'Borrar Cuenta',
+ 'Delete Dataset' => 'Borrar Set de Datos',
+ 'Delivery Date' => '',
+ 'Deposit' => '',
+ 'Description' => 'Descripción',
+ 'Difference' => '',
+ 'Directory' => 'Directorio',
+ 'Discount' => 'Descuento',
+ 'Done' => '',
+ 'Drawing' => '',
+ 'Driver' => 'Manejador',
+ 'Dropdown Limit' => '',
+ 'Due' => 'Vence',
+ 'Due Date' => 'Fecha de Vencimiento',
+ 'Due Date missing!' => 'Falta Fecha de Vencimiento!',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail Statement to' => '',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit' => '',
+ 'Edit Account' => 'Editar Cuenta',
+ 'Edit Accounts Payables Transaction' => '',
+ 'Edit Accounts Receivables Transaction' => '',
+ 'Edit Assembly' => 'Editar Ensamblaje',
+ 'Edit GIFI' => 'Editar GIFI',
+ 'Edit General Ledger Transaction' => 'Editar Transacción de Mayor General',
+ 'Edit Part' => 'Editar Parte',
+ 'Edit Preferences for' => 'Editar Preferencias para',
+ 'Edit Project' => '',
+ 'Edit Purchase Invoice' => '',
+ 'Edit Purchase Order' => 'Editar Orden de Compra',
+ 'Edit Sales Invoice' => '',
+ 'Edit Sales Order' => 'Editar Remisión',
+ 'Edit Service' => 'Editar Servicio',
+ 'Edit Template' => 'Editar Plantilla',
+ 'Edit User' => 'Editar Usuario',
+ 'Employee' => '',
+ 'Enforce transaction reversal for all dates' => 'Forzar la anulación de las transacciones para todas las fechas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => '',
+ 'Equity' => 'Capital',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate Difference' => '',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Existing Datasets' => 'Sets de dato existentes',
+ 'Expense' => 'Egreso',
+ 'Expense Account' => 'Cuenta de Egreso',
+ 'Expense/Asset' => 'Egreso/Activo',
+ 'Extended' => '',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'Foreign Exchange Gain' => 'Ganancia en Moneda Extranjera',
+ 'Foreign Exchange Loss' => 'Pérdida en Moneda Extranjera',
+ 'From' => 'Desde',
+ 'GIFI' => 'Código GIFI',
+ 'GIFI deleted!' => '',
+ 'GIFI missing!' => 'No se ha definido el código GIFI',
+ 'GIFI saved!' => '',
+ 'GL Transaction' => '',
+ 'General Ledger' => 'Mayor General',
+ 'Goods & Services' => 'Bienes y servicios',
+ 'HTML Templates' => 'Plantillas HTML',
+ 'Heading' => 'Encabezado',
+ 'Host' => 'Servidor base de datos',
+ 'Hostname missing!' => 'No se encuentra servidor de base de datos',
+ 'ID' => 'ID',
+ 'Image' => '',
+ 'In-line' => 'En linea',
+ 'Include in Report' => 'Incluya en informe',
+ 'Include in drop-down menus' => 'Incluya en menús desplegables',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluya esta cuenta en las formas del cliente/proveedor para señalar al cliente/proveedor como gravable de impuesto?',
+ 'Income' => 'Ingreso',
+ 'Income Account' => 'Cuenta de Ingreso',
+ 'Income Statement' => 'Estado de Cuentas',
+ 'Incorrect Dataset version!' => '!Versisn incorrecta de conjunto de datos!',
+ 'Incorrect Password!' => 'Contraseña Incorrecta!',
+ 'Individual Items' => 'Items Individuales',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Cuenta de Inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar este ensamblaje a obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar esta parte a obsoleto',
+ 'Inventory quantity must be zero!' => 'La cantidad en inventario debe ser
+cero!',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Invoice deleted!' => '',
+ 'Invoice posted!' => '',
+ 'Invoices' => '',
+ 'Is this a summary account to record' => 'Es esta una cuenta de resumen a registrar?',
+ 'Item deleted!' => '',
+ 'Item not on file!' => '¡El artículo no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'LaTeX Templates' => 'Plantillas de LaTeX',
+ 'Language' => 'Lenguaje',
+ 'Last Cost' => 'Ultimo Costo',
+ 'Last Invoice Number' => 'Último Número de Factura',
+ 'Last Numbers & Default Accounts' => 'Últimos Números y Cuentas por Defecto',
+ 'Last Purchase Order Number' => 'Ultima Orden de Compra',
+ 'Last Sales Order Number' => 'Número del último presupuesto',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deje los campos de servidor de base de datos y puerto vacíos al menos que quiera hacer una conexión remota',
+ 'Liability' => 'Pasivo',
+ 'Licensed to' => 'Licenciado a',
+ 'Line Total' => 'Total de la linea',
+ 'Link' => 'Enlaces',
+ 'Link Accounts' => 'Enlazar Cuentas',
+ 'List Accounts' => 'Listar Cuentas',
+ 'List GIFI' => 'Listar código GIFI',
+ 'List Price' => 'Precio de Lista',
+ 'List Transactions' => 'Listar Transacciones',
+ 'Login' => 'Login',
+ 'Logout' => 'Salir',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Microfiche' => '',
+ 'Model' => 'Modelo',
+ 'N/A' => 'N/A',
+ 'Name' => 'Nombre',
+ 'Name missing!' => '',
+ 'New Templates' => 'Nuevas Plantillas',
+ 'No' => 'No',
+ 'No Database Drivers available!' => 'No hay manejador de base de datos
+disponible!',
+ 'No Dataset selected!' => 'No se ha seleccionado el set de datos',
+ 'No email address for' => 'Falta email para',
+ 'No.' => '',
+ 'Notes' => 'Notas',
+ 'Nothing applied!' => '',
+ 'Nothing selected!' => '',
+ 'Nothing to delete!' => '!Nada para borrar!',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato de Numero',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'O' => '',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'On Hand' => 'En Existencia',
+ 'On Order' => '',
+ 'Open' => 'Abierto',
+ 'Oracle Database Administration' => 'Oracle Administración de base de datos',
+ 'Order' => 'Orden',
+ 'Order Date' => 'Fecha de Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Entry' => 'Orden de Entrada',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'Order deleted!' => '',
+ 'Order saved!' => '',
+ 'Ordered' => '',
+ 'Orphaned' => 'Huerfano',
+ 'Out of balance!' => '',
+ 'PDF' => '',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => '!Falta fecha en lista de empaque!',
+ 'Packing List Number missing!' => '!Falta nzmero en lista de empaque!',
+ 'Paid' => 'Total Pagado',
+ 'Paid in full' => '',
+ 'Part' => 'Partes',
+ 'Part Number missing!' => 'Falta del número de pieza!',
+ 'Parts' => 'Partes',
+ 'Parts Inventory' => 'Inventario de Partes',
+ 'Password' => 'Contraseña',
+ 'Password changed!' => '',
+ 'Payables' => 'Por Pagar',
+ 'Payment' => 'Pago',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payment posted!' => '',
+ 'Payments' => 'Pagos',
+ 'Pg Database Administration' => 'Pg Administración de base de datos',
+ 'Phone' => 'Teléfono',
+ 'Port' => 'Puerto',
+ 'Port missing!' => 'No se encuentra el Puerto!',
+ 'Post' => '',
+ 'Post as new' => '',
+ 'Postscript' => '',
+ 'Preferences' => 'Preferencias',
+ 'Preferences saved!' => 'Preferencias guardadas!',
+ 'Price' => 'Precio',
+ 'Print' => '',
+ 'Printer' => 'Impresora',
+ 'Project' => '',
+ 'Project Number missing!' => '',
+ 'Project deleted!' => '',
+ 'Project not on file!' => '',
+ 'Project saved!' => '',
+ 'Projects' => '',
+ 'Purchase Invoice' => '',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Purchase Orders' => 'Ordenes de Compra',
+ 'Qty' => 'Cantidad',
+ 'ROP' => 'ROP',
+ 'Rate' => 'Tarifa',
+ 'Recd' => '',
+ 'Receipt' => '',
+ 'Receipts' => '',
+ 'Receivables' => 'Por Cobrar',
+ 'Reconciliation' => '',
+ 'Record in' => 'Registrar en',
+ 'Reference' => '',
+ 'Reference missing!' => '',
+ 'Remaining' => 'Faltan',
+ 'Report for' => 'Informe para',
+ 'Reports' => 'Reportes',
+ 'Required by' => 'Requerido por',
+ 'Retained Earnings' => 'Ganacias Retenidas',
+ 'Sales' => 'Ventas',
+ 'Sales Invoice' => '',
+ 'Sales Order' => 'Orden de venta',
+ 'Sales Orders' => 'Ordenes de venta',
+ 'Save' => 'Salvar',
+ 'Save as new' => '',
+ 'Save to File' => 'Guardar en archivo',
+ 'Screen' => 'Pantalla',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione un set de
+datos para borrar y presione "Continuar"',
+ 'Select all' => '',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select from one of the names below' => '',
+ 'Select from one of the projects below' => '',
+ 'Select postscript or PDF!' => '',
+ 'Sell Price' => 'Precio de Venta',
+ 'Send by E-Mail' => 'Enviar por E-Mail',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Service Items' => 'Items de Servicio',
+ 'Service Number missing!' => 'Falta el número de servicio!',
+ 'Services' => 'Servicios',
+ 'Setup Templates' => 'Configurar Plantillas',
+ 'Ship' => '',
+ 'Ship to' => '',
+ 'Ship via' => '',
+ 'Short' => 'Corto',
+ 'Signature' => 'Firma',
+ 'Sold' => 'Vendido',
+ 'Source' => 'Fuente',
+ 'Standard' => 'Estándard',
+ 'Statement' => '',
+ 'Statement Balance' => '',
+ 'Statement sent to' => '',
+ 'Statements sent to printer!' => '',
+ 'Stock Assembly' => 'Inventariar Ensamblaje?',
+ 'Stylesheet' => 'Estilo de hoja',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'System' => 'Sistema',
+ 'Tax' => 'Impuesto',
+ 'Tax Accounts' => 'Cuentas De Impuesto',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Tax collected' => '',
+ 'Tax paid' => '',
+ 'Taxable' => 'Gravable de Impuesto',
+ 'Template saved!' => '',
+ 'Templates' => 'Plantillas',
+ 'Terms: Net' => 'Crédito',
+ 'The following Datasets are not in use and can be deleted' => 'Los
+siguientes sets de datos no estan en uso y pueden ser borrados',
+ 'The following Datasets need to be updated' => 'Es necesario actualizar las siguientes bases de datos',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta es una verificacion preliminar de fuentes existentes. Nada será creado o borrado en esta etapa!',
+ 'To' => 'Hasta ',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para agregar un usuario a un grupo, edite un nombre, cambie el nombre de entrada (login) y guarde los cambios. Un nuevo usuario, con las mismas variables será guardado bajo el nuevo nombre de entrada. (login)',
+ 'Top Level' => '',
+ 'Total' => 'Total',
+ 'Transaction Date missing!' => 'Falta la fecha de la transacción!',
+ 'Transaction deleted!' => '',
+ 'Transaction posted!' => '',
+ 'Transaction reversal enforced for all dates' => 'Se ha forzado la anulación de las transacciones para todas las fechas',
+ 'Transaction reversal enforced up to' => 'Se ha forzado la anulación de las transacciones hasta',
+ 'Transactions' => 'Transacciones',
+ 'Transactions exist, cannot delete customer!' => 'Las transacciones existen, no pueden suprimir el cliente!',
+ 'Transactions exist, cannot delete vendor!' => 'Las transacciones existen, no pueden suprimir a proveedor',
+ 'Transactions exist; cannot delete account!' => 'Las transacciones existen,
+no puede suprimir la cuenta!',
+ 'Trial Balance' => 'Balance De Comprobación',
+ 'Unit' => 'Unidad',
+ 'Unit of measure' => 'Unidad de medida',
+ 'Update' => '',
+ 'Update Dataset' => 'Actualizar conjunto de datos',
+ 'Updated' => '',
+ 'Use Templates' => 'Plantillas de Usuarios',
+ 'User' => 'Usuario',
+ 'User deleted!' => '',
+ 'User saved!' => '',
+ 'Vendor' => 'Proveedor',
+ 'Vendor deleted!' => '',
+ 'Vendor missing!' => '',
+ 'Vendor not on file!' => '',
+ 'Vendor saved!' => '',
+ 'Vendors' => '',
+ 'Version' => 'Versión',
+ 'Weight' => 'Peso',
+ 'Weight Unit' => 'Unidad de Peso',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'Year End' => 'Fin del Año Fiscal',
+ 'Yes' => 'Si',
+ 'You are logged out!' => '',
+ 'You did not enter a name!' => 'No introdujo un nombre!',
+ 'You must enter a host and port for local and remote connections!' => 'Debe
+introducir un servidor de base de datos y un puerto para conexiones locales y
+remotas!',
+ 'as at' => '',
+ 'collected on sales' => 'ingresado en ventas',
+ 'days' => 'Días',
+ 'does not exist' => 'No existe',
+ 'ea' => 'c/u',
+ 'emailed to' => 'Se envio email a',
+ 'for Period' => 'para el período',
+ 'hr' => 'hr',
+ 'is already a member!' => 'ya es miembro!',
+ 'is not a member!' => '!no es miembro!',
+ 'localhost' => 'servidor local',
+ 'paid on purchases' => 'pagado en compras',
+ 'sent to printer' => 'Enviado a la impresora',
+ 'successfully created!' => 'creado con éxito!',
+ 'successfully deleted!' => 'creado con éxito!',
+ 'to' => '',
+ 'website' => 'sitio web',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/am b/sql-ledger/locale/mx/am
new file mode 100644
index 0000000..d96b138
--- /dev/null
+++ b/sql-ledger/locale/mx/am
@@ -0,0 +1,140 @@
+$self{texts} = {
+ 'AP' => 'Ctas X Pagar',
+ 'AR' => 'Ctas X Cobrar',
+ 'Account' => 'Cuenta',
+ 'Account Number' => 'Número de Cuenta',
+ 'Account Number missing!' => 'No existe el número de cuenta!',
+ 'Account Type' => 'Tipo de Cuenta',
+ 'Account Type missing!' => 'No existe el tipo de la cuenta!',
+ 'Account deleted!' => 'Account deleted!',
+ 'Account saved!' => 'Account saved!',
+ 'Add Account' => 'Agregar Cuenta',
+ 'Add GIFI' => 'Añadir código GIFI',
+ 'Address' => 'Dirección',
+ 'Asset' => 'Activo',
+ 'Audit Control' => 'Control de auditoria',
+ 'Backup sent to' => 'Respaldo enviado a',
+ 'Books are open' => 'Los libros estan abiertos',
+ 'Business Number' => 'Numero de Negocio',
+ 'COGS' => 'Costo de Ventas',
+ 'Cannot delete account!' => 'Cannot delete account!',
+ 'Cannot delete default account!' => 'No se puede borrar cuenta por defecto!',
+ 'Cannot save account!' => 'Cannot save account!',
+ 'Cannot save preferences!' => 'Cannot save preferences!',
+ 'Character Set' => 'Tabla de Caracteres',
+ 'Chart of Accounts' => 'Catálogo Contable',
+ 'Close Books up to' => 'Se cerraron los libros hasta',
+ 'Company' => 'Compañía',
+ 'Continue' => 'Continuar',
+ 'Copy to COA' => 'Copiar al catálogo de cuentas',
+ 'Credit' => 'Crédito',
+ 'Date Format' => 'Formato de Fecha',
+ 'Debit' => 'Débito',
+ 'Delete' => 'Borrar',
+ 'Delete Account' => 'Borrar Cuenta',
+ 'Description' => 'Descripción',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'Correo Electrónico',
+ 'Edit' => 'Edit',
+ 'Edit Account' => 'Editar Cuenta',
+ 'Edit GIFI' => 'Editar GIFI',
+ 'Edit Preferences for' => 'Editar Preferencias para',
+ 'Edit Template' => 'Editar Plantilla',
+ 'Enforce transaction reversal for all dates' => 'Forzar la anulación de las transacciones para todas las fechas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Egreso',
+ 'Expense Account' => 'Cuenta de Egreso',
+ 'Expense/Asset' => 'Egreso/Activo',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Ganancia en Moneda Extranjera',
+ 'Foreign Exchange Loss' => 'Pérdida en Moneda Extranjera',
+ 'GIFI' => 'Código GIFI',
+ 'GIFI deleted!' => 'GIFI deleted!',
+ 'GIFI missing!' => 'No se ha definido el código GIFI',
+ 'GIFI saved!' => 'GIFI saved!',
+ 'Heading' => 'Encabezado',
+ 'Include in drop-down menus' => 'Incluya en menús desplegables',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluya esta cuenta en las formas del cliente/proveedor para señalar al cliente/proveedor como gravable de impuesto?',
+ 'Income' => 'Ingreso',
+ 'Income Account' => 'Cuenta de Ingreso',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Cuenta de Inventario',
+ 'Is this a summary account to record' => 'Es esta una cuenta de resumen a registrar?',
+ 'Language' => 'Lenguaje',
+ 'Last Invoice Number' => 'Último Número de Factura',
+ 'Last Numbers & Default Accounts' => 'Últimos Números y Cuentas por Defecto',
+ 'Last Purchase Order Number' => 'Ultima Orden de Compra',
+ 'Last Sales Order Number' => 'Número del último presupuesto',
+ 'Liability' => 'Pasivo',
+ 'Link' => 'Enlaces',
+ 'Name' => 'Nombre',
+ 'No' => 'No',
+ 'No email address for' => 'Falta email para',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato de Numero',
+ 'Parts Inventory' => 'Inventario de Partes',
+ 'Password' => 'Contraseña',
+ 'Payables' => 'Por Pagar',
+ 'Payment' => 'Pago',
+ 'Phone' => 'Teléfono',
+ 'Preferences saved!' => 'Preferencias guardadas!',
+ 'Rate' => 'Tarifa',
+ 'Receivables' => 'Por Cobrar',
+ 'Sales' => 'Ventas',
+ 'Save' => 'Salvar',
+ 'Service Items' => 'Items de Servicio',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Estilo de hoja',
+ 'Tax' => 'Impuesto',
+ 'Tax Accounts' => 'Cuentas De Impuesto',
+ 'Template saved!' => 'Template saved!',
+ 'Transaction reversal enforced for all dates' => 'Se ha forzado la anulación de las transacciones para todas las fechas',
+ 'Transaction reversal enforced up to' => 'Se ha forzado la anulación de las transacciones hasta',
+ 'Transactions exist; cannot delete account!' => 'Las transacciones existen,
+no puede suprimir la cuenta!',
+ 'Weight Unit' => 'Unidad de Peso',
+ 'Year End' => 'Fin del Año Fiscal',
+ 'Yes' => 'Si',
+ 'does not exist' => 'No existe',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'agregar_cuenta' => 'add_account',
+ 'continuar' => 'continue',
+ 'copiar_al_catálogo_de_cuentas' => 'copy_to_coa',
+ 'borrar' => 'delete',
+ 'edit' => 'edit',
+ 'editar_cuenta' => 'edit_account',
+ 'salvar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/ap b/sql-ledger/locale/mx/ap
new file mode 100644
index 0000000..68d095c
--- /dev/null
+++ b/sql-ledger/locale/mx/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AP Transactions' => 'Transacciones - Cuentas por Pagar',
+ 'Account' => 'Cuenta',
+ 'Add Accounts Payables Transaction' => 'Add Accounts Payables Transaction',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => '¿Está usted seguro de que desea suprimir la transacción?',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cannot post transaction for a closed period!' => 'No se puede registrar una transacción para un periodo cerrado',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moneda',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date Paid' => 'Fecha de pago',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Due Date' => 'Fecha de Vencimiento',
+ 'Due Date missing!' => 'Falta Fecha de Vencimiento!',
+ 'Edit Accounts Payables Transaction' => 'Edit Accounts Payables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluya en informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Number' => 'Orden Número',
+ 'Paid' => 'Total Pagado',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payments' => 'Pagos',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Si',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'add_accounts_payables_transaction' => 'add_accounts_payables_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'edit_accounts_payables_transaction' => 'edit_accounts_payables_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/ar b/sql-ledger/locale/mx/ar
new file mode 100644
index 0000000..3f2fd0e
--- /dev/null
+++ b/sql-ledger/locale/mx/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'AR Transaction',
+ 'AR Transactions' => 'Transacciones de Cuentas por Cobrar',
+ 'Account' => 'Cuenta',
+ 'Add Accounts Receivables Transaction' => 'Add Accounts Receivables Transaction',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => '¿Está usted seguro de que desea suprimir la transacción?',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cannot post transaction for a closed period!' => 'No se puede registrar una transacción para un periodo cerrado',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date Paid' => 'Fecha de pago',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Due Date' => 'Fecha de Vencimiento',
+ 'Due Date missing!' => 'Falta Fecha de Vencimiento!',
+ 'Edit Accounts Receivables Transaction' => 'Edit Accounts Receivables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluya en informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Number' => 'Orden Número',
+ 'Paid' => 'Total Pagado',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payments' => 'Pagos',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Remaining' => 'Faltan',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Si',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ar_transaction' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/arap b/sql-ledger/locale/mx/arap
new file mode 100644
index 0000000..f541192
--- /dev/null
+++ b/sql-ledger/locale/mx/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Dirección',
+ 'Continue' => 'Continuar',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Description' => 'Descripción',
+ 'Number' => 'Número',
+ 'Project not on file!' => 'Project not on file!',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/ca b/sql-ledger/locale/mx/ca
new file mode 100644
index 0000000..5d43318
--- /dev/null
+++ b/sql-ledger/locale/mx/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'Catálogo Contable',
+ 'Credit' => 'Crédito',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Description' => 'Descripción',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'Código GIFI',
+ 'Include in Report' => 'Incluya en informe',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'List Transactions' => 'Listar Transacciones',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Reference' => 'Reference',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Hasta ',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'listar_transacciones' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/cp b/sql-ledger/locale/mx/cp
new file mode 100644
index 0000000..95085e0
--- /dev/null
+++ b/sql-ledger/locale/mx/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Amount missing!',
+ 'Applied' => 'Applied',
+ 'Cannot post payment!' => 'Cannot post payment!',
+ 'Cannot process payment for a closed period!' => 'Cannot process payment for a closed period!',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check printed!',
+ 'Check printing failed!' => 'Check printing failed!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date missing!' => 'Date missing!',
+ 'Description' => 'Descripción',
+ 'Due' => 'Vence',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'From' => 'Desde',
+ 'Invoice' => 'Factura',
+ 'Invoices' => 'Invoices',
+ 'Nothing applied!' => 'Nothing applied!',
+ 'Number' => 'Número',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'Pago',
+ 'Payment posted!' => 'Payment posted!',
+ 'Post' => 'Post',
+ 'Print' => 'Print',
+ 'Printer' => 'Impresora',
+ 'Project not on file!' => 'Project not on file!',
+ 'Receipt' => 'Receipt',
+ 'Reference' => 'Reference',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'To' => 'Hasta ',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveedor',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/ct b/sql-ledger/locale/mx/ct
new file mode 100644
index 0000000..0db8902
--- /dev/null
+++ b/sql-ledger/locale/mx/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Agregar',
+ 'Address' => 'Dirección',
+ 'All' => 'Todos',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Cannot delete customer!',
+ 'Cannot delete vendor!' => 'Cannot delete vendor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Customer deleted!' => 'Customer deleted!',
+ 'Customer saved!' => 'Customer saved!',
+ 'Customers' => 'Customers',
+ 'Delete' => 'Borrar',
+ 'Discount' => 'Descuento',
+ 'E-mail' => 'Correo Electrónico',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Incluya en informe',
+ 'Invoice' => 'Factura',
+ 'Name' => 'Nombre',
+ 'Name missing!' => 'Name missing!',
+ 'Notes' => 'Notas',
+ 'Number' => 'Número',
+ 'Order' => 'Orden',
+ 'Orphaned' => 'Huerfano',
+ 'Phone' => 'Teléfono',
+ 'Save' => 'Salvar',
+ 'Ship to' => 'Ship to',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Taxable' => 'Gravable de Impuesto',
+ 'Terms: Net' => 'Crédito',
+ 'Transactions exist, cannot delete customer!' => 'Las transacciones existen, no pueden suprimir el cliente!',
+ 'Transactions exist, cannot delete vendor!' => 'Las transacciones existen, no pueden suprimir a proveedor',
+ 'Vendor deleted!' => 'Vendor deleted!',
+ 'Vendor saved!' => 'Vendor saved!',
+ 'Vendors' => 'Vendors',
+ 'days' => 'Días',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'agregar' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'factura' => 'invoice',
+ 'orden' => 'order',
+ 'salvar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/gl b/sql-ledger/locale/mx/gl
new file mode 100644
index 0000000..b0957b6
--- /dev/null
+++ b/sql-ledger/locale/mx/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AR Transaction' => 'AR Transaction',
+ 'Account' => 'Cuenta',
+ 'Add General Ledger Transaction' => 'Agregar Transacción - Mayor General',
+ 'Address' => 'Dirección',
+ 'All' => 'Todos',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => '¿Está usted seguro de que desea suprimir la transacción?',
+ 'Asset' => 'Activo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot have a value in both Debit and Credit!' => 'No puede tener un valor en Débito y Crédito simultáneamente!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'No se puede registrar una transacción para un periodo cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit' => 'Crédito',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito y Crédito fuera de balance.',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Edit General Ledger Transaction' => 'Editar Transacción de Mayor General',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Egreso',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'Código GIFI',
+ 'GL Transaction' => 'GL Transaction',
+ 'General Ledger' => 'Mayor General',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluya en informe',
+ 'Income' => 'Ingreso',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Liability' => 'Pasivo',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference missing!',
+ 'Reports' => 'Reportes',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Hasta ',
+ 'Transaction Date missing!' => 'Falta la fecha de la transacción!',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Si',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'gl_transaction' => 'gl_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/ic b/sql-ledger/locale/mx/ic
new file mode 100644
index 0000000..e5e1a86
--- /dev/null
+++ b/sql-ledger/locale/mx/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => 'Active',
+ 'Add' => 'Agregar',
+ 'Add Assembly' => 'Agregar Ensamblaje',
+ 'Add Part' => 'Agregar Parte',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Order' => 'Agregar Nota de Remisión',
+ 'Add Service' => 'Agregar Servicio',
+ 'Address' => 'Dirección',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Assemblies' => 'Ensamblajes',
+ 'Assemblies restocked!' => 'Assemblies restocked!',
+ 'Assembly Number missing!' => 'No existe Numero de Ensamblaje!',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Bought' => 'Comprado',
+ 'COGS' => 'Costo de Ventas',
+ 'Cannot delete item already invoiced!' => 'No puede suprimir el item ya facturado!',
+ 'Cannot delete item on order!' => 'No se puede eliminar un elemnto presente en una orden',
+ 'Cannot delete item which is part of an assembly!' => 'No puede suprimir un item que es parte de un ensamblaje!',
+ 'Cannot delete item!' => 'Cannot delete item!',
+ 'Cannot stock assemblies!' => 'Cannot stock assemblies!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'Drawing' => 'Drawing',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit Assembly' => 'Editar Ensamblaje',
+ 'Edit Part' => 'Editar Parte',
+ 'Edit Service' => 'Editar Servicio',
+ 'Expense' => 'Egreso',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'Image' => 'Image',
+ 'In-line' => 'En linea',
+ 'Include in Report' => 'Incluya en informe',
+ 'Income' => 'Ingreso',
+ 'Individual Items' => 'Items Individuales',
+ 'Inventory' => 'Inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar este ensamblaje a obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar esta parte a obsoleto',
+ 'Inventory quantity must be zero!' => 'La cantidad en inventario debe ser
+cero!',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Item deleted!' => 'Item deleted!',
+ 'Item not on file!' => '¡El artículo no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Last Cost' => 'Ultimo Costo',
+ 'Line Total' => 'Total de la linea',
+ 'Link Accounts' => 'Enlazar Cuentas',
+ 'List Price' => 'Precio de Lista',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modelo',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'On Hand' => 'En Existencia',
+ 'On Order' => 'On Order',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'Ordered' => 'Ordered',
+ 'Orphaned' => 'Huerfano',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => '!Falta fecha en lista de empaque!',
+ 'Packing List Number missing!' => '!Falta nzmero en lista de empaque!',
+ 'Part' => 'Partes',
+ 'Part Number missing!' => 'Falta del número de pieza!',
+ 'Parts' => 'Partes',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cantidad',
+ 'ROP' => 'ROP',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Requerido por',
+ 'Sales' => 'Ventas',
+ 'Sales Order' => 'Orden de venta',
+ 'Save' => 'Salvar',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sell Price' => 'Precio de Venta',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Service Number missing!' => 'Falta el número de servicio!',
+ 'Services' => 'Servicios',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Short' => 'Corto',
+ 'Sold' => 'Vendido',
+ 'Stock Assembly' => 'Inventariar Ensamblaje?',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'To' => 'Hasta ',
+ 'Top Level' => 'Top Level',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Unit of measure' => 'Unidad de medida',
+ 'Update' => 'Update',
+ 'Updated' => 'Updated',
+ 'Weight' => 'Peso',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'ea' => 'c/u',
+ 'emailed to' => 'Se envio email a',
+ 'hr' => 'hr',
+ 'sent to printer' => 'Enviado a la impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'agregar' => 'add',
+ 'agregar_ensamblaje' => 'add_assembly',
+ 'agregar_parte' => 'add_part',
+ 'agregar_servicio' => 'add_service',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'editar_ensamblaje' => 'edit_assembly',
+ 'editar_parte' => 'edit_part',
+ 'editar_servicio' => 'edit_service',
+ 'salvar' => 'save',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/io b/sql-ledger/locale/mx/io
new file mode 100644
index 0000000..89258a8
--- /dev/null
+++ b/sql-ledger/locale/mx/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Order' => 'Agregar Nota de Remisión',
+ 'Address' => 'Dirección',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'In-line' => 'En linea',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Item not on file!' => '¡El artículo no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => '!Falta fecha en lista de empaque!',
+ 'Packing List Number missing!' => '!Falta nzmero en lista de empaque!',
+ 'Part' => 'Partes',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Orden de venta',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Subject' => 'Asunto',
+ 'To' => 'Hasta ',
+ 'Unit' => 'Unidad',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'emailed to' => 'Se envio email a',
+ 'sent to printer' => 'Enviado a la impresora',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/ir b/sql-ledger/locale/mx/ir
new file mode 100644
index 0000000..2df2b83
--- /dev/null
+++ b/sql-ledger/locale/mx/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Order' => 'Agregar Nota de Remisión',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Esta seguro de que desea borrar la Factura No.:',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'No se puede registrar factura para un periodo cerrado!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Currency' => 'Moneda',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Fecha de Vencimiento',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit Purchase Invoice' => 'Edit Purchase Invoice',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'In-line' => 'En linea',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => '¡El artículo no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => '!Falta fecha en lista de empaque!',
+ 'Packing List Number missing!' => '!Falta nzmero en lista de empaque!',
+ 'Part' => 'Partes',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payments' => 'Pagos',
+ 'Phone' => 'Teléfono',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Registrar en',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Orden de venta',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Source' => 'Fuente',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'Yes' => 'Si',
+ 'ea' => 'c/u',
+ 'emailed to' => 'Se envio email a',
+ 'sent to printer' => 'Enviado a la impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'orden' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/is b/sql-ledger/locale/mx/is
new file mode 100644
index 0000000..9286ecb
--- /dev/null
+++ b/sql-ledger/locale/mx/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Agregar Nota de Remisión',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Esta seguro de que desea borrar la Factura No.:',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'No se puede registrar factura para un periodo cerrado!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Fecha de Vencimiento',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit Sales Invoice' => 'Edit Sales Invoice',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'In-line' => 'En linea',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => '¡El artículo no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => '!Falta fecha en lista de empaque!',
+ 'Packing List Number missing!' => '!Falta nzmero en lista de empaque!',
+ 'Part' => 'Partes',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payments' => 'Pagos',
+ 'Phone' => 'Teléfono',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Print' => 'Print',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Registrar en',
+ 'Remaining' => 'Faltan',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Orden de venta',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Source' => 'Fuente',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'Yes' => 'Si',
+ 'ea' => 'c/u',
+ 'emailed to' => 'Se envio email a',
+ 'sent to printer' => 'Enviado a la impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'correo_electrónico' => 'e_mail',
+ 'orden' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/login b/sql-ledger/locale/mx/login
new file mode 100644
index 0000000..0e7f5b8
--- /dev/null
+++ b/sql-ledger/locale/mx/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'Acerca',
+ 'Accounting' => 'Contabilidad',
+ 'Database Host' => 'Servidor de Base de Datos',
+ 'Dataset' => 'Set de datos',
+ 'Incorrect Dataset version!' => '!Versisn incorrecta de conjunto de datos!',
+ 'Incorrect Password!' => 'Contraseña Incorrecta!',
+ 'Licensed to' => 'Licenciado a',
+ 'Login' => 'Login',
+ 'Name' => 'Nombre',
+ 'Password' => 'Contraseña',
+ 'User' => 'Usuario',
+ 'Version' => 'Versión',
+ 'You are logged out!' => 'You are logged out!',
+ 'You did not enter a name!' => 'No introdujo un nombre!',
+ 'is not a member!' => '!no es miembro!',
+ 'localhost' => 'servidor local',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/menu b/sql-ledger/locale/mx/menu
new file mode 100644
index 0000000..c0f9e4b
--- /dev/null
+++ b/sql-ledger/locale/mx/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'Ctas X Pagar',
+ 'AP Aging' => 'Envejecimiento - CxP',
+ 'AR' => 'Ctas X Cobrar',
+ 'AR Aging' => 'Envejecimiento - CxC ',
+ 'Accounting Menu' => 'Menú de Contabilidad',
+ 'Add Account' => 'Agregar Cuenta',
+ 'Add Assembly' => 'Agregar Ensamblaje',
+ 'Add Customer' => 'Agregar Cliente',
+ 'Add GIFI' => 'Añadir código GIFI',
+ 'Add Part' => 'Agregar Parte',
+ 'Add Project' => 'Add Project',
+ 'Add Service' => 'Agregar Servicio',
+ 'Add Transaction' => 'Agregar Transaccion',
+ 'Add Vendor' => 'Agregar Proveedor',
+ 'Assemblies' => 'Ensamblajes',
+ 'Audit Control' => 'Control de auditoria',
+ 'Backup' => 'Respaldo',
+ 'Balance Sheet' => 'Hoja de Balance',
+ 'Cash' => 'Cash',
+ 'Chart of Accounts' => 'Catálogo Contable',
+ 'Check' => 'Check',
+ 'Customers' => 'Customers',
+ 'General Ledger' => 'Mayor General',
+ 'Goods & Services' => 'Bienes y servicios',
+ 'HTML Templates' => 'Plantillas HTML',
+ 'Income Statement' => 'Estado de Cuentas',
+ 'Invoice' => 'Factura',
+ 'LaTeX Templates' => 'Plantillas de LaTeX',
+ 'List Accounts' => 'Listar Cuentas',
+ 'List GIFI' => 'Listar código GIFI',
+ 'Logout' => 'Salir',
+ 'Order Entry' => 'Orden de Entrada',
+ 'Packing List' => 'Lista de Empaque',
+ 'Parts' => 'Partes',
+ 'Payment' => 'Pago',
+ 'Payments' => 'Pagos',
+ 'Preferences' => 'Preferencias',
+ 'Projects' => 'Projects',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Purchase Orders' => 'Ordenes de Compra',
+ 'Receipt' => 'Receipt',
+ 'Receipts' => 'Receipts',
+ 'Reconciliation' => 'Reconciliation',
+ 'Reports' => 'Reportes',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Sales Order' => 'Orden de venta',
+ 'Sales Orders' => 'Ordenes de venta',
+ 'Save to File' => 'Guardar en archivo',
+ 'Send by E-Mail' => 'Enviar por E-Mail',
+ 'Services' => 'Servicios',
+ 'Statement' => 'Statement',
+ 'Stock Assembly' => 'Inventariar Ensamblaje?',
+ 'Stylesheet' => 'Estilo de hoja',
+ 'System' => 'Sistema',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'Transactions' => 'Transacciones',
+ 'Trial Balance' => 'Balance De Comprobación',
+ 'Vendors' => 'Vendors',
+ 'Version' => 'Versión',
+ 'localhost' => 'servidor local',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/oe b/sql-ledger/locale/mx/oe
new file mode 100644
index 0000000..6acc57a
--- /dev/null
+++ b/sql-ledger/locale/mx/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'Agregar',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Agregar Nota de Remisión',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Order Number' => '¿Esta seguro de que desea
+borrar la Orden No.:?',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Cannot delete order!',
+ 'Cannot save order!' => 'Cannot save order!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Curr' => 'Mon.',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit Purchase Order' => 'Editar Orden de Compra',
+ 'Edit Sales Order' => 'Editar Remisión',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'In-line' => 'En linea',
+ 'Include in Report' => 'Incluya en informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Item not on file!' => '¡El artículo no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'O' => 'O',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Date' => 'Fecha de Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'Order deleted!' => 'Order deleted!',
+ 'Order saved!' => 'Order saved!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => '!Falta fecha en lista de empaque!',
+ 'Packing List Number missing!' => '!Falta nzmero en lista de empaque!',
+ 'Part' => 'Partes',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Print' => 'Print',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Purchase Orders' => 'Ordenes de Compra',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Recd',
+ 'Remaining' => 'Faltan',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Orden de venta',
+ 'Sales Orders' => 'Ordenes de venta',
+ 'Save' => 'Salvar',
+ 'Save as new' => 'Save as new',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Terms: Net' => 'Crédito',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'Yes' => 'Si',
+ 'days' => 'Días',
+ 'ea' => 'c/u',
+ 'emailed to' => 'Se envio email a',
+ 'sent to printer' => 'Enviado a la impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'agregar' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'correo_electrónico' => 'e_mail',
+ 'factura' => 'invoice',
+ 'print' => 'print',
+ 'salvar' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/pe b/sql-ledger/locale/mx/pe
new file mode 100644
index 0000000..e1306ae
--- /dev/null
+++ b/sql-ledger/locale/mx/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Agregar',
+ 'Add Project' => 'Add Project',
+ 'All' => 'Todos',
+ 'Continue' => 'Continuar',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Edit Project' => 'Edit Project',
+ 'Number' => 'Número',
+ 'Orphaned' => 'Huerfano',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Project Number missing!',
+ 'Project deleted!' => 'Project deleted!',
+ 'Project saved!' => 'Project saved!',
+ 'Projects' => 'Projects',
+ 'Save' => 'Salvar',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'agregar' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'salvar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/rc b/sql-ledger/locale/mx/rc
new file mode 100644
index 0000000..7e0dbb1
--- /dev/null
+++ b/sql-ledger/locale/mx/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'Continuar',
+ 'Date' => 'Fecha',
+ 'Deposit' => 'Deposit',
+ 'Description' => 'Descripción',
+ 'Difference' => 'Difference',
+ 'Done' => 'Done',
+ 'Exchangerate Difference' => 'Exchangerate Difference',
+ 'From' => 'Desde',
+ 'Out of balance!' => 'Out of balance!',
+ 'Payment' => 'Pago',
+ 'Reconciliation' => 'Reconciliation',
+ 'Select all' => 'Select all',
+ 'Source' => 'Fuente',
+ 'Statement Balance' => 'Statement Balance',
+ 'To' => 'Hasta ',
+ 'Update' => 'Update',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continuar' => 'continue',
+ 'done' => 'done',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/mx/rp b/sql-ledger/locale/mx/rp
new file mode 100644
index 0000000..f198c6f
--- /dev/null
+++ b/sql-ledger/locale/mx/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Envejecimiento - CxP',
+ 'AR Aging' => 'Envejecimiento - CxC ',
+ 'Account' => 'Cuenta',
+ 'Accounts' => 'Cuentas',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance Sheet' => 'Hoja de Balance',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Comparar a',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit' => 'Crédito',
+ 'Current' => 'Current',
+ 'Customer' => 'Cliente',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Decimalplaces' => 'Decimalplaces',
+ 'Description' => 'Descripción',
+ 'Due' => 'Vence',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail Statement to' => 'E-mail Statement to',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'Código GIFI',
+ 'Heading' => 'Encabezado',
+ 'ID' => 'ID',
+ 'In-line' => 'En linea',
+ 'Include in Report' => 'Incluya en informe',
+ 'Income Statement' => 'Estado de Cuentas',
+ 'Invoice' => 'Factura',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Nothing selected!',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Pagos',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Print',
+ 'Printer' => 'Impresora',
+ 'Receipts' => 'Receipts',
+ 'Report for' => 'Informe para',
+ 'Retained Earnings' => 'Ganacias Retenidas',
+ 'Screen' => 'Pantalla',
+ 'Select all' => 'Select all',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Standard' => 'Estándard',
+ 'Statement' => 'Statement',
+ 'Statement sent to' => 'Statement sent to',
+ 'Statements sent to printer!' => 'Statements sent to printer!',
+ 'Subject' => 'Asunto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Balance De Comprobación',
+ 'Vendor' => 'Proveedor',
+ 'as at' => 'as at',
+ 'collected on sales' => 'ingresado en ventas',
+ 'for Period' => 'para el período',
+ 'paid on purchases' => 'pagado en compras',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continuar' => 'continue',
+ 'correo_electrónico' => 'e_mail',
+ 'print' => 'print',
+ 'select_all' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/COPYING b/sql-ledger/locale/nl/COPYING
new file mode 100644
index 0000000..c5dd519
--- /dev/null
+++ b/sql-ledger/locale/nl/COPYING
@@ -0,0 +1,26 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Dutch texts:
+#
+# Author: AJ Hettema <Ignite@ecosse.net>
+# Oscar Buijten <oscar@elbie.com>
+# Bert Tijhuis <domino@dse.nl>
+# Paul Tammes <ptammes@home.nl>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/nl/LANGUAGE b/sql-ledger/locale/nl/LANGUAGE
new file mode 100644
index 0000000..890d7d5
--- /dev/null
+++ b/sql-ledger/locale/nl/LANGUAGE
@@ -0,0 +1 @@
+Dutch
diff --git a/sql-ledger/locale/nl/Num2text b/sql-ledger/locale/nl/Num2text
new file mode 100644
index 0000000..777c2f3
--- /dev/null
+++ b/sql-ledger/locale/nl/Num2text
@@ -0,0 +1,161 @@
+#=====================================================================
+# SQL-Ledger Accounting
+# Copyright (C) 2002
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors: Paul Tammes <finance@bermuda-holding.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#======================================================================
+#
+# this is a variation of the Lingua package
+# written for check and receipt printing
+# it returns a properly formatted text string
+# for a number up to 10**12
+
+sub init {
+ my $self = shift;
+
+ %{ $self->{numbername} } =
+ (0 => 'nul',
+ 1 => 'een',
+ 2 => 'twee',
+ 3 => 'drie',
+ 4 => 'vier',
+ 5 => 'vijf',
+ 6 => 'zes',
+ 7 => 'zeven',
+ 8 => 'acht',
+ 9 => 'negen',
+ 10 => 'tien',
+ 11 => 'elf',
+ 12 => 'twalf',
+ 13 => 'dertien',
+ 14 => 'veertien',
+ 15 => 'vijftien',
+ 16 => 'zestien',
+ 17 => 'zeventien',
+ 18 => 'achtien',
+ 19 => 'negentien',
+ 20 => 'twintig',
+ 30 => 'dertig',
+ 40 => 'veertig',
+ 50 => 'vijftig',
+ 60 => 'zestig',
+ 70 => 'zeventig',
+ 80 => 'tachtig',
+ 90 => 'negentig',
+ 10**2 => 'honderd',
+ 10**3 => 'duizend',
+ 10**6 => 'miljoen',
+ 10**9 => 'miljard',
+ 10**12 => 'biljoen'
+ );
+
+}
+
+
+sub num2text {
+ my ($self, $amount) = @_;
+
+ return $self->{numbername}{0} unless $amount;
+
+ my @textnumber = ('**');
+
+ # split amount into chunks of 3
+ my @num = reverse split //, $amount;
+ my @numblock = ();
+ my ($i, $appendn);
+ my @a = ();
+
+ while (@num) {
+ @a = ();
+ for (1 .. 3) {
+ push @a, shift @num;
+ }
+ push @numblock, join / /, reverse @a;
+ }
+
+
+ while (@numblock) {
+
+ $i = $#numblock;
+ @num = split //, $numblock[$i];
+
+ $numblock[$i] *= 1;
+
+ if ($numblock[$i] == 0) {
+ pop @numblock;
+ next;
+ }
+
+ if ($numblock[$i] > 99) {
+ # the one from hundreds
+ push @textnumber, $self->{numbername}{$num[0]};
+
+ # add hundred designation
+ push @textnumber, $self->{numbername}{10**2};
+
+ # reduce numblock
+ $numblock[$i] -= $num[0] * 100;
+ }
+
+ if ($numblock[$i] > 9) {
+ # tens
+ push @textnumber, $self->format_ten($numblock[$i]);
+ } else {
+ # ones
+ push @textnumber, $self->{numbername}{$numblock[$i]};
+ }
+
+ # add thousand, million
+ if ($i) {
+ $amount = 10**($i * 3);
+ push @textnumber, $self->{numbername}{$amount};
+ }
+
+ pop @numblock;
+
+ }
+
+ push @textnumber, '**';
+ join '', @textnumber;
+
+}
+
+
+sub format_ten {
+ my ($self, $amount) = @_;
+
+ my $textnumber = "";
+ my @num = split //, $amount;
+
+ if ($amount > 20) {
+ # reverse one and ten and glue together with 'en'
+ $amount = $num[0] * 10;
+ $textnumber = $self->{numbername}{$num[1]}.'en'.$self->{numbername}{$amount};
+ } else {
+ $textnumber = $self->{numbername}{$amount};
+ }
+
+ $textnumber;
+
+}
+
+
+1;
+
diff --git a/sql-ledger/locale/nl/admin b/sql-ledger/locale/nl/admin
new file mode 100644
index 0000000..37f5a0b
--- /dev/null
+++ b/sql-ledger/locale/nl/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Toegangsbeheer',
+ 'Accounting' => 'Boekhouding',
+ 'Add User' => 'Gebruiker toevoegen',
+ 'Address' => 'Adres',
+ 'Administration' => 'Administratie',
+ 'Administrator' => 'Beheerder',
+ 'All Datasets up to date!' => 'Alle Datasets actueel',
+ 'Change Admin Password' => 'Admin wachtwoord veranderen',
+ 'Change Password' => 'Verander wachtwoord',
+ 'Character Set' => 'Karakter set',
+ 'Click on login name to edit!' => 'Klik op login naam om deze te bewerken.',
+ 'Company' => 'Bedrijf',
+ 'Connect to' => 'Verbinden met',
+ 'Continue' => 'Verder',
+ 'Create Chart of Accounts' => 'Maak rekeningstelsel',
+ 'Create Dataset' => 'Maak dataset',
+ 'DBI not installed!' => 'DBI niet geinstalleerd',
+ 'Database' => 'Database',
+ 'Database Administration' => 'Database administratie',
+ 'Database Driver not checked!' => 'Database Driver niet aangevinkt',
+ 'Database User missing!' => 'Geen database gebruiker aanwezig!',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Geen dataset aanwezig',
+ 'Dataset updated!' => 'Dataset aangepast aan nieuwe versie!',
+ 'Date Format' => 'Datum formaat',
+ 'Delete' => 'Verwijder',
+ 'Delete Dataset' => 'Verwijder dataset',
+ 'Directory' => 'Directory',
+ 'Driver' => 'Besturings programma',
+ 'Dropdown Limit' => 'Maximum in dropdown-lijst',
+ 'E-mail' => 'E-mail',
+ 'Edit User' => 'Gebruiker wijzigen',
+ 'Existing Datasets' => 'Bestaande datasets',
+ 'Fax' => 'Fax',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Geen hostnaam!',
+ 'Incorrect Password!' => 'Verkeerd paswoord',
+ 'Language' => 'Taal',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Laat host en port veld leeg, tenzij u een netwerk connectie wilt opzetten.',
+ 'Login' => 'Login',
+ 'Multibyte Encoding' => 'Multibyte Encoding',
+ 'Name' => 'Naam',
+ 'New Templates' => 'Nieuwe templates',
+ 'No Database Drivers available!' => 'Geen database besturings programma aanwezig',
+ 'No Dataset selected!' => 'Geen dataset geselecteerd',
+ 'Nothing to delete!' => 'Niets te verwijderen',
+ 'Number Format' => 'Nummeraanduiding',
+ 'Oracle Database Administration' => 'Oracle Database Administratie',
+ 'Password' => 'Wachtwoord',
+ 'Password changed!' => 'Wachtwoord gewijzigd!',
+ 'Pg Database Administration' => 'Pg Database Administratie',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Geen port aanwezig',
+ 'Printer' => 'Printer',
+ 'Save' => 'Opslaan',
+ 'Select a Dataset to delete and press "Continue"' => 'Selecteer de te verwijderen dataset en klik op "verder"',
+ 'Setup Templates' => 'Setup templates',
+ 'Ship via' => 'Verzenden via',
+ 'Signature' => 'Handtekening',
+ 'Stylesheet' => 'Stylesheet',
+ 'Templates' => 'Templates',
+ 'The following Datasets are not in use and can be deleted' => 'De volgende datasets zijn niet ingebruik en kunnen worder verwijderd.',
+ 'The following Datasets need to be updated' => 'De volgende datasets moeten worden bijgewerkt',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Dit is een eerste controle. Er wordt niks gecreéerd of verwijderd.',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Om een gebruiker aan een groep toe te voegen, een naam te wijzigen, een login naam te wijzigen en op te slaan. Een nieuwe gebruiker zal dan worder opgeslagen met dezelfde gegevens onder de nieuwe login naam.',
+ 'Update Dataset' => 'Dataset bijwerken',
+ 'Use Templates' => 'Gebruik templates',
+ 'User' => 'Gebruiker',
+ 'User deleted!' => 'Gebruiker verwijderd!',
+ 'User saved!' => 'Gebruiker opgeslagen!',
+ 'Version' => 'Versie',
+ 'You must enter a host and port for local and remote connections!' => 'Vul een "host" en een "port" voor netwerk connecties!',
+ 'does not exist' => 'bestaat niet',
+ 'is already a member!' => 'is al een gebruiker',
+ 'localhost' => 'localhost',
+ 'locked!' => 'geblokkeerd',
+ 'successfully created!' => 'Succesvol aangemaakt',
+ 'successfully deleted!' => 'Verwijderen succesvol',
+ 'website' => 'website',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'gebruiker_toevoegen' => 'add_user',
+ 'admin_wachtwoord_veranderen' => 'change_admin_password',
+ 'verander_wachtwoord' => 'change_password',
+ 'verder' => 'continue',
+ 'maak_dataset' => 'create_dataset',
+ 'verwijder' => 'delete',
+ 'verwijder_dataset' => 'delete_dataset',
+ 'login' => 'login',
+ 'oracle_database_administratie' => 'oracle_database_administration',
+ 'pg_database_administratie' => 'pg_database_administration',
+ 'opslaan' => 'save',
+ 'dataset_bijwerken' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/all b/sql-ledger/locale/nl/all
new file mode 100644
index 0000000..2e55089
--- /dev/null
+++ b/sql-ledger/locale/nl/all
@@ -0,0 +1,491 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Crediteuren',
+ 'AP Aging' => 'Crediteuren Ouderdomsoverzicht',
+ 'AP Transaction' => 'Crediteurenboeking',
+ 'AP Transactions' => 'Crediteurenboekingen',
+ 'AR' => 'Debiteuren',
+ 'AR Aging' => 'Debiteuren Ouderdomsoverzicht',
+ 'AR Transaction' => 'Debiteurenboeking',
+ 'AR Transactions' => 'Debiteurenboekingen',
+ 'About' => 'Over',
+ 'Access Control' => 'Toegangsbeheer',
+ 'Account' => 'Rekening',
+ 'Account Number' => 'Rekeningnummer',
+ 'Account Number missing!' => 'Rekeningnummer mist!',
+ 'Account Type' => 'Rekeningtype',
+ 'Account Type missing!' => 'Rekeningtype mist!',
+ 'Account deleted!' => 'Rekening verwijderd',
+ 'Account saved!' => 'Rekening opgeslagen',
+ 'Accounting' => 'Boekhouding',
+ 'Accounting Menu' => 'Boekhoudmenu',
+ 'Accounts' => 'Rekeningen',
+ 'Active' => 'Actief',
+ 'Add' => 'Toevoegen',
+ 'Add Account' => 'Rekening toevoegen',
+ 'Add Accounts Payables Transaction' => 'Crediteurenboeking toevoegen',
+ 'Add Accounts Receivables Transaction' => 'Debiteurenboeking toevoegen',
+ 'Add Assembly' => 'Assemblage toevoegen',
+ 'Add Customer' => 'Klant toevoegen',
+ 'Add GIFI' => 'Toevoegen GIFI',
+ 'Add General Ledger Transaction' => 'Journaalpost toevoegen',
+ 'Add Part' => 'Artikel toevoegen',
+ 'Add Project' => 'Project toevoegen',
+ 'Add Purchase Invoice' => 'Inkoopfactuur toevoegen',
+ 'Add Purchase Order' => 'Inkooporder toevoegen',
+ 'Add Sales Invoice' => 'Verkoopfactuur toevoegen',
+ 'Add Sales Order' => 'Verkooporder toevoegen',
+ 'Add Service' => 'Dienst toevoegen',
+ 'Add Transaction' => 'Boeking toevoegen',
+ 'Add User' => 'Gebruiker toevoegen',
+ 'Add Vendor' => 'Leverancier toevoegen',
+ 'Address' => 'Adres',
+ 'Administration' => 'Administratie',
+ 'Administrator' => 'Beheerder',
+ 'All' => 'Allemaal',
+ 'All Datasets up to date!' => 'Alle Datasets actueel',
+ 'Amount' => 'Bedrag',
+ 'Amount Due' => 'Verschuldigd bedrag',
+ 'Amount does not equal applied!' => 'Bedrag is ongelijk aan toewijzing!',
+ 'Amount missing!' => 'Bedrag ontbreekt!',
+ 'Applied' => 'Toewijzing',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Invoice Number' => 'Weet u zeker dat u dit factuurnummer wilt verwijderen?',
+ 'Are you sure you want to delete Order Number' => 'Weet u zeker dat u dit ordernummer wilt verwijderen?',
+ 'Are you sure you want to delete Transaction' => 'Weet u zeker dat u deze boeking wilt verwijderen?',
+ 'Assemblies' => 'Assemblage, samengestelde artikelen',
+ 'Assemblies restocked!' => 'Assemblage naar voorraad geboekt',
+ 'Assembly Number missing!' => 'Assemblagenummer mist!',
+ 'Asset' => 'Activa (bezittingen)',
+ 'Attachment' => 'Bijlage',
+ 'Audit Control' => 'Accountants Controle',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'BOM' => 'Onderdelenlijst',
+ 'Backup' => 'Backup',
+ 'Backup sent to' => 'Backup gezonden aan',
+ 'Balance' => 'Saldo',
+ 'Balance Sheet' => 'Balans',
+ 'Bcc' => 'Onzichtbare kopie aan',
+ 'Bin' => 'Locatie',
+ 'Books are open' => 'Boekingsperiode is open',
+ 'Bought' => 'Ingekocht',
+ 'Business Number' => 'Kamer van Koophandel nummer',
+ 'C' => 'C',
+ 'COGS' => 'Kostprijs Verkopen',
+ 'Cannot delete account!' => 'Kan bedrag niet verwijderen!',
+ 'Cannot delete customer!' => 'Kan klant niet verwijderen!',
+ 'Cannot delete default account!' => 'Kan standaardrekening niet verwijderen!',
+ 'Cannot delete invoice!' => 'Kan factuur niet verwijderen!',
+ 'Cannot delete item already invoiced!' => 'Kan reeds gefactureerd artikel niet verwijderen!',
+ 'Cannot delete item on order!' => 'Kan onderdeel van de order niet verwijderen',
+ 'Cannot delete item which is part of an assembly!' => 'Kan onderdeel van een samengesteld artikel niet verwijderen!',
+ 'Cannot delete item!' => 'Kan onderdeel niet verwijderen!',
+ 'Cannot delete order!' => 'Kan order niet verwijderen!',
+ 'Cannot delete transaction!' => 'Kan transactie niet verwijderen!',
+ 'Cannot delete vendor!' => 'Kan leverancier niet verwijderen!',
+ 'Cannot have a value in both Debit and Credit!' => 'Waarde kan alleen debet of credit voorkomen!',
+ 'Cannot post a transaction without a value!' => 'Kan geen boeking maken zonder waarde!',
+ 'Cannot post invoice for a closed period!' => 'Kan geen factuur boeken in afgesloten periode!',
+ 'Cannot post invoice!' => 'Kan factuur niet boeken!',
+ 'Cannot post payment for a closed period!' => 'Kan geen betaling boeken voor afgesloten periode!',
+ 'Cannot post payment!' => 'Kan betaling niet boeken!',
+ 'Cannot post transaction for a closed period!' => 'Kan geen boeking maken in afgesloten periode',
+ 'Cannot post transaction!' => 'Kan transactie niet boeken!',
+ 'Cannot process payment for a closed period!' => 'Kan geen betaling verwerken voor afgesloten periode!',
+ 'Cannot save account!' => 'Kan rekening niet opslaan!',
+ 'Cannot save order!' => 'Kan order niet opslaan!',
+ 'Cannot save preferences!' => 'Kan voorkeuren niet opslaan!',
+ 'Cannot stock assemblies!' => 'Kan assemblages niet in voorraad nemen!',
+ 'Cash' => 'Kas (contant)',
+ 'Cash based' => 'Kasbasis (contante verkopen)',
+ 'Cc' => 'Copie aan',
+ 'Change Admin Password' => 'Admin wachtwoord veranderen',
+ 'Change Password' => 'Verander wachtwoord',
+ 'Character Set' => 'Karakter set',
+ 'Chart of Accounts' => 'Rekeningstelsel',
+ 'Check' => 'Cheque',
+ 'Check printed!' => 'Cheque geprint!',
+ 'Check printing failed!' => 'Cheque printen mislukt!',
+ 'Cleared Balance' => 'Totaal geboekt vorige afschriften',
+ 'Click on login name to edit!' => 'Klik op login naam om deze te bewerken.',
+ 'Close Books up to' => 'Boeken afsluiten tot',
+ 'Closed' => 'Afgesloten',
+ 'Company' => 'Bedrijf',
+ 'Compare to' => 'Vergelijk met',
+ 'Confirm!' => 'Bevestig!',
+ 'Connect to' => 'Verbinden met',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Verder',
+ 'Copies' => 'Kopieën',
+ 'Copy to COA' => 'Kopieër naar rekeningstelsel',
+ 'Create Chart of Accounts' => 'Maak rekeningstelsel',
+ 'Create Dataset' => 'Maak dataset',
+ 'Credit' => 'Credit',
+ 'Credit Limit' => 'Kredietlimiet',
+ 'Curr' => 'Val.',
+ 'Currency' => 'Valuta',
+ 'Current' => 'Huidig',
+ 'Customer' => 'Klant',
+ 'Customer deleted!' => 'Klant verwijderd!',
+ 'Customer missing!' => 'Klant ontbreekt!',
+ 'Customer not on file!' => 'Klant bestaat niet!',
+ 'Customer saved!' => 'Klant opgeslagen!',
+ 'Customers' => 'Klanten',
+ 'DBI not installed!' => 'DBI niet geinstalleerd',
+ 'Database' => 'Database',
+ 'Database Administration' => 'Database administratie',
+ 'Database Driver not checked!' => 'Database Driver niet aangevinkt',
+ 'Database Host' => 'Database computer',
+ 'Database User missing!' => 'Geen database gebruiker aanwezig!',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Geen dataset aanwezig',
+ 'Dataset updated!' => 'Dataset aangepast aan nieuwe versie!',
+ 'Date' => 'Datum',
+ 'Date Due' => 'Vervaldatum',
+ 'Date Format' => 'Datum formaat',
+ 'Date Paid' => 'Betaaldatum',
+ 'Date missing!' => 'Datum ontbreekt!',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet en credit moeten gelijk zijn!',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Decimalplaces' => 'Aantal Decimalen',
+ 'Delete' => 'Verwijder',
+ 'Delete Account' => 'Rekening verwijderen',
+ 'Delete Dataset' => 'Verwijder dataset',
+ 'Delivery Date' => 'Leverdatum',
+ 'Deposit' => 'Storting',
+ 'Description' => 'Omschrijving',
+ 'Difference' => 'Verschil',
+ 'Directory' => 'Directory',
+ 'Discount' => 'Korting',
+ 'Done' => 'Klaar',
+ 'Drawing' => 'Tekening',
+ 'Driver' => 'Besturings programma',
+ 'Dropdown Limit' => 'Maximum in dropdown-lijst',
+ 'Due' => 'Verschuldigd',
+ 'Due Date' => 'Vervaldatum',
+ 'Due Date missing!' => 'Vervaldatum mist!',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'E-mail Overzicht aan',
+ 'E-mail address missing!' => 'E-mailadres mist!',
+ 'Edit' => 'Wijzig',
+ 'Edit Account' => 'Rekening wijzigen',
+ 'Edit Accounts Payables Transaction' => 'Wijzig Crediteurenboeking',
+ 'Edit Accounts Receivables Transaction' => 'Wijzig Debiteurenboeking',
+ 'Edit Assembly' => 'Assemblage wijzigen',
+ 'Edit Customer' => 'Klant wijzigen',
+ 'Edit GIFI' => 'Wijzig GIFI',
+ 'Edit General Ledger Transaction' => 'Boeking in grootboek wijzigen',
+ 'Edit Part' => 'Artikel wijzigen',
+ 'Edit Preferences for' => 'Instellingen wijzigen voor',
+ 'Edit Project' => 'Project wijzigen',
+ 'Edit Purchase Invoice' => 'Inkoopfactuur wijzigen',
+ 'Edit Purchase Order' => 'Inkooporder wijzigen',
+ 'Edit Sales Invoice' => 'Verkoopfactuur wijzigen',
+ 'Edit Sales Order' => 'Verkoop order wijzigen',
+ 'Edit Service' => 'Dienst wijzigen',
+ 'Edit Template' => 'Template wijzigen',
+ 'Edit User' => 'Gebruiker wijzigen',
+ 'Edit Vendor' => 'Leverancier wijzigen',
+ 'Employee' => 'Werknemer',
+ 'Enforce transaction reversal for all dates' => 'Boeking terugdraaien voor alle data',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Vul max drie karakters in, gescheiden door een dubbelepunt (b.v. EUR:USD:GBP:CAD) voor lokale en buitenlandse valuta',
+ 'Equity' => 'Passiva/Eigen Vermogen',
+ 'Exch' => 'Wisselkoers',
+ 'Exchangerate' => 'Wisselkoers',
+ 'Exchangerate Difference' => 'Koersverschil',
+ 'Exchangerate for payment missing!' => 'Wisselkoers voor Betaling mist!',
+ 'Exchangerate missing!' => 'Wisselkoers mist!',
+ 'Existing Datasets' => 'Bestaande datasets',
+ 'Expense' => 'Onkosten',
+ 'Expense Account' => 'Onkostenrekening',
+ 'Expense/Asset' => 'Uitgaven',
+ 'Extended' => 'Uitgebreid',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'Foreign Exchange Gain' => 'Wisselkoers winst',
+ 'Foreign Exchange Loss' => 'Wisselkoers verlies',
+ 'From' => 'Van',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI verwijderd!',
+ 'GIFI missing!' => 'GIFI ontbreekt!',
+ 'GIFI saved!' => 'GIFI opgeslagen!',
+ 'GL Transaction' => 'Grootboekboeking (memoriaal) ',
+ 'General Ledger' => 'Grootboek',
+ 'Goods & Services' => 'Goederen & Diensten',
+ 'HTML Templates' => 'HTML Sjablonen',
+ 'Heading' => 'Kopregel',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Geen hostnaam!',
+ 'ID' => 'ID',
+ 'Image' => 'Plaatje',
+ 'In-line' => 'In Lijn',
+ 'Include in Report' => 'Uitvoer inclusief',
+ 'Include in drop-down menus' => 'Invoegen in drop-down menus',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Deze klant/leverancier toevoegen als belastbaar?',
+ 'Income' => 'Inkomsten',
+ 'Income Account' => 'Inkomstenrekening',
+ 'Income Statement' => 'Inkomstenoverzicht',
+ 'Incorrect Dataset version!' => 'Ongeldige versie Dataset!!',
+ 'Incorrect Password!' => 'Verkeerd paswoord',
+ 'Individual Items' => 'Onderliggede onderdelen',
+ 'Inventory' => 'Voorraad',
+ 'Inventory Account' => 'Voorraadrekening',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Aanwezige voorraad moet nul zijn voordat een assemblage als \'niet actief\' kan worder gemarkeerd.',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Aanwezige voorraad moet nul zijn voordat een product als \'niet actief\' kan worder gemarkeerd.',
+ 'Inventory quantity must be zero!' => 'Aanwezige voorraad moet nul zijn!',
+ 'Invoice' => 'Factuur',
+ 'Invoice Date' => 'Factuurdatum',
+ 'Invoice Date missing!' => 'Factuurdatum mist!',
+ 'Invoice Number' => 'Factuurnummer',
+ 'Invoice Number missing!' => 'Factuurnummer mist!',
+ 'Invoice deleted!' => 'Factuur verwijderd!',
+ 'Invoice posted!' => 'Factuur geboekt!',
+ 'Invoices' => 'Facturen',
+ 'Is this a summary account to record' => 'Totaalrekening voor',
+ 'Item deleted!' => 'Onderdeel verwijderd!',
+ 'Item not on file!' => 'Dit onderdeel is niet in de database gevonden!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'LaTeX Templates' => 'Latex Sjablonen',
+ 'Language' => 'Taal',
+ 'Last Cost' => 'Vorige kostprijs',
+ 'Last Invoice Number' => 'Laatste factuurnummer',
+ 'Last Numbers & Default Accounts' => 'Laatst toegekende nummers & Standaard Rekeningen',
+ 'Last Purchase Order Number' => 'Laatste inkoopordernummer',
+ 'Last Sales Order Number' => 'Laatste Verkooporder nummer',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Laat host en port veld leeg, tenzij u een netwerk connectie wilt opzetten.',
+ 'Liability' => 'Passiva',
+ 'Licensed to' => 'Gelicenseerd aan',
+ 'Line Total' => 'Totaal Regel',
+ 'Link' => 'Verbinding',
+ 'Link Accounts' => 'Rekeningen verbinden',
+ 'List Accounts' => 'Rekeningen weergeven',
+ 'List GIFI' => 'GIFI weergeven',
+ 'List Price' => 'Prijzen weergeven',
+ 'List Transactions' => 'Boekingen tonen',
+ 'Login' => 'Login',
+ 'Logout' => 'Logout',
+ 'Make' => 'Fabrikant',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Message' => 'Boodschap',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Type',
+ 'Multibyte Encoding' => '',
+ 'N/A' => 'N/A',
+ 'Name' => 'Naam',
+ 'Name missing!' => 'Naam ontbreekt!',
+ 'New Templates' => 'Nieuwe templates',
+ 'No' => 'Nee',
+ 'No Database Drivers available!' => 'Geen database besturings programma aanwezig',
+ 'No Dataset selected!' => 'Geen dataset geselecteerd',
+ 'No email address for' => 'Geen email adres voor',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Opmerkingen',
+ 'Nothing applied!' => 'Niets toegewezen!',
+ 'Nothing selected!' => 'Niets geselecteerd!',
+ 'Nothing to delete!' => 'Niets te verwijderen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Nummeraanduiding',
+ 'Number missing in Row' => 'Getal missend in regel',
+ 'O' => 'O',
+ 'Obsolete' => 'Niet actief',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'On Hand' => 'Op voorraad',
+ 'On Order' => 'In bestelling',
+ 'Open' => 'Open',
+ 'Oracle Database Administration' => 'Oracle Database Administratie',
+ 'Order' => 'Bestelling',
+ 'Order Date' => 'Orderdatum',
+ 'Order Date missing!' => 'Geen order datum aanwezig',
+ 'Order Entry' => 'Order invoer',
+ 'Order Number' => 'Referentie',
+ 'Order Number missing!' => 'Geen ordernummer aanwezig',
+ 'Order deleted!' => 'Order verwijderd!',
+ 'Order saved!' => 'Order opgeslagen!',
+ 'Ordered' => 'Besteld',
+ 'Orphaned' => 'Wees',
+ 'Out of balance!' => 'Niet in evenwicht!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakbon',
+ 'Packing List Date missing!' => 'Pakbon datum mist!',
+ 'Packing List Number missing!' => 'Pakbon nummer mist!',
+ 'Paid' => 'Betaald',
+ 'Paid in full' => 'Volledig betaald',
+ 'Part' => 'Artikel',
+ 'Part Number missing!' => 'Artikelnummer mist!',
+ 'Parts' => 'Artikelen',
+ 'Parts Inventory' => 'Artikelenvrd',
+ 'Password' => 'Wachtwoord',
+ 'Password changed!' => 'Wachtwoord gewijzigd!',
+ 'Payables' => 'Betalingen',
+ 'Payment' => 'Betaling',
+ 'Payment date missing!' => 'Geen betalingsdatum aanwezig!',
+ 'Payment posted!' => 'Betaling geboekt!',
+ 'Payments' => 'Betalingen',
+ 'Pg Database Administration' => 'Pg Database Administratie',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Geen port aanwezig',
+ 'Post' => 'Boek',
+ 'Post as new' => 'Boek als nieuw',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Instellingen',
+ 'Preferences saved!' => 'Instellingen bewaard!',
+ 'Price' => 'Prijs',
+ 'Print' => 'Afdrukken',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Projectnummer ontbreekt!',
+ 'Project deleted!' => 'Project verwijderd!',
+ 'Project not on file!' => 'Project bestaat niet!',
+ 'Project saved!' => 'Project opgeslagen!',
+ 'Projects' => 'Projecten',
+ 'Purchase Invoice' => 'Inkoopfactuur',
+ 'Purchase Order' => 'Inkooporder',
+ 'Purchase Orders' => 'Inkooporders',
+ 'Qty' => 'Aantal',
+ 'ROP' => 'Minimum voorraad',
+ 'Rate' => 'Percentage',
+ 'Recd' => 'Ontvangen',
+ 'Receipt' => 'Ontvangstbewijs',
+ 'Receipts' => 'Ontvangstbewijzen',
+ 'Receivables' => 'Vorderingen',
+ 'Reconciliation' => 'Bank Overzicht',
+ 'Record in' => 'Boeken op',
+ 'Reference' => 'Referentie',
+ 'Reference missing!' => 'Referentie ontbreekt!',
+ 'Remaining' => 'Resterend',
+ 'Report for' => 'Rapport voor',
+ 'Reports' => 'Rapporten',
+ 'Required by' => 'Nodig voor',
+ 'Retained Earnings' => 'Winstreserve',
+ 'Sales' => 'Verkoop',
+ 'Sales Invoice' => 'Verkoopfactuur',
+ 'Sales Order' => 'Verkooporder',
+ 'Sales Orders' => 'Verkooporders',
+ 'Save' => 'Opslaan',
+ 'Save as new' => 'Opslaan als nieuw',
+ 'Save to File' => 'Opslaan als bestand',
+ 'Screen' => 'Scherm',
+ 'Select a Dataset to delete and press "Continue"' => 'Selecteer de te verwijderen dataset en klik op "verder"',
+ 'Select all' => 'Selecteer alles',
+ 'Select from one of the items below' => 'Kies een van de onderstaande items',
+ 'Select from one of the names below' => 'Kies een van de onderstaande namen',
+ 'Select from one of the projects below' => 'Kies een van de onderstaande projecten',
+ 'Select postscript or PDF!' => 'Kies postscript of PDF',
+ 'Sell Price' => 'Verkoopprijs',
+ 'Send by E-Mail' => 'Verzenden per E-mail',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienst',
+ 'Service Items' => 'Dienst',
+ 'Service Number missing!' => 'Dienstnummer mist',
+ 'Services' => 'Diensten',
+ 'Setup Templates' => 'Setup templates',
+ 'Ship' => 'Verzenden',
+ 'Ship to' => 'Verzenden aan',
+ 'Ship via' => 'Verzenden via',
+ 'Short' => 'Kort',
+ 'Signature' => 'Handtekening',
+ 'Sold' => 'Verkocht',
+ 'Source' => 'Herkomst',
+ 'Standard' => 'Standaard',
+ 'Statement' => 'Overzicht',
+ 'Statement Balance' => 'Saldo Overzicht',
+ 'Statement sent to' => 'Overzicht verzonden aan',
+ 'Statements sent to printer!' => 'Overzichten afgedrukt',
+ 'Stock Assembly' => 'Assemblage voorraad',
+ 'Stylesheet' => 'Stylesheet',
+ 'Subject' => 'Onderwerp',
+ 'Subtotal' => 'Subtotaal',
+ 'System' => 'Systeem',
+ 'Tax' => 'Belasting',
+ 'Tax Accounts' => 'Belasting Rekeningen',
+ 'Tax Included' => 'Inclusief Belasting',
+ 'Tax collected' => 'Belasting verschuldigd',
+ 'Tax paid' => 'Belasting Betaald',
+ 'Taxable' => 'Belastbaar percentage',
+ 'Template saved!' => 'Template opgeslagen!',
+ 'Templates' => 'Templates',
+ 'Terms: Net' => 'Netto',
+ 'The following Datasets are not in use and can be deleted' => 'De volgende datasets zijn niet ingebruik en kunnen worder verwijderd.',
+ 'The following Datasets need to be updated' => 'De volgende datasets moeten worden bijgewerkt',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Dit is een eerste controle. Er wordt niks gecreéerd of verwijderd.',
+ 'To' => 'Tot',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Om een gebruiker aan een groep toe te voegen, een naam te wijzigen, een login naam te wijzigen en op te slaan. Een nieuwe gebruiker zal dan worder opgeslagen met dezelfde gegevens onder de nieuwe login naam.',
+ 'Top Level' => 'Top Niveau',
+ 'Total' => 'Totaal',
+ 'Transaction Date missing!' => 'Boekingsdatum mist!',
+ 'Transaction deleted!' => 'Boeking verwijderd!',
+ 'Transaction posted!' => 'Boeking opgeslagen!',
+ 'Transaction reversal enforced for all dates' => 'Boekingen verplicht terugdraaien voor alle datums',
+ 'Transaction reversal enforced up to' => 'Boekingen verplicht terugdraaien tot aan',
+ 'Transactions' => 'Boekingen',
+ 'Transactions exist, cannot delete customer!' => 'Kan klant niet verwijderen, er zijn onderliggende boekingen!',
+ 'Transactions exist, cannot delete vendor!' => 'Kan leverancier niet verwijderen, er zijn onderliggende boekingen!',
+ 'Transactions exist; cannot delete account!' => 'Kan rekening niet verwijderen, er zijn onderliggende boekingen!',
+ 'Trial Balance' => 'Proefbalans',
+ 'Unit' => 'Eenheid',
+ 'Unit of measure' => 'Rekeneenheid',
+ 'Update' => 'Bijwerken',
+ 'Update Dataset' => 'Dataset bijwerken',
+ 'Updated' => 'Bijgewerkt',
+ 'Use Templates' => 'Gebruik templates',
+ 'User' => 'Gebruiker',
+ 'User deleted!' => 'Gebruiker verwijderd!',
+ 'User saved!' => 'Gebruiker opgeslagen!',
+ 'Vendor' => 'Leverancier',
+ 'Vendor deleted!' => 'Leverancier verwijderd!',
+ 'Vendor missing!' => 'Leverancier ontbreekt!',
+ 'Vendor not on file!' => 'Leverancier bestaat niet!',
+ 'Vendor saved!' => 'Leverancier opgeslagen!',
+ 'Vendors' => 'Leveranciers',
+ 'Version' => 'Versie',
+ 'Weight' => 'Gewicht',
+ 'Weight Unit' => 'Gewichtseenheid',
+ 'What type of item is this?' => 'Wat voor soort artikel is dit?',
+ 'Year End' => 'Einde van het boekjaar',
+ 'Yes' => 'Ja',
+ 'You are logged out!' => 'U bent uitgelogd!',
+ 'You did not enter a name!' => 'U heeft geen naam gegeven!',
+ 'You must enter a host and port for local and remote connections!' => 'Vul een "host" en een "port" voor netwerk connecties!',
+ 'as at' => 'per',
+ 'collected on sales' => 'verzameld voor de verkoop',
+ 'days' => 'dagen',
+ 'does not exist' => 'bestaat niet',
+ 'ea' => 'voor',
+ 'emailed to' => 'per email verzonden aan',
+ 'for Period' => 'voor periode',
+ 'hr' => 'uur',
+ 'is already a member!' => 'is al een gebruiker',
+ 'is not a member!' => 'is geen gebruiker',
+ 'localhost' => 'localhost',
+ 'locked!' => 'geblokkeerd',
+ 'paid on purchases' => 'betaald op inkopen',
+ 'sent to printer' => 'Afgedrukt',
+ 'successfully created!' => 'Succesvol aangemaakt',
+ 'successfully deleted!' => 'Verwijderen succesvol',
+ 'to' => 'tot',
+ 'website' => 'website',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/am b/sql-ledger/locale/nl/am
new file mode 100644
index 0000000..0b3633b
--- /dev/null
+++ b/sql-ledger/locale/nl/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Crediteuren',
+ 'AR' => 'Debiteuren',
+ 'Account' => 'Rekening',
+ 'Account Number' => 'Rekeningnummer',
+ 'Account Number missing!' => 'Rekeningnummer mist!',
+ 'Account Type' => 'Rekeningtype',
+ 'Account Type missing!' => 'Rekeningtype mist!',
+ 'Account deleted!' => 'Rekening verwijderd',
+ 'Account saved!' => 'Rekening opgeslagen',
+ 'Add Account' => 'Rekening toevoegen',
+ 'Add GIFI' => 'Toevoegen GIFI',
+ 'Address' => 'Adres',
+ 'Asset' => 'Activa (bezittingen)',
+ 'Audit Control' => 'Accountants Controle',
+ 'Backup sent to' => 'Backup gezonden aan',
+ 'Books are open' => 'Boekingsperiode is open',
+ 'Business Number' => 'Kamer van Koophandel nummer',
+ 'COGS' => 'Kostprijs Verkopen',
+ 'Cannot delete account!' => 'Kan bedrag niet verwijderen!',
+ 'Cannot delete default account!' => 'Kan standaardrekening niet verwijderen!',
+ 'Cannot save account!' => 'Kan rekening niet opslaan!',
+ 'Cannot save preferences!' => 'Kan voorkeuren niet opslaan!',
+ 'Character Set' => 'Karakter set',
+ 'Chart of Accounts' => 'Rekeningstelsel',
+ 'Close Books up to' => 'Boeken afsluiten tot',
+ 'Company' => 'Bedrijf',
+ 'Continue' => 'Verder',
+ 'Copy to COA' => 'Kopieër naar rekeningstelsel',
+ 'Credit' => 'Credit',
+ 'Date Format' => 'Datum formaat',
+ 'Debit' => 'Debet',
+ 'Delete' => 'Verwijder',
+ 'Delete Account' => 'Rekening verwijderen',
+ 'Description' => 'Omschrijving',
+ 'Dropdown Limit' => 'Maximum in dropdown-lijst',
+ 'E-mail' => 'E-mail',
+ 'Edit' => 'Wijzig',
+ 'Edit Account' => 'Rekening wijzigen',
+ 'Edit GIFI' => 'Wijzig GIFI',
+ 'Edit Preferences for' => 'Instellingen wijzigen voor',
+ 'Edit Template' => 'Template wijzigen',
+ 'Enforce transaction reversal for all dates' => 'Boeking terugdraaien voor alle data',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Vul max drie karakters in, gescheiden door een dubbelepunt (b.v. EUR:USD:GBP:CAD) voor lokale en buitenlandse valuta',
+ 'Equity' => 'Passiva/Eigen Vermogen',
+ 'Expense' => 'Onkosten',
+ 'Expense Account' => 'Onkostenrekening',
+ 'Expense/Asset' => 'Uitgaven',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Wisselkoers winst',
+ 'Foreign Exchange Loss' => 'Wisselkoers verlies',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI verwijderd!',
+ 'GIFI missing!' => 'GIFI ontbreekt!',
+ 'GIFI saved!' => 'GIFI opgeslagen!',
+ 'Heading' => 'Kopregel',
+ 'Include in drop-down menus' => 'Invoegen in drop-down menus',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Deze klant/leverancier toevoegen als belastbaar?',
+ 'Income' => 'Inkomsten',
+ 'Income Account' => 'Inkomstenrekening',
+ 'Inventory' => 'Voorraad',
+ 'Inventory Account' => 'Voorraadrekening',
+ 'Is this a summary account to record' => 'Totaalrekening voor',
+ 'Language' => 'Taal',
+ 'Last Invoice Number' => 'Laatste factuurnummer',
+ 'Last Numbers & Default Accounts' => 'Laatst toegekende nummers & Standaard Rekeningen',
+ 'Last Purchase Order Number' => 'Laatste inkoopordernummer',
+ 'Last Sales Order Number' => 'Laatste Verkooporder nummer',
+ 'Liability' => 'Passiva',
+ 'Link' => 'Verbinding',
+ 'Name' => 'Naam',
+ 'No' => 'Nee',
+ 'No email address for' => 'Geen email adres voor',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Nummeraanduiding',
+ 'Parts Inventory' => 'Artikelenvrd',
+ 'Password' => 'Wachtwoord',
+ 'Payables' => 'Betalingen',
+ 'Payment' => 'Betaling',
+ 'Phone' => 'Tel.',
+ 'Preferences saved!' => 'Instellingen bewaard!',
+ 'Rate' => 'Percentage',
+ 'Receivables' => 'Vorderingen',
+ 'Sales' => 'Verkoop',
+ 'Save' => 'Opslaan',
+ 'Service Items' => 'Dienst',
+ 'Ship via' => 'Verzenden via',
+ 'Signature' => 'Handtekening',
+ 'Stylesheet' => 'Stylesheet',
+ 'Tax' => 'Belasting',
+ 'Tax Accounts' => 'Belasting Rekeningen',
+ 'Template saved!' => 'Template opgeslagen!',
+ 'Transaction reversal enforced for all dates' => 'Boekingen verplicht terugdraaien voor alle datums',
+ 'Transaction reversal enforced up to' => 'Boekingen verplicht terugdraaien tot aan',
+ 'Transactions exist; cannot delete account!' => 'Kan rekening niet verwijderen, er zijn onderliggende boekingen!',
+ 'Weight Unit' => 'Gewichtseenheid',
+ 'Year End' => 'Einde van het boekjaar',
+ 'Yes' => 'Ja',
+ 'does not exist' => 'bestaat niet',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'rekening_toevoegen' => 'add_account',
+ 'verder' => 'continue',
+ 'kopieër_naar_rekeningstelsel' => 'copy_to_coa',
+ 'verwijder' => 'delete',
+ 'wijzig' => 'edit',
+ 'rekening_wijzigen' => 'edit_account',
+ 'opslaan' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/ap b/sql-ledger/locale/nl/ap
new file mode 100644
index 0000000..177034c
--- /dev/null
+++ b/sql-ledger/locale/nl/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Crediteurenboeking',
+ 'AP Transactions' => 'Crediteurenboekingen',
+ 'Account' => 'Rekening',
+ 'Add Accounts Payables Transaction' => 'Crediteurenboeking toevoegen',
+ 'Address' => 'Adres',
+ 'Amount' => 'Bedrag',
+ 'Amount Due' => 'Verschuldigd bedrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Transaction' => 'Weet u zeker dat u deze boeking wilt verwijderen?',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'Cannot delete transaction!' => 'Kan transactie niet verwijderen!',
+ 'Cannot post payment for a closed period!' => 'Kan geen betaling boeken voor afgesloten periode!',
+ 'Cannot post transaction for a closed period!' => 'Kan geen boeking maken in afgesloten periode',
+ 'Cannot post transaction!' => 'Kan transactie niet boeken!',
+ 'Closed' => 'Afgesloten',
+ 'Confirm!' => 'Bevestig!',
+ 'Continue' => 'Verder',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Klant bestaat niet!',
+ 'Date' => 'Datum',
+ 'Date Paid' => 'Betaaldatum',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Verwijder',
+ 'Description' => 'Omschrijving',
+ 'Due Date' => 'Vervaldatum',
+ 'Due Date missing!' => 'Vervaldatum mist!',
+ 'Edit Accounts Payables Transaction' => 'Wijzig Crediteurenboeking',
+ 'Employee' => 'Werknemer',
+ 'Exch' => 'Wisselkoers',
+ 'Exchangerate' => 'Wisselkoers',
+ 'Exchangerate for payment missing!' => 'Wisselkoers voor Betaling mist!',
+ 'Exchangerate missing!' => 'Wisselkoers mist!',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Van',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Uitvoer inclusief',
+ 'Invoice' => 'Factuur',
+ 'Invoice Date' => 'Factuurdatum',
+ 'Invoice Date missing!' => 'Factuurdatum mist!',
+ 'Invoice Number' => 'Factuurnummer',
+ 'Invoice Number missing!' => 'Factuurnummer mist!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Notes' => 'Opmerkingen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Open' => 'Open',
+ 'Order' => 'Bestelling',
+ 'Order Number' => 'Referentie',
+ 'Paid' => 'Betaald',
+ 'Payment date missing!' => 'Geen betalingsdatum aanwezig!',
+ 'Payments' => 'Betalingen',
+ 'Post' => 'Boek',
+ 'Post as new' => 'Boek als nieuw',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project bestaat niet!',
+ 'Purchase Invoice' => 'Inkoopfactuur',
+ 'Select from one of the names below' => 'Kies een van de onderstaande namen',
+ 'Select from one of the projects below' => 'Kies een van de onderstaande projecten',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Herkomst',
+ 'Subtotal' => 'Subtotaal',
+ 'Tax' => 'Belasting',
+ 'Tax Included' => 'Inclusief Belasting',
+ 'Total' => 'Totaal',
+ 'Transaction deleted!' => 'Boeking verwijderd!',
+ 'Transaction posted!' => 'Boeking opgeslagen!',
+ 'Update' => 'Bijwerken',
+ 'Vendor' => 'Leverancier',
+ 'Vendor missing!' => 'Leverancier ontbreekt!',
+ 'Vendor not on file!' => 'Leverancier bestaat niet!',
+ 'Yes' => 'Ja',
+ 'to' => 'tot',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'crediteurenboeking' => 'ap_transaction',
+ 'crediteurenboeking_toevoegen' => 'add_accounts_payables_transaction',
+ 'verder' => 'continue',
+ 'verwijder' => 'delete',
+ 'wijzig_crediteurenboeking' => 'edit_accounts_payables_transaction',
+ 'boek' => 'post',
+ 'boek_als_nieuw' => 'post_as_new',
+ 'inkoopfactuur' => 'purchase_invoice',
+ 'bijwerken' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/ar b/sql-ledger/locale/nl/ar
new file mode 100644
index 0000000..73aed90
--- /dev/null
+++ b/sql-ledger/locale/nl/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Debiteurenboeking',
+ 'AR Transactions' => 'Debiteurenboekingen',
+ 'Account' => 'Rekening',
+ 'Add Accounts Receivables Transaction' => 'Debiteurenboeking toevoegen',
+ 'Address' => 'Adres',
+ 'Amount' => 'Bedrag',
+ 'Amount Due' => 'Verschuldigd bedrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Transaction' => 'Weet u zeker dat u deze boeking wilt verwijderen?',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'Cannot delete transaction!' => 'Kan transactie niet verwijderen!',
+ 'Cannot post payment for a closed period!' => 'Kan geen betaling boeken voor afgesloten periode!',
+ 'Cannot post transaction for a closed period!' => 'Kan geen boeking maken in afgesloten periode',
+ 'Cannot post transaction!' => 'Kan transactie niet boeken!',
+ 'Closed' => 'Afgesloten',
+ 'Confirm!' => 'Bevestig!',
+ 'Continue' => 'Verder',
+ 'Credit Limit' => 'Kredietlimiet',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Klant',
+ 'Customer missing!' => 'Klant ontbreekt!',
+ 'Customer not on file!' => 'Klant bestaat niet!',
+ 'Date' => 'Datum',
+ 'Date Paid' => 'Betaaldatum',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Verwijder',
+ 'Description' => 'Omschrijving',
+ 'Due Date' => 'Vervaldatum',
+ 'Due Date missing!' => 'Vervaldatum mist!',
+ 'Edit Accounts Receivables Transaction' => 'Wijzig Debiteurenboeking',
+ 'Employee' => 'Werknemer',
+ 'Exch' => 'Wisselkoers',
+ 'Exchangerate' => 'Wisselkoers',
+ 'Exchangerate for payment missing!' => 'Wisselkoers voor Betaling mist!',
+ 'Exchangerate missing!' => 'Wisselkoers mist!',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Van',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Uitvoer inclusief',
+ 'Invoice' => 'Factuur',
+ 'Invoice Date' => 'Factuurdatum',
+ 'Invoice Date missing!' => 'Factuurdatum mist!',
+ 'Invoice Number' => 'Factuurnummer',
+ 'Invoice Number missing!' => 'Factuurnummer mist!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Notes' => 'Opmerkingen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Open' => 'Open',
+ 'Order' => 'Bestelling',
+ 'Order Number' => 'Referentie',
+ 'Paid' => 'Betaald',
+ 'Payment date missing!' => 'Geen betalingsdatum aanwezig!',
+ 'Payments' => 'Betalingen',
+ 'Post' => 'Boek',
+ 'Post as new' => 'Boek als nieuw',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project bestaat niet!',
+ 'Remaining' => 'Resterend',
+ 'Sales Invoice' => 'Verkoopfactuur',
+ 'Select from one of the names below' => 'Kies een van de onderstaande namen',
+ 'Select from one of the projects below' => 'Kies een van de onderstaande projecten',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Herkomst',
+ 'Subtotal' => 'Subtotaal',
+ 'Tax' => 'Belasting',
+ 'Tax Included' => 'Inclusief Belasting',
+ 'Total' => 'Totaal',
+ 'Transaction deleted!' => 'Boeking verwijderd!',
+ 'Transaction posted!' => 'Boeking opgeslagen!',
+ 'Update' => 'Bijwerken',
+ 'Vendor not on file!' => 'Leverancier bestaat niet!',
+ 'Yes' => 'Ja',
+ 'to' => 'tot',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'debiteurenboeking' => 'ar_transaction',
+ 'verder' => 'continue',
+ 'verwijder' => 'delete',
+ 'boek' => 'post',
+ 'boek_als_nieuw' => 'post_as_new',
+ 'verkoopfactuur' => 'sales_invoice',
+ 'bijwerken' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/arap b/sql-ledger/locale/nl/arap
new file mode 100644
index 0000000..70f1eb3
--- /dev/null
+++ b/sql-ledger/locale/nl/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adres',
+ 'Continue' => 'Verder',
+ 'Customer not on file!' => 'Klant bestaat niet!',
+ 'Description' => 'Omschrijving',
+ 'Number' => 'Nummer',
+ 'Project not on file!' => 'Project bestaat niet!',
+ 'Select from one of the names below' => 'Kies een van de onderstaande namen',
+ 'Select from one of the projects below' => 'Kies een van de onderstaande projecten',
+ 'Vendor not on file!' => 'Leverancier bestaat niet!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'verder' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/ca b/sql-ledger/locale/nl/ca
new file mode 100644
index 0000000..aeb0fab
--- /dev/null
+++ b/sql-ledger/locale/nl/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Rekening',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'Balance' => 'Saldo',
+ 'Chart of Accounts' => 'Rekeningstelsel',
+ 'Credit' => 'Credit',
+ 'Date' => 'Datum',
+ 'Debit' => 'Debet',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Description' => 'Omschrijving',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Van',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Uitvoer inclusief',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'List Transactions' => 'Boekingen tonen',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Reference' => 'Referentie',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Subtotal' => 'Subtotaal',
+ 'to' => 'tot',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'boekingen_tonen' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/cp b/sql-ledger/locale/nl/cp
new file mode 100644
index 0000000..c1ae7d5
--- /dev/null
+++ b/sql-ledger/locale/nl/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Rekening',
+ 'Address' => 'Adres',
+ 'Amount' => 'Bedrag',
+ 'Amount does not equal applied!' => 'Bedrag is ongelijk aan toewijzing!',
+ 'Amount missing!' => 'Bedrag ontbreekt!',
+ 'Applied' => 'Toewijzing',
+ 'Cannot post payment!' => 'Kan betaling niet boeken!',
+ 'Cannot process payment for a closed period!' => 'Kan geen betaling verwerken voor afgesloten periode!',
+ 'Check' => 'Cheque',
+ 'Check printed!' => 'Cheque geprint!',
+ 'Check printing failed!' => 'Cheque printen mislukt!',
+ 'Continue' => 'Verder',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Klant',
+ 'Customer not on file!' => 'Klant bestaat niet!',
+ 'Date' => 'Datum',
+ 'Date missing!' => 'Datum ontbreekt!',
+ 'Description' => 'Omschrijving',
+ 'Due' => 'Verschuldigd',
+ 'Exchangerate' => 'Wisselkoers',
+ 'From' => 'Van',
+ 'Invoice' => 'Factuur',
+ 'Invoices' => 'Facturen',
+ 'Nothing applied!' => 'Niets toegewezen!',
+ 'Number' => 'Nummer',
+ 'Paid in full' => 'Volledig betaald',
+ 'Payment' => 'Betaling',
+ 'Payment posted!' => 'Betaling geboekt!',
+ 'Post' => 'Boek',
+ 'Print' => 'Afdrukken',
+ 'Printer' => 'Printer',
+ 'Project not on file!' => 'Project bestaat niet!',
+ 'Receipt' => 'Ontvangstbewijs',
+ 'Reference' => 'Referentie',
+ 'Screen' => 'Scherm',
+ 'Select from one of the names below' => 'Kies een van de onderstaande namen',
+ 'Select from one of the projects below' => 'Kies een van de onderstaande projecten',
+ 'Update' => 'Bijwerken',
+ 'Vendor' => 'Leverancier',
+ 'Vendor not on file!' => 'Leverancier bestaat niet!',
+ 'to' => 'tot',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'verder' => 'continue',
+ 'boek' => 'post',
+ 'afdrukken' => 'print',
+ 'bijwerken' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/ct b/sql-ledger/locale/nl/ct
new file mode 100644
index 0000000..430053a
--- /dev/null
+++ b/sql-ledger/locale/nl/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Toevoegen',
+ 'Address' => 'Adres',
+ 'All' => 'Allemaal',
+ 'Bcc' => 'Onzichtbare kopie aan',
+ 'Cannot delete customer!' => 'Kan klant niet verwijderen!',
+ 'Cannot delete vendor!' => 'Kan leverancier niet verwijderen!',
+ 'Cc' => 'Copie aan',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Verder',
+ 'Credit Limit' => 'Kredietlimiet',
+ 'Customer deleted!' => 'Klant verwijderd!',
+ 'Customer saved!' => 'Klant opgeslagen!',
+ 'Customers' => 'Klanten',
+ 'Delete' => 'Verwijder',
+ 'Discount' => 'Korting',
+ 'E-mail' => 'E-mail',
+ 'Edit Customer' => 'Klant wijzigen',
+ 'Edit Vendor' => 'Leverancier wijzigen',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Uitvoer inclusief',
+ 'Invoice' => 'Factuur',
+ 'Name' => 'Naam',
+ 'Name missing!' => 'Naam ontbreekt!',
+ 'Notes' => 'Opmerkingen',
+ 'Number' => 'Nummer',
+ 'Order' => 'Bestelling',
+ 'Orphaned' => 'Wees',
+ 'Phone' => 'Tel.',
+ 'Save' => 'Opslaan',
+ 'Ship to' => 'Verzenden aan',
+ 'Tax Included' => 'Inclusief Belasting',
+ 'Taxable' => 'Belastbaar percentage',
+ 'Terms: Net' => 'Netto',
+ 'Transactions exist, cannot delete customer!' => 'Kan klant niet verwijderen, er zijn onderliggende boekingen!',
+ 'Transactions exist, cannot delete vendor!' => 'Kan leverancier niet verwijderen, er zijn onderliggende boekingen!',
+ 'Vendor deleted!' => 'Leverancier verwijderd!',
+ 'Vendor saved!' => 'Leverancier opgeslagen!',
+ 'Vendors' => 'Leveranciers',
+ 'days' => 'dagen',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'toevoegen' => 'add',
+ 'verder' => 'continue',
+ 'verwijder' => 'delete',
+ 'factuur' => 'invoice',
+ 'bestelling' => 'order',
+ 'opslaan' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/gl b/sql-ledger/locale/nl/gl
new file mode 100644
index 0000000..9e76622
--- /dev/null
+++ b/sql-ledger/locale/nl/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Crediteurenboeking',
+ 'AR Transaction' => 'Debiteurenboeking',
+ 'Account' => 'Rekening',
+ 'Add General Ledger Transaction' => 'Journaalpost toevoegen',
+ 'Address' => 'Adres',
+ 'All' => 'Allemaal',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Transaction' => 'Weet u zeker dat u deze boeking wilt verwijderen?',
+ 'Asset' => 'Activa (bezittingen)',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'Balance' => 'Saldo',
+ 'Cannot delete transaction!' => 'Kan transactie niet verwijderen!',
+ 'Cannot have a value in both Debit and Credit!' => 'Waarde kan alleen debet of credit voorkomen!',
+ 'Cannot post a transaction without a value!' => 'Kan geen boeking maken zonder waarde!',
+ 'Cannot post transaction for a closed period!' => 'Kan geen boeking maken in afgesloten periode',
+ 'Confirm!' => 'Bevestig!',
+ 'Continue' => 'Verder',
+ 'Credit' => 'Credit',
+ 'Customer not on file!' => 'Klant bestaat niet!',
+ 'Date' => 'Datum',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet en credit moeten gelijk zijn!',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Verwijder',
+ 'Description' => 'Omschrijving',
+ 'Edit General Ledger Transaction' => 'Boeking in grootboek wijzigen',
+ 'Equity' => 'Passiva/Eigen Vermogen',
+ 'Expense' => 'Onkosten',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Van',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'Grootboekboeking (memoriaal) ',
+ 'General Ledger' => 'Grootboek',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Uitvoer inclusief',
+ 'Income' => 'Inkomsten',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Liability' => 'Passiva',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Notes' => 'Opmerkingen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Post' => 'Boek',
+ 'Post as new' => 'Boek als nieuw',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project bestaat niet!',
+ 'Purchase Invoice' => 'Inkoopfactuur',
+ 'Reference' => 'Referentie',
+ 'Reference missing!' => 'Referentie ontbreekt!',
+ 'Reports' => 'Rapporten',
+ 'Sales Invoice' => 'Verkoopfactuur',
+ 'Select from one of the names below' => 'Kies een van de onderstaande namen',
+ 'Select from one of the projects below' => 'Kies een van de onderstaande projecten',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Herkomst',
+ 'Subtotal' => 'Subtotaal',
+ 'Transaction Date missing!' => 'Boekingsdatum mist!',
+ 'Transaction deleted!' => 'Boeking verwijderd!',
+ 'Transaction posted!' => 'Boeking opgeslagen!',
+ 'Update' => 'Bijwerken',
+ 'Vendor not on file!' => 'Leverancier bestaat niet!',
+ 'Yes' => 'Ja',
+ 'to' => 'tot',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'crediteurenboeking' => 'ap_transaction',
+ 'debiteurenboeking' => 'ar_transaction',
+ 'verder' => 'continue',
+ 'verwijder' => 'delete',
+ 'grootboekboeking_(memoriaal)_' => 'gl_transaction',
+ 'boek' => 'post',
+ 'boek_als_nieuw' => 'post_as_new',
+ 'inkoopfactuur' => 'purchase_invoice',
+ 'verkoopfactuur' => 'sales_invoice',
+ 'bijwerken' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/ic b/sql-ledger/locale/nl/ic
new file mode 100644
index 0000000..e8d7eea
--- /dev/null
+++ b/sql-ledger/locale/nl/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => 'Actief',
+ 'Add' => 'Toevoegen',
+ 'Add Assembly' => 'Assemblage toevoegen',
+ 'Add Part' => 'Artikel toevoegen',
+ 'Add Purchase Order' => 'Inkooporder toevoegen',
+ 'Add Sales Order' => 'Verkooporder toevoegen',
+ 'Add Service' => 'Dienst toevoegen',
+ 'Address' => 'Adres',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Assemblies' => 'Assemblage, samengestelde artikelen',
+ 'Assemblies restocked!' => 'Assemblage naar voorraad geboekt',
+ 'Assembly Number missing!' => 'Assemblagenummer mist!',
+ 'Attachment' => 'Bijlage',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'BOM' => 'Onderdelenlijst',
+ 'Bcc' => 'Onzichtbare kopie aan',
+ 'Bin' => 'Locatie',
+ 'Bought' => 'Ingekocht',
+ 'COGS' => 'Kostprijs Verkopen',
+ 'Cannot delete item already invoiced!' => 'Kan reeds gefactureerd artikel niet verwijderen!',
+ 'Cannot delete item on order!' => 'Kan onderdeel van de order niet verwijderen',
+ 'Cannot delete item which is part of an assembly!' => 'Kan onderdeel van een samengesteld artikel niet verwijderen!',
+ 'Cannot delete item!' => 'Kan onderdeel niet verwijderen!',
+ 'Cannot stock assemblies!' => 'Kan assemblages niet in voorraad nemen!',
+ 'Cc' => 'Copie aan',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Verder',
+ 'Copies' => 'Kopieën',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Verwijder',
+ 'Delivery Date' => 'Leverdatum',
+ 'Description' => 'Omschrijving',
+ 'Drawing' => 'Tekening',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mailadres mist!',
+ 'Edit Assembly' => 'Assemblage wijzigen',
+ 'Edit Part' => 'Artikel wijzigen',
+ 'Edit Service' => 'Dienst wijzigen',
+ 'Expense' => 'Onkosten',
+ 'Extended' => 'Uitgebreid',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Van',
+ 'Image' => 'Plaatje',
+ 'In-line' => 'In Lijn',
+ 'Include in Report' => 'Uitvoer inclusief',
+ 'Income' => 'Inkomsten',
+ 'Individual Items' => 'Onderliggede onderdelen',
+ 'Inventory' => 'Voorraad',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Aanwezige voorraad moet nul zijn voordat een assemblage als \'niet actief\' kan worder gemarkeerd.',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Aanwezige voorraad moet nul zijn voordat een product als \'niet actief\' kan worder gemarkeerd.',
+ 'Inventory quantity must be zero!' => 'Aanwezige voorraad moet nul zijn!',
+ 'Invoice' => 'Factuur',
+ 'Invoice Date missing!' => 'Factuurdatum mist!',
+ 'Invoice Number' => 'Factuurnummer',
+ 'Invoice Number missing!' => 'Factuurnummer mist!',
+ 'Item deleted!' => 'Onderdeel verwijderd!',
+ 'Item not on file!' => 'Dit onderdeel is niet in de database gevonden!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Last Cost' => 'Vorige kostprijs',
+ 'Line Total' => 'Totaal Regel',
+ 'Link Accounts' => 'Rekeningen verbinden',
+ 'List Price' => 'Prijzen weergeven',
+ 'Make' => 'Fabrikant',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Message' => 'Boodschap',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Type',
+ 'Name' => 'Naam',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Opmerkingen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Getal missend in regel',
+ 'Obsolete' => 'Niet actief',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'On Hand' => 'Op voorraad',
+ 'On Order' => 'In bestelling',
+ 'Order' => 'Bestelling',
+ 'Order Date missing!' => 'Geen order datum aanwezig',
+ 'Order Number' => 'Referentie',
+ 'Order Number missing!' => 'Geen ordernummer aanwezig',
+ 'Ordered' => 'Besteld',
+ 'Orphaned' => 'Wees',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakbon',
+ 'Packing List Date missing!' => 'Pakbon datum mist!',
+ 'Packing List Number missing!' => 'Pakbon nummer mist!',
+ 'Part' => 'Artikel',
+ 'Part Number missing!' => 'Artikelnummer mist!',
+ 'Parts' => 'Artikelen',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prijs',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Inkooporder',
+ 'Qty' => 'Aantal',
+ 'ROP' => 'Minimum voorraad',
+ 'Recd' => 'Ontvangen',
+ 'Required by' => 'Nodig voor',
+ 'Sales' => 'Verkoop',
+ 'Sales Order' => 'Verkooporder',
+ 'Save' => 'Opslaan',
+ 'Screen' => 'Scherm',
+ 'Select from one of the items below' => 'Kies een van de onderstaande items',
+ 'Select postscript or PDF!' => 'Kies postscript of PDF',
+ 'Sell Price' => 'Verkoopprijs',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienst',
+ 'Service Number missing!' => 'Dienstnummer mist',
+ 'Services' => 'Diensten',
+ 'Ship' => 'Verzenden',
+ 'Ship to' => 'Verzenden aan',
+ 'Short' => 'Kort',
+ 'Sold' => 'Verkocht',
+ 'Stock Assembly' => 'Assemblage voorraad',
+ 'Subject' => 'Onderwerp',
+ 'Subtotal' => 'Subtotaal',
+ 'Tax' => 'Belasting',
+ 'To' => 'Tot',
+ 'Top Level' => 'Top Niveau',
+ 'Total' => 'Totaal',
+ 'Unit' => 'Eenheid',
+ 'Unit of measure' => 'Rekeneenheid',
+ 'Update' => 'Bijwerken',
+ 'Updated' => 'Bijgewerkt',
+ 'Weight' => 'Gewicht',
+ 'What type of item is this?' => 'Wat voor soort artikel is dit?',
+ 'ea' => 'voor',
+ 'emailed to' => 'per email verzonden aan',
+ 'hr' => 'uur',
+ 'sent to printer' => 'Afgedrukt',
+ 'to' => 'tot',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'toevoegen' => 'add',
+ 'assemblage_toevoegen' => 'add_assembly',
+ 'artikel_toevoegen' => 'add_part',
+ 'dienst_toevoegen' => 'add_service',
+ 'verder' => 'continue',
+ 'verwijder' => 'delete',
+ 'assemblage_wijzigen' => 'edit_assembly',
+ 'artikel_wijzigen' => 'edit_part',
+ 'dienst_wijzigen' => 'edit_service',
+ 'opslaan' => 'save',
+ 'bijwerken' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/io b/sql-ledger/locale/nl/io
new file mode 100644
index 0000000..432a8e0
--- /dev/null
+++ b/sql-ledger/locale/nl/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Inkooporder toevoegen',
+ 'Add Sales Order' => 'Verkooporder toevoegen',
+ 'Address' => 'Adres',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Attachment' => 'Bijlage',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'Bcc' => 'Onzichtbare kopie aan',
+ 'Bin' => 'Locatie',
+ 'Cc' => 'Copie aan',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Verder',
+ 'Copies' => 'Kopieën',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delivery Date' => 'Leverdatum',
+ 'Description' => 'Omschrijving',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mailadres mist!',
+ 'Extended' => 'Uitgebreid',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'In-line' => 'In Lijn',
+ 'Invoice' => 'Factuur',
+ 'Invoice Date missing!' => 'Factuurdatum mist!',
+ 'Invoice Number missing!' => 'Factuurnummer mist!',
+ 'Item not on file!' => 'Dit onderdeel is niet in de database gevonden!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Message' => 'Boodschap',
+ 'Name' => 'Naam',
+ 'No.' => 'Nr.',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Getal missend in regel',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Order' => 'Bestelling',
+ 'Order Date missing!' => 'Geen order datum aanwezig',
+ 'Order Number missing!' => 'Geen ordernummer aanwezig',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakbon',
+ 'Packing List Date missing!' => 'Pakbon datum mist!',
+ 'Packing List Number missing!' => 'Pakbon nummer mist!',
+ 'Part' => 'Artikel',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prijs',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Inkooporder',
+ 'Qty' => 'Aantal',
+ 'Recd' => 'Ontvangen',
+ 'Required by' => 'Nodig voor',
+ 'Sales Order' => 'Verkooporder',
+ 'Screen' => 'Scherm',
+ 'Select from one of the items below' => 'Kies een van de onderstaande items',
+ 'Select postscript or PDF!' => 'Kies postscript of PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienst',
+ 'Ship' => 'Verzenden',
+ 'Ship to' => 'Verzenden aan',
+ 'Subject' => 'Onderwerp',
+ 'To' => 'Tot',
+ 'Unit' => 'Eenheid',
+ 'What type of item is this?' => 'Wat voor soort artikel is dit?',
+ 'emailed to' => 'per email verzonden aan',
+ 'sent to printer' => 'Afgedrukt',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'verder' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/ir b/sql-ledger/locale/nl/ir
new file mode 100644
index 0000000..235a7d4
--- /dev/null
+++ b/sql-ledger/locale/nl/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Rekening',
+ 'Add Purchase Invoice' => 'Inkoopfactuur toevoegen',
+ 'Add Purchase Order' => 'Inkooporder toevoegen',
+ 'Add Sales Order' => 'Verkooporder toevoegen',
+ 'Address' => 'Adres',
+ 'Amount' => 'Bedrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Invoice Number' => 'Weet u zeker dat u dit factuurnummer wilt verwijderen?',
+ 'Attachment' => 'Bijlage',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'Bcc' => 'Onzichtbare kopie aan',
+ 'Bin' => 'Locatie',
+ 'Cannot delete invoice!' => 'Kan factuur niet verwijderen!',
+ 'Cannot post invoice for a closed period!' => 'Kan geen factuur boeken in afgesloten periode!',
+ 'Cannot post invoice!' => 'Kan factuur niet boeken!',
+ 'Cannot post payment for a closed period!' => 'Kan geen betaling boeken voor afgesloten periode!',
+ 'Cc' => 'Copie aan',
+ 'Confirm!' => 'Bevestig!',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Verder',
+ 'Copies' => 'Kopieën',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Klant bestaat niet!',
+ 'Date' => 'Datum',
+ 'Date Due' => 'Vervaldatum',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Verwijder',
+ 'Delivery Date' => 'Leverdatum',
+ 'Description' => 'Omschrijving',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mailadres mist!',
+ 'Edit Purchase Invoice' => 'Inkoopfactuur wijzigen',
+ 'Exch' => 'Wisselkoers',
+ 'Exchangerate' => 'Wisselkoers',
+ 'Exchangerate for payment missing!' => 'Wisselkoers voor Betaling mist!',
+ 'Exchangerate missing!' => 'Wisselkoers mist!',
+ 'Extended' => 'Uitgebreid',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'In-line' => 'In Lijn',
+ 'Invoice' => 'Factuur',
+ 'Invoice Date' => 'Factuurdatum',
+ 'Invoice Date missing!' => 'Factuurdatum mist!',
+ 'Invoice Number' => 'Factuurnummer',
+ 'Invoice Number missing!' => 'Factuurnummer mist!',
+ 'Invoice deleted!' => 'Factuur verwijderd!',
+ 'Invoice posted!' => 'Factuur geboekt!',
+ 'Item not on file!' => 'Dit onderdeel is niet in de database gevonden!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Message' => 'Boodschap',
+ 'Name' => 'Naam',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Opmerkingen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Getal missend in regel',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Order' => 'Bestelling',
+ 'Order Date missing!' => 'Geen order datum aanwezig',
+ 'Order Number' => 'Referentie',
+ 'Order Number missing!' => 'Geen ordernummer aanwezig',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakbon',
+ 'Packing List Date missing!' => 'Pakbon datum mist!',
+ 'Packing List Number missing!' => 'Pakbon nummer mist!',
+ 'Part' => 'Artikel',
+ 'Payment date missing!' => 'Geen betalingsdatum aanwezig!',
+ 'Payments' => 'Betalingen',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Boek',
+ 'Post as new' => 'Boek als nieuw',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prijs',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project bestaat niet!',
+ 'Purchase Order' => 'Inkooporder',
+ 'Qty' => 'Aantal',
+ 'Recd' => 'Ontvangen',
+ 'Record in' => 'Boeken op',
+ 'Required by' => 'Nodig voor',
+ 'Sales Order' => 'Verkooporder',
+ 'Screen' => 'Scherm',
+ 'Select from one of the items below' => 'Kies een van de onderstaande items',
+ 'Select from one of the names below' => 'Kies een van de onderstaande namen',
+ 'Select from one of the projects below' => 'Kies een van de onderstaande projecten',
+ 'Select postscript or PDF!' => 'Kies postscript of PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienst',
+ 'Ship' => 'Verzenden',
+ 'Ship to' => 'Verzenden aan',
+ 'Source' => 'Herkomst',
+ 'Subject' => 'Onderwerp',
+ 'Subtotal' => 'Subtotaal',
+ 'Tax Included' => 'Inclusief Belasting',
+ 'To' => 'Tot',
+ 'Total' => 'Totaal',
+ 'Unit' => 'Eenheid',
+ 'Update' => 'Bijwerken',
+ 'Vendor' => 'Leverancier',
+ 'Vendor missing!' => 'Leverancier ontbreekt!',
+ 'Vendor not on file!' => 'Leverancier bestaat niet!',
+ 'What type of item is this?' => 'Wat voor soort artikel is dit?',
+ 'Yes' => 'Ja',
+ 'ea' => 'voor',
+ 'emailed to' => 'per email verzonden aan',
+ 'sent to printer' => 'Afgedrukt',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'verder' => 'continue',
+ 'verwijder' => 'delete',
+ 'bestelling' => 'order',
+ 'boek' => 'post',
+ 'boek_als_nieuw' => 'post_as_new',
+ 'bijwerken' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/is b/sql-ledger/locale/nl/is
new file mode 100644
index 0000000..f868dac
--- /dev/null
+++ b/sql-ledger/locale/nl/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Rekening',
+ 'Add Purchase Order' => 'Inkooporder toevoegen',
+ 'Add Sales Invoice' => 'Verkoopfactuur toevoegen',
+ 'Add Sales Order' => 'Verkooporder toevoegen',
+ 'Address' => 'Adres',
+ 'Amount' => 'Bedrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Invoice Number' => 'Weet u zeker dat u dit factuurnummer wilt verwijderen?',
+ 'Attachment' => 'Bijlage',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'Bcc' => 'Onzichtbare kopie aan',
+ 'Bin' => 'Locatie',
+ 'Cannot delete invoice!' => 'Kan factuur niet verwijderen!',
+ 'Cannot post invoice for a closed period!' => 'Kan geen factuur boeken in afgesloten periode!',
+ 'Cannot post invoice!' => 'Kan factuur niet boeken!',
+ 'Cannot post payment for a closed period!' => 'Kan geen betaling boeken voor afgesloten periode!',
+ 'Cc' => 'Copie aan',
+ 'Confirm!' => 'Bevestig!',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Verder',
+ 'Copies' => 'Kopieën',
+ 'Credit Limit' => 'Kredietlimiet',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Klant',
+ 'Customer missing!' => 'Klant ontbreekt!',
+ 'Customer not on file!' => 'Klant bestaat niet!',
+ 'Date' => 'Datum',
+ 'Date Due' => 'Vervaldatum',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Verwijder',
+ 'Delivery Date' => 'Leverdatum',
+ 'Description' => 'Omschrijving',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mailadres mist!',
+ 'Edit Sales Invoice' => 'Verkoopfactuur wijzigen',
+ 'Exch' => 'Wisselkoers',
+ 'Exchangerate' => 'Wisselkoers',
+ 'Exchangerate for payment missing!' => 'Wisselkoers voor Betaling mist!',
+ 'Exchangerate missing!' => 'Wisselkoers mist!',
+ 'Extended' => 'Uitgebreid',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'In-line' => 'In Lijn',
+ 'Invoice' => 'Factuur',
+ 'Invoice Date' => 'Factuurdatum',
+ 'Invoice Date missing!' => 'Factuurdatum mist!',
+ 'Invoice Number' => 'Factuurnummer',
+ 'Invoice Number missing!' => 'Factuurnummer mist!',
+ 'Invoice deleted!' => 'Factuur verwijderd!',
+ 'Invoice posted!' => 'Factuur geboekt!',
+ 'Item not on file!' => 'Dit onderdeel is niet in de database gevonden!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Message' => 'Boodschap',
+ 'Name' => 'Naam',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Opmerkingen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Getal missend in regel',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Order' => 'Bestelling',
+ 'Order Date missing!' => 'Geen order datum aanwezig',
+ 'Order Number' => 'Referentie',
+ 'Order Number missing!' => 'Geen ordernummer aanwezig',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakbon',
+ 'Packing List Date missing!' => 'Pakbon datum mist!',
+ 'Packing List Number missing!' => 'Pakbon nummer mist!',
+ 'Part' => 'Artikel',
+ 'Payment date missing!' => 'Geen betalingsdatum aanwezig!',
+ 'Payments' => 'Betalingen',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Boek',
+ 'Post as new' => 'Boek als nieuw',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prijs',
+ 'Print' => 'Afdrukken',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project bestaat niet!',
+ 'Purchase Order' => 'Inkooporder',
+ 'Qty' => 'Aantal',
+ 'Recd' => 'Ontvangen',
+ 'Record in' => 'Boeken op',
+ 'Remaining' => 'Resterend',
+ 'Required by' => 'Nodig voor',
+ 'Sales Order' => 'Verkooporder',
+ 'Screen' => 'Scherm',
+ 'Select from one of the items below' => 'Kies een van de onderstaande items',
+ 'Select from one of the names below' => 'Kies een van de onderstaande namen',
+ 'Select from one of the projects below' => 'Kies een van de onderstaande projecten',
+ 'Select postscript or PDF!' => 'Kies postscript of PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienst',
+ 'Ship' => 'Verzenden',
+ 'Ship to' => 'Verzenden aan',
+ 'Ship via' => 'Verzenden via',
+ 'Source' => 'Herkomst',
+ 'Subject' => 'Onderwerp',
+ 'Subtotal' => 'Subtotaal',
+ 'Tax Included' => 'Inclusief Belasting',
+ 'To' => 'Tot',
+ 'Total' => 'Totaal',
+ 'Unit' => 'Eenheid',
+ 'Update' => 'Bijwerken',
+ 'Vendor not on file!' => 'Leverancier bestaat niet!',
+ 'What type of item is this?' => 'Wat voor soort artikel is dit?',
+ 'Yes' => 'Ja',
+ 'ea' => 'voor',
+ 'emailed to' => 'per email verzonden aan',
+ 'sent to printer' => 'Afgedrukt',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'verder' => 'continue',
+ 'verwijder' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'bestelling' => 'order',
+ 'boek' => 'post',
+ 'boek_als_nieuw' => 'post_as_new',
+ 'afdrukken' => 'print',
+ 'verzenden_aan' => 'ship_to',
+ 'bijwerken' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/login b/sql-ledger/locale/nl/login
new file mode 100644
index 0000000..4e01eb0
--- /dev/null
+++ b/sql-ledger/locale/nl/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Over',
+ 'Database Host' => 'Database computer',
+ 'Dataset' => 'Dataset',
+ 'Incorrect Dataset version!' => 'Ongeldige versie Dataset!!',
+ 'Incorrect Password!' => 'Verkeerd paswoord',
+ 'Licensed to' => 'Gelicenseerd aan',
+ 'Login' => 'Login',
+ 'Name' => 'Naam',
+ 'Password' => 'Wachtwoord',
+ 'User' => 'Gebruiker',
+ 'Version' => 'Versie',
+ 'You are logged out!' => 'U bent uitgelogd!',
+ 'You did not enter a name!' => 'U heeft geen naam gegeven!',
+ 'is not a member!' => 'is geen gebruiker',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/menu b/sql-ledger/locale/nl/menu
new file mode 100644
index 0000000..2c1a257
--- /dev/null
+++ b/sql-ledger/locale/nl/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Crediteuren',
+ 'AP Aging' => 'Crediteuren Ouderdomsoverzicht',
+ 'AR' => 'Debiteuren',
+ 'AR Aging' => 'Debiteuren Ouderdomsoverzicht',
+ 'Accounting Menu' => 'Boekhoudmenu',
+ 'Add Account' => 'Rekening toevoegen',
+ 'Add Assembly' => 'Assemblage toevoegen',
+ 'Add Customer' => 'Klant toevoegen',
+ 'Add GIFI' => 'Toevoegen GIFI',
+ 'Add Part' => 'Artikel toevoegen',
+ 'Add Project' => 'Project toevoegen',
+ 'Add Service' => 'Dienst toevoegen',
+ 'Add Transaction' => 'Boeking toevoegen',
+ 'Add Vendor' => 'Leverancier toevoegen',
+ 'Assemblies' => 'Assemblage, samengestelde artikelen',
+ 'Audit Control' => 'Accountants Controle',
+ 'Backup' => 'Backup',
+ 'Balance Sheet' => 'Balans',
+ 'Cash' => 'Kas (contant)',
+ 'Chart of Accounts' => 'Rekeningstelsel',
+ 'Check' => 'Cheque',
+ 'Customers' => 'Klanten',
+ 'General Ledger' => 'Grootboek',
+ 'Goods & Services' => 'Goederen & Diensten',
+ 'HTML Templates' => 'HTML Sjablonen',
+ 'Income Statement' => 'Inkomstenoverzicht',
+ 'Invoice' => 'Factuur',
+ 'LaTeX Templates' => 'Latex Sjablonen',
+ 'List Accounts' => 'Rekeningen weergeven',
+ 'List GIFI' => 'GIFI weergeven',
+ 'Logout' => 'Logout',
+ 'Order Entry' => 'Order invoer',
+ 'Packing List' => 'Pakbon',
+ 'Parts' => 'Artikelen',
+ 'Payment' => 'Betaling',
+ 'Payments' => 'Betalingen',
+ 'Preferences' => 'Instellingen',
+ 'Projects' => 'Projecten',
+ 'Purchase Invoice' => 'Inkoopfactuur',
+ 'Purchase Order' => 'Inkooporder',
+ 'Purchase Orders' => 'Inkooporders',
+ 'Receipt' => 'Ontvangstbewijs',
+ 'Receipts' => 'Ontvangstbewijzen',
+ 'Reconciliation' => 'Bank Overzicht',
+ 'Reports' => 'Rapporten',
+ 'Sales Invoice' => 'Verkoopfactuur',
+ 'Sales Order' => 'Verkooporder',
+ 'Sales Orders' => 'Verkooporders',
+ 'Save to File' => 'Opslaan als bestand',
+ 'Send by E-Mail' => 'Verzenden per E-mail',
+ 'Services' => 'Diensten',
+ 'Statement' => 'Overzicht',
+ 'Stock Assembly' => 'Assemblage voorraad',
+ 'Stylesheet' => 'Stylesheet',
+ 'System' => 'Systeem',
+ 'Tax collected' => 'Belasting verschuldigd',
+ 'Tax paid' => 'Belasting Betaald',
+ 'Transactions' => 'Boekingen',
+ 'Trial Balance' => 'Proefbalans',
+ 'Vendors' => 'Leveranciers',
+ 'Version' => 'Versie',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/oe b/sql-ledger/locale/nl/oe
new file mode 100644
index 0000000..cf3a062
--- /dev/null
+++ b/sql-ledger/locale/nl/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'Toevoegen',
+ 'Add Purchase Invoice' => 'Inkoopfactuur toevoegen',
+ 'Add Purchase Order' => 'Inkooporder toevoegen',
+ 'Add Sales Invoice' => 'Verkoopfactuur toevoegen',
+ 'Add Sales Order' => 'Verkooporder toevoegen',
+ 'Address' => 'Adres',
+ 'Amount' => 'Bedrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Are you sure you want to delete Order Number' => 'Weet u zeker dat u dit ordernummer wilt verwijderen?',
+ 'Attachment' => 'Bijlage',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'Bcc' => 'Onzichtbare kopie aan',
+ 'Bin' => 'Locatie',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Kan order niet verwijderen!',
+ 'Cannot save order!' => 'Kan order niet opslaan!',
+ 'Cc' => 'Copie aan',
+ 'Closed' => 'Afgesloten',
+ 'Confirm!' => 'Bevestig!',
+ 'Contact' => 'Contact',
+ 'Continue' => 'Verder',
+ 'Copies' => 'Kopieën',
+ 'Credit Limit' => 'Kredietlimiet',
+ 'Curr' => 'Val.',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Klant',
+ 'Customer missing!' => 'Klant ontbreekt!',
+ 'Customer not on file!' => 'Klant bestaat niet!',
+ 'Date' => 'Datum',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Delete' => 'Verwijder',
+ 'Delivery Date' => 'Leverdatum',
+ 'Description' => 'Omschrijving',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'E-mailadres mist!',
+ 'Edit Purchase Order' => 'Inkooporder wijzigen',
+ 'Edit Sales Order' => 'Verkoop order wijzigen',
+ 'Exchangerate' => 'Wisselkoers',
+ 'Exchangerate missing!' => 'Wisselkoers mist!',
+ 'Extended' => 'Uitgebreid',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Van',
+ 'ID' => 'ID',
+ 'In-line' => 'In Lijn',
+ 'Include in Report' => 'Uitvoer inclusief',
+ 'Invoice' => 'Factuur',
+ 'Invoice Date missing!' => 'Factuurdatum mist!',
+ 'Invoice Number missing!' => 'Factuurnummer mist!',
+ 'Item not on file!' => 'Dit onderdeel is niet in de database gevonden!',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Message' => 'Boodschap',
+ 'Name' => 'Naam',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Opmerkingen',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Getal missend in regel',
+ 'O' => 'O',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Open' => 'Open',
+ 'Order' => 'Bestelling',
+ 'Order Date' => 'Orderdatum',
+ 'Order Date missing!' => 'Geen order datum aanwezig',
+ 'Order Number' => 'Referentie',
+ 'Order Number missing!' => 'Geen ordernummer aanwezig',
+ 'Order deleted!' => 'Order verwijderd!',
+ 'Order saved!' => 'Order opgeslagen!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Pakbon',
+ 'Packing List Date missing!' => 'Pakbon datum mist!',
+ 'Packing List Number missing!' => 'Pakbon nummer mist!',
+ 'Part' => 'Artikel',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Prijs',
+ 'Print' => 'Afdrukken',
+ 'Printer' => 'Printer',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project bestaat niet!',
+ 'Purchase Order' => 'Inkooporder',
+ 'Purchase Orders' => 'Inkooporders',
+ 'Qty' => 'Aantal',
+ 'Recd' => 'Ontvangen',
+ 'Remaining' => 'Resterend',
+ 'Required by' => 'Nodig voor',
+ 'Sales Order' => 'Verkooporder',
+ 'Sales Orders' => 'Verkooporders',
+ 'Save' => 'Opslaan',
+ 'Save as new' => 'Opslaan als nieuw',
+ 'Screen' => 'Scherm',
+ 'Select from one of the items below' => 'Kies een van de onderstaande items',
+ 'Select from one of the names below' => 'Kies een van de onderstaande namen',
+ 'Select from one of the projects below' => 'Kies een van de onderstaande projecten',
+ 'Select postscript or PDF!' => 'Kies postscript of PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Dienst',
+ 'Ship' => 'Verzenden',
+ 'Ship to' => 'Verzenden aan',
+ 'Ship via' => 'Verzenden via',
+ 'Subject' => 'Onderwerp',
+ 'Subtotal' => 'Subtotaal',
+ 'Tax' => 'Belasting',
+ 'Tax Included' => 'Inclusief Belasting',
+ 'Terms: Net' => 'Netto',
+ 'To' => 'Tot',
+ 'Total' => 'Totaal',
+ 'Unit' => 'Eenheid',
+ 'Update' => 'Bijwerken',
+ 'Vendor' => 'Leverancier',
+ 'Vendor missing!' => 'Leverancier ontbreekt!',
+ 'Vendor not on file!' => 'Leverancier bestaat niet!',
+ 'What type of item is this?' => 'Wat voor soort artikel is dit?',
+ 'Yes' => 'Ja',
+ 'days' => 'dagen',
+ 'ea' => 'voor',
+ 'emailed to' => 'per email verzonden aan',
+ 'sent to printer' => 'Afgedrukt',
+ 'to' => 'tot',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'toevoegen' => 'add',
+ 'verder' => 'continue',
+ 'verwijder' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'factuur' => 'invoice',
+ 'afdrukken' => 'print',
+ 'opslaan' => 'save',
+ 'opslaan_als_nieuw' => 'save_as_new',
+ 'verzenden_aan' => 'ship_to',
+ 'bijwerken' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/pe b/sql-ledger/locale/nl/pe
new file mode 100644
index 0000000..bf05662
--- /dev/null
+++ b/sql-ledger/locale/nl/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Toevoegen',
+ 'Add Project' => 'Project toevoegen',
+ 'All' => 'Allemaal',
+ 'Continue' => 'Verder',
+ 'Delete' => 'Verwijder',
+ 'Description' => 'Omschrijving',
+ 'Edit Project' => 'Project wijzigen',
+ 'Number' => 'Nummer',
+ 'Orphaned' => 'Wees',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Projectnummer ontbreekt!',
+ 'Project deleted!' => 'Project verwijderd!',
+ 'Project saved!' => 'Project opgeslagen!',
+ 'Projects' => 'Projecten',
+ 'Save' => 'Opslaan',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'toevoegen' => 'add',
+ 'verder' => 'continue',
+ 'verwijder' => 'delete',
+ 'opslaan' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/rc b/sql-ledger/locale/nl/rc
new file mode 100644
index 0000000..d86b58e
--- /dev/null
+++ b/sql-ledger/locale/nl/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Rekening',
+ 'Balance' => 'Saldo',
+ 'Cleared Balance' => 'Totaal geboekt vorige afschriften',
+ 'Continue' => 'Verder',
+ 'Date' => 'Datum',
+ 'Deposit' => 'Storting',
+ 'Description' => 'Omschrijving',
+ 'Difference' => 'Verschil',
+ 'Done' => 'Klaar',
+ 'Exchangerate Difference' => 'Koersverschil',
+ 'From' => 'Van',
+ 'Out of balance!' => 'Niet in evenwicht!',
+ 'Payment' => 'Betaling',
+ 'Reconciliation' => 'Bank Overzicht',
+ 'Select all' => 'Selecteer alles',
+ 'Source' => 'Herkomst',
+ 'Statement Balance' => 'Saldo Overzicht',
+ 'Update' => 'Bijwerken',
+ 'to' => 'tot',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'verder' => 'continue',
+ 'klaar' => 'done',
+ 'selecteer_alles' => 'select_all',
+ 'bijwerken' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/nl/rp b/sql-ledger/locale/nl/rp
new file mode 100644
index 0000000..9061318
--- /dev/null
+++ b/sql-ledger/locale/nl/rp
@@ -0,0 +1,116 @@
+$self{texts} = {
+ 'AP Aging' => 'Crediteuren Ouderdomsoverzicht',
+ 'AR Aging' => 'Debiteuren Ouderdomsoverzicht',
+ 'Account' => 'Rekening',
+ 'Accounts' => 'Rekeningen',
+ 'Amount' => 'Bedrag',
+ 'Apr' => 'Apr',
+ 'April' => 'April',
+ 'Attachment' => 'Bijlage',
+ 'Aug' => 'Aug',
+ 'August' => 'Augustus',
+ 'Balance Sheet' => 'Balans',
+ 'Bcc' => 'Onzichtbare kopie aan',
+ 'Cash based' => 'Kasbasis (contante verkopen)',
+ 'Cc' => 'Copie aan',
+ 'Compare to' => 'Vergelijk met',
+ 'Continue' => 'Verder',
+ 'Copies' => 'Kopieën',
+ 'Credit' => 'Credit',
+ 'Current' => 'Huidig',
+ 'Customer' => 'Klant',
+ 'Date' => 'Datum',
+ 'Debit' => 'Debet',
+ 'Dec' => 'Dec',
+ 'December' => 'December',
+ 'Decimalplaces' => 'Aantal Decimalen',
+ 'Description' => 'Omschrijving',
+ 'Due' => 'Verschuldigd',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'E-mail Overzicht aan',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Van',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Kopregel',
+ 'ID' => 'ID',
+ 'In-line' => 'In Lijn',
+ 'Include in Report' => 'Uitvoer inclusief',
+ 'Income Statement' => 'Inkomstenoverzicht',
+ 'Invoice' => 'Factuur',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mrt',
+ 'March' => 'Maart',
+ 'May' => 'Mei',
+ 'May ' => 'Mei',
+ 'Message' => 'Boodschap',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Niets geselecteerd!',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Betalingen',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Afdrukken',
+ 'Printer' => 'Printer',
+ 'Receipts' => 'Ontvangstbewijzen',
+ 'Report for' => 'Rapport voor',
+ 'Retained Earnings' => 'Winstreserve',
+ 'Screen' => 'Scherm',
+ 'Select all' => 'Selecteer alles',
+ 'Select postscript or PDF!' => 'Kies postscript of PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Herkomst',
+ 'Standard' => 'Standaard',
+ 'Statement' => 'Overzicht',
+ 'Statement sent to' => 'Overzicht verzonden aan',
+ 'Statements sent to printer!' => 'Overzichten afgedrukt',
+ 'Subject' => 'Onderwerp',
+ 'Subtotal' => 'Subtotaal',
+ 'Tax' => 'Belasting',
+ 'Tax collected' => 'Belasting verschuldigd',
+ 'Tax paid' => 'Belasting Betaald',
+ 'Total' => 'Totaal',
+ 'Trial Balance' => 'Proefbalans',
+ 'Vendor' => 'Leverancier',
+ 'as at' => 'per',
+ 'collected on sales' => 'verzameld voor de verkoop',
+ 'for Period' => 'voor periode',
+ 'paid on purchases' => 'betaald op inkopen',
+ 'to' => 'tot',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'verder' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'afdrukken' => 'print',
+ 'selecteer_alles' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/no/COPYING b/sql-ledger/locale/no/COPYING
new file mode 100644
index 0000000..b853d6c
--- /dev/null
+++ b/sql-ledger/locale/no/COPYING
@@ -0,0 +1,24 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Norwegian texts:
+#
+# Author: Keld Jørn Simonsen <keld@dkuug.dk>
+# Morten Pedersen <morten@workzone.no>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/no/LANGUAGE b/sql-ledger/locale/no/LANGUAGE
new file mode 100644
index 0000000..ed23589
--- /dev/null
+++ b/sql-ledger/locale/no/LANGUAGE
@@ -0,0 +1 @@
+Norwegian
diff --git a/sql-ledger/locale/no/admin b/sql-ledger/locale/no/admin
new file mode 100644
index 0000000..f28ff84
--- /dev/null
+++ b/sql-ledger/locale/no/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Aksesskontroll',
+ 'Accounting' => 'Bokføring',
+ 'Add User' => 'Ny bruker',
+ 'Address' => 'Adresse',
+ 'Administration' => 'Administrasjon',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => 'Alle datasett oppdatert!',
+ 'Change Admin Password' => 'Endre passord for admin',
+ 'Change Password' => 'Endre passord',
+ 'Character Set' => 'Tegnsett',
+ 'Click on login name to edit!' => 'Klikk på brukernavn for å redigere!',
+ 'Company' => 'Firma',
+ 'Connect to' => 'Forbind til',
+ 'Continue' => 'Fortsett',
+ 'Create Chart of Accounts' => 'Opprett kontoplan',
+ 'Create Dataset' => 'Opprett datasett',
+ 'DBI not installed!' => 'DBI ikke installert!',
+ 'Database' => 'Database',
+ 'Database Administration' => 'Administrasjon av database',
+ 'Database Driver not checked!' => 'Databasedriver ikke kontrollert!',
+ 'Database User missing!' => 'Bruker av database mangler!',
+ 'Dataset' => 'Datasett',
+ 'Dataset missing!' => 'Datasett mangler!',
+ 'Dataset updated!' => 'Datasett oppdatert!',
+ 'Date Format' => 'Datoformat',
+ 'Delete' => 'Fjern',
+ 'Delete Dataset' => 'Fjern datasett',
+ 'Directory' => 'Katalog',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Grense for dropdown',
+ 'E-mail' => 'E-post',
+ 'Edit User' => 'Redigér bruker',
+ 'Existing Datasets' => 'Eksisterende datasett',
+ 'Fax' => 'Faks',
+ 'Host' => 'Vert',
+ 'Hostname missing!' => 'Vertsnavn mangler!',
+ 'Incorrect Password!' => 'Galt passord!',
+ 'Language' => 'Språk',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'La vert- og port-felt være tomme med mindre du vil lage en ekstern forbindelse.',
+ 'Login' => 'Login',
+ 'Multibyte Encoding' => 'Tegnsett',
+ 'Name' => 'Navn',
+ 'New Templates' => 'Nye maler',
+ 'No Database Drivers available!' => 'Ingen databasedrivere tilgjengelige!',
+ 'No Dataset selected!' => 'Ingen datasett valgt!',
+ 'Nothing to delete!' => 'Intet å slette!',
+ 'Number Format' => 'Numerisk format',
+ 'Oracle Database Administration' => 'Administrasjon av database Oracle',
+ 'Password' => 'Passord',
+ 'Password changed!' => 'Passord endret!',
+ 'Pg Database Administration' => 'Administrasjon av database Pg',
+ 'Phone' => 'Tel',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port mangler!',
+ 'Printer' => 'Printer',
+ 'Save' => 'Lagre',
+ 'Select a Dataset to delete and press "Continue"' => 'Velg et datasett det skal fjernes og trykk "Fortsett"',
+ 'Setup Templates' => 'Oppsett av maler',
+ 'Ship via' => 'Avsend via',
+ 'Signature' => 'Underskrift',
+ 'Stylesheet' => 'Stílark',
+ 'Templates' => 'Maler',
+ 'The following Datasets are not in use and can be deleted' => 'De følgende datasett er ikke i bruk og kan slettes',
+ 'The following Datasets need to be updated' => 'De følgende datasettene skal oppdateres',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Dette er en innledende kontroll for eksisterende kilder. Ingenting vil bli opprettet eller stettet på dette trinnet!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'For å tilføye en bruker til en gruppe må du endre et brukernavn og så lagre. Den nye brukeren vil så bli lagret med de samme variablene under det nye loginnavn.',
+ 'Update Dataset' => 'Oppdatér datasett',
+ 'Use Templates' => 'Bruk maler',
+ 'User' => 'Bruker',
+ 'User deleted!' => 'Bruker slettet!',
+ 'User saved!' => 'Bruker lagret!',
+ 'Version' => 'Versjon',
+ 'You must enter a host and port for local and remote connections!' => 'Du må oppgi en vert og en port for lokale og eksterne forbindelser!',
+ 'does not exist' => 'eksisterer ikke',
+ 'is already a member!' => 'er allerede et medlem!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'Låst!',
+ 'successfully created!' => 'opprettet!',
+ 'successfully deleted!' => 'fjernet!',
+ 'website' => 'nettsted',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'ny_bruker' => 'add_user',
+ 'endre_passord_for_admin' => 'change_admin_password',
+ 'endre_passord' => 'change_password',
+ 'fortsett' => 'continue',
+ 'opprett_datasett' => 'create_dataset',
+ 'fjern' => 'delete',
+ 'fjern_datasett' => 'delete_dataset',
+ 'login' => 'login',
+ 'administrasjon_av_database_oracle' => 'oracle_database_administration',
+ 'administrasjon_av_database_pg' => 'pg_database_administration',
+ 'lagre' => 'save',
+ 'oppdatér_datasett' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/no/all b/sql-ledger/locale/no/all
new file mode 100644
index 0000000..1c5d704
--- /dev/null
+++ b/sql-ledger/locale/no/all
@@ -0,0 +1,496 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Kreditorer',
+ 'AP Aging' => 'Aldersfordeling',
+ 'AP Transaction' => 'Leverandørfaktura',
+ 'AP Transactions' => 'Leverandørfakturaer',
+ 'AR' => 'Debitorer',
+ 'AR Aging' => 'Aldersfordeling',
+ 'AR Transaction' => 'Debitorpostering',
+ 'AR Transactions' => 'Debitorposteringer',
+ 'About' => 'Om',
+ 'Access Control' => 'Aksesskontroll',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Kontonummer',
+ 'Account Number missing!' => 'Kontonummer mangler!',
+ 'Account Type' => 'Kontotype',
+ 'Account Type missing!' => 'Kontotype mangler!',
+ 'Account deleted!' => 'Konto slettet!',
+ 'Account saved!' => 'Konto lagret!',
+ 'Accounting' => 'Bokføring',
+ 'Accounting Menu' => 'Konto-meny',
+ 'Accounts' => 'Kontoer',
+ 'Active' => 'Aktiv',
+ 'Add' => 'Legg til',
+ 'Add Account' => 'Ny konto',
+ 'Add Accounts Payables Transaction' => 'Ny leverandørfaktura',
+ 'Add Accounts Receivables Transaction' => 'Ny debitorpostering',
+ 'Add Assembly' => 'Ny sammensetting',
+ 'Add Customer' => 'Ny kunde',
+ 'Add GIFI' => 'Ny GIFI',
+ 'Add General Ledger Transaction' => 'Ny postering i hovedbok',
+ 'Add Part' => 'Ny vare',
+ 'Add Project' => 'Nytt prosjekt',
+ 'Add Purchase Invoice' => 'Ny innkjøpsfaktura',
+ 'Add Purchase Order' => 'Ny innkjøpsordre',
+ 'Add Sales Invoice' => 'Ny salgsfaktura',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Add Service' => 'Ny tjeneste',
+ 'Add Transaction' => 'Ny postering',
+ 'Add User' => 'Ny bruker',
+ 'Add Vendor' => 'Ny leverandør',
+ 'Address' => 'Adresse',
+ 'Administration' => 'Administrasjon',
+ 'Administrator' => 'Administrator',
+ 'All' => 'Alle',
+ 'All Datasets up to date!' => 'Alle datasett oppdatert!',
+ 'Amount' => 'Beløp',
+ 'Amount Due' => 'Forfallent beløp',
+ 'Amount does not equal applied!' => 'Beløp er ikke likt utført!',
+ 'Amount missing!' => 'Konto mangler!',
+ 'Applied' => 'Utført',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Invoice Number' => 'Er du sikker på at du vil fjerne fakturanummer',
+ 'Are you sure you want to delete Order Number' => 'Er du sikker på at du vil fjerne ordrenummer',
+ 'Are you sure you want to delete Transaction' => 'Er du sikker på at du vil fjerne postering',
+ 'Assemblies' => 'Sammensettinger',
+ 'Assemblies restocked!' => 'Sammensettinger omplassert!',
+ 'Assembly Number missing!' => 'Sammensettingsnummer mangler!',
+ 'Asset' => 'Aktiv',
+ 'Attachment' => 'Vedlegg',
+ 'Audit Control' => 'Revisjonskontroll',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'BOM' => 'BOM',
+ 'Backup' => 'Sikkerhetskopi',
+ 'Backup sent to' => 'Sikkerhetskopier sendt til',
+ 'Balance' => 'Balanse',
+ 'Balance Sheet' => 'Status',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Papirkurv',
+ 'Books are open' => 'Bokføringen er åpen for rettelser',
+ 'Bought' => 'Kjøpt',
+ 'Business Number' => 'Organisasjonsnummer',
+ 'C' => 'C',
+ 'COGS' => 'Innkjøp',
+ 'Cannot delete account!' => 'Kan ikke slette konto!',
+ 'Cannot delete customer!' => 'Kan ikke slette kunde!',
+ 'Cannot delete default account!' => 'Kan ikke slette standardkonto!',
+ 'Cannot delete invoice!' => 'Kan ikke slette faktura!',
+ 'Cannot delete item already invoiced!' => 'Kan ikke slette allerede fakturert enkeltdel!',
+ 'Cannot delete item on order!' => 'Kan ikke slette enkeltdel i ordre!',
+ 'Cannot delete item which is part of an assembly!' => 'kan ikke slette en enhet som er en del av en sammensetting!',
+ 'Cannot delete item!' => 'Kan ikke slette enkeltdel!',
+ 'Cannot delete order!' => 'Kan ikke slette ordre!',
+ 'Cannot delete transaction!' => 'Kan ikke slette postering!',
+ 'Cannot delete vendor!' => 'Kan ikke slette leverandør!',
+ 'Cannot have a value in both Debit and Credit!' => 'Kan ikke ha en verdi i både debet og kredit!',
+ 'Cannot post a transaction without a value!' => 'Kan ikke bokføre transaksjon uten verdi!',
+ 'Cannot post invoice for a closed period!' => 'Kan ikke bokføre faktura for en avsluttet periode!',
+ 'Cannot post invoice!' => 'Kan ikke bokføre faktura!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bokføre betaling for en avsluttet periode!',
+ 'Cannot post payment!' => 'Kan ikke bokføre betaling!',
+ 'Cannot post transaction for a closed period!' => 'Kan ikke bokføre postering for en avsluttet periode!',
+ 'Cannot post transaction!' => 'Kan ikke bokføre postering!',
+ 'Cannot process payment for a closed period!' => 'Kan ikke behandle betaling for avsluttet periode!',
+ 'Cannot save account!' => 'Kan ikke lagre konto!',
+ 'Cannot save order!' => 'Kan ikke lagre ordre!',
+ 'Cannot save preferences!' => 'Kan ikke lagre preferenser!',
+ 'Cannot stock assemblies!' => 'Kan ikke plasere sammensetninger!',
+ 'Cash' => 'Bank',
+ 'Cash based' => 'Bank basert',
+ 'Cc' => 'Kopi til',
+ 'Change Admin Password' => 'Endre passord for admin',
+ 'Change Password' => 'Endre passord',
+ 'Character Set' => 'Tegnsett',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Check' => 'Sjekk',
+ 'Check printed!' => 'Sjekk utskrift!',
+ 'Check printing failed!' => 'Utskrift av sjekk feilet!',
+ 'Cleared Balance' => 'Utlignet balanse',
+ 'Click on login name to edit!' => 'Klikk på brukernavn for å redigere!',
+ 'Close Books up to' => 'Avslutt bokføring opp til',
+ 'Closed' => 'Avsluttet',
+ 'Company' => 'Firma',
+ 'Compare to' => 'Sammenlign med',
+ 'Confirm!' => 'Bekreft!',
+ 'Connect to' => 'Forbind til',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsett',
+ 'Copies' => 'Kopier',
+ 'Copy to COA' => 'Kopiér til COA',
+ 'Create Chart of Accounts' => 'Opprett kontoplan',
+ 'Create Dataset' => 'Opprett datasett',
+ 'Credit' => 'Kredit',
+ 'Credit Limit' => 'Kreditgrense',
+ 'Curr' => 'Val',
+ 'Currency' => 'Valuta',
+ 'Current' => 'Nåværende',
+ 'Customer' => 'Kunde',
+ 'Customer deleted!' => 'Kunde slettet!',
+ 'Customer missing!' => 'Kunde mangler!',
+ 'Customer not on file!' => 'Kunde ikke i database!',
+ 'Customer saved!' => 'Kunde lagret!',
+ 'Customers' => 'Kunder',
+ 'DBI not installed!' => 'DBI ikke installert!',
+ 'Database' => 'Database',
+ 'Database Administration' => 'Administrasjon av database',
+ 'Database Driver not checked!' => 'Databasedriver ikke kontrollert!',
+ 'Database Host' => 'Database-vert',
+ 'Database User missing!' => 'Bruker av database mangler!',
+ 'Dataset' => 'Datasett',
+ 'Dataset missing!' => 'Datasett mangler!',
+ 'Dataset updated!' => 'Datasett oppdatert!',
+ 'Date' => 'Dato',
+ 'Date Due' => 'Forfallsdato',
+ 'Date Format' => 'Datoformat',
+ 'Date Paid' => 'Betalingsdato',
+ 'Date missing!' => 'Dato mangler!',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet og kredit må være det samme!',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Decimalplaces' => 'Desimalplasser',
+ 'Delete' => 'Fjern',
+ 'Delete Account' => 'Fjern konto',
+ 'Delete Dataset' => 'Fjern datasett',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Department' => 'Avdeling',
+ 'Deposit' => 'Depositum',
+ 'Description' => 'Beskrivelse',
+ 'Difference' => 'Forskjell',
+ 'Directory' => 'Katalog',
+ 'Discount' => 'Rabatt',
+ 'Done' => 'Ferdig',
+ 'Drawing' => 'Tegning',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Grense for dropdown',
+ 'Due' => 'Forfall',
+ 'Due Date' => 'Forfallsdato',
+ 'Due Date missing!' => 'Forfallsdato mangler!',
+ 'E-mail' => 'E-post',
+ 'E-mail Statement to' => 'Send oppgjør til',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit' => 'Redigér',
+ 'Edit Account' => 'Redigér konto',
+ 'Edit Accounts Payables Transaction' => 'Redigér leverandørpostering',
+ 'Edit Accounts Receivables Transaction' => 'Redigér debitorpostering',
+ 'Edit Assembly' => 'Redigér sammensetting',
+ 'Edit Customer' => 'Endre kundeopplysninger',
+ 'Edit GIFI' => 'Redigér GIFI',
+ 'Edit General Ledger Transaction' => 'Redigér en postering i hovedbok',
+ 'Edit Part' => 'Redigér vare',
+ 'Edit Preferences for' => 'Redigér innstillinger for',
+ 'Edit Project' => 'Redigér prosjekt',
+ 'Edit Purchase Invoice' => 'Redigér innkjøpsfaktura',
+ 'Edit Purchase Order' => 'Redigér innkjøpsordre',
+ 'Edit Sales Invoice' => 'Redigér salgsfaktura',
+ 'Edit Sales Order' => 'Redigér salgsordre',
+ 'Edit Service' => 'Redigér tjeneste',
+ 'Edit Template' => 'Redigér mal',
+ 'Edit User' => 'Redigér bruker',
+ 'Edit Vendor' => 'Endre produsent',
+ 'Employee' => 'Ansatt',
+ 'Enforce transaction reversal for all dates' => 'Tving eksplisitte transaksjonsrettelser for alle datoer',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Angi opp til 3 bokstaver adskilt med kolon (fx NOK:EUR:USD:JPY) for innenlandske og utenlandske valutaer',
+ 'Equity' => 'Egenkapital',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekslingskurs',
+ 'Exchangerate Difference' => 'Forskjell på vekslingskurs',
+ 'Exchangerate for payment missing!' => 'Vekslingskurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekslingskurs mangler!',
+ 'Existing Datasets' => 'Eksisterende datasett',
+ 'Expense' => 'Utgift',
+ 'Expense Account' => 'Utgiftskonto',
+ 'Expense/Asset' => 'Utgift/Aktiv',
+ 'Extended' => 'Utvigt',
+ 'Fax' => 'Faks',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'Foreign Exchange Gain' => 'Gevinst på valutahandel',
+ 'Foreign Exchange Loss' => 'Tap på valutahandel',
+ 'From' => 'Fra',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI slettet!',
+ 'GIFI missing!' => 'GIFI mangler!',
+ 'GIFI saved!' => 'GIFI lagret!',
+ 'GL Transaction' => 'Postering i hovedbok',
+ 'General Ledger' => 'Hovedbok',
+ 'Goods & Services' => 'Varer og tjenester',
+ 'HTML Templates' => 'HTML-maler',
+ 'Heading' => 'Overskrift',
+ 'Host' => 'Vert',
+ 'Hostname missing!' => 'Vertsnavn mangler!',
+ 'ID' => 'ID',
+ 'Image' => 'Bilde',
+ 'In-line' => 'Inne i',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Include in drop-down menus' => 'Inkludér i rullegardin-menyer',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Skal denne konto kunne velges som avgifts- eller mva-konto ved opprettelsen av kunder/leverandører?',
+ 'Income' => 'Inntekt',
+ 'Income Account' => 'Inntektskonto',
+ 'Income Statement' => 'Driftsregnskap',
+ 'Incorrect Dataset version!' => 'Gal versjon av datasett!',
+ 'Incorrect Password!' => 'Galt passord!',
+ 'Individual Items' => 'Individuelle enheter',
+ 'Inventory' => 'Artikler',
+ 'Inventory Account' => 'Lagerkonto',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Lagerbeholdning må være null for at du kan sette denne sammensetting som foreldet!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Lagerbeholdning må være null for at du kan sette denne enhet som foreldet!',
+ 'Inventory quantity must be zero!' => 'Lagerbeholdning må være null!',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Invoice deleted!' => 'Faktura slettet!',
+ 'Invoice posted!' => 'Faktura bokført!',
+ 'Invoices' => 'Fakturaer',
+ 'Is this a summary account to record' => 'Samlekonto for',
+ 'Item deleted!' => 'Enkeltdel slettet!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'LaTeX Templates' => 'LaTeX-maler',
+ 'Language' => 'Språk',
+ 'Last Cost' => 'Seneste pris',
+ 'Last Invoice Number' => 'Seneste fakturanummer',
+ 'Last Numbers & Default Accounts' => 'Løpenumre og standardkontoer',
+ 'Last Purchase Order Number' => 'Seneste innkjøpsordrenummer',
+ 'Last Sales Order Number' => 'Seneste salgsordrenummer',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'La vert- og port-felt være tomme med mindre du vil lage en ekstern forbindelse.',
+ 'Liability' => 'Passiv',
+ 'Licensed to' => 'Utført for',
+ 'Line Total' => 'Antall linjer',
+ 'Link' => 'Referanse',
+ 'Link Accounts' => 'Kople kontoer',
+ 'List Accounts' => 'List kontoer',
+ 'List GIFI' => 'List GIFI',
+ 'List Price' => 'Listepris',
+ 'List Transactions' => 'Vis bokføringer',
+ 'Login' => 'Login',
+ 'Logout' => 'Log ut',
+ 'Make' => 'Fabrikat',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Message' => 'Melding',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Modell',
+ 'Multibyte Encoding' => 'Tegnsett',
+ 'N/A' => 'I/T',
+ 'Name' => 'Navn',
+ 'Name missing!' => 'Navn mangler!',
+ 'New Templates' => 'Nye maler',
+ 'No' => 'Nei',
+ 'No Database Drivers available!' => 'Ingen databasedrivere tilgjengelige!',
+ 'No Dataset selected!' => 'Ingen datasett valgt!',
+ 'No email address for' => 'Ingen emailadresse for',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkninger',
+ 'Nothing applied!' => 'Ingenting utført!',
+ 'Nothing selected!' => 'Ingenting valgt!',
+ 'Nothing to delete!' => 'Intet å slette!',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Numerisk format',
+ 'Number missing in Row' => 'Tall mangler i rad',
+ 'O' => 'O',
+ 'Obsolete' => 'Foreldet',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'On Hand' => 'På lager',
+ 'On Order' => 'I ordre',
+ 'Open' => 'Åpne',
+ 'Oracle Database Administration' => 'Administrasjon av database Oracle',
+ 'Order' => 'Ordre',
+ 'Order Date' => 'Ordredato',
+ 'Order Date missing!' => 'Ordredato mangler!',
+ 'Order Entry' => 'Ordreinngang',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler!',
+ 'Order deleted!' => 'Ordre slettet!',
+ 'Order saved!' => 'Ordre lagret!',
+ 'Ordered' => 'Ordrer',
+ 'Orphaned' => 'Frittstående',
+ 'Out of balance!' => 'Ute av balanse!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Paid' => 'Betalt',
+ 'Paid in full' => 'Alt betalt',
+ 'Part' => 'Vare',
+ 'Part Number missing!' => 'Varenummer mangler!',
+ 'Parts' => 'Deler',
+ 'Parts Inventory' => 'Vareliste',
+ 'Password' => 'Passord',
+ 'Password changed!' => 'Passord endret!',
+ 'Payables' => 'Utbetalinger',
+ 'Payment' => 'Betaling',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payment posted!' => 'Betaling bokført!',
+ 'Payments' => 'Utbetaling',
+ 'Pg Database Administration' => 'Administrasjon av database Pg',
+ 'Phone' => 'Tel',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port mangler!',
+ 'Post' => 'Bokfør',
+ 'Post as new' => 'Bokfør som ny',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Innstillinger',
+ 'Preferences saved!' => 'Innstillinger lagret!',
+ 'Price' => 'Pris',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Printer',
+ 'Project' => 'Prosjekt',
+ 'Project Number' => 'Prosjektnummer',
+ 'Project Number missing!' => 'Prosjektnummer mangler!',
+ 'Project deleted!' => 'Prosjekt slettet!',
+ 'Project not on file!' => 'Prosjekt er ikke i database!',
+ 'Project saved!' => 'Prosjekt lagret!',
+ 'Projects' => 'Prosjekter',
+ 'Purchase Invoice' => 'Innkjøpsfaktura',
+ 'Purchase Order' => 'Innkjøpsordre',
+ 'Purchase Orders' => 'Innkjøpsordrer',
+ 'Qty' => 'Antall',
+ 'ROP' => 'Etterbestill ved',
+ 'Rate' => 'Rate',
+ 'Recd' => 'Mottatt',
+ 'Receipt' => 'Kvittering',
+ 'Receipt printed!' => 'Kvittering skrevet!',
+ 'Receipt printing failed!' => 'Kvitteringsutskrift feilet!',
+ 'Receipts' => 'Kvitteringer',
+ 'Receivables' => 'Innbetalinger',
+ 'Reconciliation' => 'Bankoppgjør',
+ 'Record in' => 'Bokfør på',
+ 'Reference' => 'Referanse',
+ 'Reference missing!' => 'Referanser mangler!',
+ 'Remaining' => 'Resterende',
+ 'Report for' => 'Rapport for',
+ 'Reports' => 'Rapporter',
+ 'Required by' => 'Bestilt av',
+ 'Retained Earnings' => 'Realisert overskudd',
+ 'Sales' => 'Salg',
+ 'Sales Invoice' => 'Salgsfaktura',
+ 'Sales Order' => 'Salgsordre',
+ 'Sales Orders' => 'Salgsordrer',
+ 'Salesperson' => '',
+ 'Save' => 'Lagre',
+ 'Save as new' => 'Lagre som ny',
+ 'Save to File' => 'Lagre i fil',
+ 'Screen' => 'Skjerm',
+ 'Select a Dataset to delete and press "Continue"' => 'Velg et datasett det skal fjernes og trykk "Fortsett"',
+ 'Select all' => 'Velg alt',
+ 'Select from one of the items below' => 'Velg en fra listen under, og trykk "Fortsett"',
+ 'Select from one of the names below' => 'Velg fra et av navnene under',
+ 'Select from one of the projects below' => 'Velg fra et av prosjektene under',
+ 'Select postscript or PDF!' => 'Velg postscript eller PDF!',
+ 'Sell Price' => 'Salgspris',
+ 'Send by E-Mail' => 'Sendt per email',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Service Items' => 'Tjenester',
+ 'Service Number missing!' => 'Tjenestenummer mangler!',
+ 'Services' => 'Tjenester',
+ 'Setup Templates' => 'Oppsett av maler',
+ 'Ship' => 'Avsend',
+ 'Ship to' => 'Avsend til',
+ 'Ship via' => 'Avsend via',
+ 'Short' => 'Kort',
+ 'Signature' => 'Underskrift',
+ 'Sold' => 'Solgt',
+ 'Source' => 'Bilag',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Oppgjør',
+ 'Statement Balance' => 'Balanseoppgjør',
+ 'Statement sent to' => 'Oppgjør sendt til',
+ 'Statements sent to printer!' => 'Oppgjør sendt til skriver!',
+ 'Stock Assembly' => 'Lagersammensetting',
+ 'Stylesheet' => 'Stílark',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'System' => 'System',
+ 'Tax' => 'Avgift/mva',
+ 'Tax Accounts' => 'Avgift/mva-kontoer',
+ 'Tax Included' => 'Inkl. avgifter og mva',
+ 'Tax collected' => 'Inngående avgift',
+ 'Tax paid' => 'Betalt avgift',
+ 'Taxable' => 'Avgifts/mvapliktig',
+ 'Template saved!' => 'Mal lagret!',
+ 'Templates' => 'Maler',
+ 'Terms: Net' => 'Netto',
+ 'The following Datasets are not in use and can be deleted' => 'De følgende datasett er ikke i bruk og kan slettes',
+ 'The following Datasets need to be updated' => 'De følgende datasettene skal oppdateres',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Dette er en innledende kontroll for eksisterende kilder. Ingenting vil bli opprettet eller stettet på dette trinnet!',
+ 'To' => 'Til',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'For å tilføye en bruker til en gruppe må du endre et brukernavn og så lagre. Den nye brukeren vil så bli lagret med de samme variablene under det nye loginnavn.',
+ 'Top Level' => 'Toppnivå',
+ 'Total' => 'I alt',
+ 'Transaction Date missing!' => 'Transaksjonsdato mangler!',
+ 'Transaction deleted!' => 'Postering slettet!',
+ 'Transaction posted!' => 'Postering bokført!',
+ 'Transaction reversal enforced for all dates' => 'Transaksjonsrettelser skal alltid bokføres eksplisitt',
+ 'Transaction reversal enforced up to' => 'Transaksjonsrettelser skal bokføres eksplisitt inntil',
+ 'Transactions' => 'Posteringer',
+ 'Transactions exist, cannot delete customer!' => 'Kunde kan ikke fjernes da det er posteringer!',
+ 'Transactions exist, cannot delete vendor!' => 'Leverandør kan ikke fjernes da det er posteringer!',
+ 'Transactions exist; cannot delete account!' => 'Konto kan ikke fjernes da det er posteringer!',
+ 'Trial Balance' => 'Foreløpig status',
+ 'Unit' => 'Enhet',
+ 'Unit of measure' => 'Måleenhet',
+ 'Update' => 'Oppdatér',
+ 'Update Dataset' => 'Oppdatér datasett',
+ 'Updated' => 'Oppdateret',
+ 'Use Templates' => 'Bruk maler',
+ 'User' => 'Bruker',
+ 'User deleted!' => 'Bruker slettet!',
+ 'User saved!' => 'Bruker lagret!',
+ 'Vendor' => 'Leverandør',
+ 'Vendor deleted!' => 'Leverandør slettet!',
+ 'Vendor missing!' => 'Leverandør mangler!',
+ 'Vendor not on file!' => 'Leverandør er ikke i database!',
+ 'Vendor saved!' => 'Leverandør lagret!',
+ 'Vendors' => 'Leverandører',
+ 'Version' => 'Versjon',
+ 'Weight' => 'Vekt',
+ 'Weight Unit' => 'Vektenhet',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'Year End' => 'Årsslutt',
+ 'Yes' => 'Ja',
+ 'You are logged out!' => 'Du er logget av!',
+ 'You did not enter a name!' => 'Du gav ikke et navn!',
+ 'You must enter a host and port for local and remote connections!' => 'Du må oppgi en vert og en port for lokale og eksterne forbindelser!',
+ 'as at' => 'som ved',
+ 'collected on sales' => 'innbetalt på salg',
+ 'days' => 'dager',
+ 'does not exist' => 'eksisterer ikke',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt på epost til',
+ 'for Period' => 'for periode',
+ 'hr' => 'time',
+ 'is already a member!' => 'er allerede et medlem!',
+ 'is not a member!' => 'er ikke et medlem!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'Låst!',
+ 'paid on purchases' => 'betalt på kjøp',
+ 'sent to printer' => 'sendt til skriver',
+ 'successfully created!' => 'opprettet!',
+ 'successfully deleted!' => 'fjernet!',
+ 'to' => 'til',
+ 'website' => 'nettsted',
+};
+
+1;
diff --git a/sql-ledger/locale/no/am b/sql-ledger/locale/no/am
new file mode 100644
index 0000000..5e56e9a
--- /dev/null
+++ b/sql-ledger/locale/no/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Kreditorer',
+ 'AR' => 'Debitorer',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Kontonummer',
+ 'Account Number missing!' => 'Kontonummer mangler!',
+ 'Account Type' => 'Kontotype',
+ 'Account Type missing!' => 'Kontotype mangler!',
+ 'Account deleted!' => 'Konto slettet!',
+ 'Account saved!' => 'Konto lagret!',
+ 'Add Account' => 'Ny konto',
+ 'Add GIFI' => 'Ny GIFI',
+ 'Address' => 'Adresse',
+ 'Asset' => 'Aktiv',
+ 'Audit Control' => 'Revisjonskontroll',
+ 'Backup sent to' => 'Sikkerhetskopier sendt til',
+ 'Books are open' => 'Bokføringen er åpen for rettelser',
+ 'Business Number' => 'Organisasjonsnummer',
+ 'COGS' => 'Innkjøp',
+ 'Cannot delete account!' => 'Kan ikke slette konto!',
+ 'Cannot delete default account!' => 'Kan ikke slette standardkonto!',
+ 'Cannot save account!' => 'Kan ikke lagre konto!',
+ 'Cannot save preferences!' => 'Kan ikke lagre preferenser!',
+ 'Character Set' => 'Tegnsett',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Close Books up to' => 'Avslutt bokføring opp til',
+ 'Company' => 'Firma',
+ 'Continue' => 'Fortsett',
+ 'Copy to COA' => 'Kopiér til COA',
+ 'Credit' => 'Kredit',
+ 'Date Format' => 'Datoformat',
+ 'Debit' => 'Debet',
+ 'Delete' => 'Fjern',
+ 'Delete Account' => 'Fjern konto',
+ 'Description' => 'Beskrivelse',
+ 'Dropdown Limit' => 'Grense for dropdown',
+ 'E-mail' => 'E-post',
+ 'Edit' => 'Redigér',
+ 'Edit Account' => 'Redigér konto',
+ 'Edit GIFI' => 'Redigér GIFI',
+ 'Edit Preferences for' => 'Redigér innstillinger for',
+ 'Edit Template' => 'Redigér mal',
+ 'Enforce transaction reversal for all dates' => 'Tving eksplisitte transaksjonsrettelser for alle datoer',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Angi opp til 3 bokstaver adskilt med kolon (fx NOK:EUR:USD:JPY) for innenlandske og utenlandske valutaer',
+ 'Equity' => 'Egenkapital',
+ 'Expense' => 'Utgift',
+ 'Expense Account' => 'Utgiftskonto',
+ 'Expense/Asset' => 'Utgift/Aktiv',
+ 'Fax' => 'Faks',
+ 'Foreign Exchange Gain' => 'Gevinst på valutahandel',
+ 'Foreign Exchange Loss' => 'Tap på valutahandel',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI slettet!',
+ 'GIFI missing!' => 'GIFI mangler!',
+ 'GIFI saved!' => 'GIFI lagret!',
+ 'Heading' => 'Overskrift',
+ 'Include in drop-down menus' => 'Inkludér i rullegardin-menyer',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Skal denne konto kunne velges som avgifts- eller mva-konto ved opprettelsen av kunder/leverandører?',
+ 'Income' => 'Inntekt',
+ 'Income Account' => 'Inntektskonto',
+ 'Inventory' => 'Artikler',
+ 'Inventory Account' => 'Lagerkonto',
+ 'Is this a summary account to record' => 'Samlekonto for',
+ 'Language' => 'Språk',
+ 'Last Invoice Number' => 'Seneste fakturanummer',
+ 'Last Numbers & Default Accounts' => 'Løpenumre og standardkontoer',
+ 'Last Purchase Order Number' => 'Seneste innkjøpsordrenummer',
+ 'Last Sales Order Number' => 'Seneste salgsordrenummer',
+ 'Liability' => 'Passiv',
+ 'Link' => 'Referanse',
+ 'Name' => 'Navn',
+ 'No' => 'Nei',
+ 'No email address for' => 'Ingen emailadresse for',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Numerisk format',
+ 'Parts Inventory' => 'Vareliste',
+ 'Password' => 'Passord',
+ 'Payables' => 'Utbetalinger',
+ 'Payment' => 'Betaling',
+ 'Phone' => 'Tel',
+ 'Preferences saved!' => 'Innstillinger lagret!',
+ 'Rate' => 'Rate',
+ 'Receivables' => 'Innbetalinger',
+ 'Sales' => 'Salg',
+ 'Save' => 'Lagre',
+ 'Service Items' => 'Tjenester',
+ 'Ship via' => 'Avsend via',
+ 'Signature' => 'Underskrift',
+ 'Stylesheet' => 'Stílark',
+ 'Tax' => 'Avgift/mva',
+ 'Tax Accounts' => 'Avgift/mva-kontoer',
+ 'Template saved!' => 'Mal lagret!',
+ 'Transaction reversal enforced for all dates' => 'Transaksjonsrettelser skal alltid bokføres eksplisitt',
+ 'Transaction reversal enforced up to' => 'Transaksjonsrettelser skal bokføres eksplisitt inntil',
+ 'Transactions exist; cannot delete account!' => 'Konto kan ikke fjernes da det er posteringer!',
+ 'Weight Unit' => 'Vektenhet',
+ 'Year End' => 'Årsslutt',
+ 'Yes' => 'Ja',
+ 'does not exist' => 'eksisterer ikke',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'ny_konto' => 'add_account',
+ 'fortsett' => 'continue',
+ 'kopiér_til_coa' => 'copy_to_coa',
+ 'fjern' => 'delete',
+ 'redigér' => 'edit',
+ 'redigér_konto' => 'edit_account',
+ 'lagre' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/no/ap b/sql-ledger/locale/no/ap
new file mode 100644
index 0000000..896bc69
--- /dev/null
+++ b/sql-ledger/locale/no/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Leverandørfaktura',
+ 'AP Transactions' => 'Leverandørfakturaer',
+ 'Account' => 'Konto',
+ 'Add Accounts Payables Transaction' => 'Ny leverandørfaktura',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløp',
+ 'Amount Due' => 'Forfallent beløp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Transaction' => 'Er du sikker på at du vil fjerne postering',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Cannot delete transaction!' => 'Kan ikke slette postering!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bokføre betaling for en avsluttet periode!',
+ 'Cannot post transaction for a closed period!' => 'Kan ikke bokføre postering for en avsluttet periode!',
+ 'Cannot post transaction!' => 'Kan ikke bokføre postering!',
+ 'Closed' => 'Avsluttet',
+ 'Confirm!' => 'Bekreft!',
+ 'Continue' => 'Fortsett',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Kunde ikke i database!',
+ 'Date' => 'Dato',
+ 'Date Paid' => 'Betalingsdato',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Fjern',
+ 'Description' => 'Beskrivelse',
+ 'Due Date' => 'Forfallsdato',
+ 'Due Date missing!' => 'Forfallsdato mangler!',
+ 'Edit Accounts Payables Transaction' => 'Redigér leverandørpostering',
+ 'Employee' => 'Ansatt',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekslingskurs',
+ 'Exchangerate for payment missing!' => 'Vekslingskurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekslingskurs mangler!',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Notes' => 'Bemerkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Open' => 'Åpne',
+ 'Order' => 'Ordre',
+ 'Order Number' => 'Ordrenummer',
+ 'Paid' => 'Betalt',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payments' => 'Utbetaling',
+ 'Post' => 'Bokfør',
+ 'Post as new' => 'Bokfør som ny',
+ 'Project' => 'Prosjekt',
+ 'Project not on file!' => 'Prosjekt er ikke i database!',
+ 'Purchase Invoice' => 'Innkjøpsfaktura',
+ 'Select from one of the names below' => 'Velg fra et av navnene under',
+ 'Select from one of the projects below' => 'Velg fra et av prosjektene under',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Bilag',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Avgift/mva',
+ 'Tax Included' => 'Inkl. avgifter og mva',
+ 'Total' => 'I alt',
+ 'Transaction deleted!' => 'Postering slettet!',
+ 'Transaction posted!' => 'Postering bokført!',
+ 'Update' => 'Oppdatér',
+ 'Vendor' => 'Leverandør',
+ 'Vendor missing!' => 'Leverandør mangler!',
+ 'Vendor not on file!' => 'Leverandør er ikke i database!',
+ 'Yes' => 'Ja',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'leverandørfaktura' => 'ap_transaction',
+ 'ny_leverandørfaktura' => 'add_accounts_payables_transaction',
+ 'fortsett' => 'continue',
+ 'fjern' => 'delete',
+ 'redigér_leverandørpostering' => 'edit_accounts_payables_transaction',
+ 'bokfør' => 'post',
+ 'bokfør_som_ny' => 'post_as_new',
+ 'innkjøpsfaktura' => 'purchase_invoice',
+ 'oppdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/no/ar b/sql-ledger/locale/no/ar
new file mode 100644
index 0000000..d9ec705
--- /dev/null
+++ b/sql-ledger/locale/no/ar
@@ -0,0 +1,134 @@
+$self{texts} = {
+ 'AR Transaction' => 'Debitorpostering',
+ 'AR Transactions' => 'Debitorposteringer',
+ 'Account' => 'Konto',
+ 'Add Accounts Receivables Transaction' => 'Ny debitorpostering',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløp',
+ 'Amount Due' => 'Forfallent beløp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Transaction' => 'Er du sikker på at du vil fjerne postering',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Cannot delete transaction!' => 'Kan ikke slette postering!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bokføre betaling for en avsluttet periode!',
+ 'Cannot post transaction for a closed period!' => 'Kan ikke bokføre postering for en avsluttet periode!',
+ 'Cannot post transaction!' => 'Kan ikke bokføre postering!',
+ 'Closed' => 'Avsluttet',
+ 'Confirm!' => 'Bekreft!',
+ 'Continue' => 'Fortsett',
+ 'Credit Limit' => 'Kreditgrense',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kunde',
+ 'Customer missing!' => 'Kunde mangler!',
+ 'Customer not on file!' => 'Kunde ikke i database!',
+ 'Date' => 'Dato',
+ 'Date Paid' => 'Betalingsdato',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Fjern',
+ 'Description' => 'Beskrivelse',
+ 'Due Date' => 'Forfallsdato',
+ 'Due Date missing!' => 'Forfallsdato mangler!',
+ 'Edit Accounts Receivables Transaction' => 'Redigér debitorpostering',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekslingskurs',
+ 'Exchangerate for payment missing!' => 'Vekslingskurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekslingskurs mangler!',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Notes' => 'Bemerkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Open' => 'Åpne',
+ 'Order' => 'Ordre',
+ 'Order Number' => 'Ordrenummer',
+ 'Paid' => 'Betalt',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payments' => 'Utbetaling',
+ 'Post' => 'Bokfør',
+ 'Post as new' => 'Bokfør som ny',
+ 'Project' => 'Prosjekt',
+ 'Project not on file!' => 'Prosjekt er ikke i database!',
+ 'Remaining' => 'Resterende',
+ 'Sales Invoice' => 'Salgsfaktura',
+ 'Salesperson' => 'Salesperson',
+ 'Select from one of the names below' => 'Velg fra et av navnene under',
+ 'Select from one of the projects below' => 'Velg fra et av prosjektene under',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Ship via' => 'Avsend via',
+ 'Source' => 'Bilag',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Avgift/mva',
+ 'Tax Included' => 'Inkl. avgifter og mva',
+ 'Total' => 'I alt',
+ 'Transaction deleted!' => 'Postering slettet!',
+ 'Transaction posted!' => 'Postering bokført!',
+ 'Update' => 'Oppdatér',
+ 'Vendor not on file!' => 'Leverandør er ikke i database!',
+ 'Yes' => 'Ja',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'debitorpostering' => 'ar_transaction',
+ 'fortsett' => 'continue',
+ 'fjern' => 'delete',
+ 'bokfør' => 'post',
+ 'bokfør_som_ny' => 'post_as_new',
+ 'salgsfaktura' => 'sales_invoice',
+ 'oppdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/no/arap b/sql-ledger/locale/no/arap
new file mode 100644
index 0000000..048ea79
--- /dev/null
+++ b/sql-ledger/locale/no/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adresse',
+ 'Continue' => 'Fortsett',
+ 'Customer not on file!' => 'Kunde ikke i database!',
+ 'Description' => 'Beskrivelse',
+ 'Number' => 'Nummer',
+ 'Project not on file!' => 'Prosjekt er ikke i database!',
+ 'Select from one of the names below' => 'Velg fra et av navnene under',
+ 'Select from one of the projects below' => 'Velg fra et av prosjektene under',
+ 'Vendor not on file!' => 'Leverandør er ikke i database!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'fortsett' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/no/ca b/sql-ledger/locale/no/ca
new file mode 100644
index 0000000..1b5cfac
--- /dev/null
+++ b/sql-ledger/locale/no/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Balance' => 'Balanse',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Credit' => 'Kredit',
+ 'Date' => 'Dato',
+ 'Debit' => 'Debet',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Description' => 'Beskrivelse',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'List Transactions' => 'Vis bokføringer',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Reference' => 'Referanse',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Subtotal' => 'Subtotal',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'vis_bokføringer' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/no/cp b/sql-ledger/locale/no/cp
new file mode 100644
index 0000000..670c80c
--- /dev/null
+++ b/sql-ledger/locale/no/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløp',
+ 'Amount does not equal applied!' => 'Beløp er ikke likt utført!',
+ 'Amount missing!' => 'Konto mangler!',
+ 'Applied' => 'Utført',
+ 'Cannot post payment!' => 'Kan ikke bokføre betaling!',
+ 'Cannot process payment for a closed period!' => 'Kan ikke behandle betaling for avsluttet periode!',
+ 'Check' => 'Sjekk',
+ 'Check printed!' => 'Sjekk utskrift!',
+ 'Check printing failed!' => 'Utskrift av sjekk feilet!',
+ 'Continue' => 'Fortsett',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kunde',
+ 'Customer not on file!' => 'Kunde ikke i database!',
+ 'Date' => 'Dato',
+ 'Date missing!' => 'Dato mangler!',
+ 'Description' => 'Beskrivelse',
+ 'Due' => 'Forfall',
+ 'Exchangerate' => 'Vekslingskurs',
+ 'From' => 'Fra',
+ 'Invoice' => 'Faktura',
+ 'Invoices' => 'Fakturaer',
+ 'Nothing applied!' => 'Ingenting utført!',
+ 'Number' => 'Nummer',
+ 'Paid in full' => 'Alt betalt',
+ 'Payment' => 'Betaling',
+ 'Payment posted!' => 'Betaling bokført!',
+ 'Post' => 'Bokfør',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Printer',
+ 'Project not on file!' => 'Prosjekt er ikke i database!',
+ 'Receipt' => 'Kvittering',
+ 'Receipt printed!' => 'Kvittering skrevet!',
+ 'Receipt printing failed!' => 'Kvitteringsutskrift feilet!',
+ 'Reference' => 'Referanse',
+ 'Screen' => 'Skjerm',
+ 'Select from one of the names below' => 'Velg fra et av navnene under',
+ 'Select from one of the projects below' => 'Velg fra et av prosjektene under',
+ 'Update' => 'Oppdatér',
+ 'Vendor' => 'Leverandør',
+ 'Vendor not on file!' => 'Leverandør er ikke i database!',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'fortsett' => 'continue',
+ 'bokfør' => 'post',
+ 'skriv_ut' => 'print',
+ 'oppdatér' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/no/ct b/sql-ledger/locale/no/ct
new file mode 100644
index 0000000..994a0cf
--- /dev/null
+++ b/sql-ledger/locale/no/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Legg til',
+ 'Address' => 'Adresse',
+ 'All' => 'Alle',
+ 'Bcc' => 'Blind kopi',
+ 'Cannot delete customer!' => 'Kan ikke slette kunde!',
+ 'Cannot delete vendor!' => 'Kan ikke slette leverandør!',
+ 'Cc' => 'Kopi til',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsett',
+ 'Credit Limit' => 'Kreditgrense',
+ 'Customer deleted!' => 'Kunde slettet!',
+ 'Customer saved!' => 'Kunde lagret!',
+ 'Customers' => 'Kunder',
+ 'Delete' => 'Fjern',
+ 'Discount' => 'Rabatt',
+ 'E-mail' => 'E-post',
+ 'Edit Customer' => 'Endre kundeopplysninger',
+ 'Edit Vendor' => 'Endre produsent',
+ 'Fax' => 'Faks',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Invoice' => 'Faktura',
+ 'Name' => 'Navn',
+ 'Name missing!' => 'Navn mangler!',
+ 'Notes' => 'Bemerkninger',
+ 'Number' => 'Nummer',
+ 'Order' => 'Ordre',
+ 'Orphaned' => 'Frittstående',
+ 'Phone' => 'Tel',
+ 'Save' => 'Lagre',
+ 'Ship to' => 'Avsend til',
+ 'Tax Included' => 'Inkl. avgifter og mva',
+ 'Taxable' => 'Avgifts/mvapliktig',
+ 'Terms: Net' => 'Netto',
+ 'Transactions exist, cannot delete customer!' => 'Kunde kan ikke fjernes da det er posteringer!',
+ 'Transactions exist, cannot delete vendor!' => 'Leverandør kan ikke fjernes da det er posteringer!',
+ 'Vendor deleted!' => 'Leverandør slettet!',
+ 'Vendor saved!' => 'Leverandør lagret!',
+ 'Vendors' => 'Leverandører',
+ 'days' => 'dager',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'legg_til' => 'add',
+ 'fortsett' => 'continue',
+ 'fjern' => 'delete',
+ 'faktura' => 'invoice',
+ 'ordre' => 'order',
+ 'lagre' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/no/gl b/sql-ledger/locale/no/gl
new file mode 100644
index 0000000..0ce247d
--- /dev/null
+++ b/sql-ledger/locale/no/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Leverandørfaktura',
+ 'AR Transaction' => 'Debitorpostering',
+ 'Account' => 'Konto',
+ 'Add General Ledger Transaction' => 'Ny postering i hovedbok',
+ 'Address' => 'Adresse',
+ 'All' => 'Alle',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Transaction' => 'Er du sikker på at du vil fjerne postering',
+ 'Asset' => 'Aktiv',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Balance' => 'Balanse',
+ 'Cannot delete transaction!' => 'Kan ikke slette postering!',
+ 'Cannot have a value in both Debit and Credit!' => 'Kan ikke ha en verdi i både debet og kredit!',
+ 'Cannot post a transaction without a value!' => 'Kan ikke bokføre transaksjon uten verdi!',
+ 'Cannot post transaction for a closed period!' => 'Kan ikke bokføre postering for en avsluttet periode!',
+ 'Confirm!' => 'Bekreft!',
+ 'Continue' => 'Fortsett',
+ 'Credit' => 'Kredit',
+ 'Customer not on file!' => 'Kunde ikke i database!',
+ 'Date' => 'Dato',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet og kredit må være det samme!',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Fjern',
+ 'Description' => 'Beskrivelse',
+ 'Edit General Ledger Transaction' => 'Redigér en postering i hovedbok',
+ 'Equity' => 'Egenkapital',
+ 'Expense' => 'Utgift',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'Postering i hovedbok',
+ 'General Ledger' => 'Hovedbok',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Income' => 'Inntekt',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Liability' => 'Passiv',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Notes' => 'Bemerkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Post' => 'Bokfør',
+ 'Post as new' => 'Bokfør som ny',
+ 'Project' => 'Prosjekt',
+ 'Project not on file!' => 'Prosjekt er ikke i database!',
+ 'Purchase Invoice' => 'Innkjøpsfaktura',
+ 'Reference' => 'Referanse',
+ 'Reference missing!' => 'Referanser mangler!',
+ 'Reports' => 'Rapporter',
+ 'Sales Invoice' => 'Salgsfaktura',
+ 'Select from one of the names below' => 'Velg fra et av navnene under',
+ 'Select from one of the projects below' => 'Velg fra et av prosjektene under',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Bilag',
+ 'Subtotal' => 'Subtotal',
+ 'Transaction Date missing!' => 'Transaksjonsdato mangler!',
+ 'Transaction deleted!' => 'Postering slettet!',
+ 'Transaction posted!' => 'Postering bokført!',
+ 'Update' => 'Oppdatér',
+ 'Vendor not on file!' => 'Leverandør er ikke i database!',
+ 'Yes' => 'Ja',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'leverandørfaktura' => 'ap_transaction',
+ 'debitorpostering' => 'ar_transaction',
+ 'fortsett' => 'continue',
+ 'fjern' => 'delete',
+ 'postering_i_hovedbok' => 'gl_transaction',
+ 'bokfør' => 'post',
+ 'bokfør_som_ny' => 'post_as_new',
+ 'innkjøpsfaktura' => 'purchase_invoice',
+ 'salgsfaktura' => 'sales_invoice',
+ 'oppdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/no/ic b/sql-ledger/locale/no/ic
new file mode 100644
index 0000000..37c9015
--- /dev/null
+++ b/sql-ledger/locale/no/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => 'Aktiv',
+ 'Add' => 'Legg til',
+ 'Add Assembly' => 'Ny sammensetting',
+ 'Add Part' => 'Ny vare',
+ 'Add Purchase Order' => 'Ny innkjøpsordre',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Add Service' => 'Ny tjeneste',
+ 'Address' => 'Adresse',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Assemblies' => 'Sammensettinger',
+ 'Assemblies restocked!' => 'Sammensettinger omplassert!',
+ 'Assembly Number missing!' => 'Sammensettingsnummer mangler!',
+ 'Attachment' => 'Vedlegg',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Papirkurv',
+ 'Bought' => 'Kjøpt',
+ 'COGS' => 'Innkjøp',
+ 'Cannot delete item already invoiced!' => 'Kan ikke slette allerede fakturert enkeltdel!',
+ 'Cannot delete item on order!' => 'Kan ikke slette enkeltdel i ordre!',
+ 'Cannot delete item which is part of an assembly!' => 'kan ikke slette en enhet som er en del av en sammensetting!',
+ 'Cannot delete item!' => 'Kan ikke slette enkeltdel!',
+ 'Cannot stock assemblies!' => 'Kan ikke plasere sammensetninger!',
+ 'Cc' => 'Kopi til',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsett',
+ 'Copies' => 'Kopier',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Fjern',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'Drawing' => 'Tegning',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit Assembly' => 'Redigér sammensetting',
+ 'Edit Part' => 'Redigér vare',
+ 'Edit Service' => 'Redigér tjeneste',
+ 'Expense' => 'Utgift',
+ 'Extended' => 'Utvigt',
+ 'Fax' => 'Faks',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'Image' => 'Bilde',
+ 'In-line' => 'Inne i',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Income' => 'Inntekt',
+ 'Individual Items' => 'Individuelle enheter',
+ 'Inventory' => 'Artikler',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Lagerbeholdning må være null for at du kan sette denne sammensetting som foreldet!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Lagerbeholdning må være null for at du kan sette denne enhet som foreldet!',
+ 'Inventory quantity must be zero!' => 'Lagerbeholdning må være null!',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Item deleted!' => 'Enkeltdel slettet!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Last Cost' => 'Seneste pris',
+ 'Line Total' => 'Antall linjer',
+ 'Link Accounts' => 'Kople kontoer',
+ 'List Price' => 'Listepris',
+ 'Make' => 'Fabrikat',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Message' => 'Melding',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Modell',
+ 'Name' => 'Navn',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tall mangler i rad',
+ 'Obsolete' => 'Foreldet',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'On Hand' => 'På lager',
+ 'On Order' => 'I ordre',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Ordredato mangler!',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler!',
+ 'Ordered' => 'Ordrer',
+ 'Orphaned' => 'Frittstående',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Part Number missing!' => 'Varenummer mangler!',
+ 'Parts' => 'Deler',
+ 'Phone' => 'Tel',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Printer' => 'Printer',
+ 'Project' => 'Prosjekt',
+ 'Purchase Order' => 'Innkjøpsordre',
+ 'Qty' => 'Antall',
+ 'ROP' => 'Etterbestill ved',
+ 'Recd' => 'Mottatt',
+ 'Required by' => 'Bestilt av',
+ 'Sales' => 'Salg',
+ 'Sales Order' => 'Salgsordre',
+ 'Save' => 'Lagre',
+ 'Screen' => 'Skjerm',
+ 'Select from one of the items below' => 'Velg en fra listen under, og trykk "Fortsett"',
+ 'Select postscript or PDF!' => 'Velg postscript eller PDF!',
+ 'Sell Price' => 'Salgspris',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Service Number missing!' => 'Tjenestenummer mangler!',
+ 'Services' => 'Tjenester',
+ 'Ship' => 'Avsend',
+ 'Ship to' => 'Avsend til',
+ 'Short' => 'Kort',
+ 'Sold' => 'Solgt',
+ 'Stock Assembly' => 'Lagersammensetting',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Avgift/mva',
+ 'To' => 'Til',
+ 'Top Level' => 'Toppnivå',
+ 'Total' => 'I alt',
+ 'Unit' => 'Enhet',
+ 'Unit of measure' => 'Måleenhet',
+ 'Update' => 'Oppdatér',
+ 'Updated' => 'Oppdateret',
+ 'Weight' => 'Vekt',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt på epost til',
+ 'hr' => 'time',
+ 'sent to printer' => 'sendt til skriver',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'legg_til' => 'add',
+ 'ny_sammensetting' => 'add_assembly',
+ 'ny_vare' => 'add_part',
+ 'ny_tjeneste' => 'add_service',
+ 'fortsett' => 'continue',
+ 'fjern' => 'delete',
+ 'redigér_sammensetting' => 'edit_assembly',
+ 'redigér_vare' => 'edit_part',
+ 'redigér_tjeneste' => 'edit_service',
+ 'lagre' => 'save',
+ 'oppdatér' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/no/io b/sql-ledger/locale/no/io
new file mode 100644
index 0000000..064657b
--- /dev/null
+++ b/sql-ledger/locale/no/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Ny innkjøpsordre',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Address' => 'Adresse',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Attachment' => 'Vedlegg',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Papirkurv',
+ 'Cc' => 'Kopi til',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsett',
+ 'Copies' => 'Kopier',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Extended' => 'Utvigt',
+ 'Fax' => 'Faks',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'In-line' => 'Inne i',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Message' => 'Melding',
+ 'Name' => 'Navn',
+ 'No.' => 'Nr.',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tall mangler i rad',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Ordredato mangler!',
+ 'Order Number missing!' => 'Ordrenummer mangler!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Phone' => 'Tel',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Printer' => 'Printer',
+ 'Project' => 'Prosjekt',
+ 'Purchase Order' => 'Innkjøpsordre',
+ 'Qty' => 'Antall',
+ 'Recd' => 'Mottatt',
+ 'Required by' => 'Bestilt av',
+ 'Sales Order' => 'Salgsordre',
+ 'Screen' => 'Skjerm',
+ 'Select from one of the items below' => 'Velg en fra listen under, og trykk "Fortsett"',
+ 'Select postscript or PDF!' => 'Velg postscript eller PDF!',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Ship' => 'Avsend',
+ 'Ship to' => 'Avsend til',
+ 'Subject' => 'Emne',
+ 'To' => 'Til',
+ 'Unit' => 'Enhet',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'emailed to' => 'sendt på epost til',
+ 'sent to printer' => 'sendt til skriver',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'fortsett' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/no/ir b/sql-ledger/locale/no/ir
new file mode 100644
index 0000000..ab755ba
--- /dev/null
+++ b/sql-ledger/locale/no/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Invoice' => 'Ny innkjøpsfaktura',
+ 'Add Purchase Order' => 'Ny innkjøpsordre',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Invoice Number' => 'Er du sikker på at du vil fjerne fakturanummer',
+ 'Attachment' => 'Vedlegg',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Papirkurv',
+ 'Cannot delete invoice!' => 'Kan ikke slette faktura!',
+ 'Cannot post invoice for a closed period!' => 'Kan ikke bokføre faktura for en avsluttet periode!',
+ 'Cannot post invoice!' => 'Kan ikke bokføre faktura!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bokføre betaling for en avsluttet periode!',
+ 'Cc' => 'Kopi til',
+ 'Confirm!' => 'Bekreft!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsett',
+ 'Copies' => 'Kopier',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Kunde ikke i database!',
+ 'Date' => 'Dato',
+ 'Date Due' => 'Forfallsdato',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Fjern',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit Purchase Invoice' => 'Redigér innkjøpsfaktura',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekslingskurs',
+ 'Exchangerate for payment missing!' => 'Vekslingskurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekslingskurs mangler!',
+ 'Extended' => 'Utvigt',
+ 'Fax' => 'Faks',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'In-line' => 'Inne i',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Invoice deleted!' => 'Faktura slettet!',
+ 'Invoice posted!' => 'Faktura bokført!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Message' => 'Melding',
+ 'Name' => 'Navn',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tall mangler i rad',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Ordredato mangler!',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payments' => 'Utbetaling',
+ 'Phone' => 'Tel',
+ 'Post' => 'Bokfør',
+ 'Post as new' => 'Bokfør som ny',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Printer' => 'Printer',
+ 'Project' => 'Prosjekt',
+ 'Project not on file!' => 'Prosjekt er ikke i database!',
+ 'Purchase Order' => 'Innkjøpsordre',
+ 'Qty' => 'Antall',
+ 'Recd' => 'Mottatt',
+ 'Record in' => 'Bokfør på',
+ 'Required by' => 'Bestilt av',
+ 'Sales Order' => 'Salgsordre',
+ 'Screen' => 'Skjerm',
+ 'Select from one of the items below' => 'Velg en fra listen under, og trykk "Fortsett"',
+ 'Select from one of the names below' => 'Velg fra et av navnene under',
+ 'Select from one of the projects below' => 'Velg fra et av prosjektene under',
+ 'Select postscript or PDF!' => 'Velg postscript eller PDF!',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Ship' => 'Avsend',
+ 'Ship to' => 'Avsend til',
+ 'Source' => 'Bilag',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Inkl. avgifter og mva',
+ 'To' => 'Til',
+ 'Total' => 'I alt',
+ 'Unit' => 'Enhet',
+ 'Update' => 'Oppdatér',
+ 'Vendor' => 'Leverandør',
+ 'Vendor missing!' => 'Leverandør mangler!',
+ 'Vendor not on file!' => 'Leverandør er ikke i database!',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'Yes' => 'Ja',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt på epost til',
+ 'sent to printer' => 'sendt til skriver',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'fortsett' => 'continue',
+ 'fjern' => 'delete',
+ 'ordre' => 'order',
+ 'bokfør' => 'post',
+ 'bokfør_som_ny' => 'post_as_new',
+ 'oppdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/no/is b/sql-ledger/locale/no/is
new file mode 100644
index 0000000..47f3222
--- /dev/null
+++ b/sql-ledger/locale/no/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Order' => 'Ny innkjøpsordre',
+ 'Add Sales Invoice' => 'Ny salgsfaktura',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Invoice Number' => 'Er du sikker på at du vil fjerne fakturanummer',
+ 'Attachment' => 'Vedlegg',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Papirkurv',
+ 'Cannot delete invoice!' => 'Kan ikke slette faktura!',
+ 'Cannot post invoice for a closed period!' => 'Kan ikke bokføre faktura for en avsluttet periode!',
+ 'Cannot post invoice!' => 'Kan ikke bokføre faktura!',
+ 'Cannot post payment for a closed period!' => 'Kan ikke bokføre betaling for en avsluttet periode!',
+ 'Cc' => 'Kopi til',
+ 'Confirm!' => 'Bekreft!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsett',
+ 'Copies' => 'Kopier',
+ 'Credit Limit' => 'Kreditgrense',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kunde',
+ 'Customer missing!' => 'Kunde mangler!',
+ 'Customer not on file!' => 'Kunde ikke i database!',
+ 'Date' => 'Dato',
+ 'Date Due' => 'Forfallsdato',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Fjern',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit Sales Invoice' => 'Redigér salgsfaktura',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Vekslingskurs',
+ 'Exchangerate for payment missing!' => 'Vekslingskurs for betaling mangler!',
+ 'Exchangerate missing!' => 'Vekslingskurs mangler!',
+ 'Extended' => 'Utvigt',
+ 'Fax' => 'Faks',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'In-line' => 'Inne i',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadato',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Invoice deleted!' => 'Faktura slettet!',
+ 'Invoice posted!' => 'Faktura bokført!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Message' => 'Melding',
+ 'Name' => 'Navn',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tall mangler i rad',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Order' => 'Ordre',
+ 'Order Date missing!' => 'Ordredato mangler!',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Payment date missing!' => 'Betalingsdato mangler!',
+ 'Payments' => 'Utbetaling',
+ 'Phone' => 'Tel',
+ 'Post' => 'Bokfør',
+ 'Post as new' => 'Bokfør som ny',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Printer',
+ 'Project' => 'Prosjekt',
+ 'Project not on file!' => 'Prosjekt er ikke i database!',
+ 'Purchase Order' => 'Innkjøpsordre',
+ 'Qty' => 'Antall',
+ 'Recd' => 'Mottatt',
+ 'Record in' => 'Bokfør på',
+ 'Remaining' => 'Resterende',
+ 'Required by' => 'Bestilt av',
+ 'Sales Order' => 'Salgsordre',
+ 'Screen' => 'Skjerm',
+ 'Select from one of the items below' => 'Velg en fra listen under, og trykk "Fortsett"',
+ 'Select from one of the names below' => 'Velg fra et av navnene under',
+ 'Select from one of the projects below' => 'Velg fra et av prosjektene under',
+ 'Select postscript or PDF!' => 'Velg postscript eller PDF!',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Ship' => 'Avsend',
+ 'Ship to' => 'Avsend til',
+ 'Ship via' => 'Avsend via',
+ 'Source' => 'Bilag',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Inkl. avgifter og mva',
+ 'To' => 'Til',
+ 'Total' => 'I alt',
+ 'Unit' => 'Enhet',
+ 'Update' => 'Oppdatér',
+ 'Vendor not on file!' => 'Leverandør er ikke i database!',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'Yes' => 'Ja',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt på epost til',
+ 'sent to printer' => 'sendt til skriver',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'fortsett' => 'continue',
+ 'fjern' => 'delete',
+ 'e_post' => 'e_mail',
+ 'ordre' => 'order',
+ 'bokfør' => 'post',
+ 'bokfør_som_ny' => 'post_as_new',
+ 'skriv_ut' => 'print',
+ 'avsend_til' => 'ship_to',
+ 'oppdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/no/login b/sql-ledger/locale/no/login
new file mode 100644
index 0000000..742ef4a
--- /dev/null
+++ b/sql-ledger/locale/no/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Om',
+ 'Database Host' => 'Database-vert',
+ 'Dataset' => 'Datasett',
+ 'Incorrect Dataset version!' => 'Gal versjon av datasett!',
+ 'Incorrect Password!' => 'Galt passord!',
+ 'Licensed to' => 'Utført for',
+ 'Login' => 'Login',
+ 'Name' => 'Navn',
+ 'Password' => 'Passord',
+ 'User' => 'Bruker',
+ 'Version' => 'Versjon',
+ 'You are logged out!' => 'Du er logget av!',
+ 'You did not enter a name!' => 'Du gav ikke et navn!',
+ 'is not a member!' => 'er ikke et medlem!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/no/menu b/sql-ledger/locale/no/menu
new file mode 100644
index 0000000..f8f95a0
--- /dev/null
+++ b/sql-ledger/locale/no/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Kreditorer',
+ 'AP Aging' => 'Aldersfordeling',
+ 'AR' => 'Debitorer',
+ 'AR Aging' => 'Aldersfordeling',
+ 'Accounting Menu' => 'Konto-meny',
+ 'Add Account' => 'Ny konto',
+ 'Add Assembly' => 'Ny sammensetting',
+ 'Add Customer' => 'Ny kunde',
+ 'Add GIFI' => 'Ny GIFI',
+ 'Add Part' => 'Ny vare',
+ 'Add Project' => 'Nytt prosjekt',
+ 'Add Service' => 'Ny tjeneste',
+ 'Add Transaction' => 'Ny postering',
+ 'Add Vendor' => 'Ny leverandør',
+ 'Assemblies' => 'Sammensettinger',
+ 'Audit Control' => 'Revisjonskontroll',
+ 'Backup' => 'Sikkerhetskopi',
+ 'Balance Sheet' => 'Status',
+ 'Cash' => 'Bank',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Check' => 'Sjekk',
+ 'Customers' => 'Kunder',
+ 'General Ledger' => 'Hovedbok',
+ 'Goods & Services' => 'Varer og tjenester',
+ 'HTML Templates' => 'HTML-maler',
+ 'Income Statement' => 'Driftsregnskap',
+ 'Invoice' => 'Faktura',
+ 'LaTeX Templates' => 'LaTeX-maler',
+ 'List Accounts' => 'List kontoer',
+ 'List GIFI' => 'List GIFI',
+ 'Logout' => 'Log ut',
+ 'Order Entry' => 'Ordreinngang',
+ 'Packing List' => 'Følgeseddel',
+ 'Parts' => 'Deler',
+ 'Payment' => 'Betaling',
+ 'Payments' => 'Utbetaling',
+ 'Preferences' => 'Innstillinger',
+ 'Projects' => 'Prosjekter',
+ 'Purchase Invoice' => 'Innkjøpsfaktura',
+ 'Purchase Order' => 'Innkjøpsordre',
+ 'Purchase Orders' => 'Innkjøpsordrer',
+ 'Receipt' => 'Kvittering',
+ 'Receipts' => 'Kvitteringer',
+ 'Reconciliation' => 'Bankoppgjør',
+ 'Reports' => 'Rapporter',
+ 'Sales Invoice' => 'Salgsfaktura',
+ 'Sales Order' => 'Salgsordre',
+ 'Sales Orders' => 'Salgsordrer',
+ 'Save to File' => 'Lagre i fil',
+ 'Send by E-Mail' => 'Sendt per email',
+ 'Services' => 'Tjenester',
+ 'Statement' => 'Oppgjør',
+ 'Stock Assembly' => 'Lagersammensetting',
+ 'Stylesheet' => 'Stílark',
+ 'System' => 'System',
+ 'Tax collected' => 'Inngående avgift',
+ 'Tax paid' => 'Betalt avgift',
+ 'Transactions' => 'Posteringer',
+ 'Trial Balance' => 'Foreløpig status',
+ 'Vendors' => 'Leverandører',
+ 'Version' => 'Versjon',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/no/oe b/sql-ledger/locale/no/oe
new file mode 100644
index 0000000..efadfa6
--- /dev/null
+++ b/sql-ledger/locale/no/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'Legg til',
+ 'Add Purchase Invoice' => 'Ny innkjøpsfaktura',
+ 'Add Purchase Order' => 'Ny innkjøpsordre',
+ 'Add Sales Invoice' => 'Ny salgsfaktura',
+ 'Add Sales Order' => 'Ny salgsordre',
+ 'Address' => 'Adresse',
+ 'Amount' => 'Beløp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Order Number' => 'Er du sikker på at du vil fjerne ordrenummer',
+ 'Attachment' => 'Vedlegg',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Bcc' => 'Blind kopi',
+ 'Bin' => 'Papirkurv',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Kan ikke slette ordre!',
+ 'Cannot save order!' => 'Kan ikke lagre ordre!',
+ 'Cc' => 'Kopi til',
+ 'Closed' => 'Avsluttet',
+ 'Confirm!' => 'Bekreft!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsett',
+ 'Copies' => 'Kopier',
+ 'Credit Limit' => 'Kreditgrense',
+ 'Curr' => 'Val',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kunde',
+ 'Customer missing!' => 'Kunde mangler!',
+ 'Customer not on file!' => 'Kunde ikke i database!',
+ 'Date' => 'Dato',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Delete' => 'Fjern',
+ 'Delivery Date' => 'Leveringsdato',
+ 'Description' => 'Beskrivelse',
+ 'E-mail' => 'E-post',
+ 'E-mail address missing!' => 'E-post-adresse mangler!',
+ 'Edit Purchase Order' => 'Redigér innkjøpsordre',
+ 'Edit Sales Order' => 'Redigér salgsordre',
+ 'Exchangerate' => 'Vekslingskurs',
+ 'Exchangerate missing!' => 'Vekslingskurs mangler!',
+ 'Extended' => 'Utvigt',
+ 'Fax' => 'Faks',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'ID' => 'ID',
+ 'In-line' => 'Inne i',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Fakturadato mangler!',
+ 'Invoice Number missing!' => 'Fakturanummer mangler!',
+ 'Item not on file!' => 'Enkeltdel er ikke i databasen!',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Message' => 'Melding',
+ 'Name' => 'Navn',
+ 'No.' => 'Nr.',
+ 'Notes' => 'Bemerkninger',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Tall mangler i rad',
+ 'O' => 'O',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'Open' => 'Åpne',
+ 'Order' => 'Ordre',
+ 'Order Date' => 'Ordredato',
+ 'Order Date missing!' => 'Ordredato mangler!',
+ 'Order Number' => 'Ordrenummer',
+ 'Order Number missing!' => 'Ordrenummer mangler!',
+ 'Order deleted!' => 'Ordre slettet!',
+ 'Order saved!' => 'Ordre lagret!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Følgeseddel',
+ 'Packing List Date missing!' => 'Dato for pakkeliste mangler!',
+ 'Packing List Number missing!' => 'Nummer for pakkeliste mangler!',
+ 'Part' => 'Vare',
+ 'Phone' => 'Tel',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Printer',
+ 'Project' => 'Prosjekt',
+ 'Project not on file!' => 'Prosjekt er ikke i database!',
+ 'Purchase Order' => 'Innkjøpsordre',
+ 'Purchase Orders' => 'Innkjøpsordrer',
+ 'Qty' => 'Antall',
+ 'Recd' => 'Mottatt',
+ 'Remaining' => 'Resterende',
+ 'Required by' => 'Bestilt av',
+ 'Sales Order' => 'Salgsordre',
+ 'Sales Orders' => 'Salgsordrer',
+ 'Save' => 'Lagre',
+ 'Save as new' => 'Lagre som ny',
+ 'Screen' => 'Skjerm',
+ 'Select from one of the items below' => 'Velg en fra listen under, og trykk "Fortsett"',
+ 'Select from one of the names below' => 'Velg fra et av navnene under',
+ 'Select from one of the projects below' => 'Velg fra et av prosjektene under',
+ 'Select postscript or PDF!' => 'Velg postscript eller PDF!',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Service' => 'Tjeneste',
+ 'Ship' => 'Avsend',
+ 'Ship to' => 'Avsend til',
+ 'Ship via' => 'Avsend via',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Avgift/mva',
+ 'Tax Included' => 'Inkl. avgifter og mva',
+ 'Terms: Net' => 'Netto',
+ 'To' => 'Til',
+ 'Total' => 'I alt',
+ 'Unit' => 'Enhet',
+ 'Update' => 'Oppdatér',
+ 'Vendor' => 'Leverandør',
+ 'Vendor missing!' => 'Leverandør mangler!',
+ 'Vendor not on file!' => 'Leverandør er ikke i database!',
+ 'What type of item is this?' => 'Hvilken type ting er dette?',
+ 'Yes' => 'Ja',
+ 'days' => 'dager',
+ 'ea' => 'stk',
+ 'emailed to' => 'sendt på epost til',
+ 'sent to printer' => 'sendt til skriver',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'legg_til' => 'add',
+ 'fortsett' => 'continue',
+ 'fjern' => 'delete',
+ 'e_post' => 'e_mail',
+ 'faktura' => 'invoice',
+ 'skriv_ut' => 'print',
+ 'lagre' => 'save',
+ 'lagre_som_ny' => 'save_as_new',
+ 'avsend_til' => 'ship_to',
+ 'oppdatér' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/no/pe b/sql-ledger/locale/no/pe
new file mode 100644
index 0000000..95a1fa2
--- /dev/null
+++ b/sql-ledger/locale/no/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Legg til',
+ 'Add Project' => 'Nytt prosjekt',
+ 'All' => 'Alle',
+ 'Continue' => 'Fortsett',
+ 'Delete' => 'Fjern',
+ 'Description' => 'Beskrivelse',
+ 'Edit Project' => 'Redigér prosjekt',
+ 'Number' => 'Nummer',
+ 'Orphaned' => 'Frittstående',
+ 'Project' => 'Prosjekt',
+ 'Project Number missing!' => 'Prosjektnummer mangler!',
+ 'Project deleted!' => 'Prosjekt slettet!',
+ 'Project saved!' => 'Prosjekt lagret!',
+ 'Projects' => 'Prosjekter',
+ 'Save' => 'Lagre',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'legg_til' => 'add',
+ 'fortsett' => 'continue',
+ 'fjern' => 'delete',
+ 'lagre' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/no/rc b/sql-ledger/locale/no/rc
new file mode 100644
index 0000000..4ff2cc8
--- /dev/null
+++ b/sql-ledger/locale/no/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Balance' => 'Balanse',
+ 'Cleared Balance' => 'Utlignet balanse',
+ 'Continue' => 'Fortsett',
+ 'Date' => 'Dato',
+ 'Deposit' => 'Depositum',
+ 'Description' => 'Beskrivelse',
+ 'Difference' => 'Forskjell',
+ 'Done' => 'Ferdig',
+ 'Exchangerate Difference' => 'Forskjell på vekslingskurs',
+ 'From' => 'Fra',
+ 'Out of balance!' => 'Ute av balanse!',
+ 'Payment' => 'Betaling',
+ 'Reconciliation' => 'Bankoppgjør',
+ 'Select all' => 'Velg alt',
+ 'Source' => 'Bilag',
+ 'Statement Balance' => 'Balanseoppgjør',
+ 'Update' => 'Oppdatér',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'fortsett' => 'continue',
+ 'ferdig' => 'done',
+ 'velg_alt' => 'select_all',
+ 'oppdatér' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/no/rp b/sql-ledger/locale/no/rp
new file mode 100644
index 0000000..3592fd1
--- /dev/null
+++ b/sql-ledger/locale/no/rp
@@ -0,0 +1,120 @@
+$self{texts} = {
+ 'AP Aging' => 'Aldersfordeling',
+ 'AR Aging' => 'Aldersfordeling',
+ 'Account' => 'Konto',
+ 'Accounts' => 'Kontoer',
+ 'Amount' => 'Beløp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Attachment' => 'Vedlegg',
+ 'Aug' => 'aug',
+ 'August' => 'august',
+ 'Balance' => 'Balanse',
+ 'Balance Sheet' => 'Status',
+ 'Bcc' => 'Blind kopi',
+ 'Cash based' => 'Bank basert',
+ 'Cc' => 'Kopi til',
+ 'Compare to' => 'Sammenlign med',
+ 'Continue' => 'Fortsett',
+ 'Copies' => 'Kopier',
+ 'Credit' => 'Kredit',
+ 'Current' => 'Nåværende',
+ 'Customer' => 'Kunde',
+ 'Date' => 'Dato',
+ 'Debit' => 'Debet',
+ 'Dec' => 'des',
+ 'December' => 'desember',
+ 'Decimalplaces' => 'Desimalplasser',
+ 'Department' => 'Avdeling',
+ 'Description' => 'Beskrivelse',
+ 'Due' => 'Forfall',
+ 'E-mail' => 'E-post',
+ 'E-mail Statement to' => 'Send oppgjør til',
+ 'Feb' => 'feb',
+ 'February' => 'februar',
+ 'From' => 'Fra',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Overskrift',
+ 'ID' => 'ID',
+ 'In-line' => 'Inne i',
+ 'Include in Report' => 'Inkludér i rapport',
+ 'Income Statement' => 'Driftsregnskap',
+ 'Invoice' => 'Faktura',
+ 'Jan' => 'jan',
+ 'January' => 'januar',
+ 'Jul' => 'jul',
+ 'July' => 'juli',
+ 'Jun' => 'jun',
+ 'June' => 'juni',
+ 'Mar' => 'mar',
+ 'March' => 'mars',
+ 'May' => 'mai',
+ 'May ' => 'mai ',
+ 'Message' => 'Melding',
+ 'N/A' => 'I/T',
+ 'Nothing selected!' => 'Ingenting valgt!',
+ 'Nov' => 'nov',
+ 'November' => 'november',
+ 'Oct' => 'okt',
+ 'October' => 'oktober',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Utbetaling',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Printer',
+ 'Project Number' => 'Prosjektnummer',
+ 'Receipts' => 'Kvitteringer',
+ 'Report for' => 'Rapport for',
+ 'Retained Earnings' => 'Realisert overskudd',
+ 'Screen' => 'Skjerm',
+ 'Select all' => 'Velg alt',
+ 'Select postscript or PDF!' => 'Velg postscript eller PDF!',
+ 'Sep' => 'sep',
+ 'September' => 'september',
+ 'Source' => 'Bilag',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Oppgjør',
+ 'Statement sent to' => 'Oppgjør sendt til',
+ 'Statements sent to printer!' => 'Oppgjør sendt til skriver!',
+ 'Subject' => 'Emne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Avgift/mva',
+ 'Tax collected' => 'Inngående avgift',
+ 'Tax paid' => 'Betalt avgift',
+ 'Total' => 'I alt',
+ 'Trial Balance' => 'Foreløpig status',
+ 'Vendor' => 'Leverandør',
+ 'as at' => 'som ved',
+ 'collected on sales' => 'innbetalt på salg',
+ 'for Period' => 'for periode',
+ 'paid on purchases' => 'betalt på kjøp',
+ 'to' => 'til',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'fortsett' => 'continue',
+ 'e_post' => 'e_mail',
+ 'skriv_ut' => 'print',
+ 'velg_alt' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/COPYING b/sql-ledger/locale/pa/COPYING
new file mode 100644
index 0000000..44b6a93
--- /dev/null
+++ b/sql-ledger/locale/pa/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Spanish texts:
+#
+# Author: Maria Gabriela Fong <mgfong@maga.tzo.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/pa/LANGUAGE b/sql-ledger/locale/pa/LANGUAGE
new file mode 100644
index 0000000..012de50
--- /dev/null
+++ b/sql-ledger/locale/pa/LANGUAGE
@@ -0,0 +1 @@
+Panamanian Spanish
diff --git a/sql-ledger/locale/pa/admin b/sql-ledger/locale/pa/admin
new file mode 100644
index 0000000..1e69b26
--- /dev/null
+++ b/sql-ledger/locale/pa/admin
@@ -0,0 +1,128 @@
+$self{texts} = {
+ 'Access Control' => 'Control de Acceso',
+ 'Accounting' => 'Contabilidad',
+ 'Add User' => 'Agregar Usuario',
+ 'Address' => 'Dirección',
+ 'Administration' => 'Administración',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => 'Todos los datasets actualizados',
+ 'Change Admin Password' => 'Cambiar Contraseña de Administrador',
+ 'Change Password' => 'Cambiar Contraseña',
+ 'Character Set' => 'Tabla de Caracteres',
+ 'Click on login name to edit!' => 'Haga clic en el nombre de entrada a
+editar',
+ 'Company' => 'Compañía',
+ 'Connect to' => 'Conectar a',
+ 'Continue' => 'Continuar',
+ 'Create Chart of Accounts' => 'Crear catálogo de cuentas',
+ 'Create Dataset' => 'Crear set de datos',
+ 'DBI not installed!' => 'DBI no instalado!',
+ 'Database' => 'Base de datos',
+ 'Database Administration' => 'Administración de base de datos',
+ 'Database Driver not checked!' => 'Driver de base de datos no revisado',
+ 'Database User missing!' => 'No se encuentra usuario de base de datos',
+ 'Dataset' => 'Set de datos',
+ 'Dataset missing!' => 'No se encuentra Set de datos!',
+ 'Dataset updated!' => 'Dataset updated!',
+ 'Date Format' => 'Formato de Fecha',
+ 'Delete' => 'Borrar',
+ 'Delete Dataset' => 'Borrar Set de Datos',
+ 'Directory' => 'Directorio',
+ 'Driver' => 'Manejador',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'Correo Electrónico',
+ 'Edit User' => 'Editar Usuario',
+ 'Existing Datasets' => 'Sets de dato existentes',
+ 'Fax' => 'Fax',
+ 'Host' => 'Servidor base de datos',
+ 'Hostname missing!' => 'No se encuentra servidor de base de datos',
+ 'Incorrect Password!' => 'Contraseña Incorrecta!',
+ 'Language' => 'Lenguaje',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deje los campos de servidor de base de datos y puerto vacíos al menos que quiera hacer una conexión remota',
+ 'Login' => 'Login',
+ 'Name' => 'Nombre',
+ 'New Templates' => 'Nuevas Plantillas',
+ 'No Database Drivers available!' => 'No hay manejador de base de datos
+disponible!',
+ 'No Dataset selected!' => 'No se ha seleccionado el set de datos',
+ 'Nothing to delete!' => 'Noda que borrar',
+ 'Number Format' => 'Formato de Numero',
+ 'Oracle Database Administration' => 'Administración de base de datos Oracle',
+ 'Password' => 'Contraseña',
+ 'Password changed!' => 'Password changed!',
+ 'Pg Database Administration' => 'Administración de base de datos Pg',
+ 'Phone' => 'Teléfono',
+ 'Port' => 'Puerto',
+ 'Port missing!' => 'No se encuentra el Puerto!',
+ 'Printer' => 'Impresora',
+ 'Save' => 'Salvar',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione un set de
+datos para borrar y presione "Continuar"',
+ 'Setup Templates' => 'Configurar Plantillas',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Estilo de hoja',
+ 'Templates' => 'Plantillas',
+ 'The following Datasets are not in use and can be deleted' => 'Los
+siguientes sets de datos no estan en uso y pueden ser borrados',
+ 'The following Datasets need to be updated' => 'Los siguientes datasets necesitan ser actualizados',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta es una verificacion preliminar de fuentes existentes. Nada será creado o borrado en esta etapa!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para agregar un usuario a un grupo, edite un nombre, cambie el nombre de entrada (login) y guarde los cambios. Un nuevo usuario, con las mismas variables será guardado bajo el nuevo nombre de entrada. (login)',
+ 'Update Dataset' => 'Actualizar Dataset',
+ 'Use Templates' => 'Plantillas de Usuarios',
+ 'User' => 'Usuario',
+ 'User deleted!' => 'User deleted!',
+ 'User saved!' => 'User saved!',
+ 'Version' => 'Versión',
+ 'You must enter a host and port for local and remote connections!' => 'Debe
+introducir un servidor de base de datos y un puerto para conexiones locales y
+remotas!',
+ 'does not exist' => 'No existe',
+ 'is already a member!' => 'ya es miembro!',
+ 'localhost' => 'servidor local',
+ 'successfully created!' => 'creado con éxito!',
+ 'successfully deleted!' => 'creado con éxito!',
+ 'website' => 'sitio web',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'agregar_usuario' => 'add_user',
+ 'cambiar_contraseña_de_administrador' => 'change_admin_password',
+ 'cambiar_contraseña' => 'change_password',
+ 'continuar' => 'continue',
+ 'crear_set_de_datos' => 'create_dataset',
+ 'borrar' => 'delete',
+ 'borrar_set_de_datos' => 'delete_dataset',
+ 'login' => 'login',
+ 'administración_de_base_de_datos_oracle' => 'oracle_database_administration',
+ 'administración_de_base_de_datos_pg' => 'pg_database_administration',
+ 'salvar' => 'save',
+ 'actualizar_dataset' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/all b/sql-ledger/locale/pa/all
new file mode 100644
index 0000000..2981a10
--- /dev/null
+++ b/sql-ledger/locale/pa/all
@@ -0,0 +1,496 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Ctas X Pagar',
+ 'AP Aging' => 'Envejecimiento - CxP',
+ 'AP Transaction' => '',
+ 'AP Transactions' => 'Transacciones - Cuentas por Pagar',
+ 'AR' => 'Ctas X Cobrar',
+ 'AR Aging' => 'Envejecimiento - CxC ',
+ 'AR Transaction' => '',
+ 'AR Transactions' => 'Transacciones de Cuentas por Cobrar',
+ 'About' => 'Acerca',
+ 'Access Control' => 'Control de Acceso',
+ 'Account' => 'Cuenta',
+ 'Account Number' => 'Número de Cuenta',
+ 'Account Number missing!' => 'No existe el número de cuenta!',
+ 'Account Type' => 'Tipo de Cuenta',
+ 'Account Type missing!' => 'No existe el tipo de la cuenta!',
+ 'Account deleted!' => '',
+ 'Account saved!' => '',
+ 'Accounting' => 'Contabilidad',
+ 'Accounting Menu' => 'Menú de Contabilidad',
+ 'Accounts' => 'Cuentas',
+ 'Active' => '',
+ 'Add' => 'Agregar',
+ 'Add Account' => 'Agregar Cuenta',
+ 'Add Accounts Payables Transaction' => '',
+ 'Add Accounts Receivables Transaction' => '',
+ 'Add Assembly' => 'Agregar Ensamblaje',
+ 'Add Customer' => 'Agregar Cliente',
+ 'Add GIFI' => 'Agregar GIFI',
+ 'Add General Ledger Transaction' => 'Agregar Transacción - Mayor General',
+ 'Add Part' => 'Agregar Parte',
+ 'Add Project' => '',
+ 'Add Purchase Invoice' => '',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Invoice' => '',
+ 'Add Sales Order' => 'Agregar Orden de Venta',
+ 'Add Service' => 'Agregar Servicio',
+ 'Add Transaction' => 'Agregar Transaccion',
+ 'Add User' => 'Agregar Usuario',
+ 'Add Vendor' => 'Agregar Proveedor',
+ 'Address' => 'Dirección',
+ 'Administration' => 'Administración',
+ 'Administrator' => '',
+ 'All' => 'Todos',
+ 'All Datasets up to date!' => 'Todos los datasets actualizados',
+ 'Amount' => 'Total',
+ 'Amount Due' => '',
+ 'Amount does not equal applied!' => '',
+ 'Amount missing!' => '',
+ 'Applied' => '',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Esta seguro de que desea borrar la Factura No.:',
+ 'Are you sure you want to delete Order Number' => '¿Esta seguro de que desea
+borrar la Orden No.:?',
+ 'Are you sure you want to delete Transaction' => '¿Está usted seguro de que desea suprimir la transacción?',
+ 'Assemblies' => 'Ensamblajes',
+ 'Assemblies restocked!' => '',
+ 'Assembly Number missing!' => 'No existe Numero de Ensamblaje!',
+ 'Asset' => 'Activo',
+ 'Attachment' => 'Adjunto',
+ 'Audit Control' => 'Control de Audito',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => '',
+ 'Backup' => 'Respaldar datos',
+ 'Backup sent to' => 'Respaldo enviado a',
+ 'Balance' => '',
+ 'Balance Sheet' => 'Hoja de Balance',
+ 'Bcc' => '',
+ 'Bin' => 'Bin',
+ 'Books are open' => 'Libros estan abiertos',
+ 'Bought' => 'Comprado',
+ 'Business Number' => 'Numero de Negocio',
+ 'C' => '',
+ 'COGS' => 'Costo de Ventas',
+ 'Cannot delete account!' => '',
+ 'Cannot delete customer!' => '',
+ 'Cannot delete default account!' => 'No se puede borrar cuenta por defecto!',
+ 'Cannot delete invoice!' => '',
+ 'Cannot delete item already invoiced!' => 'No puede suprimir el item ya facturado!',
+ 'Cannot delete item on order!' => 'No se puede borrar el item ya en cotizacion',
+ 'Cannot delete item which is part of an assembly!' => 'No puede suprimir un item que es parte de un ensamblaje!',
+ 'Cannot delete item!' => '',
+ 'Cannot delete order!' => '',
+ 'Cannot delete transaction!' => '',
+ 'Cannot delete vendor!' => '',
+ 'Cannot have a value in both Debit and Credit!' => 'No puede tener un valor en Débito y Crédito simultáneamente!',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => 'No se puede registrar factura para un periodo cerrado!',
+ 'Cannot post invoice!' => '',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cannot post payment!' => '',
+ 'Cannot post transaction for a closed period!' => 'No puede guardar transaccion para un periodo cerrado',
+ 'Cannot post transaction!' => '',
+ 'Cannot process payment for a closed period!' => '',
+ 'Cannot save account!' => '',
+ 'Cannot save order!' => '',
+ 'Cannot save preferences!' => '',
+ 'Cannot stock assemblies!' => '',
+ 'Cash' => '',
+ 'Cash based' => '',
+ 'Cc' => '',
+ 'Change Admin Password' => 'Cambiar Contraseña de Administrador',
+ 'Change Password' => 'Cambiar Contraseña',
+ 'Character Set' => 'Tabla de Caracteres',
+ 'Chart of Accounts' => 'Catálogo Contable',
+ 'Check' => '',
+ 'Check printed!' => '',
+ 'Check printing failed!' => '',
+ 'Cleared Balance' => '',
+ 'Click on login name to edit!' => 'Haga clic en el nombre de entrada a
+editar',
+ 'Close Books up to' => 'Cerrar libros hasta',
+ 'Closed' => 'Cerrado',
+ 'Company' => 'Compañía',
+ 'Compare to' => 'Comparar a',
+ 'Confirm!' => 'Confirmar!',
+ 'Connect to' => 'Conectar a',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Copy to COA' => 'Copiar a catálogo de cuentas',
+ 'Create Chart of Accounts' => 'Crear catálogo de cuentas',
+ 'Create Dataset' => 'Crear set de datos',
+ 'Credit' => 'Crédito',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Curr' => '$',
+ 'Currency' => 'Moneda',
+ 'Current' => '',
+ 'Customer' => 'Cliente',
+ 'Customer deleted!' => '',
+ 'Customer missing!' => '',
+ 'Customer not on file!' => '',
+ 'Customer saved!' => '',
+ 'Customers' => '',
+ 'DBI not installed!' => 'DBI no instalado!',
+ 'Database' => 'Base de datos',
+ 'Database Administration' => 'Administración de base de datos',
+ 'Database Driver not checked!' => 'Driver de base de datos no revisado',
+ 'Database Host' => 'Servidor de Base de Datos',
+ 'Database User missing!' => 'No se encuentra usuario de base de datos',
+ 'Dataset' => 'Set de datos',
+ 'Dataset missing!' => 'No se encuentra Set de datos!',
+ 'Dataset updated!' => '',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Fecha de Vencimiento',
+ 'Date Format' => 'Formato de Fecha',
+ 'Date Paid' => 'Fecha de pago',
+ 'Date missing!' => '',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito y Crédito fuera de balance.',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Decimalplaces' => '',
+ 'Delete' => 'Borrar',
+ 'Delete Account' => 'Borrar Cuenta',
+ 'Delete Dataset' => 'Borrar Set de Datos',
+ 'Delivery Date' => '',
+ 'Deposit' => '',
+ 'Description' => 'Descripción',
+ 'Difference' => '',
+ 'Directory' => 'Directorio',
+ 'Discount' => 'Descuento',
+ 'Done' => '',
+ 'Drawing' => '',
+ 'Driver' => 'Manejador',
+ 'Dropdown Limit' => '',
+ 'Due' => 'Vence',
+ 'Due Date' => 'Fecha de Vencimiento',
+ 'Due Date missing!' => 'Falta Fecha de Vencimiento!',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail Statement to' => '',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit' => '',
+ 'Edit Account' => 'Editar Cuenta',
+ 'Edit Accounts Payables Transaction' => '',
+ 'Edit Accounts Receivables Transaction' => '',
+ 'Edit Assembly' => 'Editar Ensamblaje',
+ 'Edit GIFI' => 'Editar GIFI',
+ 'Edit General Ledger Transaction' => 'Editar Transacción de Mayor General',
+ 'Edit Part' => 'Editar Parte',
+ 'Edit Preferences for' => 'Editar Preferencias para',
+ 'Edit Project' => '',
+ 'Edit Purchase Invoice' => '',
+ 'Edit Purchase Order' => 'Editar Orden de Compra',
+ 'Edit Sales Invoice' => '',
+ 'Edit Sales Order' => 'Editar Orden de Venta',
+ 'Edit Service' => 'Editar Servicio',
+ 'Edit Template' => 'Editar Plantilla',
+ 'Edit User' => 'Editar Usuario',
+ 'Employee' => '',
+ 'Enforce transaction reversal for all dates' => 'Forzar reversión de transacciones para todas las fechas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => '',
+ 'Equity' => 'Capital',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate Difference' => '',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Existing Datasets' => 'Sets de dato existentes',
+ 'Expense' => 'Egreso',
+ 'Expense Account' => 'Cuenta de Egreso',
+ 'Expense/Asset' => 'Egreso/Activo',
+ 'Extended' => '',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'Foreign Exchange Gain' => 'Ganancia en Moneda Extranjera',
+ 'Foreign Exchange Loss' => 'Pérdida en Moneda Extranjera',
+ 'From' => 'Desde',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => '',
+ 'GIFI missing!' => 'No se encuentra GIFI',
+ 'GIFI saved!' => '',
+ 'GL Transaction' => '',
+ 'General Ledger' => 'Mayor General',
+ 'Goods & Services' => 'Partes y Servicios',
+ 'HTML Templates' => 'Plantillas HTML',
+ 'Heading' => 'Encabezado',
+ 'Host' => 'Servidor base de datos',
+ 'Hostname missing!' => 'No se encuentra servidor de base de datos',
+ 'ID' => 'ID',
+ 'Image' => '',
+ 'In-line' => 'En-linea',
+ 'Include in Report' => 'Incluya en informe',
+ 'Include in drop-down menus' => 'Incluya en menús desplegables',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluya esta cuenta en las formas del cliente/proveedor para señalar al cliente/proveedor como gravable de impuesto?',
+ 'Income' => 'Ingreso',
+ 'Income Account' => 'Cuenta de Ingreso',
+ 'Income Statement' => 'Estado de Cuentas',
+ 'Incorrect Dataset version!' => 'Version de dataset Incorrecta',
+ 'Incorrect Password!' => 'Contraseña Incorrecta!',
+ 'Individual Items' => 'Items Individuales',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Cuenta de Inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar este ensamblaje a obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar esta parte a obsoleto',
+ 'Inventory quantity must be zero!' => 'La cantidad en inventario debe ser
+cero!',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Invoice deleted!' => '',
+ 'Invoice posted!' => '',
+ 'Invoices' => '',
+ 'Is this a summary account to record' => 'Es esta una cuenta de resumen a registrar?',
+ 'Item deleted!' => '',
+ 'Item not on file!' => 'El item no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'LaTeX Templates' => 'Plantillas LaTeX',
+ 'Language' => 'Lenguaje',
+ 'Last Cost' => 'Ultimo Costo',
+ 'Last Invoice Number' => 'Último Número de Factura',
+ 'Last Numbers & Default Accounts' => 'Últimos Números y Cuentas por Defecto',
+ 'Last Purchase Order Number' => 'Ultima Orden de Compra',
+ 'Last Sales Order Number' => 'Ultima Orden de Venta',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deje los campos de servidor de base de datos y puerto vacíos al menos que quiera hacer una conexión remota',
+ 'Liability' => 'Pasivo',
+ 'Licensed to' => 'Licenciado a',
+ 'Line Total' => 'Total de Línea',
+ 'Link' => 'Enlaces',
+ 'Link Accounts' => 'Enlazar Cuentas',
+ 'List Accounts' => 'Listar Cuentas',
+ 'List GIFI' => 'Listar GIFI',
+ 'List Price' => 'Precio de Lista',
+ 'List Transactions' => 'Listar Transacciones',
+ 'Login' => 'Login',
+ 'Logout' => 'Logout',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Microfiche' => '',
+ 'Model' => 'Modelo',
+ 'N/A' => 'N/D',
+ 'Name' => 'Nombre',
+ 'Name missing!' => '',
+ 'New Templates' => 'Nuevas Plantillas',
+ 'No' => 'No',
+ 'No Database Drivers available!' => 'No hay manejador de base de datos
+disponible!',
+ 'No Dataset selected!' => 'No se ha seleccionado el set de datos',
+ 'No email address for' => 'Falta dirección email para',
+ 'No.' => '',
+ 'Notes' => 'Notas',
+ 'Nothing applied!' => '',
+ 'Nothing selected!' => '',
+ 'Nothing to delete!' => 'Noda que borrar',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato de Numero',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'O' => '',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'On Hand' => 'En Existencia',
+ 'On Order' => '',
+ 'Open' => 'Abierto',
+ 'Oracle Database Administration' => 'Administración de base de datos Oracle',
+ 'Order' => 'Orden',
+ 'Order Date' => 'Fecha de Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Entry' => 'Orden de Entrada',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'Order deleted!' => '',
+ 'Order saved!' => '',
+ 'Ordered' => '',
+ 'Orphaned' => 'Huerfano',
+ 'Out of balance!' => '',
+ 'PDF' => '',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'No se encuentra fecha de Lista de Empaque',
+ 'Packing List Number missing!' => 'No se encuentra Número de Lista de Empaque',
+ 'Paid' => 'Total Pagado',
+ 'Paid in full' => '',
+ 'Part' => 'Partes',
+ 'Part Number missing!' => 'Falta del número de pieza!',
+ 'Parts' => 'Partes',
+ 'Parts Inventory' => 'Inventario de Partes',
+ 'Password' => 'Contraseña',
+ 'Password changed!' => '',
+ 'Payables' => 'Por Pagar',
+ 'Payment' => 'Pago',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payment posted!' => '',
+ 'Payments' => 'Pagos',
+ 'Pg Database Administration' => 'Administración de base de datos Pg',
+ 'Phone' => 'Teléfono',
+ 'Port' => 'Puerto',
+ 'Port missing!' => 'No se encuentra el Puerto!',
+ 'Post' => '',
+ 'Post as new' => '',
+ 'Postscript' => '',
+ 'Preferences' => 'Preferencias',
+ 'Preferences saved!' => 'Preferencias guardadas!',
+ 'Price' => 'Precio',
+ 'Print' => '',
+ 'Printer' => 'Impresora',
+ 'Project' => '',
+ 'Project Number missing!' => '',
+ 'Project deleted!' => '',
+ 'Project not on file!' => '',
+ 'Project saved!' => '',
+ 'Projects' => '',
+ 'Purchase Invoice' => '',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Purchase Orders' => 'Ordenes de Compra',
+ 'Qty' => 'Cantidad',
+ 'ROP' => 'ROP',
+ 'Rate' => 'Tarifa',
+ 'Recd' => '',
+ 'Receipt' => '',
+ 'Receipts' => '',
+ 'Receivables' => 'Por Cobrar',
+ 'Reconciliation' => '',
+ 'Record in' => 'Registrar en',
+ 'Reference' => '',
+ 'Reference missing!' => '',
+ 'Remaining' => 'Remanente',
+ 'Report for' => 'Reportar por',
+ 'Reports' => 'Reportes',
+ 'Required by' => 'Requerido por',
+ 'Retained Earnings' => 'Ganacias Retenidas',
+ 'Sales' => 'Ventas',
+ 'Sales Invoice' => '',
+ 'Sales Order' => 'Orden de venta',
+ 'Sales Orders' => 'Ordenes de venta',
+ 'Save' => 'Salvar',
+ 'Save as new' => '',
+ 'Save to File' => 'Respaldar a Archivo',
+ 'Screen' => 'Pantalla',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione un set de
+datos para borrar y presione "Continuar"',
+ 'Select all' => '',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select from one of the names below' => '',
+ 'Select from one of the projects below' => '',
+ 'Select postscript or PDF!' => '',
+ 'Sell Price' => 'Precio de Venta',
+ 'Send by E-Mail' => 'Enviar por E-Mail',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Service Items' => 'Items de Servicio',
+ 'Service Number missing!' => 'Falta el número de servicio!',
+ 'Services' => 'Servicios',
+ 'Setup Templates' => 'Configurar Plantillas',
+ 'Ship' => '',
+ 'Ship to' => '',
+ 'Ship via' => '',
+ 'Short' => 'Corto',
+ 'Signature' => 'Firma',
+ 'Sold' => 'Vendido',
+ 'Source' => 'Fuente',
+ 'Standard' => 'Estandar',
+ 'Statement' => '',
+ 'Statement Balance' => '',
+ 'Statement sent to' => '',
+ 'Statements sent to printer!' => '',
+ 'Stock Assembly' => 'Inventariar Ensamblaje?',
+ 'Stylesheet' => 'Estilo de hoja',
+ 'Subject' => 'Sujeto',
+ 'Subtotal' => 'Subtotal',
+ 'System' => 'Sistema',
+ 'Tax' => 'Impuesto',
+ 'Tax Accounts' => 'Cuentas De Impuesto',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Tax collected' => '',
+ 'Tax paid' => '',
+ 'Taxable' => 'Gravable de Impuesto',
+ 'Template saved!' => '',
+ 'Templates' => 'Plantillas',
+ 'Terms: Net' => 'Crédito',
+ 'The following Datasets are not in use and can be deleted' => 'Los
+siguientes sets de datos no estan en uso y pueden ser borrados',
+ 'The following Datasets need to be updated' => 'Los siguientes datasets necesitan ser actualizados',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta es una verificacion preliminar de fuentes existentes. Nada será creado o borrado en esta etapa!',
+ 'To' => 'Hasta ',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para agregar un usuario a un grupo, edite un nombre, cambie el nombre de entrada (login) y guarde los cambios. Un nuevo usuario, con las mismas variables será guardado bajo el nuevo nombre de entrada. (login)',
+ 'Top Level' => '',
+ 'Total' => 'Total',
+ 'Transaction Date missing!' => 'Falta la fecha de la transacción!',
+ 'Transaction deleted!' => '',
+ 'Transaction posted!' => '',
+ 'Transaction reversal enforced for all dates' => 'Retorno de transacciones forzado para todas las fechas',
+ 'Transaction reversal enforced up to' => 'Reversal de transacciones forzado hasta ',
+ 'Transactions' => 'Transacciones',
+ 'Transactions exist, cannot delete customer!' => 'Las transacciones existen, no pueden suprimir el cliente!',
+ 'Transactions exist, cannot delete vendor!' => 'Las transacciones existen, no pueden suprimir a proveedor',
+ 'Transactions exist; cannot delete account!' => 'Las transacciones existen,
+no puede suprimir la cuenta!',
+ 'Trial Balance' => 'Balance De Comprobación',
+ 'Unit' => 'Unidad',
+ 'Unit of measure' => 'Unidad de medida',
+ 'Update' => '',
+ 'Update Dataset' => 'Actualizar Dataset',
+ 'Updated' => '',
+ 'Use Templates' => 'Plantillas de Usuarios',
+ 'User' => 'Usuario',
+ 'User deleted!' => '',
+ 'User saved!' => '',
+ 'Vendor' => 'Proveedor',
+ 'Vendor deleted!' => '',
+ 'Vendor missing!' => '',
+ 'Vendor not on file!' => '',
+ 'Vendor saved!' => '',
+ 'Vendors' => '',
+ 'Version' => 'Versión',
+ 'Weight' => 'Peso',
+ 'Weight Unit' => 'Unidad de Peso',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'Year End' => 'Fin del Año Fiscal',
+ 'Yes' => 'Si',
+ 'You are logged out!' => '',
+ 'You did not enter a name!' => 'No introdujo un nombre!',
+ 'You must enter a host and port for local and remote connections!' => 'Debe
+introducir un servidor de base de datos y un puerto para conexiones locales y
+remotas!',
+ 'as at' => '',
+ 'collected on sales' => 'Recabado en ventas',
+ 'days' => 'Días',
+ 'does not exist' => 'No existe',
+ 'ea' => 'c/u',
+ 'emailed to' => 'enviado a (e-mail)',
+ 'for Period' => 'para el período',
+ 'hr' => 'hr',
+ 'is already a member!' => 'ya es miembro!',
+ 'is not a member!' => 'no es un miembro!',
+ 'localhost' => 'servidor local',
+ 'paid on purchases' => 'pagado en compras',
+ 'sent to printer' => 'enviar a impresora',
+ 'successfully created!' => 'creado con éxito!',
+ 'successfully deleted!' => 'creado con éxito!',
+ 'to' => '',
+ 'website' => 'sitio web',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/am b/sql-ledger/locale/pa/am
new file mode 100644
index 0000000..47edf44
--- /dev/null
+++ b/sql-ledger/locale/pa/am
@@ -0,0 +1,140 @@
+$self{texts} = {
+ 'AP' => 'Ctas X Pagar',
+ 'AR' => 'Ctas X Cobrar',
+ 'Account' => 'Cuenta',
+ 'Account Number' => 'Número de Cuenta',
+ 'Account Number missing!' => 'No existe el número de cuenta!',
+ 'Account Type' => 'Tipo de Cuenta',
+ 'Account Type missing!' => 'No existe el tipo de la cuenta!',
+ 'Account deleted!' => 'Account deleted!',
+ 'Account saved!' => 'Account saved!',
+ 'Add Account' => 'Agregar Cuenta',
+ 'Add GIFI' => 'Agregar GIFI',
+ 'Address' => 'Dirección',
+ 'Asset' => 'Activo',
+ 'Audit Control' => 'Control de Audito',
+ 'Backup sent to' => 'Respaldo enviado a',
+ 'Books are open' => 'Libros estan abiertos',
+ 'Business Number' => 'Numero de Negocio',
+ 'COGS' => 'Costo de Ventas',
+ 'Cannot delete account!' => 'Cannot delete account!',
+ 'Cannot delete default account!' => 'No se puede borrar cuenta por defecto!',
+ 'Cannot save account!' => 'Cannot save account!',
+ 'Cannot save preferences!' => 'Cannot save preferences!',
+ 'Character Set' => 'Tabla de Caracteres',
+ 'Chart of Accounts' => 'Catálogo Contable',
+ 'Close Books up to' => 'Cerrar libros hasta',
+ 'Company' => 'Compañía',
+ 'Continue' => 'Continuar',
+ 'Copy to COA' => 'Copiar a catálogo de cuentas',
+ 'Credit' => 'Crédito',
+ 'Date Format' => 'Formato de Fecha',
+ 'Debit' => 'Débito',
+ 'Delete' => 'Borrar',
+ 'Delete Account' => 'Borrar Cuenta',
+ 'Description' => 'Descripción',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'Correo Electrónico',
+ 'Edit' => 'Edit',
+ 'Edit Account' => 'Editar Cuenta',
+ 'Edit GIFI' => 'Editar GIFI',
+ 'Edit Preferences for' => 'Editar Preferencias para',
+ 'Edit Template' => 'Editar Plantilla',
+ 'Enforce transaction reversal for all dates' => 'Forzar reversión de transacciones para todas las fechas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Egreso',
+ 'Expense Account' => 'Cuenta de Egreso',
+ 'Expense/Asset' => 'Egreso/Activo',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Ganancia en Moneda Extranjera',
+ 'Foreign Exchange Loss' => 'Pérdida en Moneda Extranjera',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI deleted!',
+ 'GIFI missing!' => 'No se encuentra GIFI',
+ 'GIFI saved!' => 'GIFI saved!',
+ 'Heading' => 'Encabezado',
+ 'Include in drop-down menus' => 'Incluya en menús desplegables',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluya esta cuenta en las formas del cliente/proveedor para señalar al cliente/proveedor como gravable de impuesto?',
+ 'Income' => 'Ingreso',
+ 'Income Account' => 'Cuenta de Ingreso',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Cuenta de Inventario',
+ 'Is this a summary account to record' => 'Es esta una cuenta de resumen a registrar?',
+ 'Language' => 'Lenguaje',
+ 'Last Invoice Number' => 'Último Número de Factura',
+ 'Last Numbers & Default Accounts' => 'Últimos Números y Cuentas por Defecto',
+ 'Last Purchase Order Number' => 'Ultima Orden de Compra',
+ 'Last Sales Order Number' => 'Ultima Orden de Venta',
+ 'Liability' => 'Pasivo',
+ 'Link' => 'Enlaces',
+ 'Name' => 'Nombre',
+ 'No' => 'No',
+ 'No email address for' => 'Falta dirección email para',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato de Numero',
+ 'Parts Inventory' => 'Inventario de Partes',
+ 'Password' => 'Contraseña',
+ 'Payables' => 'Por Pagar',
+ 'Payment' => 'Pago',
+ 'Phone' => 'Teléfono',
+ 'Preferences saved!' => 'Preferencias guardadas!',
+ 'Rate' => 'Tarifa',
+ 'Receivables' => 'Por Cobrar',
+ 'Sales' => 'Ventas',
+ 'Save' => 'Salvar',
+ 'Service Items' => 'Items de Servicio',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Estilo de hoja',
+ 'Tax' => 'Impuesto',
+ 'Tax Accounts' => 'Cuentas De Impuesto',
+ 'Template saved!' => 'Template saved!',
+ 'Transaction reversal enforced for all dates' => 'Retorno de transacciones forzado para todas las fechas',
+ 'Transaction reversal enforced up to' => 'Reversal de transacciones forzado hasta ',
+ 'Transactions exist; cannot delete account!' => 'Las transacciones existen,
+no puede suprimir la cuenta!',
+ 'Weight Unit' => 'Unidad de Peso',
+ 'Year End' => 'Fin del Año Fiscal',
+ 'Yes' => 'Si',
+ 'does not exist' => 'No existe',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'agregar_cuenta' => 'add_account',
+ 'continuar' => 'continue',
+ 'copiar_a_catálogo_de_cuentas' => 'copy_to_coa',
+ 'borrar' => 'delete',
+ 'edit' => 'edit',
+ 'editar_cuenta' => 'edit_account',
+ 'salvar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/ap b/sql-ledger/locale/pa/ap
new file mode 100644
index 0000000..0741d00
--- /dev/null
+++ b/sql-ledger/locale/pa/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AP Transactions' => 'Transacciones - Cuentas por Pagar',
+ 'Account' => 'Cuenta',
+ 'Add Accounts Payables Transaction' => 'Add Accounts Payables Transaction',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => '¿Está usted seguro de que desea suprimir la transacción?',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cannot post transaction for a closed period!' => 'No puede guardar transaccion para un periodo cerrado',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moneda',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date Paid' => 'Fecha de pago',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Due Date' => 'Fecha de Vencimiento',
+ 'Due Date missing!' => 'Falta Fecha de Vencimiento!',
+ 'Edit Accounts Payables Transaction' => 'Edit Accounts Payables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluya en informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Number' => 'Orden Número',
+ 'Paid' => 'Total Pagado',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payments' => 'Pagos',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Si',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'add_accounts_payables_transaction' => 'add_accounts_payables_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'edit_accounts_payables_transaction' => 'edit_accounts_payables_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/ar b/sql-ledger/locale/pa/ar
new file mode 100644
index 0000000..7106f79
--- /dev/null
+++ b/sql-ledger/locale/pa/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'AR Transaction',
+ 'AR Transactions' => 'Transacciones de Cuentas por Cobrar',
+ 'Account' => 'Cuenta',
+ 'Add Accounts Receivables Transaction' => 'Add Accounts Receivables Transaction',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => '¿Está usted seguro de que desea suprimir la transacción?',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cannot post transaction for a closed period!' => 'No puede guardar transaccion para un periodo cerrado',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date Paid' => 'Fecha de pago',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Due Date' => 'Fecha de Vencimiento',
+ 'Due Date missing!' => 'Falta Fecha de Vencimiento!',
+ 'Edit Accounts Receivables Transaction' => 'Edit Accounts Receivables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluya en informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Number' => 'Orden Número',
+ 'Paid' => 'Total Pagado',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payments' => 'Pagos',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Remaining' => 'Remanente',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Si',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ar_transaction' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/arap b/sql-ledger/locale/pa/arap
new file mode 100644
index 0000000..f541192
--- /dev/null
+++ b/sql-ledger/locale/pa/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Dirección',
+ 'Continue' => 'Continuar',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Description' => 'Descripción',
+ 'Number' => 'Número',
+ 'Project not on file!' => 'Project not on file!',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/ca b/sql-ledger/locale/pa/ca
new file mode 100644
index 0000000..0d3d00e
--- /dev/null
+++ b/sql-ledger/locale/pa/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'Catálogo Contable',
+ 'Credit' => 'Crédito',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Description' => 'Descripción',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Incluya en informe',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'List Transactions' => 'Listar Transacciones',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Reference' => 'Reference',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Hasta ',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'listar_transacciones' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/cp b/sql-ledger/locale/pa/cp
new file mode 100644
index 0000000..95085e0
--- /dev/null
+++ b/sql-ledger/locale/pa/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Amount missing!',
+ 'Applied' => 'Applied',
+ 'Cannot post payment!' => 'Cannot post payment!',
+ 'Cannot process payment for a closed period!' => 'Cannot process payment for a closed period!',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check printed!',
+ 'Check printing failed!' => 'Check printing failed!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date missing!' => 'Date missing!',
+ 'Description' => 'Descripción',
+ 'Due' => 'Vence',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'From' => 'Desde',
+ 'Invoice' => 'Factura',
+ 'Invoices' => 'Invoices',
+ 'Nothing applied!' => 'Nothing applied!',
+ 'Number' => 'Número',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'Pago',
+ 'Payment posted!' => 'Payment posted!',
+ 'Post' => 'Post',
+ 'Print' => 'Print',
+ 'Printer' => 'Impresora',
+ 'Project not on file!' => 'Project not on file!',
+ 'Receipt' => 'Receipt',
+ 'Reference' => 'Reference',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'To' => 'Hasta ',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveedor',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/ct b/sql-ledger/locale/pa/ct
new file mode 100644
index 0000000..0db8902
--- /dev/null
+++ b/sql-ledger/locale/pa/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Agregar',
+ 'Address' => 'Dirección',
+ 'All' => 'Todos',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Cannot delete customer!',
+ 'Cannot delete vendor!' => 'Cannot delete vendor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Customer deleted!' => 'Customer deleted!',
+ 'Customer saved!' => 'Customer saved!',
+ 'Customers' => 'Customers',
+ 'Delete' => 'Borrar',
+ 'Discount' => 'Descuento',
+ 'E-mail' => 'Correo Electrónico',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Incluya en informe',
+ 'Invoice' => 'Factura',
+ 'Name' => 'Nombre',
+ 'Name missing!' => 'Name missing!',
+ 'Notes' => 'Notas',
+ 'Number' => 'Número',
+ 'Order' => 'Orden',
+ 'Orphaned' => 'Huerfano',
+ 'Phone' => 'Teléfono',
+ 'Save' => 'Salvar',
+ 'Ship to' => 'Ship to',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Taxable' => 'Gravable de Impuesto',
+ 'Terms: Net' => 'Crédito',
+ 'Transactions exist, cannot delete customer!' => 'Las transacciones existen, no pueden suprimir el cliente!',
+ 'Transactions exist, cannot delete vendor!' => 'Las transacciones existen, no pueden suprimir a proveedor',
+ 'Vendor deleted!' => 'Vendor deleted!',
+ 'Vendor saved!' => 'Vendor saved!',
+ 'Vendors' => 'Vendors',
+ 'days' => 'Días',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'agregar' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'factura' => 'invoice',
+ 'orden' => 'order',
+ 'salvar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/gl b/sql-ledger/locale/pa/gl
new file mode 100644
index 0000000..8667f1c
--- /dev/null
+++ b/sql-ledger/locale/pa/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AR Transaction' => 'AR Transaction',
+ 'Account' => 'Cuenta',
+ 'Add General Ledger Transaction' => 'Agregar Transacción - Mayor General',
+ 'Address' => 'Dirección',
+ 'All' => 'Todos',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => '¿Está usted seguro de que desea suprimir la transacción?',
+ 'Asset' => 'Activo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot have a value in both Debit and Credit!' => 'No puede tener un valor en Débito y Crédito simultáneamente!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'No puede guardar transaccion para un periodo cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit' => 'Crédito',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito y Crédito fuera de balance.',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Edit General Ledger Transaction' => 'Editar Transacción de Mayor General',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Egreso',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'GL Transaction',
+ 'General Ledger' => 'Mayor General',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluya en informe',
+ 'Income' => 'Ingreso',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Liability' => 'Pasivo',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference missing!',
+ 'Reports' => 'Reportes',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Hasta ',
+ 'Transaction Date missing!' => 'Falta la fecha de la transacción!',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Si',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'gl_transaction' => 'gl_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/ic b/sql-ledger/locale/pa/ic
new file mode 100644
index 0000000..44cfa36
--- /dev/null
+++ b/sql-ledger/locale/pa/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => 'Active',
+ 'Add' => 'Agregar',
+ 'Add Assembly' => 'Agregar Ensamblaje',
+ 'Add Part' => 'Agregar Parte',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Order' => 'Agregar Orden de Venta',
+ 'Add Service' => 'Agregar Servicio',
+ 'Address' => 'Dirección',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Assemblies' => 'Ensamblajes',
+ 'Assemblies restocked!' => 'Assemblies restocked!',
+ 'Assembly Number missing!' => 'No existe Numero de Ensamblaje!',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Bought' => 'Comprado',
+ 'COGS' => 'Costo de Ventas',
+ 'Cannot delete item already invoiced!' => 'No puede suprimir el item ya facturado!',
+ 'Cannot delete item on order!' => 'No se puede borrar el item ya en cotizacion',
+ 'Cannot delete item which is part of an assembly!' => 'No puede suprimir un item que es parte de un ensamblaje!',
+ 'Cannot delete item!' => 'Cannot delete item!',
+ 'Cannot stock assemblies!' => 'Cannot stock assemblies!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'Drawing' => 'Drawing',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit Assembly' => 'Editar Ensamblaje',
+ 'Edit Part' => 'Editar Parte',
+ 'Edit Service' => 'Editar Servicio',
+ 'Expense' => 'Egreso',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'Image' => 'Image',
+ 'In-line' => 'En-linea',
+ 'Include in Report' => 'Incluya en informe',
+ 'Income' => 'Ingreso',
+ 'Individual Items' => 'Items Individuales',
+ 'Inventory' => 'Inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar este ensamblaje a obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'La cantidad en inventario debe ser cero antes de cambiar esta parte a obsoleto',
+ 'Inventory quantity must be zero!' => 'La cantidad en inventario debe ser
+cero!',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Item deleted!' => 'Item deleted!',
+ 'Item not on file!' => 'El item no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Last Cost' => 'Ultimo Costo',
+ 'Line Total' => 'Total de Línea',
+ 'Link Accounts' => 'Enlazar Cuentas',
+ 'List Price' => 'Precio de Lista',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modelo',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'On Hand' => 'En Existencia',
+ 'On Order' => 'On Order',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'Ordered' => 'Ordered',
+ 'Orphaned' => 'Huerfano',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'No se encuentra fecha de Lista de Empaque',
+ 'Packing List Number missing!' => 'No se encuentra Número de Lista de Empaque',
+ 'Part' => 'Partes',
+ 'Part Number missing!' => 'Falta del número de pieza!',
+ 'Parts' => 'Partes',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cantidad',
+ 'ROP' => 'ROP',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Requerido por',
+ 'Sales' => 'Ventas',
+ 'Sales Order' => 'Orden de venta',
+ 'Save' => 'Salvar',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sell Price' => 'Precio de Venta',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Service Number missing!' => 'Falta el número de servicio!',
+ 'Services' => 'Servicios',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Short' => 'Corto',
+ 'Sold' => 'Vendido',
+ 'Stock Assembly' => 'Inventariar Ensamblaje?',
+ 'Subject' => 'Sujeto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'To' => 'Hasta ',
+ 'Top Level' => 'Top Level',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Unit of measure' => 'Unidad de medida',
+ 'Update' => 'Update',
+ 'Updated' => 'Updated',
+ 'Weight' => 'Peso',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'ea' => 'c/u',
+ 'emailed to' => 'enviado a (e-mail)',
+ 'hr' => 'hr',
+ 'sent to printer' => 'enviar a impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'agregar' => 'add',
+ 'agregar_ensamblaje' => 'add_assembly',
+ 'agregar_parte' => 'add_part',
+ 'agregar_servicio' => 'add_service',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'editar_ensamblaje' => 'edit_assembly',
+ 'editar_parte' => 'edit_part',
+ 'editar_servicio' => 'edit_service',
+ 'salvar' => 'save',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/io b/sql-ledger/locale/pa/io
new file mode 100644
index 0000000..1252b51
--- /dev/null
+++ b/sql-ledger/locale/pa/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Order' => 'Agregar Orden de Venta',
+ 'Address' => 'Dirección',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'In-line' => 'En-linea',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Item not on file!' => 'El item no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'No se encuentra fecha de Lista de Empaque',
+ 'Packing List Number missing!' => 'No se encuentra Número de Lista de Empaque',
+ 'Part' => 'Partes',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Orden de venta',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Subject' => 'Sujeto',
+ 'To' => 'Hasta ',
+ 'Unit' => 'Unidad',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'emailed to' => 'enviado a (e-mail)',
+ 'sent to printer' => 'enviar a impresora',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/ir b/sql-ledger/locale/pa/ir
new file mode 100644
index 0000000..042ca21
--- /dev/null
+++ b/sql-ledger/locale/pa/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Order' => 'Agregar Orden de Venta',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Esta seguro de que desea borrar la Factura No.:',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'No se puede registrar factura para un periodo cerrado!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Currency' => 'Moneda',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Fecha de Vencimiento',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit Purchase Invoice' => 'Edit Purchase Invoice',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'In-line' => 'En-linea',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'El item no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'No se encuentra fecha de Lista de Empaque',
+ 'Packing List Number missing!' => 'No se encuentra Número de Lista de Empaque',
+ 'Part' => 'Partes',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payments' => 'Pagos',
+ 'Phone' => 'Teléfono',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Registrar en',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Orden de venta',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Source' => 'Fuente',
+ 'Subject' => 'Sujeto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'Yes' => 'Si',
+ 'ea' => 'c/u',
+ 'emailed to' => 'enviado a (e-mail)',
+ 'sent to printer' => 'enviar a impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'orden' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/is b/sql-ledger/locale/pa/is
new file mode 100644
index 0000000..577b51f
--- /dev/null
+++ b/sql-ledger/locale/pa/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Agregar Orden de Venta',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Esta seguro de que desea borrar la Factura No.:',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'No se puede registrar factura para un periodo cerrado!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'No se puede registrar pago para un periodo cerrado',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Fecha de Vencimiento',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit Sales Invoice' => 'Edit Sales Invoice',
+ 'Exch' => 'Interc.',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'In-line' => 'En-linea',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha de Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'El item no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'No se encuentra fecha de Lista de Empaque',
+ 'Packing List Number missing!' => 'No se encuentra Número de Lista de Empaque',
+ 'Part' => 'Partes',
+ 'Payment date missing!' => 'No se encuentra la fecha de Pago!',
+ 'Payments' => 'Pagos',
+ 'Phone' => 'Teléfono',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Print' => 'Print',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Registrar en',
+ 'Remaining' => 'Remanente',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Orden de venta',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Source' => 'Fuente',
+ 'Subject' => 'Sujeto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'Yes' => 'Si',
+ 'ea' => 'c/u',
+ 'emailed to' => 'enviado a (e-mail)',
+ 'sent to printer' => 'enviar a impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'correo_electrónico' => 'e_mail',
+ 'orden' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/login b/sql-ledger/locale/pa/login
new file mode 100644
index 0000000..d6199be
--- /dev/null
+++ b/sql-ledger/locale/pa/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'Acerca',
+ 'Accounting' => 'Contabilidad',
+ 'Database Host' => 'Servidor de Base de Datos',
+ 'Dataset' => 'Set de datos',
+ 'Incorrect Dataset version!' => 'Version de dataset Incorrecta',
+ 'Incorrect Password!' => 'Contraseña Incorrecta!',
+ 'Licensed to' => 'Licenciado a',
+ 'Login' => 'Login',
+ 'Name' => 'Nombre',
+ 'Password' => 'Contraseña',
+ 'User' => 'Usuario',
+ 'Version' => 'Versión',
+ 'You are logged out!' => 'You are logged out!',
+ 'You did not enter a name!' => 'No introdujo un nombre!',
+ 'is not a member!' => 'no es un miembro!',
+ 'localhost' => 'servidor local',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/menu b/sql-ledger/locale/pa/menu
new file mode 100644
index 0000000..25ba596
--- /dev/null
+++ b/sql-ledger/locale/pa/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'Ctas X Pagar',
+ 'AP Aging' => 'Envejecimiento - CxP',
+ 'AR' => 'Ctas X Cobrar',
+ 'AR Aging' => 'Envejecimiento - CxC ',
+ 'Accounting Menu' => 'Menú de Contabilidad',
+ 'Add Account' => 'Agregar Cuenta',
+ 'Add Assembly' => 'Agregar Ensamblaje',
+ 'Add Customer' => 'Agregar Cliente',
+ 'Add GIFI' => 'Agregar GIFI',
+ 'Add Part' => 'Agregar Parte',
+ 'Add Project' => 'Add Project',
+ 'Add Service' => 'Agregar Servicio',
+ 'Add Transaction' => 'Agregar Transaccion',
+ 'Add Vendor' => 'Agregar Proveedor',
+ 'Assemblies' => 'Ensamblajes',
+ 'Audit Control' => 'Control de Audito',
+ 'Backup' => 'Respaldar datos',
+ 'Balance Sheet' => 'Hoja de Balance',
+ 'Cash' => 'Cash',
+ 'Chart of Accounts' => 'Catálogo Contable',
+ 'Check' => 'Check',
+ 'Customers' => 'Customers',
+ 'General Ledger' => 'Mayor General',
+ 'Goods & Services' => 'Partes y Servicios',
+ 'HTML Templates' => 'Plantillas HTML',
+ 'Income Statement' => 'Estado de Cuentas',
+ 'Invoice' => 'Factura',
+ 'LaTeX Templates' => 'Plantillas LaTeX',
+ 'List Accounts' => 'Listar Cuentas',
+ 'List GIFI' => 'Listar GIFI',
+ 'Logout' => 'Logout',
+ 'Order Entry' => 'Orden de Entrada',
+ 'Packing List' => 'Lista de Empaque',
+ 'Parts' => 'Partes',
+ 'Payment' => 'Pago',
+ 'Payments' => 'Pagos',
+ 'Preferences' => 'Preferencias',
+ 'Projects' => 'Projects',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Purchase Orders' => 'Ordenes de Compra',
+ 'Receipt' => 'Receipt',
+ 'Receipts' => 'Receipts',
+ 'Reconciliation' => 'Reconciliation',
+ 'Reports' => 'Reportes',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Sales Order' => 'Orden de venta',
+ 'Sales Orders' => 'Ordenes de venta',
+ 'Save to File' => 'Respaldar a Archivo',
+ 'Send by E-Mail' => 'Enviar por E-Mail',
+ 'Services' => 'Servicios',
+ 'Statement' => 'Statement',
+ 'Stock Assembly' => 'Inventariar Ensamblaje?',
+ 'Stylesheet' => 'Estilo de hoja',
+ 'System' => 'Sistema',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'Transactions' => 'Transacciones',
+ 'Trial Balance' => 'Balance De Comprobación',
+ 'Vendors' => 'Vendors',
+ 'Version' => 'Versión',
+ 'localhost' => 'servidor local',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/oe b/sql-ledger/locale/pa/oe
new file mode 100644
index 0000000..a7ee60a
--- /dev/null
+++ b/sql-ledger/locale/pa/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'Agregar',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Agregar Orden de Venta',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Order Number' => '¿Esta seguro de que desea
+borrar la Orden No.:?',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Cannot delete order!',
+ 'Cannot save order!' => 'Cannot save order!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit Limit' => 'Limite de Credito',
+ 'Curr' => '$',
+ 'Currency' => 'Moneda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Fecha',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail address missing!' => 'Falta E-mail!',
+ 'Edit Purchase Order' => 'Editar Orden de Compra',
+ 'Edit Sales Order' => 'Editar Orden de Venta',
+ 'Exchangerate' => 'Tasa de Intercambio',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'In-line' => 'En-linea',
+ 'Include in Report' => 'Incluya en informe',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta la Fecha de la Factura!',
+ 'Invoice Number missing!' => 'Falta el Número de Factura!',
+ 'Item not on file!' => 'El item no se encuentra en archivo!',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'No se encuentra el número en la fila',
+ 'O' => 'O',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Date' => 'Fecha de Orden',
+ 'Order Date missing!' => 'No se encuentra la fecha de orden!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'No se encuentra el número de orden!',
+ 'Order deleted!' => 'Order deleted!',
+ 'Order saved!' => 'Order saved!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'No se encuentra fecha de Lista de Empaque',
+ 'Packing List Number missing!' => 'No se encuentra Número de Lista de Empaque',
+ 'Part' => 'Partes',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Print' => 'Print',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Purchase Orders' => 'Ordenes de Compra',
+ 'Qty' => 'Cantidad',
+ 'Recd' => 'Recd',
+ 'Remaining' => 'Remanente',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Orden de venta',
+ 'Sales Orders' => 'Ordenes de venta',
+ 'Save' => 'Salvar',
+ 'Save as new' => 'Save as new',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los items',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Subject' => 'Sujeto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Terms: Net' => 'Crédito',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Update',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => '¿Que tipo de Item es este?',
+ 'Yes' => 'Si',
+ 'days' => 'Días',
+ 'ea' => 'c/u',
+ 'emailed to' => 'enviado a (e-mail)',
+ 'sent to printer' => 'enviar a impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'agregar' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'correo_electrónico' => 'e_mail',
+ 'factura' => 'invoice',
+ 'print' => 'print',
+ 'salvar' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'si' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/pe b/sql-ledger/locale/pa/pe
new file mode 100644
index 0000000..e1306ae
--- /dev/null
+++ b/sql-ledger/locale/pa/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Agregar',
+ 'Add Project' => 'Add Project',
+ 'All' => 'Todos',
+ 'Continue' => 'Continuar',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Edit Project' => 'Edit Project',
+ 'Number' => 'Número',
+ 'Orphaned' => 'Huerfano',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Project Number missing!',
+ 'Project deleted!' => 'Project deleted!',
+ 'Project saved!' => 'Project saved!',
+ 'Projects' => 'Projects',
+ 'Save' => 'Salvar',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'agregar' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'salvar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/rc b/sql-ledger/locale/pa/rc
new file mode 100644
index 0000000..7e0dbb1
--- /dev/null
+++ b/sql-ledger/locale/pa/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'Continuar',
+ 'Date' => 'Fecha',
+ 'Deposit' => 'Deposit',
+ 'Description' => 'Descripción',
+ 'Difference' => 'Difference',
+ 'Done' => 'Done',
+ 'Exchangerate Difference' => 'Exchangerate Difference',
+ 'From' => 'Desde',
+ 'Out of balance!' => 'Out of balance!',
+ 'Payment' => 'Pago',
+ 'Reconciliation' => 'Reconciliation',
+ 'Select all' => 'Select all',
+ 'Source' => 'Fuente',
+ 'Statement Balance' => 'Statement Balance',
+ 'To' => 'Hasta ',
+ 'Update' => 'Update',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continuar' => 'continue',
+ 'done' => 'done',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/pa/rp b/sql-ledger/locale/pa/rp
new file mode 100644
index 0000000..ad8b35b
--- /dev/null
+++ b/sql-ledger/locale/pa/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Envejecimiento - CxP',
+ 'AR Aging' => 'Envejecimiento - CxC ',
+ 'Account' => 'Cuenta',
+ 'Accounts' => 'Cuentas',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Adjunto',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance Sheet' => 'Hoja de Balance',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Comparar a',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit' => 'Crédito',
+ 'Current' => 'Current',
+ 'Customer' => 'Cliente',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dic',
+ 'December' => 'Diciembre',
+ 'Decimalplaces' => 'Decimalplaces',
+ 'Description' => 'Descripción',
+ 'Due' => 'Vence',
+ 'E-mail' => 'Correo Electrónico',
+ 'E-mail Statement to' => 'E-mail Statement to',
+ 'Feb' => 'Feb',
+ 'February' => 'Febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Encabezado',
+ 'ID' => 'ID',
+ 'In-line' => 'En-linea',
+ 'Include in Report' => 'Incluya en informe',
+ 'Income Statement' => 'Estado de Cuentas',
+ 'Invoice' => 'Factura',
+ 'Jan' => 'Ene',
+ 'January' => 'Enero',
+ 'Jul' => 'Jul',
+ 'July' => 'Julio',
+ 'Jun' => 'Jun',
+ 'June' => 'Junio',
+ 'Mar' => 'Mar',
+ 'March' => 'Marzo',
+ 'May' => 'May',
+ 'May ' => 'Mayo',
+ 'Message' => 'Mensaje',
+ 'N/A' => 'N/D',
+ 'Nothing selected!' => 'Nothing selected!',
+ 'Nov' => 'Nov',
+ 'November' => 'Noviembre',
+ 'Oct' => 'Oct',
+ 'October' => 'Octubre',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Pagos',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Print',
+ 'Printer' => 'Impresora',
+ 'Receipts' => 'Receipts',
+ 'Report for' => 'Reportar por',
+ 'Retained Earnings' => 'Ganacias Retenidas',
+ 'Screen' => 'Pantalla',
+ 'Select all' => 'Select all',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Sep',
+ 'September' => 'Septiembre',
+ 'Source' => 'Fuente',
+ 'Standard' => 'Estandar',
+ 'Statement' => 'Statement',
+ 'Statement sent to' => 'Statement sent to',
+ 'Statements sent to printer!' => 'Statements sent to printer!',
+ 'Subject' => 'Sujeto',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Impuesto',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'To' => 'Hasta ',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Balance De Comprobación',
+ 'Vendor' => 'Proveedor',
+ 'as at' => 'as at',
+ 'collected on sales' => 'Recabado en ventas',
+ 'for Period' => 'para el período',
+ 'paid on purchases' => 'pagado en compras',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continuar' => 'continue',
+ 'correo_electrónico' => 'e_mail',
+ 'print' => 'print',
+ 'select_all' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/COPYING b/sql-ledger/locale/pl/COPYING
new file mode 100644
index 0000000..e8ae224
--- /dev/null
+++ b/sql-ledger/locale/pl/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Polish texts:
+#
+# Author: Peter Dabrowski <meritage@mail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/pl/LANGUAGE b/sql-ledger/locale/pl/LANGUAGE
new file mode 100644
index 0000000..692d024
--- /dev/null
+++ b/sql-ledger/locale/pl/LANGUAGE
@@ -0,0 +1 @@
+Polish
diff --git a/sql-ledger/locale/pl/admin b/sql-ledger/locale/pl/admin
new file mode 100644
index 0000000..9dc5b6a
--- /dev/null
+++ b/sql-ledger/locale/pl/admin
@@ -0,0 +1,122 @@
+$self{texts} = {
+ 'Access Control' => 'Kontrola Dostêpu',
+ 'Accounting' => 'Ksiêgowo¶æ',
+ 'Add User' => 'Dodaj U¿ytkownika',
+ 'Address' => 'Adres',
+ 'Administration' => 'Administracja',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => 'Zbiory Danych uzupe³nione!',
+ 'Change Admin Password' => 'Zmiana Has³a Administratora',
+ 'Change Password' => 'Zmieñ Has³o',
+ 'Character Set' => 'Zestaw Znaków',
+ 'Click on login name to edit!' => 'Kliknij nazwê u¿ytkownika ¿eby dokonaæ zmian!',
+ 'Company' => 'Firma',
+ 'Connect to' => 'Pod³±cz do',
+ 'Continue' => 'Kontynuj',
+ 'Create Chart of Accounts' => 'Utwórz Wzór Kont',
+ 'Create Dataset' => 'Utwórz Zbiór Danych',
+ 'DBI not installed!' => 'Nie zainstalowane DBI!',
+ 'Database' => 'Baza Danych',
+ 'Database Administration' => 'Administracja Bazy Danych',
+ 'Database Driver not checked!' => 'Sterownik Bazy Danych nie zaznaczony!',
+ 'Database User missing!' => 'Brak U¿ytkownika Bazy Danych!',
+ 'Dataset' => 'Zbiór Danych',
+ 'Dataset missing!' => 'Brak Zbioru Danych',
+ 'Dataset updated!' => 'Zbiór Danych uzupe³niony!',
+ 'Date Format' => 'Format Daty',
+ 'Delete' => 'Usuñ',
+ 'Delete Dataset' => 'Usuñ Zbior Danych',
+ 'Directory' => 'Katalog',
+ 'Driver' => 'Sterownik',
+ 'Dropdown Limit' => 'Limit Rozwiniêcia',
+ 'E-mail' => 'E-mail',
+ 'Edit User' => 'Zmiany U¿ytkownika',
+ 'Existing Datasets' => 'Istniej±cy Zbiór Danych',
+ 'Fax' => 'Fax',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Brak Nazwy Hosta',
+ 'Incorrect Password!' => 'Nieprawid³owe Has³o',
+ 'Language' => 'Jêzyk',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Opu¶æ pole wêz³a i portu, chyba ¿e chcesz mieæ zdalne po³±czenie',
+ 'Login' => 'Zarejestrój siê',
+ 'Name' => 'Nazwa',
+ 'New Templates' => 'Nowe Szablony',
+ 'No Database Drivers available!' => 'Sterownik Bazy Danych jest niedostêpny',
+ 'No Dataset selected!' => 'Nie jest zaznaczony Zbiór Danych',
+ 'Nothing to delete!' => 'Niema nic do usuniêcia!',
+ 'Number Format' => 'Format Numeru',
+ 'Oracle Database Administration' => 'Administracja Bazy Danych Oracle',
+ 'Password' => 'Has³o',
+ 'Password changed!' => 'Has³o zmienione',
+ 'Pg Database Administration' => 'Administracja Bazy Danych Pg',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Brak Portu',
+ 'Printer' => 'Drukarka',
+ 'Save' => 'Zapisz',
+ 'Select a Dataset to delete and press "Continue"' => 'Wybierz Zbiór Danych do usuniêcia i naci¶nij "Kontynuj"',
+ 'Setup Templates' => 'Ustaw Szablony',
+ 'Ship via' => 'Wy¶lij przez',
+ 'Signature' => 'Podpis',
+ 'Stylesheet' => 'Strona Stylowa',
+ 'Templates' => 'Szablony',
+ 'The following Datasets are not in use and can be deleted' => 'Te Zbiory Danych s± nieu¿ywane i mo¿na je usun±æ',
+ 'The following Datasets need to be updated' => 'Zbiory Danych do uzupe³nienia',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Jest to wstêpne sprawdzenie istniej±cych ¿róde³. Narazie nic nie bêdzie utworzone lub usuniête.',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => '¯eby dodaæ do grupy u¿ytkownika zmieñ nazwê, nazwê zarejestrowania i zapisz. Nowy u¿ytkownik z tymi samymi zmiennymi warto¶ciami bêdzie zapisany pod now± nazw± rejestruj±c±',
+ 'Update Dataset' => 'Uzupe³nij Zbiór Danych',
+ 'Use Templates' => 'U¿yj Szablony',
+ 'User' => 'U¿ytkownik',
+ 'User deleted!' => 'U¿ytkownik usuniêty',
+ 'User saved!' => 'U¿ytkownik zapisany',
+ 'Version' => 'Wersja',
+ 'You must enter a host and port for local and remote connections!' => 'Wstaw wêze³ i port dla lokalnego i zdalnego po³±czenia',
+ 'does not exist' => 'nie istnieje',
+ 'is already a member!' => 'Jest ju¿ cz³onkiem',
+ 'localhost' => 'host lokalny',
+ 'successfully created!' => 'stworzone z powodzeniem',
+ 'successfully deleted!' => 'usuniête z powodzeniem',
+ 'website' => 'witryna WWW',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'dodaj_u¿ytkownika' => 'add_user',
+ 'zmiana_has³a_administratora' => 'change_admin_password',
+ 'zmieñ_has³o' => 'change_password',
+ 'kontynuj' => 'continue',
+ 'utwórz_zbiór_danych' => 'create_dataset',
+ 'usuñ' => 'delete',
+ 'usuñ_zbior_danych' => 'delete_dataset',
+ 'zarejestrój_siê' => 'login',
+ 'administracja_bazy_danych_oracle' => 'oracle_database_administration',
+ 'administracja_bazy_danych_pg' => 'pg_database_administration',
+ 'zapisz' => 'save',
+ 'uzupe³nij_zbiór_danych' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/all b/sql-ledger/locale/pl/all
new file mode 100644
index 0000000..fabdb59
--- /dev/null
+++ b/sql-ledger/locale/pl/all
@@ -0,0 +1,487 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Ksiêga Zobowi±zañ',
+ 'AP Aging' => 'Zobowi±zania Przeterminowane',
+ 'AP Transaction' => 'Transakcja Zobowi±zañ',
+ 'AP Transactions' => 'Transakcje Zobowi±zañ',
+ 'AR' => 'Ksiêga Nale¿no¶ci',
+ 'AR Aging' => 'Nale¿no¶ci Przeterminowane',
+ 'AR Transaction' => 'Transakcja Nale¿no¶ci',
+ 'AR Transactions' => 'Transakcje Nale¿no¶ci',
+ 'About' => 'Na Temat',
+ 'Access Control' => 'Kontrola Dostêpu',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Numer Konta',
+ 'Account Number missing!' => 'Brak Numeru Konta!',
+ 'Account Type' => 'Rodzaj Konta',
+ 'Account Type missing!' => 'Brak Rodzaju Konta!',
+ 'Account deleted!' => 'Usuniêto Konto',
+ 'Account saved!' => 'Zapisano Konto',
+ 'Accounting' => 'Ksiêgowo¶æ',
+ 'Accounting Menu' => 'Menu Ksiêgowo¶ci',
+ 'Accounts' => 'Konta',
+ 'Active' => 'Aktywne',
+ 'Add' => 'Dodaj',
+ 'Add Account' => 'Dodaj Konto',
+ 'Add Accounts Payables Transaction' => 'Rejestr w Ksiêdze Zobowi±zañ',
+ 'Add Accounts Receivables Transaction' => 'Rejestr w Ksiêdze Nale¿no¶ci',
+ 'Add Assembly' => 'Dodaj Zestawienie',
+ 'Add Customer' => 'Dodaj Odbiorcê',
+ 'Add GIFI' => 'Dodaj GIFI',
+ 'Add General Ledger Transaction' => 'Dodaj Transakcjê w Ksiêdze G³ównej',
+ 'Add Part' => 'Dodaj Produkt',
+ 'Add Project' => 'Dodaj Projekt',
+ 'Add Purchase Invoice' => 'Zarejestrój Fakturê VAT Zakupu',
+ 'Add Purchase Order' => 'Dodaj Zamówienie Zakupu',
+ 'Add Sales Invoice' => 'Zarejestrój Fakturê VAT Sprzeda¿y',
+ 'Add Sales Order' => 'Dodaj Zamówienie Klienta',
+ 'Add Service' => 'Dodaj Us³ugi',
+ 'Add Transaction' => 'Dodaj Transakcjê',
+ 'Add User' => 'Dodaj U¿ytkownika',
+ 'Add Vendor' => 'Dodaj Dostawcê',
+ 'Address' => 'Adres',
+ 'Administration' => 'Administracja',
+ 'Administrator' => 'Administrator',
+ 'All' => 'Wszystko',
+ 'All Datasets up to date!' => 'Zbiory Danych uzupe³nione!',
+ 'Amount' => 'Kwota',
+ 'Amount Due' => 'Kwota Nale¿na',
+ 'Amount does not equal applied!' => 'Kwota nie jest równa',
+ 'Amount missing!' => 'Brakuje kwoty!',
+ 'Applied' => 'Zastosowano',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Are you sure you want to delete Invoice Number' => 'Czy chcesz usun±æ Numer Faktury?',
+ 'Are you sure you want to delete Order Number' => 'Czy chcesz usun±æ Numer Zamówienia?',
+ 'Are you sure you want to delete Transaction' => 'Czy chcesz usun±æ Transakcjê?',
+ 'Assemblies' => 'Zestawienia',
+ 'Assemblies restocked!' => 'Zestawienia uzupe³nione',
+ 'Assembly Number missing!' => 'Brak Numeru Zestawienia!',
+ 'Asset' => 'Aktywy',
+ 'Attachment' => 'Za³±cznik',
+ 'Audit Control' => 'Kontrola Audytu',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'BOM' => 'Zestawienie materia³owe',
+ 'Backup' => 'Kopia Zapasowa',
+ 'Backup sent to' => 'Kopia Zapasowa wys³ana do',
+ 'Balance' => 'Saldo',
+ 'Balance Sheet' => 'Bilans',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Pojemnik',
+ 'Books are open' => 'Ksiêgi otwarte',
+ 'Bought' => 'Zakupione',
+ 'Business Number' => 'NIP',
+ 'C' => 'C',
+ 'COGS' => 'Koszta Sprzeda¿y',
+ 'Cannot delete account!' => 'Nie mo¿esz usun±æ konta!',
+ 'Cannot delete customer!' => 'Nie mo¿esz usun±æ klienta!',
+ 'Cannot delete default account!' => 'Konto Domy¶lne nie mo¿e byæ usuniête!',
+ 'Cannot delete invoice!' => 'Nie mo¿esz usun±æ factury!',
+ 'Cannot delete item already invoiced!' => 'Nie mo¿na usun±æ pozycji zafakturowanej!',
+ 'Cannot delete item on order!' => 'Nie mo¿na usunac zamówionego produktu!',
+ 'Cannot delete item which is part of an assembly!' => 'Nie mo¿na usun±æ czê¶ci z zestawienia!',
+ 'Cannot delete item!' => 'Nie mo¿esz usun±æ pozycji!',
+ 'Cannot delete order!' => 'Nie mo¿esz usun±æ zamówienia!',
+ 'Cannot delete transaction!' => 'Nie mo¿esz usun±æ transakcji!',
+ 'Cannot delete vendor!' => 'Nie mo¿esz usun±æ dostawcy!',
+ 'Cannot have a value in both Debit and Credit!' => 'Nie mo¿na wpisaæ warto¶ci w Debet i Kredyt równocze¶nie!',
+ 'Cannot post a transaction without a value!' => 'Nie mo¿esz zatwierdziæ transakcji bez warto¶ci',
+ 'Cannot post invoice for a closed period!' => 'Nie mo¿na zksiêgowaæ faktury pozamkniêciu okresu!',
+ 'Cannot post invoice!' => 'Nie mo¿esz zatwierdziæ faktury!',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cannot post payment!' => 'Nie mo¿esz zatwierdziæ p³atno¶ci!',
+ 'Cannot post transaction for a closed period!' => 'Nie mo¿na zaksiêgowaæ transakcji po zamkniêciu okresu!',
+ 'Cannot post transaction!' => 'Nie mo¿esz zatwierdziæ transakcji!',
+ 'Cannot process payment for a closed period!' => 'Niemo¿na przetworzyæ p³atno¶ci po zamkniêciu okresu',
+ 'Cannot save account!' => 'Nie mo¿na zapisaæ konta!',
+ 'Cannot save order!' => 'Nie mo¿na zapisaæ zamowienia!',
+ 'Cannot save preferences!' => 'Nie mo¿na zapisaæ preferencji!',
+ 'Cannot stock assemblies!' => 'Nie mo¿na wstawiæ z³o¿enia',
+ 'Cash' => 'Kasa',
+ 'Cash based' => 'Tryb Kasowy',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => 'Zmiana Has³a Administratora',
+ 'Change Password' => 'Zmieñ Has³o',
+ 'Character Set' => 'Zestaw Znaków',
+ 'Chart of Accounts' => 'Plan Kont',
+ 'Check' => 'Czek',
+ 'Check printed!' => 'Czek wydrukowany!',
+ 'Check printing failed!' => 'B³±dw drukowaniu czeku',
+ 'Cleared Balance' => 'Zgadzaj±ce Saldo',
+ 'Click on login name to edit!' => 'Kliknij nazwê u¿ytkownika ¿eby dokonaæ zmian!',
+ 'Close Books up to' => 'Zamkniêcie Ksi±g do',
+ 'Closed' => 'Zamkniêto',
+ 'Company' => 'Firma',
+ 'Compare to' => 'Porównaj z',
+ 'Confirm!' => 'Potwierd¿!',
+ 'Connect to' => 'Pod³±cz do',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Kontynuj',
+ 'Copies' => 'Kopie',
+ 'Copy to COA' => 'Skopiuj do Planu Kont',
+ 'Create Chart of Accounts' => 'Utwórz Wzór Kont',
+ 'Create Dataset' => 'Utwórz Zbiór Danych',
+ 'Credit' => 'Kredyt',
+ 'Credit Limit' => 'Limit Kredytu',
+ 'Curr' => 'Waluta',
+ 'Currency' => 'Waluta',
+ 'Current' => 'Bi¿±cy',
+ 'Customer' => 'Klient',
+ 'Customer deleted!' => 'Klient usuniêty',
+ 'Customer missing!' => 'Brak Klienta',
+ 'Customer not on file!' => 'Brak Klienta w bazie danych',
+ 'Customer saved!' => 'Klient zapisany!',
+ 'Customers' => 'Klienci',
+ 'DBI not installed!' => 'Nie zainstalowane DBI!',
+ 'Database' => 'Baza Danych',
+ 'Database Administration' => 'Administracja Bazy Danych',
+ 'Database Driver not checked!' => 'Sterownik Bazy Danych nie zaznaczony!',
+ 'Database Host' => 'Host Bazy Danych',
+ 'Database User missing!' => 'Brak U¿ytkownika Bazy Danych!',
+ 'Dataset' => 'Zbiór Danych',
+ 'Dataset missing!' => 'Brak Zbioru Danych',
+ 'Dataset updated!' => 'Zbiór Danych uzupe³niony!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Termin P³atno¶ci',
+ 'Date Format' => 'Format Daty',
+ 'Date Paid' => 'Data Zap³aty',
+ 'Date missing!' => 'Brak Daty',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet i Kredyt siê niebalansuj±!',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Decimalplaces' => 'Miejsca Dziesiêtne',
+ 'Delete' => 'Usuñ',
+ 'Delete Account' => 'Usuñ Konto',
+ 'Delete Dataset' => 'Usuñ Zbior Danych',
+ 'Delivery Date' => 'Data Dostawy',
+ 'Deposit' => 'Wp³ata',
+ 'Description' => 'Opis',
+ 'Difference' => 'Ró¿nica',
+ 'Directory' => 'Katalog',
+ 'Discount' => 'Rabat',
+ 'Done' => 'Zrobione',
+ 'Drawing' => 'Rysunek',
+ 'Driver' => 'Sterownik',
+ 'Dropdown Limit' => 'Limit Rozwiniêcia',
+ 'Due' => 'P³atno¶æ',
+ 'Due Date' => 'Termin P³atno¶ci',
+ 'Due Date missing!' => 'Brak Terminu P³atno¶ci!',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'E-mail Wykaz do',
+ 'E-mail address missing!' => 'Brak adresu E-mail!',
+ 'Edit' => 'Zmieñ',
+ 'Edit Account' => 'Zmiany Konta',
+ 'Edit Accounts Payables Transaction' => 'Zmiany Transakcji Konta Zobowi±zañ',
+ 'Edit Accounts Receivables Transaction' => 'Zmiany Transakcji Konta Nale¿no¶ci',
+ 'Edit Assembly' => 'Zmiany Zestawieñ',
+ 'Edit GIFI' => 'Zmieñ GIFI',
+ 'Edit General Ledger Transaction' => 'Zmiany w Ksiêdze G³ównej',
+ 'Edit Part' => 'Zmiany Produktu',
+ 'Edit Preferences for' => 'Zmiany Preferencji dla',
+ 'Edit Project' => 'Zmiany Projektu',
+ 'Edit Purchase Invoice' => 'Zmiany Faktury Zamówienia',
+ 'Edit Purchase Order' => 'Zmiany Zamówienia Zakupu',
+ 'Edit Sales Invoice' => 'Zmiany Faktury Sprzeda¿y',
+ 'Edit Sales Order' => 'Zmiany Zamówienia Klienta',
+ 'Edit Service' => 'Zmiany Us³ug',
+ 'Edit Template' => 'Zmiany Wzorca',
+ 'Edit User' => 'Zmiany U¿ytkownika',
+ 'Employee' => 'Pracownik',
+ 'Enforce transaction reversal for all dates' => 'Egzekwój zmiany transakcji dla wszystkich okresów',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Wpisz symbole (nap. PLN:USD:EUR:YEN) krajowych i zagranicznych walut ',
+ 'Equity' => 'Kapita³',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate Difference' => 'Ró¿nica Kursowa',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Existing Datasets' => 'Istniej±cy Zbiór Danych',
+ 'Expense' => 'Koszt',
+ 'Expense Account' => 'Konto Kosztów',
+ 'Expense/Asset' => 'Koszt/Aktywy',
+ 'Extended' => 'Warto¶æ Netto',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'Foreign Exchange Gain' => 'Zysk przy Wymianie Walut',
+ 'Foreign Exchange Loss' => 'Strata przy Wymianie Walut',
+ 'From' => 'Od',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI usuniête',
+ 'GIFI missing!' => 'Brakuje GIFI',
+ 'GIFI saved!' => 'GIFI zapisane',
+ 'GL Transaction' => 'Transakcja Ksiêgi G³ównej',
+ 'General Ledger' => 'Ksiêga G³ówna',
+ 'Goods & Services' => 'Produkty i Us³ugi',
+ 'HTML Templates' => 'Szablony HTML',
+ 'Heading' => 'Nag³ówek',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Brak Nazwy Hosta',
+ 'ID' => 'Identyfikator',
+ 'Image' => 'Grafika',
+ 'In-line' => 'W³±czony',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Include in drop-down menus' => 'Do³±cz w menu rozwijanym',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Do³±cz Konto w formularzach Kontrachentów ¿eby wskazaæ ¿e podlegaj± opodatkowaniu',
+ 'Income' => 'Przychód',
+ 'Income Account' => 'Konto Przychodów',
+ 'Income Statement' => 'Rachunek Zysków i Strat',
+ 'Incorrect Dataset version!' => 'Nieprawid³owa wersja Zbioru Danych',
+ 'Incorrect Password!' => 'Nieprawid³owe Has³o',
+ 'Individual Items' => 'Indywidualne Czê¶ci',
+ 'Inventory' => 'Inwentarz',
+ 'Inventory Account' => 'Konto Materia³owe',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Ilo¶æ Inventarza musi byæ równa zero zanim bêdzie mozna zdezaktualizowaæ to z³o¿enie!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Ilo¶æ inventarza musi byæ równa zero zanim bêdzie mo¿na zdezaktualizowaæ t± czê¶æ!',
+ 'Inventory quantity must be zero!' => 'Ilo¶æc Inventarza musi byæ równa zero',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Data Wystawienia',
+ 'Invoice Date missing!' => 'Brak Daty Wystawienia',
+ 'Invoice Number' => 'Numer Faktury',
+ 'Invoice Number missing!' => 'Brak Numeru Faktury',
+ 'Invoice deleted!' => 'Faktura usuniêta',
+ 'Invoice posted!' => 'Faktura zatwierdzona',
+ 'Invoices' => 'Faktury',
+ 'Is this a summary account to record' => 'Czy jest to konto sumaryczne?',
+ 'Item deleted!' => 'Pozycja usuniêta',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'LaTeX Templates' => 'Szablony LaTeX',
+ 'Language' => 'Jêzyk',
+ 'Last Cost' => 'Cena Zakupu',
+ 'Last Invoice Number' => 'Ostatni Numer Faktury',
+ 'Last Numbers & Default Accounts' => 'Ostatnie Numery i Konta Domy¶lne',
+ 'Last Purchase Order Number' => 'Ostatni Numer Faktury Zamówienia',
+ 'Last Sales Order Number' => 'Ostatni Numer Faktury Sprzeda¿y',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Opu¶æ pole wêz³a i portu, chyba ¿e chcesz mieæ zdalne po³±czenie',
+ 'Liability' => 'Zobowi±zania',
+ 'Licensed to' => 'Licencja nale¿y do:',
+ 'Line Total' => 'Suma ca³kowita',
+ 'Link' => 'Dowi±zanie',
+ 'Link Accounts' => 'Konta dowi±zane',
+ 'List Accounts' => 'Spis Kont',
+ 'List GIFI' => 'Wykaz GIFI',
+ 'List Price' => 'Cena',
+ 'List Transactions' => 'Wykaz Transakcji',
+ 'Login' => 'Zarejestrój siê',
+ 'Logout' => 'Wyrejestrój siê',
+ 'Make' => 'Marka',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Model',
+ 'N/A' => 'N/A',
+ 'Name' => 'Nazwa',
+ 'Name missing!' => 'Brak Nazwy',
+ 'New Templates' => 'Nowe Szablony',
+ 'No' => 'Nie',
+ 'No Database Drivers available!' => 'Sterownik Bazy Danych jest niedostêpny',
+ 'No Dataset selected!' => 'Nie jest zaznaczony Zbiór Danych',
+ 'No email address for' => 'Brak adresu email',
+ 'No.' => '',
+ 'Notes' => 'Noty',
+ 'Nothing applied!' => 'Niczego nie zastosowano',
+ 'Nothing selected!' => 'Nic nie zaznaczone!',
+ 'Nothing to delete!' => 'Niema nic do usuniêcia!',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number Format' => 'Format Numeru',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'O' => 'O',
+ 'Obsolete' => 'Zdezaktualizowane',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'On Hand' => 'Na Stanie',
+ 'On Order' => 'Zamawiane',
+ 'Open' => 'Otworzono',
+ 'Oracle Database Administration' => 'Administracja Bazy Danych Oracle',
+ 'Order' => 'Zamówienie',
+ 'Order Date' => 'Data Zamówienia',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Entry' => 'Wystawianie Zamówieñ',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'Order deleted!' => 'Zamówienie usuniête',
+ 'Order saved!' => 'Zamówienie zapisane',
+ 'Ordered' => 'Zamówione',
+ 'Orphaned' => 'Zbêdne',
+ 'Out of balance!' => 'Niezgodne Saldo',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Paid' => 'Zap³acono',
+ 'Paid in full' => 'Zap³acono w ca³o¶ci',
+ 'Part' => 'Produkt',
+ 'Part Number missing!' => 'Brak Symbolu Produktu!',
+ 'Parts' => 'Produkty',
+ 'Parts Inventory' => 'Inwentarz',
+ 'Password' => 'Has³o',
+ 'Password changed!' => 'Has³o zmienione',
+ 'Payables' => 'Zobowi±zania',
+ 'Payment' => 'P³atno¶æ',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payment posted!' => 'P³atno¶æ zatwierdzona',
+ 'Payments' => 'P³atno¶ci',
+ 'Pg Database Administration' => 'Administracja Bazy Danych Pg',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Brak Portu',
+ 'Post' => 'Zatwierd¿',
+ 'Post as new' => 'Zatwierd¿ jako nowe',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Preferencje',
+ 'Preferences saved!' => 'Preferencje Zapisane!',
+ 'Price' => 'Cena Netto',
+ 'Print' => 'Drukuj',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Projekt',
+ 'Project Number missing!' => 'Brak Numeru Projektu',
+ 'Project deleted!' => 'Projekt usuniêty',
+ 'Project not on file!' => 'Brak Projektu w zbiorze danych!',
+ 'Project saved!' => 'Projekt zapisany',
+ 'Projects' => 'Projekty',
+ 'Purchase Invoice' => 'Faktura VAT Zakupu',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Purchase Orders' => 'Zamówienia Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'ROP' => 'PPZ',
+ 'Rate' => 'Stawka',
+ 'Recd' => 'Otrzymano',
+ 'Receipt' => 'Wp³ata',
+ 'Receipts' => 'Wp³aty',
+ 'Receivables' => 'Nale¿no¶ci',
+ 'Reconciliation' => 'Zgodno¶æ Rozliczeñ',
+ 'Record in' => 'Zapisz w',
+ 'Reference' => 'Odno¶nik',
+ 'Reference missing!' => 'Brak Odno¶nika',
+ 'Remaining' => 'Pozosta³e',
+ 'Report for' => 'Raport dla',
+ 'Reports' => 'Sprawozdania',
+ 'Required by' => 'Termin Dostawy',
+ 'Retained Earnings' => 'Zysk',
+ 'Sales' => 'Sprzeda¿',
+ 'Sales Invoice' => 'Faktura VAT Sprzeda¿y',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Sales Orders' => 'Zamówienia Klientów',
+ 'Save' => 'Zapisz',
+ 'Save as new' => 'Zapisz jako nowe',
+ 'Save to File' => 'Zapisz w zbiorze',
+ 'Screen' => 'Ekran',
+ 'Select a Dataset to delete and press "Continue"' => 'Wybierz Zbiór Danych do usuniêcia i naci¶nij "Kontynuj"',
+ 'Select all' => 'Wybierz wszystko',
+ 'Select from one of the items below' => 'Wybierz jeden z poni¿szych artyku³ów',
+ 'Select from one of the names below' => 'Wybierz nazwê z poni¿szych',
+ 'Select from one of the projects below' => 'Wybierz z projektów',
+ 'Select postscript or PDF!' => 'Wybierz postscript lub PDF',
+ 'Sell Price' => 'Cena Sprzeda¿y',
+ 'Send by E-Mail' => 'Wys³ano przy u¿yciu E-Mail',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Service' => 'Us³ugi',
+ 'Service Items' => 'Artyku³y Us³ugowe',
+ 'Service Number missing!' => 'Brak Numeru Us³ugi!',
+ 'Services' => 'Us³ugi',
+ 'Setup Templates' => 'Ustaw Szablony',
+ 'Ship' => 'Wy¶lij',
+ 'Ship to' => 'Wy¶lij do',
+ 'Ship via' => 'Wy¶lij przez',
+ 'Short' => 'Niedobór',
+ 'Signature' => 'Podpis',
+ 'Sold' => 'Sprzedane',
+ 'Source' => '¯ród³o',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Wykaz',
+ 'Statement Balance' => 'Wykaz Salda',
+ 'Statement sent to' => 'Wykaz wys³any do',
+ 'Statements sent to printer!' => 'Wykaz wys³any do drukarki',
+ 'Stock Assembly' => 'Wstaw Z³o¿enie',
+ 'Stylesheet' => 'Strona Stylowa',
+ 'Subject' => 'Tre¶æ',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'System' => 'System',
+ 'Tax' => 'Podatek',
+ 'Tax Accounts' => 'Konta Podatkowe',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'Tax collected' => 'Podatek pobrany',
+ 'Tax paid' => 'Podatek zap³acony',
+ 'Taxable' => 'Opodatkowane',
+ 'Template saved!' => 'Szablon zapisany',
+ 'Templates' => 'Szablony',
+ 'Terms: Net' => 'Warunki: Netto',
+ 'The following Datasets are not in use and can be deleted' => 'Te Zbiory Danych s± nieu¿ywane i mo¿na je usun±æ',
+ 'The following Datasets need to be updated' => 'Zbiory Danych do uzupe³nienia',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Jest to wstêpne sprawdzenie istniej±cych ¿róde³. Narazie nic nie bêdzie utworzone lub usuniête.',
+ 'To' => 'do',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => '¯eby dodaæ do grupy u¿ytkownika zmieñ nazwê, nazwê zarejestrowania i zapisz. Nowy u¿ytkownik z tymi samymi zmiennymi warto¶ciami bêdzie zapisany pod now± nazw± rejestruj±c±',
+ 'Top Level' => 'Najwy¿szy Poziom',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Transaction Date missing!' => 'Brak Daty Transakcji!',
+ 'Transaction deleted!' => 'Transakcja usuniêta',
+ 'Transaction posted!' => 'Transakcja zatwierdzona',
+ 'Transaction reversal enforced for all dates' => 'Zmiana transakcji narzucona dla wszystkich okresów',
+ 'Transaction reversal enforced up to' => 'Zmiana transakcji narzucona do',
+ 'Transactions' => 'Transakcje',
+ 'Transactions exist, cannot delete customer!' => 'Istniej± Transakcje, niemo¿na usun±æ odbiorcy',
+ 'Transactions exist, cannot delete vendor!' => 'Istniej± Transakcje, nie mo¿na usun±æ dostawcy',
+ 'Transactions exist; cannot delete account!' => 'Istniej± Transakcje, nie mo¿na usun±æ konta',
+ 'Trial Balance' => 'Bilans Porównawczy',
+ 'Unit' => 'Jednostka',
+ 'Unit of measure' => 'Jednostka miary',
+ 'Update' => 'Uzupe³nij',
+ 'Update Dataset' => 'Uzupe³nij Zbiór Danych',
+ 'Updated' => 'Uzupe³nione',
+ 'Use Templates' => 'U¿yj Szablony',
+ 'User' => 'U¿ytkownik',
+ 'User deleted!' => 'U¿ytkownik usuniêty',
+ 'User saved!' => 'U¿ytkownik zapisany',
+ 'Vendor' => 'Dostawca',
+ 'Vendor deleted!' => 'Dostawca usuniêty',
+ 'Vendor missing!' => 'Brak Dostawcy',
+ 'Vendor not on file!' => 'Brak Dostawcy w bazie danych',
+ 'Vendor saved!' => 'Dostawca zapisany',
+ 'Vendors' => 'Dostawcy',
+ 'Version' => 'Wersja',
+ 'Weight' => 'Waga',
+ 'Weight Unit' => 'Jednostka Wagi',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'Year End' => 'Koniec Roku Finansowego',
+ 'Yes' => 'Tak',
+ 'You are logged out!' => 'Jeste¶ wyrejestrowany!',
+ 'You did not enter a name!' => 'Nie wstawiono nazwy!',
+ 'You must enter a host and port for local and remote connections!' => 'Wstaw wêze³ i port dla lokalnego i zdalnego po³±czenia',
+ 'as at' => 'tak samo',
+ 'collected on sales' => 'zebrany przy sprzeda¿y',
+ 'days' => 'dni',
+ 'does not exist' => 'nie istnieje',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'for Period' => 'za Okres',
+ 'hr' => 'godz',
+ 'is already a member!' => 'Jest ju¿ cz³onkiem',
+ 'is not a member!' => 'Nie jest cz³onkiem',
+ 'localhost' => 'host lokalny',
+ 'paid on purchases' => 'zap³acony przy zakupach',
+ 'sent to printer' => 'wys³ano do drukarki',
+ 'successfully created!' => 'stworzone z powodzeniem',
+ 'successfully deleted!' => 'usuniête z powodzeniem',
+ 'to' => 'do',
+ 'website' => 'witryna WWW',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/am b/sql-ledger/locale/pl/am
new file mode 100644
index 0000000..98de453
--- /dev/null
+++ b/sql-ledger/locale/pl/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Ksiêga Zobowi±zañ',
+ 'AR' => 'Ksiêga Nale¿no¶ci',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Numer Konta',
+ 'Account Number missing!' => 'Brak Numeru Konta!',
+ 'Account Type' => 'Rodzaj Konta',
+ 'Account Type missing!' => 'Brak Rodzaju Konta!',
+ 'Account deleted!' => 'Usuniêto Konto',
+ 'Account saved!' => 'Zapisano Konto',
+ 'Add Account' => 'Dodaj Konto',
+ 'Add GIFI' => 'Dodaj GIFI',
+ 'Address' => 'Adres',
+ 'Asset' => 'Aktywy',
+ 'Audit Control' => 'Kontrola Audytu',
+ 'Backup sent to' => 'Kopia Zapasowa wys³ana do',
+ 'Books are open' => 'Ksiêgi otwarte',
+ 'Business Number' => 'NIP',
+ 'COGS' => 'Koszta Sprzeda¿y',
+ 'Cannot delete account!' => 'Nie mo¿esz usun±æ konta!',
+ 'Cannot delete default account!' => 'Konto Domy¶lne nie mo¿e byæ usuniête!',
+ 'Cannot save account!' => 'Nie mo¿na zapisaæ konta!',
+ 'Cannot save preferences!' => 'Nie mo¿na zapisaæ preferencji!',
+ 'Character Set' => 'Zestaw Znaków',
+ 'Chart of Accounts' => 'Plan Kont',
+ 'Close Books up to' => 'Zamkniêcie Ksi±g do',
+ 'Company' => 'Firma',
+ 'Continue' => 'Kontynuj',
+ 'Copy to COA' => 'Skopiuj do Planu Kont',
+ 'Credit' => 'Kredyt',
+ 'Date Format' => 'Format Daty',
+ 'Debit' => 'Debet',
+ 'Delete' => 'Usuñ',
+ 'Delete Account' => 'Usuñ Konto',
+ 'Description' => 'Opis',
+ 'Dropdown Limit' => 'Limit Rozwiniêcia',
+ 'E-mail' => 'E-mail',
+ 'Edit' => 'Zmieñ',
+ 'Edit Account' => 'Zmiany Konta',
+ 'Edit GIFI' => 'Zmieñ GIFI',
+ 'Edit Preferences for' => 'Zmiany Preferencji dla',
+ 'Edit Template' => 'Zmiany Wzorca',
+ 'Enforce transaction reversal for all dates' => 'Egzekwój zmiany transakcji dla wszystkich okresów',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Wpisz symbole (nap. PLN:USD:EUR:YEN) krajowych i zagranicznych walut ',
+ 'Equity' => 'Kapita³',
+ 'Expense' => 'Koszt',
+ 'Expense Account' => 'Konto Kosztów',
+ 'Expense/Asset' => 'Koszt/Aktywy',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Zysk przy Wymianie Walut',
+ 'Foreign Exchange Loss' => 'Strata przy Wymianie Walut',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI usuniête',
+ 'GIFI missing!' => 'Brakuje GIFI',
+ 'GIFI saved!' => 'GIFI zapisane',
+ 'Heading' => 'Nag³ówek',
+ 'Include in drop-down menus' => 'Do³±cz w menu rozwijanym',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Do³±cz Konto w formularzach Kontrachentów ¿eby wskazaæ ¿e podlegaj± opodatkowaniu',
+ 'Income' => 'Przychód',
+ 'Income Account' => 'Konto Przychodów',
+ 'Inventory' => 'Inwentarz',
+ 'Inventory Account' => 'Konto Materia³owe',
+ 'Is this a summary account to record' => 'Czy jest to konto sumaryczne?',
+ 'Language' => 'Jêzyk',
+ 'Last Invoice Number' => 'Ostatni Numer Faktury',
+ 'Last Numbers & Default Accounts' => 'Ostatnie Numery i Konta Domy¶lne',
+ 'Last Purchase Order Number' => 'Ostatni Numer Faktury Zamówienia',
+ 'Last Sales Order Number' => 'Ostatni Numer Faktury Sprzeda¿y',
+ 'Liability' => 'Zobowi±zania',
+ 'Link' => 'Dowi±zanie',
+ 'Name' => 'Nazwa',
+ 'No' => 'Nie',
+ 'No email address for' => 'Brak adresu email',
+ 'Number' => 'Numer Katalogu',
+ 'Number Format' => 'Format Numeru',
+ 'Parts Inventory' => 'Inwentarz',
+ 'Password' => 'Has³o',
+ 'Payables' => 'Zobowi±zania',
+ 'Payment' => 'P³atno¶æ',
+ 'Phone' => 'Tel.',
+ 'Preferences saved!' => 'Preferencje Zapisane!',
+ 'Rate' => 'Stawka',
+ 'Receivables' => 'Nale¿no¶ci',
+ 'Sales' => 'Sprzeda¿',
+ 'Save' => 'Zapisz',
+ 'Service Items' => 'Artyku³y Us³ugowe',
+ 'Ship via' => 'Wy¶lij przez',
+ 'Signature' => 'Podpis',
+ 'Stylesheet' => 'Strona Stylowa',
+ 'Tax' => 'Podatek',
+ 'Tax Accounts' => 'Konta Podatkowe',
+ 'Template saved!' => 'Szablon zapisany',
+ 'Transaction reversal enforced for all dates' => 'Zmiana transakcji narzucona dla wszystkich okresów',
+ 'Transaction reversal enforced up to' => 'Zmiana transakcji narzucona do',
+ 'Transactions exist; cannot delete account!' => 'Istniej± Transakcje, nie mo¿na usun±æ konta',
+ 'Weight Unit' => 'Jednostka Wagi',
+ 'Year End' => 'Koniec Roku Finansowego',
+ 'Yes' => 'Tak',
+ 'does not exist' => 'nie istnieje',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'dodaj_konto' => 'add_account',
+ 'kontynuj' => 'continue',
+ 'skopiuj_do_planu_kont' => 'copy_to_coa',
+ 'usuñ' => 'delete',
+ 'zmieñ' => 'edit',
+ 'zmiany_konta' => 'edit_account',
+ 'zapisz' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/ap b/sql-ledger/locale/pl/ap
new file mode 100644
index 0000000..5e5f8f8
--- /dev/null
+++ b/sql-ledger/locale/pl/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Transakcja Zobowi±zañ',
+ 'AP Transactions' => 'Transakcje Zobowi±zañ',
+ 'Account' => 'Konto',
+ 'Add Accounts Payables Transaction' => 'Rejestr w Ksiêdze Zobowi±zañ',
+ 'Address' => 'Adres',
+ 'Amount' => 'Kwota',
+ 'Amount Due' => 'Kwota Nale¿na',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Are you sure you want to delete Transaction' => 'Czy chcesz usun±æ Transakcjê?',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'Cannot delete transaction!' => 'Nie mo¿esz usun±æ transakcji!',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cannot post transaction for a closed period!' => 'Nie mo¿na zaksiêgowaæ transakcji po zamkniêciu okresu!',
+ 'Cannot post transaction!' => 'Nie mo¿esz zatwierdziæ transakcji!',
+ 'Closed' => 'Zamkniêto',
+ 'Confirm!' => 'Potwierd¿!',
+ 'Continue' => 'Kontynuj',
+ 'Currency' => 'Waluta',
+ 'Customer not on file!' => 'Brak Klienta w bazie danych',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data Zap³aty',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Delete' => 'Usuñ',
+ 'Description' => 'Opis',
+ 'Due Date' => 'Termin P³atno¶ci',
+ 'Due Date missing!' => 'Brak Terminu P³atno¶ci!',
+ 'Edit Accounts Payables Transaction' => 'Zmiany Transakcji Konta Zobowi±zañ',
+ 'Employee' => 'Pracownik',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'ID' => 'Identyfikator',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Data Wystawienia',
+ 'Invoice Date missing!' => 'Brak Daty Wystawienia',
+ 'Invoice Number' => 'Numer Faktury',
+ 'Invoice Number missing!' => 'Brak Numeru Faktury',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Open' => 'Otworzono',
+ 'Order' => 'Zamówienie',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Paid' => 'Zap³acono',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payments' => 'P³atno¶ci',
+ 'Post' => 'Zatwierd¿',
+ 'Post as new' => 'Zatwierd¿ jako nowe',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Brak Projektu w zbiorze danych!',
+ 'Purchase Invoice' => 'Faktura VAT Zakupu',
+ 'Select from one of the names below' => 'Wybierz nazwê z poni¿szych',
+ 'Select from one of the projects below' => 'Wybierz z projektów',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Source' => '¯ród³o',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'Tax' => 'Podatek',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Transaction deleted!' => 'Transakcja usuniêta',
+ 'Transaction posted!' => 'Transakcja zatwierdzona',
+ 'Update' => 'Uzupe³nij',
+ 'Vendor' => 'Dostawca',
+ 'Vendor missing!' => 'Brak Dostawcy',
+ 'Vendor not on file!' => 'Brak Dostawcy w bazie danych',
+ 'Yes' => 'Tak',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transakcja_zobowi±zañ' => 'ap_transaction',
+ 'rejestr_w_ksiêdze_zobowi±zañ' => 'add_accounts_payables_transaction',
+ 'kontynuj' => 'continue',
+ 'usuñ' => 'delete',
+ 'zmiany_transakcji_konta_zobowi±zañ' => 'edit_accounts_payables_transaction',
+ 'zatwierd¿' => 'post',
+ 'zatwierd¿_jako_nowe' => 'post_as_new',
+ 'faktura_vat_zakupu' => 'purchase_invoice',
+ 'uzupe³nij' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/ar b/sql-ledger/locale/pl/ar
new file mode 100644
index 0000000..22a90b8
--- /dev/null
+++ b/sql-ledger/locale/pl/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Transakcja Nale¿no¶ci',
+ 'AR Transactions' => 'Transakcje Nale¿no¶ci',
+ 'Account' => 'Konto',
+ 'Add Accounts Receivables Transaction' => 'Rejestr w Ksiêdze Nale¿no¶ci',
+ 'Address' => 'Adres',
+ 'Amount' => 'Kwota',
+ 'Amount Due' => 'Kwota Nale¿na',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Are you sure you want to delete Transaction' => 'Czy chcesz usun±æ Transakcjê?',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'Cannot delete transaction!' => 'Nie mo¿esz usun±æ transakcji!',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cannot post transaction for a closed period!' => 'Nie mo¿na zaksiêgowaæ transakcji po zamkniêciu okresu!',
+ 'Cannot post transaction!' => 'Nie mo¿esz zatwierdziæ transakcji!',
+ 'Closed' => 'Zamkniêto',
+ 'Confirm!' => 'Potwierd¿!',
+ 'Continue' => 'Kontynuj',
+ 'Credit Limit' => 'Limit Kredytu',
+ 'Currency' => 'Waluta',
+ 'Customer' => 'Klient',
+ 'Customer missing!' => 'Brak Klienta',
+ 'Customer not on file!' => 'Brak Klienta w bazie danych',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data Zap³aty',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Delete' => 'Usuñ',
+ 'Description' => 'Opis',
+ 'Due Date' => 'Termin P³atno¶ci',
+ 'Due Date missing!' => 'Brak Terminu P³atno¶ci!',
+ 'Edit Accounts Receivables Transaction' => 'Zmiany Transakcji Konta Nale¿no¶ci',
+ 'Employee' => 'Pracownik',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'ID' => 'Identyfikator',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Data Wystawienia',
+ 'Invoice Date missing!' => 'Brak Daty Wystawienia',
+ 'Invoice Number' => 'Numer Faktury',
+ 'Invoice Number missing!' => 'Brak Numeru Faktury',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Open' => 'Otworzono',
+ 'Order' => 'Zamówienie',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Paid' => 'Zap³acono',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payments' => 'P³atno¶ci',
+ 'Post' => 'Zatwierd¿',
+ 'Post as new' => 'Zatwierd¿ jako nowe',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Brak Projektu w zbiorze danych!',
+ 'Remaining' => 'Pozosta³e',
+ 'Sales Invoice' => 'Faktura VAT Sprzeda¿y',
+ 'Select from one of the names below' => 'Wybierz nazwê z poni¿szych',
+ 'Select from one of the projects below' => 'Wybierz z projektów',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Source' => '¯ród³o',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'Tax' => 'Podatek',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Transaction deleted!' => 'Transakcja usuniêta',
+ 'Transaction posted!' => 'Transakcja zatwierdzona',
+ 'Update' => 'Uzupe³nij',
+ 'Vendor not on file!' => 'Brak Dostawcy w bazie danych',
+ 'Yes' => 'Tak',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transakcja_nale¿no¶ci' => 'ar_transaction',
+ 'kontynuj' => 'continue',
+ 'usuñ' => 'delete',
+ 'zatwierd¿' => 'post',
+ 'zatwierd¿_jako_nowe' => 'post_as_new',
+ 'faktura_vat_sprzeda¿y' => 'sales_invoice',
+ 'uzupe³nij' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/arap b/sql-ledger/locale/pl/arap
new file mode 100644
index 0000000..b24860e
--- /dev/null
+++ b/sql-ledger/locale/pl/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adres',
+ 'Continue' => 'Kontynuj',
+ 'Customer not on file!' => 'Brak Klienta w bazie danych',
+ 'Description' => 'Opis',
+ 'Number' => 'Numer Katalogu',
+ 'Project not on file!' => 'Brak Projektu w zbiorze danych!',
+ 'Select from one of the names below' => 'Wybierz nazwê z poni¿szych',
+ 'Select from one of the projects below' => 'Wybierz z projektów',
+ 'Vendor not on file!' => 'Brak Dostawcy w bazie danych',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'kontynuj' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/ca b/sql-ledger/locale/pl/ca
new file mode 100644
index 0000000..07f9e6d
--- /dev/null
+++ b/sql-ledger/locale/pl/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'Balance' => 'Saldo',
+ 'Chart of Accounts' => 'Plan Kont',
+ 'Credit' => 'Kredyt',
+ 'Date' => 'Data',
+ 'Debit' => 'Debet',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Description' => 'Opis',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'List Transactions' => 'Wykaz Transakcji',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Reference' => 'Odno¶nik',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'To' => 'do',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'wykaz_transakcji' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/cp b/sql-ledger/locale/pl/cp
new file mode 100644
index 0000000..bd154d9
--- /dev/null
+++ b/sql-ledger/locale/pl/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Address' => 'Adres',
+ 'Amount' => 'Kwota',
+ 'Amount does not equal applied!' => 'Kwota nie jest równa',
+ 'Amount missing!' => 'Brakuje kwoty!',
+ 'Applied' => 'Zastosowano',
+ 'Cannot post payment!' => 'Nie mo¿esz zatwierdziæ p³atno¶ci!',
+ 'Cannot process payment for a closed period!' => 'Niemo¿na przetworzyæ p³atno¶ci po zamkniêciu okresu',
+ 'Check' => 'Czek',
+ 'Check printed!' => 'Czek wydrukowany!',
+ 'Check printing failed!' => 'B³±dw drukowaniu czeku',
+ 'Continue' => 'Kontynuj',
+ 'Currency' => 'Waluta',
+ 'Customer' => 'Klient',
+ 'Customer not on file!' => 'Brak Klienta w bazie danych',
+ 'Date' => 'Data',
+ 'Date missing!' => 'Brak Daty',
+ 'Description' => 'Opis',
+ 'Due' => 'P³atno¶æ',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'From' => 'Od',
+ 'Invoice' => 'Faktura',
+ 'Invoices' => 'Faktury',
+ 'Nothing applied!' => 'Niczego nie zastosowano',
+ 'Number' => 'Numer Katalogu',
+ 'Paid in full' => 'Zap³acono w ca³o¶ci',
+ 'Payment' => 'P³atno¶æ',
+ 'Payment posted!' => 'P³atno¶æ zatwierdzona',
+ 'Post' => 'Zatwierd¿',
+ 'Print' => 'Drukuj',
+ 'Printer' => 'Drukarka',
+ 'Project not on file!' => 'Brak Projektu w zbiorze danych!',
+ 'Receipt' => 'Wp³ata',
+ 'Reference' => 'Odno¶nik',
+ 'Screen' => 'Ekran',
+ 'Select from one of the names below' => 'Wybierz nazwê z poni¿szych',
+ 'Select from one of the projects below' => 'Wybierz z projektów',
+ 'To' => 'do',
+ 'Update' => 'Uzupe³nij',
+ 'Vendor' => 'Dostawca',
+ 'Vendor not on file!' => 'Brak Dostawcy w bazie danych',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'kontynuj' => 'continue',
+ 'zatwierd¿' => 'post',
+ 'drukuj' => 'print',
+ 'uzupe³nij' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/ct b/sql-ledger/locale/pl/ct
new file mode 100644
index 0000000..e210cda
--- /dev/null
+++ b/sql-ledger/locale/pl/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Dodaj',
+ 'Address' => 'Adres',
+ 'All' => 'Wszystko',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Nie mo¿esz usun±æ klienta!',
+ 'Cannot delete vendor!' => 'Nie mo¿esz usun±æ dostawcy!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Kontynuj',
+ 'Credit Limit' => 'Limit Kredytu',
+ 'Customer deleted!' => 'Klient usuniêty',
+ 'Customer saved!' => 'Klient zapisany!',
+ 'Customers' => 'Klienci',
+ 'Delete' => 'Usuñ',
+ 'Discount' => 'Rabat',
+ 'E-mail' => 'E-mail',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Invoice' => 'Faktura',
+ 'Name' => 'Nazwa',
+ 'Name missing!' => 'Brak Nazwy',
+ 'Notes' => 'Noty',
+ 'Number' => 'Numer Katalogu',
+ 'Order' => 'Zamówienie',
+ 'Orphaned' => 'Zbêdne',
+ 'Phone' => 'Tel.',
+ 'Save' => 'Zapisz',
+ 'Ship to' => 'Wy¶lij do',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'Taxable' => 'Opodatkowane',
+ 'Terms: Net' => 'Warunki: Netto',
+ 'Transactions exist, cannot delete customer!' => 'Istniej± Transakcje, niemo¿na usun±æ odbiorcy',
+ 'Transactions exist, cannot delete vendor!' => 'Istniej± Transakcje, nie mo¿na usun±æ dostawcy',
+ 'Vendor deleted!' => 'Dostawca usuniêty',
+ 'Vendor saved!' => 'Dostawca zapisany',
+ 'Vendors' => 'Dostawcy',
+ 'days' => 'dni',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'dodaj' => 'add',
+ 'kontynuj' => 'continue',
+ 'usuñ' => 'delete',
+ 'faktura' => 'invoice',
+ 'zamówienie' => 'order',
+ 'zapisz' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/gl b/sql-ledger/locale/pl/gl
new file mode 100644
index 0000000..1f8883f
--- /dev/null
+++ b/sql-ledger/locale/pl/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Transakcja Zobowi±zañ',
+ 'AR Transaction' => 'Transakcja Nale¿no¶ci',
+ 'Account' => 'Konto',
+ 'Add General Ledger Transaction' => 'Dodaj Transakcjê w Ksiêdze G³ównej',
+ 'Address' => 'Adres',
+ 'All' => 'Wszystko',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Are you sure you want to delete Transaction' => 'Czy chcesz usun±æ Transakcjê?',
+ 'Asset' => 'Aktywy',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'Balance' => 'Saldo',
+ 'Cannot delete transaction!' => 'Nie mo¿esz usun±æ transakcji!',
+ 'Cannot have a value in both Debit and Credit!' => 'Nie mo¿na wpisaæ warto¶ci w Debet i Kredyt równocze¶nie!',
+ 'Cannot post a transaction without a value!' => 'Nie mo¿esz zatwierdziæ transakcji bez warto¶ci',
+ 'Cannot post transaction for a closed period!' => 'Nie mo¿na zaksiêgowaæ transakcji po zamkniêciu okresu!',
+ 'Confirm!' => 'Potwierd¿!',
+ 'Continue' => 'Kontynuj',
+ 'Credit' => 'Kredyt',
+ 'Customer not on file!' => 'Brak Klienta w bazie danych',
+ 'Date' => 'Data',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet i Kredyt siê niebalansuj±!',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Delete' => 'Usuñ',
+ 'Description' => 'Opis',
+ 'Edit General Ledger Transaction' => 'Zmiany w Ksiêdze G³ównej',
+ 'Equity' => 'Kapita³',
+ 'Expense' => 'Koszt',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'Transakcja Ksiêgi G³ównej',
+ 'General Ledger' => 'Ksiêga G³ówna',
+ 'ID' => 'Identyfikator',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Income' => 'Przychód',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'Liability' => 'Zobowi±zania',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Post' => 'Zatwierd¿',
+ 'Post as new' => 'Zatwierd¿ jako nowe',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Brak Projektu w zbiorze danych!',
+ 'Purchase Invoice' => 'Faktura VAT Zakupu',
+ 'Reference' => 'Odno¶nik',
+ 'Reference missing!' => 'Brak Odno¶nika',
+ 'Reports' => 'Sprawozdania',
+ 'Sales Invoice' => 'Faktura VAT Sprzeda¿y',
+ 'Select from one of the names below' => 'Wybierz nazwê z poni¿szych',
+ 'Select from one of the projects below' => 'Wybierz z projektów',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Source' => '¯ród³o',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'To' => 'do',
+ 'Transaction Date missing!' => 'Brak Daty Transakcji!',
+ 'Transaction deleted!' => 'Transakcja usuniêta',
+ 'Transaction posted!' => 'Transakcja zatwierdzona',
+ 'Update' => 'Uzupe³nij',
+ 'Vendor not on file!' => 'Brak Dostawcy w bazie danych',
+ 'Yes' => 'Tak',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transakcja_zobowi±zañ' => 'ap_transaction',
+ 'transakcja_nale¿no¶ci' => 'ar_transaction',
+ 'kontynuj' => 'continue',
+ 'usuñ' => 'delete',
+ 'transakcja_ksiêgi_g³ównej' => 'gl_transaction',
+ 'zatwierd¿' => 'post',
+ 'zatwierd¿_jako_nowe' => 'post_as_new',
+ 'faktura_vat_zakupu' => 'purchase_invoice',
+ 'faktura_vat_sprzeda¿y' => 'sales_invoice',
+ 'uzupe³nij' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/ic b/sql-ledger/locale/pl/ic
new file mode 100644
index 0000000..c7fc309
--- /dev/null
+++ b/sql-ledger/locale/pl/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Aktywne',
+ 'Add' => 'Dodaj',
+ 'Add Assembly' => 'Dodaj Zestawienie',
+ 'Add Part' => 'Dodaj Produkt',
+ 'Add Purchase Order' => 'Dodaj Zamówienie Zakupu',
+ 'Add Sales Order' => 'Dodaj Zamówienie Klienta',
+ 'Add Service' => 'Dodaj Us³ugi',
+ 'Address' => 'Adres',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Assemblies' => 'Zestawienia',
+ 'Assemblies restocked!' => 'Zestawienia uzupe³nione',
+ 'Assembly Number missing!' => 'Brak Numeru Zestawienia!',
+ 'Attachment' => 'Za³±cznik',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'BOM' => 'Zestawienie materia³owe',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Pojemnik',
+ 'Bought' => 'Zakupione',
+ 'COGS' => 'Koszta Sprzeda¿y',
+ 'Cannot delete item already invoiced!' => 'Nie mo¿na usun±æ pozycji zafakturowanej!',
+ 'Cannot delete item on order!' => 'Nie mo¿na usunac zamówionego produktu!',
+ 'Cannot delete item which is part of an assembly!' => 'Nie mo¿na usun±æ czê¶ci z zestawienia!',
+ 'Cannot delete item!' => 'Nie mo¿esz usun±æ pozycji!',
+ 'Cannot stock assemblies!' => 'Nie mo¿na wstawiæ z³o¿enia',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Kontynuj',
+ 'Copies' => 'Kopie',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Delete' => 'Usuñ',
+ 'Delivery Date' => 'Data Dostawy',
+ 'Description' => 'Opis',
+ 'Drawing' => 'Rysunek',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Brak adresu E-mail!',
+ 'Edit Assembly' => 'Zmiany Zestawieñ',
+ 'Edit Part' => 'Zmiany Produktu',
+ 'Edit Service' => 'Zmiany Us³ug',
+ 'Expense' => 'Koszt',
+ 'Extended' => 'Warto¶æ Netto',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'Image' => 'Grafika',
+ 'In-line' => 'W³±czony',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Income' => 'Przychód',
+ 'Individual Items' => 'Indywidualne Czê¶ci',
+ 'Inventory' => 'Inwentarz',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Ilo¶æ Inventarza musi byæ równa zero zanim bêdzie mozna zdezaktualizowaæ to z³o¿enie!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Ilo¶æ inventarza musi byæ równa zero zanim bêdzie mo¿na zdezaktualizowaæ t± czê¶æ!',
+ 'Inventory quantity must be zero!' => 'Ilo¶æc Inventarza musi byæ równa zero',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Brak Daty Wystawienia',
+ 'Invoice Number' => 'Numer Faktury',
+ 'Invoice Number missing!' => 'Brak Numeru Faktury',
+ 'Item deleted!' => 'Pozycja usuniêta',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'Last Cost' => 'Cena Zakupu',
+ 'Line Total' => 'Suma ca³kowita',
+ 'Link Accounts' => 'Konta dowi±zane',
+ 'List Price' => 'Cena',
+ 'Make' => 'Marka',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Microfiche' => 'Mikrofilm',
+ 'Model' => 'Model',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'Obsolete' => 'Zdezaktualizowane',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'On Hand' => 'Na Stanie',
+ 'On Order' => 'Zamawiane',
+ 'Order' => 'Zamówienie',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'Ordered' => 'Zamówione',
+ 'Orphaned' => 'Zbêdne',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Part Number missing!' => 'Brak Symbolu Produktu!',
+ 'Parts' => 'Produkty',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'ROP' => 'PPZ',
+ 'Recd' => 'Otrzymano',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales' => 'Sprzeda¿',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Save' => 'Zapisz',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybierz jeden z poni¿szych artyku³ów',
+ 'Select postscript or PDF!' => 'Wybierz postscript lub PDF',
+ 'Sell Price' => 'Cena Sprzeda¿y',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Service' => 'Us³ugi',
+ 'Service Number missing!' => 'Brak Numeru Us³ugi!',
+ 'Services' => 'Us³ugi',
+ 'Ship' => 'Wy¶lij',
+ 'Ship to' => 'Wy¶lij do',
+ 'Short' => 'Niedobór',
+ 'Sold' => 'Sprzedane',
+ 'Stock Assembly' => 'Wstaw Z³o¿enie',
+ 'Subject' => 'Tre¶æ',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'Tax' => 'Podatek',
+ 'To' => 'do',
+ 'Top Level' => 'Najwy¿szy Poziom',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Unit' => 'Jednostka',
+ 'Unit of measure' => 'Jednostka miary',
+ 'Update' => 'Uzupe³nij',
+ 'Updated' => 'Uzupe³nione',
+ 'Weight' => 'Waga',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'hr' => 'godz',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'dodaj' => 'add',
+ 'dodaj_zestawienie' => 'add_assembly',
+ 'dodaj_produkt' => 'add_part',
+ 'dodaj_us³ugi' => 'add_service',
+ 'kontynuj' => 'continue',
+ 'usuñ' => 'delete',
+ 'zmiany_zestawieñ' => 'edit_assembly',
+ 'zmiany_produktu' => 'edit_part',
+ 'zmiany_us³ug' => 'edit_service',
+ 'zapisz' => 'save',
+ 'uzupe³nij' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/io b/sql-ledger/locale/pl/io
new file mode 100644
index 0000000..9807907
--- /dev/null
+++ b/sql-ledger/locale/pl/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Dodaj Zamówienie Zakupu',
+ 'Add Sales Order' => 'Dodaj Zamówienie Klienta',
+ 'Address' => 'Adres',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Attachment' => 'Za³±cznik',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Pojemnik',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Kontynuj',
+ 'Copies' => 'Kopie',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Delivery Date' => 'Data Dostawy',
+ 'Description' => 'Opis',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Brak adresu E-mail!',
+ 'Extended' => 'Warto¶æ Netto',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'In-line' => 'W³±czony',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Brak Daty Wystawienia',
+ 'Invoice Number missing!' => 'Brak Numeru Faktury',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Order' => 'Zamówienie',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'Recd' => 'Otrzymano',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybierz jeden z poni¿szych artyku³ów',
+ 'Select postscript or PDF!' => 'Wybierz postscript lub PDF',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Service' => 'Us³ugi',
+ 'Ship' => 'Wy¶lij',
+ 'Ship to' => 'Wy¶lij do',
+ 'Subject' => 'Tre¶æ',
+ 'To' => 'do',
+ 'Unit' => 'Jednostka',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'kontynuj' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/ir b/sql-ledger/locale/pl/ir
new file mode 100644
index 0000000..2196cd1
--- /dev/null
+++ b/sql-ledger/locale/pl/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Invoice' => 'Zarejestrój Fakturê VAT Zakupu',
+ 'Add Purchase Order' => 'Dodaj Zamówienie Zakupu',
+ 'Add Sales Order' => 'Dodaj Zamówienie Klienta',
+ 'Address' => 'Adres',
+ 'Amount' => 'Kwota',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Are you sure you want to delete Invoice Number' => 'Czy chcesz usun±æ Numer Faktury?',
+ 'Attachment' => 'Za³±cznik',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Pojemnik',
+ 'Cannot delete invoice!' => 'Nie mo¿esz usun±æ factury!',
+ 'Cannot post invoice for a closed period!' => 'Nie mo¿na zksiêgowaæ faktury pozamkniêciu okresu!',
+ 'Cannot post invoice!' => 'Nie mo¿esz zatwierdziæ faktury!',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Potwierd¿!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Kontynuj',
+ 'Copies' => 'Kopie',
+ 'Currency' => 'Waluta',
+ 'Customer not on file!' => 'Brak Klienta w bazie danych',
+ 'Date' => 'Data',
+ 'Date Due' => 'Termin P³atno¶ci',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Delete' => 'Usuñ',
+ 'Delivery Date' => 'Data Dostawy',
+ 'Description' => 'Opis',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Brak adresu E-mail!',
+ 'Edit Purchase Invoice' => 'Zmiany Faktury Zamówienia',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Extended' => 'Warto¶æ Netto',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'In-line' => 'W³±czony',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Data Wystawienia',
+ 'Invoice Date missing!' => 'Brak Daty Wystawienia',
+ 'Invoice Number' => 'Numer Faktury',
+ 'Invoice Number missing!' => 'Brak Numeru Faktury',
+ 'Invoice deleted!' => 'Faktura usuniêta',
+ 'Invoice posted!' => 'Faktura zatwierdzona',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Order' => 'Zamówienie',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payments' => 'P³atno¶ci',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Zatwierd¿',
+ 'Post as new' => 'Zatwierd¿ jako nowe',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Brak Projektu w zbiorze danych!',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'Recd' => 'Otrzymano',
+ 'Record in' => 'Zapisz w',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybierz jeden z poni¿szych artyku³ów',
+ 'Select from one of the names below' => 'Wybierz nazwê z poni¿szych',
+ 'Select from one of the projects below' => 'Wybierz z projektów',
+ 'Select postscript or PDF!' => 'Wybierz postscript lub PDF',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Service' => 'Us³ugi',
+ 'Ship' => 'Wy¶lij',
+ 'Ship to' => 'Wy¶lij do',
+ 'Source' => '¯ród³o',
+ 'Subject' => 'Tre¶æ',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Unit' => 'Jednostka',
+ 'Update' => 'Uzupe³nij',
+ 'Vendor' => 'Dostawca',
+ 'Vendor missing!' => 'Brak Dostawcy',
+ 'Vendor not on file!' => 'Brak Dostawcy w bazie danych',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'Yes' => 'Tak',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'kontynuj' => 'continue',
+ 'usuñ' => 'delete',
+ 'zamówienie' => 'order',
+ 'zatwierd¿' => 'post',
+ 'zatwierd¿_jako_nowe' => 'post_as_new',
+ 'uzupe³nij' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/is b/sql-ledger/locale/pl/is
new file mode 100644
index 0000000..b431b77
--- /dev/null
+++ b/sql-ledger/locale/pl/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Order' => 'Dodaj Zamówienie Zakupu',
+ 'Add Sales Invoice' => 'Zarejestrój Fakturê VAT Sprzeda¿y',
+ 'Add Sales Order' => 'Dodaj Zamówienie Klienta',
+ 'Address' => 'Adres',
+ 'Amount' => 'Kwota',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Are you sure you want to delete Invoice Number' => 'Czy chcesz usun±æ Numer Faktury?',
+ 'Attachment' => 'Za³±cznik',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Pojemnik',
+ 'Cannot delete invoice!' => 'Nie mo¿esz usun±æ factury!',
+ 'Cannot post invoice for a closed period!' => 'Nie mo¿na zksiêgowaæ faktury pozamkniêciu okresu!',
+ 'Cannot post invoice!' => 'Nie mo¿esz zatwierdziæ faktury!',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Potwierd¿!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Kontynuj',
+ 'Copies' => 'Kopie',
+ 'Credit Limit' => 'Limit Kredytu',
+ 'Currency' => 'Waluta',
+ 'Customer' => 'Klient',
+ 'Customer missing!' => 'Brak Klienta',
+ 'Customer not on file!' => 'Brak Klienta w bazie danych',
+ 'Date' => 'Data',
+ 'Date Due' => 'Termin P³atno¶ci',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Delete' => 'Usuñ',
+ 'Delivery Date' => 'Data Dostawy',
+ 'Description' => 'Opis',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Brak adresu E-mail!',
+ 'Edit Sales Invoice' => 'Zmiany Faktury Sprzeda¿y',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Extended' => 'Warto¶æ Netto',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'In-line' => 'W³±czony',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Data Wystawienia',
+ 'Invoice Date missing!' => 'Brak Daty Wystawienia',
+ 'Invoice Number' => 'Numer Faktury',
+ 'Invoice Number missing!' => 'Brak Numeru Faktury',
+ 'Invoice deleted!' => 'Faktura usuniêta',
+ 'Invoice posted!' => 'Faktura zatwierdzona',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Order' => 'Zamówienie',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payments' => 'P³atno¶ci',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Zatwierd¿',
+ 'Post as new' => 'Zatwierd¿ jako nowe',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Print' => 'Drukuj',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Brak Projektu w zbiorze danych!',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'Recd' => 'Otrzymano',
+ 'Record in' => 'Zapisz w',
+ 'Remaining' => 'Pozosta³e',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybierz jeden z poni¿szych artyku³ów',
+ 'Select from one of the names below' => 'Wybierz nazwê z poni¿szych',
+ 'Select from one of the projects below' => 'Wybierz z projektów',
+ 'Select postscript or PDF!' => 'Wybierz postscript lub PDF',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Service' => 'Us³ugi',
+ 'Ship' => 'Wy¶lij',
+ 'Ship to' => 'Wy¶lij do',
+ 'Ship via' => 'Wy¶lij przez',
+ 'Source' => '¯ród³o',
+ 'Subject' => 'Tre¶æ',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Unit' => 'Jednostka',
+ 'Update' => 'Uzupe³nij',
+ 'Vendor not on file!' => 'Brak Dostawcy w bazie danych',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'Yes' => 'Tak',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'kontynuj' => 'continue',
+ 'usuñ' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'zamówienie' => 'order',
+ 'zatwierd¿' => 'post',
+ 'zatwierd¿_jako_nowe' => 'post_as_new',
+ 'drukuj' => 'print',
+ 'wy¶lij_do' => 'ship_to',
+ 'uzupe³nij' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/login b/sql-ledger/locale/pl/login
new file mode 100644
index 0000000..cd96d95
--- /dev/null
+++ b/sql-ledger/locale/pl/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'Na Temat',
+ 'Accounting' => 'Ksiêgowo¶æ',
+ 'Database Host' => 'Host Bazy Danych',
+ 'Dataset' => 'Zbiór Danych',
+ 'Incorrect Dataset version!' => 'Nieprawid³owa wersja Zbioru Danych',
+ 'Incorrect Password!' => 'Nieprawid³owe Has³o',
+ 'Licensed to' => 'Licencja nale¿y do:',
+ 'Login' => 'Zarejestrój siê',
+ 'Name' => 'Nazwa',
+ 'Password' => 'Has³o',
+ 'User' => 'U¿ytkownik',
+ 'Version' => 'Wersja',
+ 'You are logged out!' => 'Jeste¶ wyrejestrowany!',
+ 'You did not enter a name!' => 'Nie wstawiono nazwy!',
+ 'is not a member!' => 'Nie jest cz³onkiem',
+ 'localhost' => 'host lokalny',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'zarejestrój_siê' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/menu b/sql-ledger/locale/pl/menu
new file mode 100644
index 0000000..0bd3b89
--- /dev/null
+++ b/sql-ledger/locale/pl/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'Ksiêga Zobowi±zañ',
+ 'AP Aging' => 'Zobowi±zania Przeterminowane',
+ 'AR' => 'Ksiêga Nale¿no¶ci',
+ 'AR Aging' => 'Nale¿no¶ci Przeterminowane',
+ 'Accounting Menu' => 'Menu Ksiêgowo¶ci',
+ 'Add Account' => 'Dodaj Konto',
+ 'Add Assembly' => 'Dodaj Zestawienie',
+ 'Add Customer' => 'Dodaj Odbiorcê',
+ 'Add GIFI' => 'Dodaj GIFI',
+ 'Add Part' => 'Dodaj Produkt',
+ 'Add Project' => 'Dodaj Projekt',
+ 'Add Service' => 'Dodaj Us³ugi',
+ 'Add Transaction' => 'Dodaj Transakcjê',
+ 'Add Vendor' => 'Dodaj Dostawcê',
+ 'Assemblies' => 'Zestawienia',
+ 'Audit Control' => 'Kontrola Audytu',
+ 'Backup' => 'Kopia Zapasowa',
+ 'Balance Sheet' => 'Bilans',
+ 'Cash' => 'Kasa',
+ 'Chart of Accounts' => 'Plan Kont',
+ 'Check' => 'Czek',
+ 'Customers' => 'Klienci',
+ 'General Ledger' => 'Ksiêga G³ówna',
+ 'Goods & Services' => 'Produkty i Us³ugi',
+ 'HTML Templates' => 'Szablony HTML',
+ 'Income Statement' => 'Rachunek Zysków i Strat',
+ 'Invoice' => 'Faktura',
+ 'LaTeX Templates' => 'Szablony LaTeX',
+ 'List Accounts' => 'Spis Kont',
+ 'List GIFI' => 'Wykaz GIFI',
+ 'Logout' => 'Wyrejestrój siê',
+ 'Order Entry' => 'Wystawianie Zamówieñ',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Parts' => 'Produkty',
+ 'Payment' => 'P³atno¶æ',
+ 'Payments' => 'P³atno¶ci',
+ 'Preferences' => 'Preferencje',
+ 'Projects' => 'Projekty',
+ 'Purchase Invoice' => 'Faktura VAT Zakupu',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Purchase Orders' => 'Zamówienia Zakupu',
+ 'Receipt' => 'Wp³ata',
+ 'Receipts' => 'Wp³aty',
+ 'Reconciliation' => 'Zgodno¶æ Rozliczeñ',
+ 'Reports' => 'Sprawozdania',
+ 'Sales Invoice' => 'Faktura VAT Sprzeda¿y',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Sales Orders' => 'Zamówienia Klientów',
+ 'Save to File' => 'Zapisz w zbiorze',
+ 'Send by E-Mail' => 'Wys³ano przy u¿yciu E-Mail',
+ 'Services' => 'Us³ugi',
+ 'Statement' => 'Wykaz',
+ 'Stock Assembly' => 'Wstaw Z³o¿enie',
+ 'Stylesheet' => 'Strona Stylowa',
+ 'System' => 'System',
+ 'Tax collected' => 'Podatek pobrany',
+ 'Tax paid' => 'Podatek zap³acony',
+ 'Transactions' => 'Transakcje',
+ 'Trial Balance' => 'Bilans Porównawczy',
+ 'Vendors' => 'Dostawcy',
+ 'Version' => 'Wersja',
+ 'localhost' => 'host lokalny',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/oe b/sql-ledger/locale/pl/oe
new file mode 100644
index 0000000..511b834
--- /dev/null
+++ b/sql-ledger/locale/pl/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Dodaj',
+ 'Add Purchase Invoice' => 'Zarejestrój Fakturê VAT Zakupu',
+ 'Add Purchase Order' => 'Dodaj Zamówienie Zakupu',
+ 'Add Sales Invoice' => 'Zarejestrój Fakturê VAT Sprzeda¿y',
+ 'Add Sales Order' => 'Dodaj Zamówienie Klienta',
+ 'Address' => 'Adres',
+ 'Amount' => 'Kwota',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Are you sure you want to delete Order Number' => 'Czy chcesz usun±æ Numer Zamówienia?',
+ 'Attachment' => 'Za³±cznik',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Pojemnik',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Nie mo¿esz usun±æ zamówienia!',
+ 'Cannot save order!' => 'Nie mo¿na zapisaæ zamowienia!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Zamkniêto',
+ 'Confirm!' => 'Potwierd¿!',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Kontynuj',
+ 'Copies' => 'Kopie',
+ 'Credit Limit' => 'Limit Kredytu',
+ 'Curr' => 'Waluta',
+ 'Currency' => 'Waluta',
+ 'Customer' => 'Klient',
+ 'Customer missing!' => 'Brak Klienta',
+ 'Customer not on file!' => 'Brak Klienta w bazie danych',
+ 'Date' => 'Data',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Delete' => 'Usuñ',
+ 'Delivery Date' => 'Data Dostawy',
+ 'Description' => 'Opis',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Brak adresu E-mail!',
+ 'Edit Purchase Order' => 'Zmiany Zamówienia Zakupu',
+ 'Edit Sales Order' => 'Zmiany Zamówienia Klienta',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Extended' => 'Warto¶æ Netto',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'ID' => 'Identyfikator',
+ 'In-line' => 'W³±czony',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Brak Daty Wystawienia',
+ 'Invoice Number missing!' => 'Brak Numeru Faktury',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'O' => 'O',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Open' => 'Otworzono',
+ 'Order' => 'Zamówienie',
+ 'Order Date' => 'Data Zamówienia',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'Order deleted!' => 'Zamówienie usuniête',
+ 'Order saved!' => 'Zamówienie zapisane',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Print' => 'Drukuj',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Brak Projektu w zbiorze danych!',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Purchase Orders' => 'Zamówienia Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'Recd' => 'Otrzymano',
+ 'Remaining' => 'Pozosta³e',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Sales Orders' => 'Zamówienia Klientów',
+ 'Save' => 'Zapisz',
+ 'Save as new' => 'Zapisz jako nowe',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybierz jeden z poni¿szych artyku³ów',
+ 'Select from one of the names below' => 'Wybierz nazwê z poni¿szych',
+ 'Select from one of the projects below' => 'Wybierz z projektów',
+ 'Select postscript or PDF!' => 'Wybierz postscript lub PDF',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Service' => 'Us³ugi',
+ 'Ship' => 'Wy¶lij',
+ 'Ship to' => 'Wy¶lij do',
+ 'Ship via' => 'Wy¶lij przez',
+ 'Subject' => 'Tre¶æ',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'Tax' => 'Podatek',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'Terms: Net' => 'Warunki: Netto',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Unit' => 'Jednostka',
+ 'Update' => 'Uzupe³nij',
+ 'Vendor' => 'Dostawca',
+ 'Vendor missing!' => 'Brak Dostawcy',
+ 'Vendor not on file!' => 'Brak Dostawcy w bazie danych',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'Yes' => 'Tak',
+ 'days' => 'dni',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'dodaj' => 'add',
+ 'kontynuj' => 'continue',
+ 'usuñ' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'faktura' => 'invoice',
+ 'drukuj' => 'print',
+ 'zapisz' => 'save',
+ 'zapisz_jako_nowe' => 'save_as_new',
+ 'wy¶lij_do' => 'ship_to',
+ 'uzupe³nij' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/pe b/sql-ledger/locale/pl/pe
new file mode 100644
index 0000000..88ab7fd
--- /dev/null
+++ b/sql-ledger/locale/pl/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Dodaj',
+ 'Add Project' => 'Dodaj Projekt',
+ 'All' => 'Wszystko',
+ 'Continue' => 'Kontynuj',
+ 'Delete' => 'Usuñ',
+ 'Description' => 'Opis',
+ 'Edit Project' => 'Zmiany Projektu',
+ 'Number' => 'Numer Katalogu',
+ 'Orphaned' => 'Zbêdne',
+ 'Project' => 'Projekt',
+ 'Project Number missing!' => 'Brak Numeru Projektu',
+ 'Project deleted!' => 'Projekt usuniêty',
+ 'Project saved!' => 'Projekt zapisany',
+ 'Projects' => 'Projekty',
+ 'Save' => 'Zapisz',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'dodaj' => 'add',
+ 'kontynuj' => 'continue',
+ 'usuñ' => 'delete',
+ 'zapisz' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/rc b/sql-ledger/locale/pl/rc
new file mode 100644
index 0000000..98bc9bd
--- /dev/null
+++ b/sql-ledger/locale/pl/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Balance' => 'Saldo',
+ 'Cleared Balance' => 'Zgadzaj±ce Saldo',
+ 'Continue' => 'Kontynuj',
+ 'Date' => 'Data',
+ 'Deposit' => 'Wp³ata',
+ 'Description' => 'Opis',
+ 'Difference' => 'Ró¿nica',
+ 'Done' => 'Zrobione',
+ 'Exchangerate Difference' => 'Ró¿nica Kursowa',
+ 'From' => 'Od',
+ 'Out of balance!' => 'Niezgodne Saldo',
+ 'Payment' => 'P³atno¶æ',
+ 'Reconciliation' => 'Zgodno¶æ Rozliczeñ',
+ 'Select all' => 'Wybierz wszystko',
+ 'Source' => '¯ród³o',
+ 'Statement Balance' => 'Wykaz Salda',
+ 'To' => 'do',
+ 'Update' => 'Uzupe³nij',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'kontynuj' => 'continue',
+ 'zrobione' => 'done',
+ 'wybierz_wszystko' => 'select_all',
+ 'uzupe³nij' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/pl/rp b/sql-ledger/locale/pl/rp
new file mode 100644
index 0000000..6abd702
--- /dev/null
+++ b/sql-ledger/locale/pl/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Zobowi±zania Przeterminowane',
+ 'AR Aging' => 'Nale¿no¶ci Przeterminowane',
+ 'Account' => 'Konto',
+ 'Accounts' => 'Konta',
+ 'Amount' => 'Kwota',
+ 'Apr' => 'Kwiecieñ',
+ 'April' => 'Kwiecieñ',
+ 'Attachment' => 'Za³±cznik',
+ 'Aug' => 'Sierpieñ',
+ 'August' => 'Sierpieñ',
+ 'Balance Sheet' => 'Bilans',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Tryb Kasowy',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Porównaj z',
+ 'Continue' => 'Kontynuj',
+ 'Copies' => 'Kopie',
+ 'Credit' => 'Kredyt',
+ 'Current' => 'Bi¿±cy',
+ 'Customer' => 'Klient',
+ 'Date' => 'Data',
+ 'Debit' => 'Debet',
+ 'Dec' => 'Grudzieñ',
+ 'December' => 'Grudzieñ',
+ 'Decimalplaces' => 'Miejsca Dziesiêtne',
+ 'Description' => 'Opis',
+ 'Due' => 'P³atno¶æ',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'E-mail Wykaz do',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Nag³ówek',
+ 'ID' => 'Identyfikator',
+ 'In-line' => 'W³±czony',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Income Statement' => 'Rachunek Zysków i Strat',
+ 'Invoice' => 'Faktura',
+ 'Jan' => 'Styczeñ',
+ 'January' => 'Styczeñ',
+ 'Jul' => 'Lipiec',
+ 'July' => 'Lipiec',
+ 'Jun' => 'Czerwiec',
+ 'June' => 'Czerwiec',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Nic nie zaznaczone!',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'PDF' => 'PDF',
+ 'Payments' => 'P³atno¶ci',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Drukuj',
+ 'Printer' => 'Drukarka',
+ 'Receipts' => 'Wp³aty',
+ 'Report for' => 'Raport dla',
+ 'Retained Earnings' => 'Zysk',
+ 'Screen' => 'Ekran',
+ 'Select all' => 'Wybierz wszystko',
+ 'Select postscript or PDF!' => 'Wybierz postscript lub PDF',
+ 'Sep' => 'Wrzesieñ',
+ 'September' => 'Wrzesieñ',
+ 'Source' => '¯ród³o',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Wykaz',
+ 'Statement sent to' => 'Wykaz wys³any do',
+ 'Statements sent to printer!' => 'Wykaz wys³any do drukarki',
+ 'Subject' => 'Tre¶æ',
+ 'Subtotal' => 'Warto¶æ Netto',
+ 'Tax' => 'Podatek',
+ 'Tax collected' => 'Podatek pobrany',
+ 'Tax paid' => 'Podatek zap³acony',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Trial Balance' => 'Bilans Porównawczy',
+ 'Vendor' => 'Dostawca',
+ 'as at' => 'tak samo',
+ 'collected on sales' => 'zebrany przy sprzeda¿y',
+ 'for Period' => 'za Okres',
+ 'paid on purchases' => 'zap³acony przy zakupach',
+ 'to' => 'do',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'kontynuj' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'drukuj' => 'print',
+ 'wybierz_wszystko' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/COPYING b/sql-ledger/locale/pt/COPYING
new file mode 100644
index 0000000..bd508c5
--- /dev/null
+++ b/sql-ledger/locale/pt/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Portugese texts:
+#
+# Author: Paulo Rodrigues <prodrigues@vianetworks.pt>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/pt/LANGUAGE b/sql-ledger/locale/pt/LANGUAGE
new file mode 100644
index 0000000..3d5f0c1
--- /dev/null
+++ b/sql-ledger/locale/pt/LANGUAGE
@@ -0,0 +1 @@
+Portuguese
diff --git a/sql-ledger/locale/pt/admin b/sql-ledger/locale/pt/admin
new file mode 100644
index 0000000..827c4e9
--- /dev/null
+++ b/sql-ledger/locale/pt/admin
@@ -0,0 +1,122 @@
+$self{texts} = {
+ 'Access Control' => 'Controlo de Acessos',
+ 'Accounting' => 'Contabilidade',
+ 'Add User' => 'Novo Utilizador',
+ 'Address' => 'Endereço',
+ 'Administration' => 'Administração',
+ 'Administrator' => 'Administrador',
+ 'All Datasets up to date!' => 'Todos os Datasets estão Actualizados!',
+ 'Change Admin Password' => 'Mudar Password Admin',
+ 'Change Password' => 'Mudar Password',
+ 'Character Set' => 'Character Set',
+ 'Click on login name to edit!' => 'Clique no login para editar!',
+ 'Company' => 'Companhia',
+ 'Connect to' => 'Ligar a',
+ 'Continue' => 'Continuar',
+ 'Create Chart of Accounts' => 'Criar Plano de Contas',
+ 'Create Dataset' => 'Criar Dataset',
+ 'DBI not installed!' => 'DBI não está instalado!',
+ 'Database' => 'Base de Dados',
+ 'Database Administration' => 'Administração de Base de Dados',
+ 'Database Driver not checked!' => 'Não seleccionou Driver Base de Dados',
+ 'Database User missing!' => 'Não existe Utilizador de Base de Dados',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Dataset não existe!',
+ 'Dataset updated!' => 'Dataset actualizado!',
+ 'Date Format' => 'Formato de Data',
+ 'Delete' => 'Remover',
+ 'Delete Dataset' => 'Remover Dataset',
+ 'Directory' => 'Directoria',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'E-Mail',
+ 'Edit User' => 'Editar Utilizador',
+ 'Existing Datasets' => 'Datasets Existentes',
+ 'Fax' => 'Fax',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Não indicou Hostname!',
+ 'Incorrect Password!' => 'Password Incorrecta!',
+ 'Language' => 'Língua',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Não indique host nem port, a não ser que deseje efectuar uma ligação remota',
+ 'Login' => 'Login',
+ 'Name' => 'Nome',
+ 'New Templates' => 'Novos Modelos',
+ 'No Database Drivers available!' => 'Não há Drivers de Base de Dados disponiveis!',
+ 'No Dataset selected!' => 'Não seleccionou Dataset!',
+ 'Nothing to delete!' => 'Nada para remover!',
+ 'Number Format' => 'Formato numérico',
+ 'Oracle Database Administration' => 'Administração Base de Dados Oracle',
+ 'Password' => 'Password',
+ 'Password changed!' => 'Password alterada',
+ 'Pg Database Administration' => 'Administração Base de Dados Postgres',
+ 'Phone' => 'Tel',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Falta o port!',
+ 'Printer' => 'Impressora',
+ 'Save' => 'Guardar',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione um Dataset a remover e clique "Continuar"',
+ 'Setup Templates' => 'Configurar Modelos',
+ 'Ship via' => 'Expedir via',
+ 'Signature' => 'Assinatura',
+ 'Stylesheet' => 'Stylesheet',
+ 'Templates' => 'Modelos',
+ 'The following Datasets are not in use and can be deleted' => 'Os seguintes Datasets estão em uso e não podem ser removidos',
+ 'The following Datasets need to be updated' => 'Os seguintes Datasets necessitam ser actualizados',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta é uma validação preliminar. Nada será criado nem removido neste ponto!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para adicionar um utilizador a um grupo, edite um nome, mude o login e guarde. O novo utilizador com as mesmas variáveis será guardado sob o novo login',
+ 'Update Dataset' => 'Actualizar Dataset',
+ 'Use Templates' => 'Usar Templates',
+ 'User' => 'Utilizador',
+ 'User deleted!' => 'Utilizador removido',
+ 'User saved!' => 'Utilizador guardado',
+ 'Version' => 'Versão',
+ 'You must enter a host and port for local and remote connections!' => 'Tem de indicar host e port para ligações locais e remotas!',
+ 'does not exist' => 'não existe',
+ 'is already a member!' => 'já é membro!',
+ 'localhost' => 'localhost',
+ 'successfully created!' => 'criado com sucesso!',
+ 'successfully deleted!' => 'removido com sucesso!',
+ 'website' => 'website',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'novo_utilizador' => 'add_user',
+ 'mudar_password_admin' => 'change_admin_password',
+ 'mudar_password' => 'change_password',
+ 'continuar' => 'continue',
+ 'criar_dataset' => 'create_dataset',
+ 'remover' => 'delete',
+ 'remover_dataset' => 'delete_dataset',
+ 'login' => 'login',
+ 'administração_base_de_dados_oracle' => 'oracle_database_administration',
+ 'administração_base_de_dados_postgres' => 'pg_database_administration',
+ 'guardar' => 'save',
+ 'actualizar_dataset' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/all b/sql-ledger/locale/pt/all
new file mode 100644
index 0000000..bcfd222
--- /dev/null
+++ b/sql-ledger/locale/pt/all
@@ -0,0 +1,487 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Fornecedores',
+ 'AP Aging' => 'Idade Saldos Fornecedores',
+ 'AP Transaction' => 'Transacção Fornecedores',
+ 'AP Transactions' => 'Transacções Fornecedores',
+ 'AR' => 'Clientes',
+ 'AR Aging' => 'Idade Saldos Clientes',
+ 'AR Transaction' => 'Transacção Clientes',
+ 'AR Transactions' => 'Transacções Clientes',
+ 'About' => 'Acerca',
+ 'Access Control' => 'Controlo de Acessos',
+ 'Account' => 'Conta',
+ 'Account Number' => 'Número da Conta',
+ 'Account Number missing!' => 'Número da Conta não encontrado!',
+ 'Account Type' => 'Tipo de Conta',
+ 'Account Type missing!' => 'Tipo de Conta não encontrado!',
+ 'Account deleted!' => 'Conta apagada',
+ 'Account saved!' => 'Conta guardada',
+ 'Accounting' => 'Contabilidade',
+ 'Accounting Menu' => 'Menu de Contabilidade',
+ 'Accounts' => 'Contas',
+ 'Active' => 'Activo',
+ 'Add' => 'Novo',
+ 'Add Account' => 'Nova Conta',
+ 'Add Accounts Payables Transaction' => 'Nova Transacção Fornecedores',
+ 'Add Accounts Receivables Transaction' => 'Nova Transacção Clientes',
+ 'Add Assembly' => 'Novo Conjunto',
+ 'Add Customer' => 'Novo Cliente',
+ 'Add GIFI' => 'Adicionar CFOP',
+ 'Add General Ledger Transaction' => 'Nova Transacção Livro Razão',
+ 'Add Part' => 'Novo Produto',
+ 'Add Project' => 'Novo Projecto',
+ 'Add Purchase Invoice' => 'Nova Factura de Compra',
+ 'Add Purchase Order' => 'Nova Ordem de Compra',
+ 'Add Sales Invoice' => 'Nova Factura de Venda',
+ 'Add Sales Order' => 'Nova Encomenda de Cliente',
+ 'Add Service' => 'Novo Serviço',
+ 'Add Transaction' => 'Nova Transacção',
+ 'Add User' => 'Novo Utilizador',
+ 'Add Vendor' => 'Novo Fornecedor',
+ 'Address' => 'Endereço',
+ 'Administration' => 'Administração',
+ 'Administrator' => 'Administrador',
+ 'All' => 'Todos',
+ 'All Datasets up to date!' => 'Todos os Datasets estão Actualizados!',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Total em dívida',
+ 'Amount does not equal applied!' => 'Valor diferente do aplicado!',
+ 'Amount missing!' => 'Falta o valor!',
+ 'Applied' => 'Aplicado',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => 'Tem a certeza que quer APAGAR a Factura Número',
+ 'Are you sure you want to delete Order Number' => 'Confirma a remoção da Encomenda?',
+ 'Are you sure you want to delete Transaction' => 'Tem a certeza que quer APAGAR a Transacção',
+ 'Assemblies' => 'Conjuntos',
+ 'Assemblies restocked!' => '',
+ 'Assembly Number missing!' => 'Falta o Número de Produto',
+ 'Asset' => 'Activo',
+ 'Attachment' => 'Attachment',
+ 'Audit Control' => 'Controlo de Auditoria',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'BOM',
+ 'Backup' => 'Backup',
+ 'Backup sent to' => 'Backup enviado para',
+ 'Balance' => 'Saldo',
+ 'Balance Sheet' => 'Folha de Balanço',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Books are open' => 'Livros Abertos',
+ 'Bought' => 'Comprado',
+ 'Business Number' => 'Número de negócio',
+ 'C' => '',
+ 'COGS' => 'Custo de Vendas',
+ 'Cannot delete account!' => 'Não é possivel apagar a conta!',
+ 'Cannot delete customer!' => 'Não é possivel apagar o cliente!',
+ 'Cannot delete default account!' => 'Não é possível apagar a conta por defeito!',
+ 'Cannot delete invoice!' => 'Não é possivel apagar a factura!',
+ 'Cannot delete item already invoiced!' => 'Não posso apagar item já facturado!',
+ 'Cannot delete item on order!' => 'Não pode apagar item no pedido',
+ 'Cannot delete item which is part of an assembly!' => 'Não é possível apagar Produto que faz parte de um Conjunto!',
+ 'Cannot delete item!' => 'Não é possivel apagar o item!',
+ 'Cannot delete order!' => 'Não é possivel apagar a encomenda!',
+ 'Cannot delete transaction!' => 'Não é possivel apagar a transacção',
+ 'Cannot delete vendor!' => 'Não é possivel apagar o fornecedor',
+ 'Cannot have a value in both Debit and Credit!' => 'Não pode ter o valor a Débito E Crédito!',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => 'Não pode lançar factura em período fechado!',
+ 'Cannot post invoice!' => 'Não é possivel lançar factura!',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cannot post payment!' => 'Não é possivel lançar pagamento',
+ 'Cannot post transaction for a closed period!' => 'Não é possivel lançar transacção para um periodo fechado!',
+ 'Cannot post transaction!' => 'Não é possivel lançar transacção',
+ 'Cannot process payment for a closed period!' => 'Não é possivel lançar pagamento para um período fechado',
+ 'Cannot save account!' => 'Não é possível guardar conta!',
+ 'Cannot save order!' => 'Não é possível guardar encomenda!',
+ 'Cannot save preferences!' => 'Não é possível guardar preferências!',
+ 'Cannot stock assemblies!' => '',
+ 'Cash' => 'Dinheiro',
+ 'Cash based' => '',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => 'Mudar Password Admin',
+ 'Change Password' => 'Mudar Password',
+ 'Character Set' => 'Character Set',
+ 'Chart of Accounts' => 'Plano de Contas',
+ 'Check' => 'Cheque',
+ 'Check printed!' => 'Cheque impresso!',
+ 'Check printing failed!' => 'Falhou a impressão de cheques!',
+ 'Cleared Balance' => '',
+ 'Click on login name to edit!' => 'Clique no login para editar!',
+ 'Close Books up to' => 'Fechar Livros até',
+ 'Closed' => 'Fechado',
+ 'Company' => 'Companhia',
+ 'Compare to' => 'Comparar com',
+ 'Confirm!' => 'Confirmar!',
+ 'Connect to' => 'Ligar a',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Copy to COA' => 'Copiar para Plano de Contas',
+ 'Create Chart of Accounts' => 'Criar Plano de Contas',
+ 'Create Dataset' => 'Criar Dataset',
+ 'Credit' => 'Crédito',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Curr' => 'Moeda',
+ 'Currency' => 'Moeda',
+ 'Current' => '',
+ 'Customer' => 'Cliente',
+ 'Customer deleted!' => 'Cliente apagado!',
+ 'Customer missing!' => 'Falta cliente!',
+ 'Customer not on file!' => 'Cliente inexistente!',
+ 'Customer saved!' => 'Cliente guardado!',
+ 'Customers' => 'Clientes',
+ 'DBI not installed!' => 'DBI não está instalado!',
+ 'Database' => 'Base de Dados',
+ 'Database Administration' => 'Administração de Base de Dados',
+ 'Database Driver not checked!' => 'Não seleccionou Driver Base de Dados',
+ 'Database Host' => 'Servidor de Base de Dados',
+ 'Database User missing!' => 'Não existe Utilizador de Base de Dados',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Dataset não existe!',
+ 'Dataset updated!' => 'Dataset actualizado!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data de Vencimento',
+ 'Date Format' => 'Formato de Data',
+ 'Date Paid' => 'Data de pagamento',
+ 'Date missing!' => 'Falta a data!',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito e crédito fora de balanço!',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Decimalplaces' => 'Casas decimais',
+ 'Delete' => 'Remover',
+ 'Delete Account' => 'Apagar Conta',
+ 'Delete Dataset' => 'Remover Dataset',
+ 'Delivery Date' => 'Data de entrega',
+ 'Deposit' => 'Depósito',
+ 'Description' => 'Descrição',
+ 'Difference' => 'Diferença',
+ 'Directory' => 'Directoria',
+ 'Discount' => 'Desconto',
+ 'Done' => 'Pronto',
+ 'Drawing' => '',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => '',
+ 'Due' => 'Vence',
+ 'Due Date' => 'Data de Vencimento',
+ 'Due Date missing!' => 'Falta Data de Vencimento!',
+ 'E-mail' => 'E-Mail',
+ 'E-mail Statement to' => '',
+ 'E-mail address missing!' => 'Falta Endereço de E-mail!',
+ 'Edit' => 'Editar',
+ 'Edit Account' => 'Editar Conta',
+ 'Edit Accounts Payables Transaction' => 'Editar transacção Fornecedores',
+ 'Edit Accounts Receivables Transaction' => 'Editar transacção Clientes',
+ 'Edit Assembly' => 'Editar Conjunto',
+ 'Edit GIFI' => 'Editar CFOP',
+ 'Edit General Ledger Transaction' => 'Editar Transacção Livro Razão',
+ 'Edit Part' => 'Editar Produto',
+ 'Edit Preferences for' => 'Editar Preferências para',
+ 'Edit Project' => 'Editar Projecto',
+ 'Edit Purchase Invoice' => 'Editar Factura de Compra',
+ 'Edit Purchase Order' => 'Editar Ordem de Compra',
+ 'Edit Sales Invoice' => 'Editar Factura de Venda',
+ 'Edit Sales Order' => 'Editar Encomenda',
+ 'Edit Service' => 'Editar Serviço',
+ 'Edit Template' => 'Editar Modelo',
+ 'Edit User' => 'Editar Utilizador',
+ 'Employee' => 'Funcionário',
+ 'Enforce transaction reversal for all dates' => 'Forçar anulação das transacções para todas as datas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Indique as suas moedas nativa e estrangeiras usando os códigos de 3 letras (p.ex. EUR:USD:CAD)',
+ 'Equity' => 'Capital',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de Câmbio',
+ 'Exchangerate Difference' => 'Diferença na Taxa de Câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Existing Datasets' => 'Datasets Existentes',
+ 'Expense' => 'Despesa',
+ 'Expense Account' => 'Conta de Despesas',
+ 'Expense/Asset' => 'Despesa/Activo',
+ 'Extended' => '',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'Foreign Exchange Gain' => 'Diferenças de Câmbio - Proveitos',
+ 'Foreign Exchange Loss' => 'Diferenças de Câmbio - Prejuizos',
+ 'From' => 'De',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'GIFI deleted!' => 'CFOP apagado',
+ 'GIFI missing!' => 'Falta CFOP!',
+ 'GIFI saved!' => 'CFOP guardado',
+ 'GL Transaction' => 'Transacção Livro Razão',
+ 'General Ledger' => 'Livro Razão',
+ 'Goods & Services' => 'Bens e Serviços',
+ 'HTML Templates' => 'Templates HTML',
+ 'Heading' => 'Cabeçalho',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Não indicou Hostname!',
+ 'ID' => 'ID',
+ 'Image' => 'Imagem',
+ 'In-line' => 'Inline',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Include in drop-down menus' => 'Incluir nos menus drop-down',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluir esta conta nos formulários de cliente/fornecedor para marcar cliente/fornecedor como sujeito a impostos.',
+ 'Income' => 'Receita',
+ 'Income Account' => 'Conta de Receitas',
+ 'Income Statement' => 'Estado de Receitas',
+ 'Incorrect Dataset version!' => 'Versão Dataset incorrecta!',
+ 'Incorrect Password!' => 'Password Incorrecta!',
+ 'Individual Items' => 'Produtos Individuais',
+ 'Inventory' => 'Inventário',
+ 'Inventory Account' => 'Conta de Inventário',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Quantidade em Stock tem de ser zero para poder declarar este conjunto obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Quantidade em Stock tem de ser zero para poder declarar esta peça obsoleta!',
+ 'Inventory quantity must be zero!' => 'Quantidade em Stock tem de ser zero!',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data de Factura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Número de Factura não encontrado!',
+ 'Invoice deleted!' => 'Factura apagada',
+ 'Invoice posted!' => 'Factura processada',
+ 'Invoices' => 'Facturas',
+ 'Is this a summary account to record' => 'Esta é uma conta sumária a registar',
+ 'Item deleted!' => 'Item apagado',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'LaTeX Templates' => 'Modelos LaTeX',
+ 'Language' => 'Língua',
+ 'Last Cost' => 'Último Custo',
+ 'Last Invoice Number' => 'Último Número de Factura',
+ 'Last Numbers & Default Accounts' => 'Últimos números e Contas por defeito',
+ 'Last Purchase Order Number' => 'Ultimo numero de Ordem de Compra',
+ 'Last Sales Order Number' => 'Último número de Encomenda de vendas',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Não indique host nem port, a não ser que deseje efectuar uma ligação remota',
+ 'Liability' => 'Passivo',
+ 'Licensed to' => 'Licenciado a',
+ 'Line Total' => 'Total da Linha',
+ 'Link' => 'Ligar',
+ 'Link Accounts' => 'Ligar Contas',
+ 'List Accounts' => 'Listar Contas',
+ 'List GIFI' => 'Listar CFOP',
+ 'List Price' => 'Listar Preço',
+ 'List Transactions' => 'Listar Transacções',
+ 'Login' => 'Login',
+ 'Logout' => 'Logout',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Microfiche' => 'Microficha',
+ 'Model' => 'Modelo',
+ 'N/A' => 'N/D',
+ 'Name' => 'Nome',
+ 'Name missing!' => 'Falta o nome!',
+ 'New Templates' => 'Novos Modelos',
+ 'No' => 'Não',
+ 'No Database Drivers available!' => 'Não há Drivers de Base de Dados disponiveis!',
+ 'No Dataset selected!' => 'Não seleccionou Dataset!',
+ 'No email address for' => 'Não existe endereço de email para',
+ 'No.' => '',
+ 'Notes' => 'Notas',
+ 'Nothing applied!' => 'Nada aplicado',
+ 'Nothing selected!' => 'Nada seleccionado',
+ 'Nothing to delete!' => 'Nada para remover!',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato numérico',
+ 'Number missing in Row' => 'Falta numero na Linha',
+ 'O' => '',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'On Hand' => 'Em Stock',
+ 'On Order' => 'Encomendado',
+ 'Open' => 'Abrir',
+ 'Oracle Database Administration' => 'Administração Base de Dados Oracle',
+ 'Order' => 'Encomenda',
+ 'Order Date' => 'Data da Encomenda',
+ 'Order Date missing!' => 'Falta data da Encomenda',
+ 'Order Entry' => 'Encomendas de Clientes',
+ 'Order Number' => 'Encomenda Número',
+ 'Order Number missing!' => 'Falta numero da Encomenda!',
+ 'Order deleted!' => 'Encomenda apagada',
+ 'Order saved!' => 'Encomenda guardada',
+ 'Ordered' => 'Encomendado',
+ 'Orphaned' => 'Órfão',
+ 'Out of balance!' => '',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Expedição',
+ 'Packing List Date missing!' => 'Falta Data da Lista de Expedição',
+ 'Packing List Number missing!' => 'Falta Numero de Lista de Expedição',
+ 'Paid' => 'Total Pago',
+ 'Paid in full' => '',
+ 'Part' => 'Produto',
+ 'Part Number missing!' => 'Número de produto não encontrado!',
+ 'Parts' => 'Produtos',
+ 'Parts Inventory' => 'Inventário',
+ 'Password' => 'Password',
+ 'Password changed!' => 'Password alterada',
+ 'Payables' => 'Fornecedores',
+ 'Payment' => 'Pagamento',
+ 'Payment date missing!' => 'Falta Data de Pagamento!',
+ 'Payment posted!' => 'Pagamento processado',
+ 'Payments' => 'Pagamentos',
+ 'Pg Database Administration' => 'Administração Base de Dados Postgres',
+ 'Phone' => 'Tel',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Falta o port!',
+ 'Post' => 'Processar',
+ 'Post as new' => 'Processar como novo',
+ 'Postscript' => 'PostScript',
+ 'Preferences' => 'Preferências',
+ 'Preferences saved!' => 'Preferências Guardadas!',
+ 'Price' => 'Preço',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projecto',
+ 'Project Number missing!' => 'Falta o número do projecto',
+ 'Project deleted!' => 'Projecto apagado',
+ 'Project not on file!' => 'Projecto não existe',
+ 'Project saved!' => 'Projecto guardado',
+ 'Projects' => 'Projectos',
+ 'Purchase Invoice' => 'Factura de Compra',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Purchase Orders' => 'Ordens de Compra',
+ 'Qty' => 'Qtd',
+ 'ROP' => 'Nível mínimo de stock',
+ 'Rate' => 'Taxa',
+ 'Recd' => 'Recebido',
+ 'Receipt' => 'Recibo',
+ 'Receipts' => 'Recibos',
+ 'Receivables' => 'Clientes',
+ 'Reconciliation' => 'Reconciliação',
+ 'Record in' => 'Registar em',
+ 'Reference' => 'Referência',
+ 'Reference missing!' => 'Falta referência',
+ 'Remaining' => 'Sobram',
+ 'Report for' => 'Relatório para',
+ 'Reports' => 'Relatórios',
+ 'Required by' => 'Requerido por',
+ 'Retained Earnings' => 'Lucros Retidos',
+ 'Sales' => 'Vendas',
+ 'Sales Invoice' => 'Factura de Venda',
+ 'Sales Order' => 'Encomenda de Venda',
+ 'Sales Orders' => 'Encomendas de Venda',
+ 'Save' => 'Guardar',
+ 'Save as new' => 'Guardar como novo',
+ 'Save to File' => 'Guardar em Ficheiro',
+ 'Screen' => 'Ecran',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione um Dataset a remover e clique "Continuar"',
+ 'Select all' => 'Seleccionar todos',
+ 'Select from one of the items below' => 'Seleccione um dos items abaixo',
+ 'Select from one of the names below' => 'Seleccione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Seleccione um dos projectos abaixo',
+ 'Select postscript or PDF!' => 'Seleccione PostScript ou PDF',
+ 'Sell Price' => 'Preço de Venda',
+ 'Send by E-Mail' => 'Enviar por Email',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Service Items' => 'Items de Serviço',
+ 'Service Number missing!' => 'Número do serviço não encontrado!',
+ 'Services' => 'Serviços',
+ 'Setup Templates' => 'Configurar Modelos',
+ 'Ship' => 'Expedir',
+ 'Ship to' => 'Expedir para',
+ 'Ship via' => 'Expedir via',
+ 'Short' => 'Curta',
+ 'Signature' => 'Assinatura',
+ 'Sold' => 'Vendido',
+ 'Source' => 'Origem',
+ 'Standard' => 'Padrão',
+ 'Statement' => '',
+ 'Statement Balance' => '',
+ 'Statement sent to' => '',
+ 'Statements sent to printer!' => '',
+ 'Stock Assembly' => 'Conjunto em stock',
+ 'Stylesheet' => 'Stylesheet',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'System' => 'Sistema',
+ 'Tax' => 'Imposto',
+ 'Tax Accounts' => 'Contas de Impostos',
+ 'Tax Included' => 'Impostos incluídos',
+ 'Tax collected' => 'Imposto recolhido',
+ 'Tax paid' => 'Imposto pago',
+ 'Taxable' => 'Sujeito a impostos',
+ 'Template saved!' => 'Modelo guardado',
+ 'Templates' => 'Modelos',
+ 'Terms: Net' => 'Termos: A pronto',
+ 'The following Datasets are not in use and can be deleted' => 'Os seguintes Datasets estão em uso e não podem ser removidos',
+ 'The following Datasets need to be updated' => 'Os seguintes Datasets necessitam ser actualizados',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Esta é uma validação preliminar. Nada será criado nem removido neste ponto!',
+ 'To' => 'Até',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para adicionar um utilizador a um grupo, edite um nome, mude o login e guarde. O novo utilizador com as mesmas variáveis será guardado sob o novo login',
+ 'Top Level' => 'Nivel de topo',
+ 'Total' => 'Total',
+ 'Transaction Date missing!' => 'Falta Data de transacção!',
+ 'Transaction deleted!' => 'Transacção apagada',
+ 'Transaction posted!' => 'Transacção processada',
+ 'Transaction reversal enforced for all dates' => 'Cancelamento de transacção forçado para todas as datas',
+ 'Transaction reversal enforced up to' => 'Cancelamento de transacção forçado até',
+ 'Transactions' => 'Transacções',
+ 'Transactions exist, cannot delete customer!' => 'Existem transacções, não pode apagar o cliente!',
+ 'Transactions exist, cannot delete vendor!' => 'Existem transacções, não pode apagar fornecedor!',
+ 'Transactions exist; cannot delete account!' => 'Existem Transacções, não é possivel remover conta!',
+ 'Trial Balance' => 'Balancete',
+ 'Unit' => 'Unidade',
+ 'Unit of measure' => 'Unidade de medida',
+ 'Update' => 'Actualizar',
+ 'Update Dataset' => 'Actualizar Dataset',
+ 'Updated' => 'Actualizado',
+ 'Use Templates' => 'Usar Templates',
+ 'User' => 'Utilizador',
+ 'User deleted!' => 'Utilizador removido',
+ 'User saved!' => 'Utilizador guardado',
+ 'Vendor' => 'Fornecedor',
+ 'Vendor deleted!' => 'Fornecedor apagado',
+ 'Vendor missing!' => 'Falta fornecedor',
+ 'Vendor not on file!' => 'Fornecedor não existe',
+ 'Vendor saved!' => 'Fornecedor guardado',
+ 'Vendors' => 'Fornecedores',
+ 'Version' => 'Versão',
+ 'Weight' => 'Peso',
+ 'Weight Unit' => 'Unidade de Peso',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'Year End' => 'Fim de ano',
+ 'Yes' => 'Sim',
+ 'You are logged out!' => 'Terminou a sessão!',
+ 'You did not enter a name!' => 'Não indicou nome!',
+ 'You must enter a host and port for local and remote connections!' => 'Tem de indicar host e port para ligações locais e remotas!',
+ 'as at' => '',
+ 'collected on sales' => 'recolhido sobre vendas',
+ 'days' => 'dias',
+ 'does not exist' => 'não existe',
+ 'ea' => 'cd',
+ 'emailed to' => 'enviado por email para',
+ 'for Period' => 'pelo período',
+ 'hr' => 'hr',
+ 'is already a member!' => 'já é membro!',
+ 'is not a member!' => 'não é membro!',
+ 'localhost' => 'localhost',
+ 'paid on purchases' => 'pago em aquisições',
+ 'sent to printer' => 'enviado para a impressora',
+ 'successfully created!' => 'criado com sucesso!',
+ 'successfully deleted!' => 'removido com sucesso!',
+ 'to' => 'para',
+ 'website' => 'website',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/am b/sql-ledger/locale/pt/am
new file mode 100644
index 0000000..a926fe3
--- /dev/null
+++ b/sql-ledger/locale/pt/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Fornecedores',
+ 'AR' => 'Clientes',
+ 'Account' => 'Conta',
+ 'Account Number' => 'Número da Conta',
+ 'Account Number missing!' => 'Número da Conta não encontrado!',
+ 'Account Type' => 'Tipo de Conta',
+ 'Account Type missing!' => 'Tipo de Conta não encontrado!',
+ 'Account deleted!' => 'Conta apagada',
+ 'Account saved!' => 'Conta guardada',
+ 'Add Account' => 'Nova Conta',
+ 'Add GIFI' => 'Adicionar CFOP',
+ 'Address' => 'Endereço',
+ 'Asset' => 'Activo',
+ 'Audit Control' => 'Controlo de Auditoria',
+ 'Backup sent to' => 'Backup enviado para',
+ 'Books are open' => 'Livros Abertos',
+ 'Business Number' => 'Número de negócio',
+ 'COGS' => 'Custo de Vendas',
+ 'Cannot delete account!' => 'Não é possivel apagar a conta!',
+ 'Cannot delete default account!' => 'Não é possível apagar a conta por defeito!',
+ 'Cannot save account!' => 'Não é possível guardar conta!',
+ 'Cannot save preferences!' => 'Não é possível guardar preferências!',
+ 'Character Set' => 'Character Set',
+ 'Chart of Accounts' => 'Plano de Contas',
+ 'Close Books up to' => 'Fechar Livros até',
+ 'Company' => 'Companhia',
+ 'Continue' => 'Continuar',
+ 'Copy to COA' => 'Copiar para Plano de Contas',
+ 'Credit' => 'Crédito',
+ 'Date Format' => 'Formato de Data',
+ 'Debit' => 'Débito',
+ 'Delete' => 'Remover',
+ 'Delete Account' => 'Apagar Conta',
+ 'Description' => 'Descrição',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'E-Mail',
+ 'Edit' => 'Editar',
+ 'Edit Account' => 'Editar Conta',
+ 'Edit GIFI' => 'Editar CFOP',
+ 'Edit Preferences for' => 'Editar Preferências para',
+ 'Edit Template' => 'Editar Modelo',
+ 'Enforce transaction reversal for all dates' => 'Forçar anulação das transacções para todas as datas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Indique as suas moedas nativa e estrangeiras usando os códigos de 3 letras (p.ex. EUR:USD:CAD)',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Despesa',
+ 'Expense Account' => 'Conta de Despesas',
+ 'Expense/Asset' => 'Despesa/Activo',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Diferenças de Câmbio - Proveitos',
+ 'Foreign Exchange Loss' => 'Diferenças de Câmbio - Prejuizos',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'GIFI deleted!' => 'CFOP apagado',
+ 'GIFI missing!' => 'Falta CFOP!',
+ 'GIFI saved!' => 'CFOP guardado',
+ 'Heading' => 'Cabeçalho',
+ 'Include in drop-down menus' => 'Incluir nos menus drop-down',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluir esta conta nos formulários de cliente/fornecedor para marcar cliente/fornecedor como sujeito a impostos.',
+ 'Income' => 'Receita',
+ 'Income Account' => 'Conta de Receitas',
+ 'Inventory' => 'Inventário',
+ 'Inventory Account' => 'Conta de Inventário',
+ 'Is this a summary account to record' => 'Esta é uma conta sumária a registar',
+ 'Language' => 'Língua',
+ 'Last Invoice Number' => 'Último Número de Factura',
+ 'Last Numbers & Default Accounts' => 'Últimos números e Contas por defeito',
+ 'Last Purchase Order Number' => 'Ultimo numero de Ordem de Compra',
+ 'Last Sales Order Number' => 'Último número de Encomenda de vendas',
+ 'Liability' => 'Passivo',
+ 'Link' => 'Ligar',
+ 'Name' => 'Nome',
+ 'No' => 'Não',
+ 'No email address for' => 'Não existe endereço de email para',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato numérico',
+ 'Parts Inventory' => 'Inventário',
+ 'Password' => 'Password',
+ 'Payables' => 'Fornecedores',
+ 'Payment' => 'Pagamento',
+ 'Phone' => 'Tel',
+ 'Preferences saved!' => 'Preferências Guardadas!',
+ 'Rate' => 'Taxa',
+ 'Receivables' => 'Clientes',
+ 'Sales' => 'Vendas',
+ 'Save' => 'Guardar',
+ 'Service Items' => 'Items de Serviço',
+ 'Ship via' => 'Expedir via',
+ 'Signature' => 'Assinatura',
+ 'Stylesheet' => 'Stylesheet',
+ 'Tax' => 'Imposto',
+ 'Tax Accounts' => 'Contas de Impostos',
+ 'Template saved!' => 'Modelo guardado',
+ 'Transaction reversal enforced for all dates' => 'Cancelamento de transacção forçado para todas as datas',
+ 'Transaction reversal enforced up to' => 'Cancelamento de transacção forçado até',
+ 'Transactions exist; cannot delete account!' => 'Existem Transacções, não é possivel remover conta!',
+ 'Weight Unit' => 'Unidade de Peso',
+ 'Year End' => 'Fim de ano',
+ 'Yes' => 'Sim',
+ 'does not exist' => 'não existe',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'nova_conta' => 'add_account',
+ 'continuar' => 'continue',
+ 'copiar_para_plano_de_contas' => 'copy_to_coa',
+ 'remover' => 'delete',
+ 'editar' => 'edit',
+ 'editar_conta' => 'edit_account',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/ap b/sql-ledger/locale/pt/ap
new file mode 100644
index 0000000..f3a6467
--- /dev/null
+++ b/sql-ledger/locale/pt/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Transacção Fornecedores',
+ 'AP Transactions' => 'Transacções Fornecedores',
+ 'Account' => 'Conta',
+ 'Add Accounts Payables Transaction' => 'Nova Transacção Fornecedores',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Total em dívida',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => 'Tem a certeza que quer APAGAR a Transacção',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Não é possivel apagar a transacção',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cannot post transaction for a closed period!' => 'Não é possivel lançar transacção para um periodo fechado!',
+ 'Cannot post transaction!' => 'Não é possivel lançar transacção',
+ 'Closed' => 'Fechado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moeda',
+ 'Customer not on file!' => 'Cliente inexistente!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data de pagamento',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Remover',
+ 'Description' => 'Descrição',
+ 'Due Date' => 'Data de Vencimento',
+ 'Due Date missing!' => 'Falta Data de Vencimento!',
+ 'Edit Accounts Payables Transaction' => 'Editar transacção Fornecedores',
+ 'Employee' => 'Funcionário',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de Câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data de Factura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Número de Factura não encontrado!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Open' => 'Abrir',
+ 'Order' => 'Encomenda',
+ 'Order Number' => 'Encomenda Número',
+ 'Paid' => 'Total Pago',
+ 'Payment date missing!' => 'Falta Data de Pagamento!',
+ 'Payments' => 'Pagamentos',
+ 'Post' => 'Processar',
+ 'Post as new' => 'Processar como novo',
+ 'Project' => 'Projecto',
+ 'Project not on file!' => 'Projecto não existe',
+ 'Purchase Invoice' => 'Factura de Compra',
+ 'Select from one of the names below' => 'Seleccione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Seleccione um dos projectos abaixo',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Source' => 'Origem',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'Tax Included' => 'Impostos incluídos',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transacção apagada',
+ 'Transaction posted!' => 'Transacção processada',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Fornecedor',
+ 'Vendor missing!' => 'Falta fornecedor',
+ 'Vendor not on file!' => 'Fornecedor não existe',
+ 'Yes' => 'Sim',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transacção_fornecedores' => 'ap_transaction',
+ 'nova_transacção_fornecedores' => 'add_accounts_payables_transaction',
+ 'continuar' => 'continue',
+ 'remover' => 'delete',
+ 'editar_transacção_fornecedores' => 'edit_accounts_payables_transaction',
+ 'processar' => 'post',
+ 'processar_como_novo' => 'post_as_new',
+ 'factura_de_compra' => 'purchase_invoice',
+ 'actualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/ar b/sql-ledger/locale/pt/ar
new file mode 100644
index 0000000..7790e3c
--- /dev/null
+++ b/sql-ledger/locale/pt/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Transacção Clientes',
+ 'AR Transactions' => 'Transacções Clientes',
+ 'Account' => 'Conta',
+ 'Add Accounts Receivables Transaction' => 'Nova Transacção Clientes',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Amount Due' => 'Total em dívida',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => 'Tem a certeza que quer APAGAR a Transacção',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Cannot delete transaction!' => 'Não é possivel apagar a transacção',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cannot post transaction for a closed period!' => 'Não é possivel lançar transacção para um periodo fechado!',
+ 'Cannot post transaction!' => 'Não é possivel lançar transacção',
+ 'Closed' => 'Fechado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Currency' => 'Moeda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Falta cliente!',
+ 'Customer not on file!' => 'Cliente inexistente!',
+ 'Date' => 'Data',
+ 'Date Paid' => 'Data de pagamento',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Remover',
+ 'Description' => 'Descrição',
+ 'Due Date' => 'Data de Vencimento',
+ 'Due Date missing!' => 'Falta Data de Vencimento!',
+ 'Edit Accounts Receivables Transaction' => 'Editar transacção Clientes',
+ 'Employee' => 'Funcionário',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de Câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data de Factura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Número de Factura não encontrado!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Open' => 'Abrir',
+ 'Order' => 'Encomenda',
+ 'Order Number' => 'Encomenda Número',
+ 'Paid' => 'Total Pago',
+ 'Payment date missing!' => 'Falta Data de Pagamento!',
+ 'Payments' => 'Pagamentos',
+ 'Post' => 'Processar',
+ 'Post as new' => 'Processar como novo',
+ 'Project' => 'Projecto',
+ 'Project not on file!' => 'Projecto não existe',
+ 'Remaining' => 'Sobram',
+ 'Sales Invoice' => 'Factura de Venda',
+ 'Select from one of the names below' => 'Seleccione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Seleccione um dos projectos abaixo',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Source' => 'Origem',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'Tax Included' => 'Impostos incluídos',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transacção apagada',
+ 'Transaction posted!' => 'Transacção processada',
+ 'Update' => 'Actualizar',
+ 'Vendor not on file!' => 'Fornecedor não existe',
+ 'Yes' => 'Sim',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transacção_clientes' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'remover' => 'delete',
+ 'processar' => 'post',
+ 'processar_como_novo' => 'post_as_new',
+ 'factura_de_venda' => 'sales_invoice',
+ 'actualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/arap b/sql-ledger/locale/pt/arap
new file mode 100644
index 0000000..bbfaad0
--- /dev/null
+++ b/sql-ledger/locale/pt/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Endereço',
+ 'Continue' => 'Continuar',
+ 'Customer not on file!' => 'Cliente inexistente!',
+ 'Description' => 'Descrição',
+ 'Number' => 'Número',
+ 'Project not on file!' => 'Projecto não existe',
+ 'Select from one of the names below' => 'Seleccione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Seleccione um dos projectos abaixo',
+ 'Vendor not on file!' => 'Fornecedor não existe',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/ca b/sql-ledger/locale/pt/ca
new file mode 100644
index 0000000..01ea0fe
--- /dev/null
+++ b/sql-ledger/locale/pt/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Saldo',
+ 'Chart of Accounts' => 'Plano de Contas',
+ 'Credit' => 'Crédito',
+ 'Date' => 'Data',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Description' => 'Descrição',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'List Transactions' => 'Listar Transacções',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Reference' => 'Referência',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Subtotal' => 'Sub-total',
+ 'To' => 'Até',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'listar_transacções' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/cp b/sql-ledger/locale/pt/cp
new file mode 100644
index 0000000..1d62d31
--- /dev/null
+++ b/sql-ledger/locale/pt/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Amount does not equal applied!' => 'Valor diferente do aplicado!',
+ 'Amount missing!' => 'Falta o valor!',
+ 'Applied' => 'Aplicado',
+ 'Cannot post payment!' => 'Não é possivel lançar pagamento',
+ 'Cannot process payment for a closed period!' => 'Não é possivel lançar pagamento para um período fechado',
+ 'Check' => 'Cheque',
+ 'Check printed!' => 'Cheque impresso!',
+ 'Check printing failed!' => 'Falhou a impressão de cheques!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Moeda',
+ 'Customer' => 'Cliente',
+ 'Customer not on file!' => 'Cliente inexistente!',
+ 'Date' => 'Data',
+ 'Date missing!' => 'Falta a data!',
+ 'Description' => 'Descrição',
+ 'Due' => 'Vence',
+ 'Exchangerate' => 'Taxa de Câmbio',
+ 'From' => 'De',
+ 'Invoice' => 'Factura',
+ 'Invoices' => 'Facturas',
+ 'Nothing applied!' => 'Nada aplicado',
+ 'Number' => 'Número',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'Pagamento',
+ 'Payment posted!' => 'Pagamento processado',
+ 'Post' => 'Processar',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Project not on file!' => 'Projecto não existe',
+ 'Receipt' => 'Recibo',
+ 'Reference' => 'Referência',
+ 'Screen' => 'Ecran',
+ 'Select from one of the names below' => 'Seleccione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Seleccione um dos projectos abaixo',
+ 'To' => 'Até',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Fornecedor',
+ 'Vendor not on file!' => 'Fornecedor não existe',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+ 'processar' => 'post',
+ 'imprimir' => 'print',
+ 'actualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/ct b/sql-ledger/locale/pt/ct
new file mode 100644
index 0000000..74187f2
--- /dev/null
+++ b/sql-ledger/locale/pt/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Novo',
+ 'Address' => 'Endereço',
+ 'All' => 'Todos',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Não é possivel apagar o cliente!',
+ 'Cannot delete vendor!' => 'Não é possivel apagar o fornecedor',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Customer deleted!' => 'Cliente apagado!',
+ 'Customer saved!' => 'Cliente guardado!',
+ 'Customers' => 'Clientes',
+ 'Delete' => 'Remover',
+ 'Discount' => 'Desconto',
+ 'E-mail' => 'E-Mail',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Invoice' => 'Factura',
+ 'Name' => 'Nome',
+ 'Name missing!' => 'Falta o nome!',
+ 'Notes' => 'Notas',
+ 'Number' => 'Número',
+ 'Order' => 'Encomenda',
+ 'Orphaned' => 'Órfão',
+ 'Phone' => 'Tel',
+ 'Save' => 'Guardar',
+ 'Ship to' => 'Expedir para',
+ 'Tax Included' => 'Impostos incluídos',
+ 'Taxable' => 'Sujeito a impostos',
+ 'Terms: Net' => 'Termos: A pronto',
+ 'Transactions exist, cannot delete customer!' => 'Existem transacções, não pode apagar o cliente!',
+ 'Transactions exist, cannot delete vendor!' => 'Existem transacções, não pode apagar fornecedor!',
+ 'Vendor deleted!' => 'Fornecedor apagado',
+ 'Vendor saved!' => 'Fornecedor guardado',
+ 'Vendors' => 'Fornecedores',
+ 'days' => 'dias',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'novo' => 'add',
+ 'continuar' => 'continue',
+ 'remover' => 'delete',
+ 'factura' => 'invoice',
+ 'encomenda' => 'order',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/gl b/sql-ledger/locale/pt/gl
new file mode 100644
index 0000000..e2065ec
--- /dev/null
+++ b/sql-ledger/locale/pt/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Transacção Fornecedores',
+ 'AR Transaction' => 'Transacção Clientes',
+ 'Account' => 'Conta',
+ 'Add General Ledger Transaction' => 'Nova Transacção Livro Razão',
+ 'Address' => 'Endereço',
+ 'All' => 'Todos',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Transaction' => 'Tem a certeza que quer APAGAR a Transacção',
+ 'Asset' => 'Activo',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance' => 'Saldo',
+ 'Cannot delete transaction!' => 'Não é possivel apagar a transacção',
+ 'Cannot have a value in both Debit and Credit!' => 'Não pode ter o valor a Débito E Crédito!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'Não é possivel lançar transacção para um periodo fechado!',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit' => 'Crédito',
+ 'Customer not on file!' => 'Cliente inexistente!',
+ 'Date' => 'Data',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito e crédito fora de balanço!',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Remover',
+ 'Description' => 'Descrição',
+ 'Edit General Ledger Transaction' => 'Editar Transacção Livro Razão',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Despesa',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'GL Transaction' => 'Transacção Livro Razão',
+ 'General Ledger' => 'Livro Razão',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Income' => 'Receita',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Liability' => 'Passivo',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Post' => 'Processar',
+ 'Post as new' => 'Processar como novo',
+ 'Project' => 'Projecto',
+ 'Project not on file!' => 'Projecto não existe',
+ 'Purchase Invoice' => 'Factura de Compra',
+ 'Reference' => 'Referência',
+ 'Reference missing!' => 'Falta referência',
+ 'Reports' => 'Relatórios',
+ 'Sales Invoice' => 'Factura de Venda',
+ 'Select from one of the names below' => 'Seleccione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Seleccione um dos projectos abaixo',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Source' => 'Origem',
+ 'Subtotal' => 'Sub-total',
+ 'To' => 'Até',
+ 'Transaction Date missing!' => 'Falta Data de transacção!',
+ 'Transaction deleted!' => 'Transacção apagada',
+ 'Transaction posted!' => 'Transacção processada',
+ 'Update' => 'Actualizar',
+ 'Vendor not on file!' => 'Fornecedor não existe',
+ 'Yes' => 'Sim',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'transacção_fornecedores' => 'ap_transaction',
+ 'transacção_clientes' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'remover' => 'delete',
+ 'transacção_livro_razão' => 'gl_transaction',
+ 'processar' => 'post',
+ 'processar_como_novo' => 'post_as_new',
+ 'factura_de_compra' => 'purchase_invoice',
+ 'factura_de_venda' => 'sales_invoice',
+ 'actualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/ic b/sql-ledger/locale/pt/ic
new file mode 100644
index 0000000..80d4eb6
--- /dev/null
+++ b/sql-ledger/locale/pt/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Activo',
+ 'Add' => 'Novo',
+ 'Add Assembly' => 'Novo Conjunto',
+ 'Add Part' => 'Novo Produto',
+ 'Add Purchase Order' => 'Nova Ordem de Compra',
+ 'Add Sales Order' => 'Nova Encomenda de Cliente',
+ 'Add Service' => 'Novo Serviço',
+ 'Address' => 'Endereço',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Assemblies' => 'Conjuntos',
+ 'Assemblies restocked!' => 'Assemblies restocked!',
+ 'Assembly Number missing!' => 'Falta o Número de Produto',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Bought' => 'Comprado',
+ 'COGS' => 'Custo de Vendas',
+ 'Cannot delete item already invoiced!' => 'Não posso apagar item já facturado!',
+ 'Cannot delete item on order!' => 'Não pode apagar item no pedido',
+ 'Cannot delete item which is part of an assembly!' => 'Não é possível apagar Produto que faz parte de um Conjunto!',
+ 'Cannot delete item!' => 'Não é possivel apagar o item!',
+ 'Cannot stock assemblies!' => 'Cannot stock assemblies!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Remover',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'Drawing' => 'Drawing',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Falta Endereço de E-mail!',
+ 'Edit Assembly' => 'Editar Conjunto',
+ 'Edit Part' => 'Editar Produto',
+ 'Edit Service' => 'Editar Serviço',
+ 'Expense' => 'Despesa',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'Image' => 'Imagem',
+ 'In-line' => 'Inline',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Income' => 'Receita',
+ 'Individual Items' => 'Produtos Individuais',
+ 'Inventory' => 'Inventário',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Quantidade em Stock tem de ser zero para poder declarar este conjunto obsoleto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Quantidade em Stock tem de ser zero para poder declarar esta peça obsoleta!',
+ 'Inventory quantity must be zero!' => 'Quantidade em Stock tem de ser zero!',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Número de Factura não encontrado!',
+ 'Item deleted!' => 'Item apagado',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Last Cost' => 'Último Custo',
+ 'Line Total' => 'Total da Linha',
+ 'Link Accounts' => 'Ligar Contas',
+ 'List Price' => 'Listar Preço',
+ 'Make' => 'Marca',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Microfiche' => 'Microficha',
+ 'Model' => 'Modelo',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta numero na Linha',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'On Hand' => 'Em Stock',
+ 'On Order' => 'Encomendado',
+ 'Order' => 'Encomenda',
+ 'Order Date missing!' => 'Falta data da Encomenda',
+ 'Order Number' => 'Encomenda Número',
+ 'Order Number missing!' => 'Falta numero da Encomenda!',
+ 'Ordered' => 'Encomendado',
+ 'Orphaned' => 'Órfão',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Expedição',
+ 'Packing List Date missing!' => 'Falta Data da Lista de Expedição',
+ 'Packing List Number missing!' => 'Falta Numero de Lista de Expedição',
+ 'Part' => 'Produto',
+ 'Part Number missing!' => 'Número de produto não encontrado!',
+ 'Parts' => 'Produtos',
+ 'Phone' => 'Tel',
+ 'Postscript' => 'PostScript',
+ 'Price' => 'Preço',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projecto',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Qty' => 'Qtd',
+ 'ROP' => 'Nível mínimo de stock',
+ 'Recd' => 'Recebido',
+ 'Required by' => 'Requerido por',
+ 'Sales' => 'Vendas',
+ 'Sales Order' => 'Encomenda de Venda',
+ 'Save' => 'Guardar',
+ 'Screen' => 'Ecran',
+ 'Select from one of the items below' => 'Seleccione um dos items abaixo',
+ 'Select postscript or PDF!' => 'Seleccione PostScript ou PDF',
+ 'Sell Price' => 'Preço de Venda',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Service Number missing!' => 'Número do serviço não encontrado!',
+ 'Services' => 'Serviços',
+ 'Ship' => 'Expedir',
+ 'Ship to' => 'Expedir para',
+ 'Short' => 'Curta',
+ 'Sold' => 'Vendido',
+ 'Stock Assembly' => 'Conjunto em stock',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'To' => 'Até',
+ 'Top Level' => 'Nivel de topo',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidade',
+ 'Unit of measure' => 'Unidade de medida',
+ 'Update' => 'Actualizar',
+ 'Updated' => 'Actualizado',
+ 'Weight' => 'Peso',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'ea' => 'cd',
+ 'emailed to' => 'enviado por email para',
+ 'hr' => 'hr',
+ 'sent to printer' => 'enviado para a impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'novo' => 'add',
+ 'novo_conjunto' => 'add_assembly',
+ 'novo_produto' => 'add_part',
+ 'novo_serviço' => 'add_service',
+ 'continuar' => 'continue',
+ 'remover' => 'delete',
+ 'editar_conjunto' => 'edit_assembly',
+ 'editar_produto' => 'edit_part',
+ 'editar_serviço' => 'edit_service',
+ 'guardar' => 'save',
+ 'actualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/io b/sql-ledger/locale/pt/io
new file mode 100644
index 0000000..b85c352
--- /dev/null
+++ b/sql-ledger/locale/pt/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Nova Ordem de Compra',
+ 'Add Sales Order' => 'Nova Encomenda de Cliente',
+ 'Address' => 'Endereço',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Falta Endereço de E-mail!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'In-line' => 'Inline',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number missing!' => 'Número de Factura não encontrado!',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta numero na Linha',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Order' => 'Encomenda',
+ 'Order Date missing!' => 'Falta data da Encomenda',
+ 'Order Number missing!' => 'Falta numero da Encomenda!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Expedição',
+ 'Packing List Date missing!' => 'Falta Data da Lista de Expedição',
+ 'Packing List Number missing!' => 'Falta Numero de Lista de Expedição',
+ 'Part' => 'Produto',
+ 'Phone' => 'Tel',
+ 'Postscript' => 'PostScript',
+ 'Price' => 'Preço',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projecto',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Qty' => 'Qtd',
+ 'Recd' => 'Recebido',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Encomenda de Venda',
+ 'Screen' => 'Ecran',
+ 'Select from one of the items below' => 'Seleccione um dos items abaixo',
+ 'Select postscript or PDF!' => 'Seleccione PostScript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Ship' => 'Expedir',
+ 'Ship to' => 'Expedir para',
+ 'Subject' => 'Assunto',
+ 'To' => 'Até',
+ 'Unit' => 'Unidade',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'emailed to' => 'enviado por email para',
+ 'sent to printer' => 'enviado para a impressora',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/ir b/sql-ledger/locale/pt/ir
new file mode 100644
index 0000000..88fb49e
--- /dev/null
+++ b/sql-ledger/locale/pt/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Add Purchase Invoice' => 'Nova Factura de Compra',
+ 'Add Purchase Order' => 'Nova Ordem de Compra',
+ 'Add Sales Order' => 'Nova Encomenda de Cliente',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => 'Tem a certeza que quer APAGAR a Factura Número',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Não é possivel apagar a factura!',
+ 'Cannot post invoice for a closed period!' => 'Não pode lançar factura em período fechado!',
+ 'Cannot post invoice!' => 'Não é possivel lançar factura!',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Currency' => 'Moeda',
+ 'Customer not on file!' => 'Cliente inexistente!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data de Vencimento',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Remover',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Falta Endereço de E-mail!',
+ 'Edit Purchase Invoice' => 'Editar Factura de Compra',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de Câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'In-line' => 'Inline',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data de Factura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Número de Factura não encontrado!',
+ 'Invoice deleted!' => 'Factura apagada',
+ 'Invoice posted!' => 'Factura processada',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta numero na Linha',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Order' => 'Encomenda',
+ 'Order Date missing!' => 'Falta data da Encomenda',
+ 'Order Number' => 'Encomenda Número',
+ 'Order Number missing!' => 'Falta numero da Encomenda!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Expedição',
+ 'Packing List Date missing!' => 'Falta Data da Lista de Expedição',
+ 'Packing List Number missing!' => 'Falta Numero de Lista de Expedição',
+ 'Part' => 'Produto',
+ 'Payment date missing!' => 'Falta Data de Pagamento!',
+ 'Payments' => 'Pagamentos',
+ 'Phone' => 'Tel',
+ 'Post' => 'Processar',
+ 'Post as new' => 'Processar como novo',
+ 'Postscript' => 'PostScript',
+ 'Price' => 'Preço',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projecto',
+ 'Project not on file!' => 'Projecto não existe',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Qty' => 'Qtd',
+ 'Recd' => 'Recebido',
+ 'Record in' => 'Registar em',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Encomenda de Venda',
+ 'Screen' => 'Ecran',
+ 'Select from one of the items below' => 'Seleccione um dos items abaixo',
+ 'Select from one of the names below' => 'Seleccione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Seleccione um dos projectos abaixo',
+ 'Select postscript or PDF!' => 'Seleccione PostScript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Ship' => 'Expedir',
+ 'Ship to' => 'Expedir para',
+ 'Source' => 'Origem',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax Included' => 'Impostos incluídos',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidade',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Fornecedor',
+ 'Vendor missing!' => 'Falta fornecedor',
+ 'Vendor not on file!' => 'Fornecedor não existe',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'Yes' => 'Sim',
+ 'ea' => 'cd',
+ 'emailed to' => 'enviado por email para',
+ 'sent to printer' => 'enviado para a impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'remover' => 'delete',
+ 'encomenda' => 'order',
+ 'processar' => 'post',
+ 'processar_como_novo' => 'post_as_new',
+ 'actualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/is b/sql-ledger/locale/pt/is
new file mode 100644
index 0000000..9a33604
--- /dev/null
+++ b/sql-ledger/locale/pt/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Add Purchase Order' => 'Nova Ordem de Compra',
+ 'Add Sales Invoice' => 'Nova Factura de Venda',
+ 'Add Sales Order' => 'Nova Encomenda de Cliente',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Invoice Number' => 'Tem a certeza que quer APAGAR a Factura Número',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Não é possivel apagar a factura!',
+ 'Cannot post invoice for a closed period!' => 'Não pode lançar factura em período fechado!',
+ 'Cannot post invoice!' => 'Não é possivel lançar factura!',
+ 'Cannot post payment for a closed period!' => 'Não pode lançar pagamento em período fechado!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Currency' => 'Moeda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Falta cliente!',
+ 'Customer not on file!' => 'Cliente inexistente!',
+ 'Date' => 'Data',
+ 'Date Due' => 'Data de Vencimento',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Remover',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Falta Endereço de E-mail!',
+ 'Edit Sales Invoice' => 'Editar Factura de Venda',
+ 'Exch' => 'Câmbio',
+ 'Exchangerate' => 'Taxa de Câmbio',
+ 'Exchangerate for payment missing!' => 'Falta a taxa de câmbio para o pagamento!',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'In-line' => 'Inline',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Data de Factura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number' => 'Número de Factura',
+ 'Invoice Number missing!' => 'Número de Factura não encontrado!',
+ 'Invoice deleted!' => 'Factura apagada',
+ 'Invoice posted!' => 'Factura processada',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta numero na Linha',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Order' => 'Encomenda',
+ 'Order Date missing!' => 'Falta data da Encomenda',
+ 'Order Number' => 'Encomenda Número',
+ 'Order Number missing!' => 'Falta numero da Encomenda!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Expedição',
+ 'Packing List Date missing!' => 'Falta Data da Lista de Expedição',
+ 'Packing List Number missing!' => 'Falta Numero de Lista de Expedição',
+ 'Part' => 'Produto',
+ 'Payment date missing!' => 'Falta Data de Pagamento!',
+ 'Payments' => 'Pagamentos',
+ 'Phone' => 'Tel',
+ 'Post' => 'Processar',
+ 'Post as new' => 'Processar como novo',
+ 'Postscript' => 'PostScript',
+ 'Price' => 'Preço',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projecto',
+ 'Project not on file!' => 'Projecto não existe',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Qty' => 'Qtd',
+ 'Recd' => 'Recebido',
+ 'Record in' => 'Registar em',
+ 'Remaining' => 'Sobram',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Encomenda de Venda',
+ 'Screen' => 'Ecran',
+ 'Select from one of the items below' => 'Seleccione um dos items abaixo',
+ 'Select from one of the names below' => 'Seleccione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Seleccione um dos projectos abaixo',
+ 'Select postscript or PDF!' => 'Seleccione PostScript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Ship' => 'Expedir',
+ 'Ship to' => 'Expedir para',
+ 'Ship via' => 'Expedir via',
+ 'Source' => 'Origem',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax Included' => 'Impostos incluídos',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidade',
+ 'Update' => 'Actualizar',
+ 'Vendor not on file!' => 'Fornecedor não existe',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'Yes' => 'Sim',
+ 'ea' => 'cd',
+ 'emailed to' => 'enviado por email para',
+ 'sent to printer' => 'enviado para a impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'remover' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'encomenda' => 'order',
+ 'processar' => 'post',
+ 'processar_como_novo' => 'post_as_new',
+ 'imprimir' => 'print',
+ 'expedir_para' => 'ship_to',
+ 'actualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/login b/sql-ledger/locale/pt/login
new file mode 100644
index 0000000..cbe7624
--- /dev/null
+++ b/sql-ledger/locale/pt/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'Acerca',
+ 'Accounting' => 'Contabilidade',
+ 'Database Host' => 'Servidor de Base de Dados',
+ 'Dataset' => 'Dataset',
+ 'Incorrect Dataset version!' => 'Versão Dataset incorrecta!',
+ 'Incorrect Password!' => 'Password Incorrecta!',
+ 'Licensed to' => 'Licenciado a',
+ 'Login' => 'Login',
+ 'Name' => 'Nome',
+ 'Password' => 'Password',
+ 'User' => 'Utilizador',
+ 'Version' => 'Versão',
+ 'You are logged out!' => 'Terminou a sessão!',
+ 'You did not enter a name!' => 'Não indicou nome!',
+ 'is not a member!' => 'não é membro!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/menu b/sql-ledger/locale/pt/menu
new file mode 100644
index 0000000..97b81f7
--- /dev/null
+++ b/sql-ledger/locale/pt/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'Fornecedores',
+ 'AP Aging' => 'Idade Saldos Fornecedores',
+ 'AR' => 'Clientes',
+ 'AR Aging' => 'Idade Saldos Clientes',
+ 'Accounting Menu' => 'Menu de Contabilidade',
+ 'Add Account' => 'Nova Conta',
+ 'Add Assembly' => 'Novo Conjunto',
+ 'Add Customer' => 'Novo Cliente',
+ 'Add GIFI' => 'Adicionar CFOP',
+ 'Add Part' => 'Novo Produto',
+ 'Add Project' => 'Novo Projecto',
+ 'Add Service' => 'Novo Serviço',
+ 'Add Transaction' => 'Nova Transacção',
+ 'Add Vendor' => 'Novo Fornecedor',
+ 'Assemblies' => 'Conjuntos',
+ 'Audit Control' => 'Controlo de Auditoria',
+ 'Backup' => 'Backup',
+ 'Balance Sheet' => 'Folha de Balanço',
+ 'Cash' => 'Dinheiro',
+ 'Chart of Accounts' => 'Plano de Contas',
+ 'Check' => 'Cheque',
+ 'Customers' => 'Clientes',
+ 'General Ledger' => 'Livro Razão',
+ 'Goods & Services' => 'Bens e Serviços',
+ 'HTML Templates' => 'Templates HTML',
+ 'Income Statement' => 'Estado de Receitas',
+ 'Invoice' => 'Factura',
+ 'LaTeX Templates' => 'Modelos LaTeX',
+ 'List Accounts' => 'Listar Contas',
+ 'List GIFI' => 'Listar CFOP',
+ 'Logout' => 'Logout',
+ 'Order Entry' => 'Encomendas de Clientes',
+ 'Packing List' => 'Lista de Expedição',
+ 'Parts' => 'Produtos',
+ 'Payment' => 'Pagamento',
+ 'Payments' => 'Pagamentos',
+ 'Preferences' => 'Preferências',
+ 'Projects' => 'Projectos',
+ 'Purchase Invoice' => 'Factura de Compra',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Purchase Orders' => 'Ordens de Compra',
+ 'Receipt' => 'Recibo',
+ 'Receipts' => 'Recibos',
+ 'Reconciliation' => 'Reconciliação',
+ 'Reports' => 'Relatórios',
+ 'Sales Invoice' => 'Factura de Venda',
+ 'Sales Order' => 'Encomenda de Venda',
+ 'Sales Orders' => 'Encomendas de Venda',
+ 'Save to File' => 'Guardar em Ficheiro',
+ 'Send by E-Mail' => 'Enviar por Email',
+ 'Services' => 'Serviços',
+ 'Statement' => 'Statement',
+ 'Stock Assembly' => 'Conjunto em stock',
+ 'Stylesheet' => 'Stylesheet',
+ 'System' => 'Sistema',
+ 'Tax collected' => 'Imposto recolhido',
+ 'Tax paid' => 'Imposto pago',
+ 'Transactions' => 'Transacções',
+ 'Trial Balance' => 'Balancete',
+ 'Vendors' => 'Fornecedores',
+ 'Version' => 'Versão',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/oe b/sql-ledger/locale/pt/oe
new file mode 100644
index 0000000..1be330f
--- /dev/null
+++ b/sql-ledger/locale/pt/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Novo',
+ 'Add Purchase Invoice' => 'Nova Factura de Compra',
+ 'Add Purchase Order' => 'Nova Ordem de Compra',
+ 'Add Sales Invoice' => 'Nova Factura de Venda',
+ 'Add Sales Order' => 'Nova Encomenda de Cliente',
+ 'Address' => 'Endereço',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Are you sure you want to delete Order Number' => 'Confirma a remoção da Encomenda?',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Não é possivel apagar a encomenda!',
+ 'Cannot save order!' => 'Não é possível guardar encomenda!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Fechado',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Credit Limit' => 'Limite de Crédito',
+ 'Curr' => 'Moeda',
+ 'Currency' => 'Moeda',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Falta cliente!',
+ 'Customer not on file!' => 'Cliente inexistente!',
+ 'Date' => 'Data',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Delete' => 'Remover',
+ 'Delivery Date' => 'Data de entrega',
+ 'Description' => 'Descrição',
+ 'E-mail' => 'E-Mail',
+ 'E-mail address missing!' => 'Falta Endereço de E-mail!',
+ 'Edit Purchase Order' => 'Editar Ordem de Compra',
+ 'Edit Sales Order' => 'Editar Encomenda',
+ 'Exchangerate' => 'Taxa de Câmbio',
+ 'Exchangerate missing!' => 'Falta a taxa de câmbio!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'ID' => 'ID',
+ 'In-line' => 'Inline',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Data de Factura não encontrada!',
+ 'Invoice Number missing!' => 'Número de Factura não encontrado!',
+ 'Item not on file!' => 'Item não está no arquivo!',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'Name' => 'Nome',
+ 'No.' => 'No.',
+ 'Notes' => 'Notas',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta numero na Linha',
+ 'O' => 'O',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'Open' => 'Abrir',
+ 'Order' => 'Encomenda',
+ 'Order Date' => 'Data da Encomenda',
+ 'Order Date missing!' => 'Falta data da Encomenda',
+ 'Order Number' => 'Encomenda Número',
+ 'Order Number missing!' => 'Falta numero da Encomenda!',
+ 'Order deleted!' => 'Encomenda apagada',
+ 'Order saved!' => 'Encomenda guardada',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Expedição',
+ 'Packing List Date missing!' => 'Falta Data da Lista de Expedição',
+ 'Packing List Number missing!' => 'Falta Numero de Lista de Expedição',
+ 'Part' => 'Produto',
+ 'Phone' => 'Tel',
+ 'Postscript' => 'PostScript',
+ 'Price' => 'Preço',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Project' => 'Projecto',
+ 'Project not on file!' => 'Projecto não existe',
+ 'Purchase Order' => 'Ordem de Compra',
+ 'Purchase Orders' => 'Ordens de Compra',
+ 'Qty' => 'Qtd',
+ 'Recd' => 'Recebido',
+ 'Remaining' => 'Sobram',
+ 'Required by' => 'Requerido por',
+ 'Sales Order' => 'Encomenda de Venda',
+ 'Sales Orders' => 'Encomendas de Venda',
+ 'Save' => 'Guardar',
+ 'Save as new' => 'Guardar como novo',
+ 'Screen' => 'Ecran',
+ 'Select from one of the items below' => 'Seleccione um dos items abaixo',
+ 'Select from one of the names below' => 'Seleccione um dos nomes abaixo',
+ 'Select from one of the projects below' => 'Seleccione um dos projectos abaixo',
+ 'Select postscript or PDF!' => 'Seleccione PostScript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Service' => 'Serviço',
+ 'Ship' => 'Expedir',
+ 'Ship to' => 'Expedir para',
+ 'Ship via' => 'Expedir via',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'Tax Included' => 'Impostos incluídos',
+ 'Terms: Net' => 'Termos: A pronto',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidade',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Fornecedor',
+ 'Vendor missing!' => 'Falta fornecedor',
+ 'Vendor not on file!' => 'Fornecedor não existe',
+ 'What type of item is this?' => 'Que tipo de Item é este?',
+ 'Yes' => 'Sim',
+ 'days' => 'dias',
+ 'ea' => 'cd',
+ 'emailed to' => 'enviado por email para',
+ 'sent to printer' => 'enviado para a impressora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'novo' => 'add',
+ 'continuar' => 'continue',
+ 'remover' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'factura' => 'invoice',
+ 'imprimir' => 'print',
+ 'guardar' => 'save',
+ 'guardar_como_novo' => 'save_as_new',
+ 'expedir_para' => 'ship_to',
+ 'actualizar' => 'update',
+ 'sim' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/pe b/sql-ledger/locale/pt/pe
new file mode 100644
index 0000000..fc71393
--- /dev/null
+++ b/sql-ledger/locale/pt/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Novo',
+ 'Add Project' => 'Novo Projecto',
+ 'All' => 'Todos',
+ 'Continue' => 'Continuar',
+ 'Delete' => 'Remover',
+ 'Description' => 'Descrição',
+ 'Edit Project' => 'Editar Projecto',
+ 'Number' => 'Número',
+ 'Orphaned' => 'Órfão',
+ 'Project' => 'Projecto',
+ 'Project Number missing!' => 'Falta o número do projecto',
+ 'Project deleted!' => 'Projecto apagado',
+ 'Project saved!' => 'Projecto guardado',
+ 'Projects' => 'Projectos',
+ 'Save' => 'Guardar',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'novo' => 'add',
+ 'continuar' => 'continue',
+ 'remover' => 'delete',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/rc b/sql-ledger/locale/pt/rc
new file mode 100644
index 0000000..28c8216
--- /dev/null
+++ b/sql-ledger/locale/pt/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Conta',
+ 'Balance' => 'Saldo',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'Continuar',
+ 'Date' => 'Data',
+ 'Deposit' => 'Depósito',
+ 'Description' => 'Descrição',
+ 'Difference' => 'Diferença',
+ 'Done' => 'Pronto',
+ 'Exchangerate Difference' => 'Diferença na Taxa de Câmbio',
+ 'From' => 'De',
+ 'Out of balance!' => 'Out of balance!',
+ 'Payment' => 'Pagamento',
+ 'Reconciliation' => 'Reconciliação',
+ 'Select all' => 'Seleccionar todos',
+ 'Source' => 'Origem',
+ 'Statement Balance' => 'Statement Balance',
+ 'To' => 'Até',
+ 'Update' => 'Actualizar',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continuar' => 'continue',
+ 'pronto' => 'done',
+ 'seleccionar_todos' => 'select_all',
+ 'actualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/pt/rp b/sql-ledger/locale/pt/rp
new file mode 100644
index 0000000..c452e9c
--- /dev/null
+++ b/sql-ledger/locale/pt/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Idade Saldos Fornecedores',
+ 'AR Aging' => 'Idade Saldos Clientes',
+ 'Account' => 'Conta',
+ 'Accounts' => 'Contas',
+ 'Amount' => 'Total',
+ 'Apr' => 'Abr',
+ 'April' => 'Abril',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Ago',
+ 'August' => 'Agosto',
+ 'Balance Sheet' => 'Folha de Balanço',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Comparar com',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Cópias',
+ 'Credit' => 'Crédito',
+ 'Current' => 'Current',
+ 'Customer' => 'Cliente',
+ 'Date' => 'Data',
+ 'Debit' => 'Débito',
+ 'Dec' => 'Dez',
+ 'December' => 'Dezembro',
+ 'Decimalplaces' => 'Casas decimais',
+ 'Description' => 'Descrição',
+ 'Due' => 'Vence',
+ 'E-mail' => 'E-Mail',
+ 'E-mail Statement to' => 'E-mail Statement to',
+ 'Feb' => 'Fev',
+ 'February' => 'Fevereiro',
+ 'From' => 'De',
+ 'GIFI' => 'CFOP - Código Fiscal da Operação',
+ 'Heading' => 'Cabeçalho',
+ 'ID' => 'ID',
+ 'In-line' => 'Inline',
+ 'Include in Report' => 'Incluir no Relatório',
+ 'Income Statement' => 'Estado de Receitas',
+ 'Invoice' => 'Factura',
+ 'Jan' => 'Jan',
+ 'January' => 'Janeiro',
+ 'Jul' => 'Jul',
+ 'July' => 'Julho',
+ 'Jun' => 'Jun',
+ 'June' => 'Junho',
+ 'Mar' => 'Mar',
+ 'March' => 'Março',
+ 'May' => 'Mai',
+ 'May ' => 'Maio',
+ 'Message' => 'Mensagem',
+ 'N/A' => 'N/D',
+ 'Nothing selected!' => 'Nada seleccionado',
+ 'Nov' => 'Nov',
+ 'November' => 'Novembro',
+ 'Oct' => 'Out',
+ 'October' => 'Outubro',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Pagamentos',
+ 'Postscript' => 'PostScript',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impressora',
+ 'Receipts' => 'Recibos',
+ 'Report for' => 'Relatório para',
+ 'Retained Earnings' => 'Lucros Retidos',
+ 'Screen' => 'Ecran',
+ 'Select all' => 'Seleccionar todos',
+ 'Select postscript or PDF!' => 'Seleccione PostScript ou PDF',
+ 'Sep' => 'Set',
+ 'September' => 'Setembro',
+ 'Source' => 'Origem',
+ 'Standard' => 'Padrão',
+ 'Statement' => 'Statement',
+ 'Statement sent to' => 'Statement sent to',
+ 'Statements sent to printer!' => 'Statements sent to printer!',
+ 'Subject' => 'Assunto',
+ 'Subtotal' => 'Sub-total',
+ 'Tax' => 'Imposto',
+ 'Tax collected' => 'Imposto recolhido',
+ 'Tax paid' => 'Imposto pago',
+ 'To' => 'Até',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Balancete',
+ 'Vendor' => 'Fornecedor',
+ 'as at' => 'as at',
+ 'collected on sales' => 'recolhido sobre vendas',
+ 'for Period' => 'pelo período',
+ 'paid on purchases' => 'pago em aquisições',
+ 'to' => 'para',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continuar' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'imprimir' => 'print',
+ 'seleccionar_todos' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/COPYING b/sql-ledger/locale/ru/COPYING
new file mode 100644
index 0000000..411c170
--- /dev/null
+++ b/sql-ledger/locale/ru/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2002
+#
+# Russian texts:
+#
+# Author:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/ru/LANGUAGE b/sql-ledger/locale/ru/LANGUAGE
new file mode 100644
index 0000000..64c9578
--- /dev/null
+++ b/sql-ledger/locale/ru/LANGUAGE
@@ -0,0 +1 @@
+Russian
diff --git a/sql-ledger/locale/ru/admin b/sql-ledger/locale/ru/admin
new file mode 100644
index 0000000..3f10bcf
--- /dev/null
+++ b/sql-ledger/locale/ru/admin
@@ -0,0 +1,122 @@
+$self{texts} = {
+ 'Access Control' => 'ëÏÎÔÒÏÌØ ÄÏÓÔÕÐÁ',
+ 'Accounting' => 'Accounting',
+ 'Add User' => 'îÏ×ÙÊ ÐÏÌØÚÏ×ÁÔÅÌØ',
+ 'Address' => 'áÄÒÅÓ',
+ 'Administration' => 'áÄÍÉÎÉÓÔÒÉÒÏ×ÁÎÉÅ',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => 'All Datasets up to date!',
+ 'Change Admin Password' => 'éÚÍÅÎÉÔØ ÐÁÒÏÌØ áÄÍÉÎÉÓÔÒÁÔÏÒÁ',
+ 'Change Password' => 'éÚÍÅÎÉÔØ ÐÁÒÏÌØ',
+ 'Character Set' => 'ëÏÄÉÒÏ×ËÁ',
+ 'Click on login name to edit!' => 'Kliknij nazwê u¿ytkownika ¿eby dokonaæ zmian',
+ 'Company' => 'ïÒÇÁÎÉÚÁÃÉÑ',
+ 'Connect to' => 'ðÏÄËÌÀÞÉÔØÓÑ Ë',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Create Chart of Accounts' => 'óÏÚÄÁÔØ çðó',
+ 'Create Dataset' => 'Utwórz Zbiór Danych',
+ 'DBI not installed!' => 'îÅ ÕÓÔÁÎÏ×ÌÅÎ ÄÒÁÊ×ÅÒ DBI!',
+ 'Database' => 'âÁÚÁ ÄÁÎÎÙÈ',
+ 'Database Administration' => 'áÄÍÉÎÉÓÔÒÉÒÏ×ÁÎÉÅ ÂÁÚÙ ÄÁÎÎÙÈ',
+ 'Database Driver not checked!' => 'Sterownik Bazy Danych nie zaznaczony!',
+ 'Database User missing!' => 'Brak U¿ytkownika Bazy Danych!',
+ 'Dataset' => 'Zbiór Danych',
+ 'Dataset missing!' => 'Brak Zbioru Danych',
+ 'Dataset updated!' => 'Dataset updated!',
+ 'Date Format' => 'æÏÒÍÁÔ ÄÁÔÙ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Delete Dataset' => 'Usuñ Zbior Danych',
+ 'Directory' => 'ëÁÔÁÌÏÇ',
+ 'Driver' => 'Sterownik',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'E-mail',
+ 'Edit User' => 'Zmiany U¿ytkownika',
+ 'Existing Datasets' => 'Istniej±cy Zbiór Danych',
+ 'Fax' => 'Fax',
+ 'Host' => 'Wêze³',
+ 'Hostname missing!' => 'Brak Nazwy Wêz³a',
+ 'Incorrect Password!' => 'Nieprawid³owe Has³o',
+ 'Language' => 'ñÚÙË',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Opu¶æ pole wêz³a i portu, chyba ¿e chcesz mieæ zdalne po³±czenie',
+ 'Login' => 'Zarejestrój siê',
+ 'Name' => 'Nazwa',
+ 'New Templates' => 'Nowe Szablony',
+ 'No Database Drivers available!' => 'Sterownik Bazy Danych jest niedostêpny',
+ 'No Dataset selected!' => 'Nie jest zaznaczony Zbiór Danych',
+ 'Nothing to delete!' => 'Niema nic do usuniêcia!',
+ 'Number Format' => 'Format Numeru',
+ 'Oracle Database Administration' => 'Administracja Bazy Danych Oracle',
+ 'Password' => 'Has³o',
+ 'Password changed!' => 'Password changed!',
+ 'Pg Database Administration' => 'Administracja Bazy Danych Pg',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Brak Portu',
+ 'Printer' => 'Drukarka',
+ 'Save' => 'Zapisz',
+ 'Select a Dataset to delete and press "Continue"' => 'Wybierz Zbiór Danych do usuniêcia i naci¶nij "Kontynuj"',
+ 'Setup Templates' => 'Ustaw Szablony',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'ðÏÄÐÉÓØ',
+ 'Stylesheet' => 'ïÆÏÒÍÌÅÎÉÅ',
+ 'Templates' => 'æÏÒÍÙ',
+ 'The following Datasets are not in use and can be deleted' => 'Te Zbiory Danych s± nieu¿ywane i mo¿na je usun±æ',
+ 'The following Datasets need to be updated' => 'Zbiory Danych do uzupe³nienia',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Jest to wstêpne sprawdzenie istniej±cych ¿róde³. Narazie nic nie bêdzie utworzone lub usuniête.',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => '¯eby dodaæ do grupy u¿ytkownika zmieñ nazwê, nazwê zarejestrowania i zapisz. Nowy u¿ytkownik z tymi samymi zmiennymi warto¶ciami bêdzie zapisany pod now± nazw± rejestruj±c±',
+ 'Update Dataset' => 'Uzupe³nij Zbiór Danych',
+ 'Use Templates' => 'U¿yj Szablony',
+ 'User' => 'U¿ytkownik',
+ 'User deleted!' => 'User deleted!',
+ 'User saved!' => 'User saved!',
+ 'Version' => '÷ÅÒÓÉÑ',
+ 'You must enter a host and port for local and remote connections!' => 'Wstaw wêze³ i port dla lokalnego i zdalnego po³±czenia',
+ 'does not exist' => 'nie istnieje',
+ 'is already a member!' => 'Jest ju¿ cz³onkiem',
+ 'localhost' => 'wêze³',
+ 'successfully created!' => 'stworzone z powodzeniem',
+ 'successfully deleted!' => 'usuniête z powodzeniem',
+ 'website' => 'witryna WWW',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'îÏ×ÙÊ_ÐÏÌØÚÏ×ÁÔÅÌØ' => 'add_user',
+ 'éÚÍÅÎÉÔØ_ÐÁÒÏÌØ_áÄÍÉÎÉÓÔÒÁÔÏÒÁ' => 'change_admin_password',
+ 'éÚÍÅÎÉÔØ_ÐÁÒÏÌØ' => 'change_password',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'utwórz_zbiór_danych' => 'create_dataset',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'usuñ_zbior_danych' => 'delete_dataset',
+ 'zarejestrój_siê' => 'login',
+ 'administracja_bazy_danych_oracle' => 'oracle_database_administration',
+ 'administracja_bazy_danych_pg' => 'pg_database_administration',
+ 'zapisz' => 'save',
+ 'uzupe³nij_zbiór_danych' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/all b/sql-ledger/locale/ru/all
new file mode 100644
index 0000000..a87eee9
--- /dev/null
+++ b/sql-ledger/locale/ru/all
@@ -0,0 +1,487 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'òÁÓÈÏÄ',
+ 'AP Aging' => 'AP Aging',
+ 'AP Transaction' => '',
+ 'AP Transactions' => 'ðÒÏ×ÏÄËÉ ÒÁÓÈÏÄÁ',
+ 'AR' => 'äÏÈÏÄ',
+ 'AR Aging' => 'AR Aging',
+ 'AR Transaction' => '',
+ 'AR Transactions' => 'ðÒÏ×ÏÄËÉ ÄÏÈÏÄÁ',
+ 'About' => 'ï ÐÒÏÇÒÁÍÍÅ',
+ 'Access Control' => 'ëÏÎÔÒÏÌØ ÄÏÓÔÕÐÁ',
+ 'Account' => 'óÞÅÔ',
+ 'Account Number' => 'ëÏÄ ÓÞÅÔÁ',
+ 'Account Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ!',
+ 'Account Type' => 'ôÉÐ ÓÞÅÔÁ',
+ 'Account Type missing!' => 'îÅ ÕËÁÚÁÎ ÔÉÐ ÓÞÅÔÁ!',
+ 'Account deleted!' => '',
+ 'Account saved!' => '',
+ 'Accounting' => 'Accounting',
+ 'Accounting Menu' => 'Accounting Menu',
+ 'Accounts' => 'óÞÅÔÁ',
+ 'Active' => '',
+ 'Add' => 'îÏ×ÙÊ',
+ 'Add Account' => 'îÏ×ÙÊ ÓÞÅÔ',
+ 'Add Accounts Payables Transaction' => '',
+ 'Add Accounts Receivables Transaction' => '',
+ 'Add Assembly' => 'îÏ×ÙÊ ËÏÍÐÌÅËÔ',
+ 'Add Customer' => 'îÏ×ÙÊ ËÌÉÅÎÔ',
+ 'Add GIFI' => 'îÏ×ÙÊ GIFI',
+ 'Add General Ledger Transaction' => 'îÏ×ÁÑ ÐÒÏ×ÏÄËÁ',
+ 'Add Part' => 'îÏ×ÙÊ ÐÒÏÄÕËÔ',
+ 'Add Project' => '',
+ 'Add Purchase Invoice' => '',
+ 'Add Purchase Order' => 'îÏ×ÙÊ ÚÁËÁÚ ÐÏÓÔÁ×ÝÉËÁ',
+ 'Add Sales Invoice' => '',
+ 'Add Sales Order' => 'îÏ×ÙÊ ÚÁËÁÚ ËÌÉÅÎÔÁ',
+ 'Add Service' => 'îÏ×ÁÑ ÕÓÌÕÇÁ',
+ 'Add Transaction' => 'îÏ×ÁÑ ÐÒÏ×ÏÄËÁ',
+ 'Add User' => 'îÏ×ÙÊ ÐÏÌØÚÏ×ÁÔÅÌØ',
+ 'Add Vendor' => 'îÏ×ÙÊ ÐÏÓÔÁ×ÝÉË',
+ 'Address' => 'áÄÒÅÓ',
+ 'Administration' => 'áÄÍÉÎÉÓÔÒÉÒÏ×ÁÎÉÅ',
+ 'Administrator' => '',
+ 'All' => '÷ÓÅ',
+ 'All Datasets up to date!' => 'All Datasets up to date!',
+ 'Amount' => 'óÕÍÍÁ',
+ 'Amount Due' => '',
+ 'Amount does not equal applied!' => '',
+ 'Amount missing!' => '',
+ 'Applied' => '',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Are you sure you want to delete Invoice Number' => '÷Ù Õ×ÅÒÅÎÙ, ÞÔÏ ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÄÁÎÎÙÊ ÓÞÅÔ?',
+ 'Are you sure you want to delete Order Number' => '÷Ù Õ×ÅÒÅÎÙ, ÞÔÏ ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÄÁÎÎÙÊ ÚÁËÁÚ?',
+ 'Are you sure you want to delete Transaction' => '÷Ù Õ×ÅÒÅÎÙ, ÓÔÏ ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÄÁÎÎÕÀ ÐÒÏ×ÏÄËÕ?',
+ 'Assemblies' => 'ëÏÍÐÌÅËÔÙ',
+ 'Assemblies restocked!' => '',
+ 'Assembly Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ËÏÍÐÌÅËÔÁ!',
+ 'Asset' => 'áËÔÉ×',
+ 'Attachment' => '÷ÌÏÖÅÎÉÅ',
+ 'Audit Control' => 'ëÏÎÔÒÏÌØ',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'BOM' => '',
+ 'Backup' => 'òÅÚÅÒ×ÎÁÑ ËÏÐÉÑ',
+ 'Backup sent to' => 'òÅÚÅÒ×ÎÁÑ ËÏÐÉÑ ÏÔÏÓÌÁÎÁ ÎÁ',
+ 'Balance' => '',
+ 'Balance Sheet' => 'âÁÌÁÎÓ',
+ 'Bcc' => '',
+ 'Bin' => 'Bin',
+ 'Books are open' => 'ëÎÉÇÁ ÏÔËÒÙÔÁ',
+ 'Bought' => 'ëÕÐÌÅÎÏ',
+ 'Business Number' => 'òîî',
+ 'C' => '',
+ 'COGS' => 'COGS',
+ 'Cannot delete account!' => '',
+ 'Cannot delete customer!' => '',
+ 'Cannot delete default account!' => 'îÅÌØÚÑ ÕÄÁÌÉÔØ ÏÓÎÏ×ÎÏÊ ÓÞÅÔ!',
+ 'Cannot delete invoice!' => '',
+ 'Cannot delete item already invoiced!' => 'Nie mo¿na usun±æ pozycji zafakturowanej!',
+ 'Cannot delete item on order!' => 'Nie mo¿na usunac zamówionego produktu!',
+ 'Cannot delete item which is part of an assembly!' => 'Nie mo¿na usun±æ czê¶ci z zestawienia!',
+ 'Cannot delete item!' => '',
+ 'Cannot delete order!' => '',
+ 'Cannot delete transaction!' => '',
+ 'Cannot delete vendor!' => '',
+ 'Cannot have a value in both Debit and Credit!' => 'Nie mo¿na wpisaæ warto¶ci w Debet i Kredyt równocze¶nie!',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => 'Nie mo¿na zksiêgowaæ faktury pozamkniêciu okresu',
+ 'Cannot post invoice!' => '',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cannot post payment!' => '',
+ 'Cannot post transaction for a closed period!' => 'Nie mo¿na zaksiêgowaæ transakcji w zamkniêtym okresie',
+ 'Cannot post transaction!' => '',
+ 'Cannot process payment for a closed period!' => '',
+ 'Cannot save account!' => '',
+ 'Cannot save order!' => '',
+ 'Cannot save preferences!' => '',
+ 'Cannot stock assemblies!' => '',
+ 'Cash' => '',
+ 'Cash based' => '',
+ 'Cc' => '',
+ 'Change Admin Password' => 'éÚÍÅÎÉÔØ ÐÁÒÏÌØ áÄÍÉÎÉÓÔÒÁÔÏÒÁ',
+ 'Change Password' => 'éÚÍÅÎÉÔØ ÐÁÒÏÌØ',
+ 'Character Set' => 'ëÏÄÉÒÏ×ËÁ',
+ 'Chart of Accounts' => 'ðÌÁÎ ÓÞÅÔÏ×',
+ 'Check' => '',
+ 'Check printed!' => '',
+ 'Check printing failed!' => '',
+ 'Cleared Balance' => '',
+ 'Click on login name to edit!' => 'Kliknij nazwê u¿ytkownika ¿eby dokonaæ zmian',
+ 'Close Books up to' => 'Zamkniêcie Ksi±g do!',
+ 'Closed' => 'úÁËÒÙÔ',
+ 'Company' => 'ïÒÇÁÎÉÚÁÃÉÑ',
+ 'Compare to' => 'óÒÁ×ÎÉÔØ Ó',
+ 'Confirm!' => 'ðÏÄÔ×ÅÒÄÉÔØ!',
+ 'Connect to' => 'ðÏÄËÌÀÞÉÔØÓÑ Ë',
+ 'Contact' => 'ëÏÎÔÁËÔÎÏÅ ÌÉÃÏ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Copies' => 'ëÏÐÉÊ',
+ 'Copy to COA' => 'ëÏÐÉÒÏ×ÁÔØ × çðó',
+ 'Create Chart of Accounts' => 'óÏÚÄÁÔØ çðó',
+ 'Create Dataset' => 'Utwórz Zbiór Danych',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Credit Limit' => 'ìÉÍÉÔ ËÒÅÄÉÔÁ',
+ 'Curr' => '÷ÁÌÀÔÁ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Current' => '',
+ 'Customer' => 'ëÌÉÅÎÔ',
+ 'Customer deleted!' => '',
+ 'Customer missing!' => '',
+ 'Customer not on file!' => '',
+ 'Customer saved!' => '',
+ 'Customers' => '',
+ 'DBI not installed!' => 'îÅ ÕÓÔÁÎÏ×ÌÅÎ ÄÒÁÊ×ÅÒ DBI!',
+ 'Database' => 'âÁÚÁ ÄÁÎÎÙÈ',
+ 'Database Administration' => 'áÄÍÉÎÉÓÔÒÉÒÏ×ÁÎÉÅ ÂÁÚÙ ÄÁÎÎÙÈ',
+ 'Database Driver not checked!' => 'Sterownik Bazy Danych nie zaznaczony!',
+ 'Database Host' => 'Wêze³ Bazy Danych',
+ 'Database User missing!' => 'Brak U¿ytkownika Bazy Danych!',
+ 'Dataset' => 'Zbiór Danych',
+ 'Dataset missing!' => 'Brak Zbioru Danych',
+ 'Dataset updated!' => '',
+ 'Date' => 'äÁÔÁ',
+ 'Date Due' => 'ïÐÌÁÔÉÔØ ÄÏ',
+ 'Date Format' => 'æÏÒÍÁÔ ÄÁÔÙ',
+ 'Date Paid' => 'äÁÔÁ ÏÐÌÁÔÙ',
+ 'Date missing!' => '',
+ 'Debit' => 'äÅÂÅÔ',
+ 'Debit and credit out of balance!' => 'Debet i Kredyt siê niebalansuj±!',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Decimalplaces' => '',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Delete Account' => 'õÄÁÌÍÔØ ÓÞÅÔ',
+ 'Delete Dataset' => 'Usuñ Zbior Danych',
+ 'Delivery Date' => '',
+ 'Deposit' => '',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Difference' => '',
+ 'Directory' => 'ëÁÔÁÌÏÇ',
+ 'Discount' => 'óËÉÄËÁ',
+ 'Done' => '',
+ 'Drawing' => '',
+ 'Driver' => 'Sterownik',
+ 'Dropdown Limit' => '',
+ 'Due' => 'äÏ',
+ 'Due Date' => 'ïÐÌÁÔÉÔØ ÄÏ',
+ 'Due Date missing!' => 'îÅ ÕËÁÚÁÎ ÓÒÏË ÏÐÌÁÔÙ!',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => '',
+ 'E-mail address missing!' => 'îÅ ÕËÁÚÁÎ ÁÄÒÅÓ E-mail!',
+ 'Edit' => '',
+ 'Edit Account' => 'éÚÍÅÎÉÔØ ÓÞÅÔ',
+ 'Edit Accounts Payables Transaction' => '',
+ 'Edit Accounts Receivables Transaction' => '',
+ 'Edit Assembly' => 'éÚÍÅÎÉÔØ ËÏÍÐÌÅËÔ',
+ 'Edit GIFI' => 'éÚÍÅÎÉÔØ GIFI',
+ 'Edit General Ledger Transaction' => 'Zmiany w Ksiêdze G³ównej',
+ 'Edit Part' => 'Zmiany Produktu',
+ 'Edit Preferences for' => 'Zmiany Preferencji dla',
+ 'Edit Project' => '',
+ 'Edit Purchase Invoice' => '',
+ 'Edit Purchase Order' => 'Zmiany Zamówienia Zakupu',
+ 'Edit Sales Invoice' => '',
+ 'Edit Sales Order' => 'Zmiany Zamówienia Klienta',
+ 'Edit Service' => 'éÚÍÅÎÉÔØ ÕÓÌÕÇÕ',
+ 'Edit Template' => 'Zmiany Wzorca',
+ 'Edit User' => 'Zmiany U¿ytkownika',
+ 'Employee' => '',
+ 'Enforce transaction reversal for all dates' => 'Egzekwuj zmiany transakcji dla wszystkich terminów',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => '',
+ 'Equity' => 'Kapita³',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate Difference' => '',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Existing Datasets' => 'Istniej±cy Zbiór Danych',
+ 'Expense' => 'òÁÓÈÏÄ',
+ 'Expense Account' => 'Konto Kosztów',
+ 'Expense/Asset' => 'Koszt/Aktywy',
+ 'Extended' => '',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'Foreign Exchange Gain' => 'Zysk przy Wymianie Walut',
+ 'Foreign Exchange Loss' => 'Strata przy Wymianie Walut',
+ 'From' => 'Od',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => '',
+ 'GIFI missing!' => 'Brakuje GIFI',
+ 'GIFI saved!' => '',
+ 'GL Transaction' => '',
+ 'General Ledger' => 'Ksiêga G³ówna',
+ 'Goods & Services' => 'Produkty i Us³ugi',
+ 'HTML Templates' => 'Szablony HTML',
+ 'Heading' => 'òÁÚÄÅÌ',
+ 'Host' => 'Wêze³',
+ 'Hostname missing!' => 'Brak Nazwy Wêz³a',
+ 'ID' => 'Identyfikator',
+ 'Image' => '',
+ 'In-line' => 'W³±czony',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Include in drop-down menus' => 'Do³±cz w menu rozwijanym',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Do³±cz Konto w formularzach Kontrachentów ¿eby wskazaæ ¿e podlegaj± opodatkowaniu',
+ 'Income' => 'äÏÈÏÄ',
+ 'Income Account' => 'Konto Przychodów',
+ 'Income Statement' => 'Rachunek Zysków i Strat',
+ 'Incorrect Dataset version!' => 'Nieprawid³owa wersja Zbioru Danych',
+ 'Incorrect Password!' => 'Nieprawid³owe Has³o',
+ 'Individual Items' => 'Indywidualne Czê¶ci',
+ 'Inventory' => 'éÎ×ÅÎÔÁÒÎÙÊ',
+ 'Inventory Account' => 'Konto Materia³owe',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Ilo¶æ Inventarza musi byæ równa zero zanim bêdzie mozna zdezaktualizowaæ to z³o¿enie!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Ilo¶æ inventarza musi byæ równa zero zanim bêdzie mo¿na zdezaktualizowaæ t± czê¶æ!',
+ 'Inventory quantity must be zero!' => 'Ilo¶æc Inventarza musi byæ równa zero',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ',
+ 'Invoice Date missing!' => 'îÅ ÕËÁÚÁÎÁ ÄÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number' => 'îÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice deleted!' => '',
+ 'Invoice posted!' => '',
+ 'Invoices' => '',
+ 'Is this a summary account to record' => 'Czy jest to konto sumaryczne?',
+ 'Item deleted!' => '',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'LaTeX Templates' => 'Szablony LaTeX',
+ 'Language' => 'ñÚÙË',
+ 'Last Cost' => 'Cena Zakupu',
+ 'Last Invoice Number' => 'Ostatni Numer Faktury',
+ 'Last Numbers & Default Accounts' => 'Ostatnie Numery i Konta Domy¶lne',
+ 'Last Purchase Order Number' => 'Ostatni Numer Faktury Zamówienia',
+ 'Last Sales Order Number' => 'Ostatni Numer Faktury Sprzeda¿y',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Opu¶æ pole wêz³a i portu, chyba ¿e chcesz mieæ zdalne po³±czenie',
+ 'Liability' => 'ðÁÓÓÉ×',
+ 'Licensed to' => 'ìÉÃÅÎÚÉÅÊ ÏÂÌÁÄÁÅÔ:',
+ 'Line Total' => 'Suma ca³kowita',
+ 'Link' => 'Dowi±zanie',
+ 'Link Accounts' => 'Konta dowi±zane',
+ 'List Accounts' => 'Spis Kont',
+ 'List GIFI' => 'Wykaz GIFI',
+ 'List Price' => 'Cena',
+ 'List Transactions' => 'Wykaz Transakcji',
+ 'Login' => 'Zarejestrój siê',
+ 'Logout' => 'Wyrejestrój siê',
+ 'Make' => 'Marka',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Microfiche' => '',
+ 'Model' => 'Model',
+ 'N/A' => 'N/A',
+ 'Name' => 'Nazwa',
+ 'Name missing!' => '',
+ 'New Templates' => 'Nowe Szablony',
+ 'No' => 'Nie',
+ 'No Database Drivers available!' => 'Sterownik Bazy Danych jest niedostêpny',
+ 'No Dataset selected!' => 'Nie jest zaznaczony Zbiór Danych',
+ 'No email address for' => 'Brak adresu email',
+ 'No.' => '',
+ 'Notes' => 'Noty',
+ 'Nothing applied!' => '',
+ 'Nothing selected!' => '',
+ 'Nothing to delete!' => 'Niema nic do usuniêcia!',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number Format' => 'Format Numeru',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'O' => '',
+ 'Obsolete' => 'Zdezaktualizowany',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'On Hand' => 'Na Stanie',
+ 'On Order' => '',
+ 'Open' => 'Otwórz',
+ 'Oracle Database Administration' => 'Administracja Bazy Danych Oracle',
+ 'Order' => 'Zamówienie',
+ 'Order Date' => 'Data Zamówienia',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Entry' => 'Wystawianie Zamówieñ',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'Order deleted!' => '',
+ 'Order saved!' => '',
+ 'Ordered' => '',
+ 'Orphaned' => 'Zbêdny',
+ 'Out of balance!' => '',
+ 'PDF' => '',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Paid' => 'Zap³acono',
+ 'Paid in full' => '',
+ 'Part' => 'Produkt',
+ 'Part Number missing!' => 'Brak Symbolu Produktu!',
+ 'Parts' => 'Produkty',
+ 'Parts Inventory' => 'Inwentarz',
+ 'Password' => 'Has³o',
+ 'Password changed!' => '',
+ 'Payables' => 'Zobowi±zania',
+ 'Payment' => 'P³atno¶æ',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payment posted!' => '',
+ 'Payments' => 'Rozliczenia P³atno¶ci',
+ 'Pg Database Administration' => 'Administracja Bazy Danych Pg',
+ 'Phone' => 'Tel.',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Brak Portu',
+ 'Post' => '',
+ 'Post as new' => '',
+ 'Postscript' => '',
+ 'Preferences' => 'Preferencje',
+ 'Preferences saved!' => 'Preferencje Zapisane!',
+ 'Price' => 'Cena Netto',
+ 'Print' => '',
+ 'Printer' => 'Drukarka',
+ 'Project' => '',
+ 'Project Number missing!' => '',
+ 'Project deleted!' => '',
+ 'Project not on file!' => '',
+ 'Project saved!' => '',
+ 'Projects' => '',
+ 'Purchase Invoice' => '',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Purchase Orders' => 'Zamówienia Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'ROP' => 'PPZ',
+ 'Rate' => 'Stawka',
+ 'Recd' => '',
+ 'Receipt' => '',
+ 'Receipts' => '',
+ 'Receivables' => 'Nale¿no¶ci',
+ 'Reconciliation' => '',
+ 'Record in' => 'ïÔÎÅÓÔÉ ÎÁ ÓÞÅÔ',
+ 'Reference' => '',
+ 'Reference missing!' => '',
+ 'Remaining' => 'Pozosta³e',
+ 'Report for' => 'Raport dla',
+ 'Reports' => 'Sprawozdania',
+ 'Required by' => 'Termin Dostawy',
+ 'Retained Earnings' => 'Zysk',
+ 'Sales' => 'Sprzeda¿',
+ 'Sales Invoice' => '',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Sales Orders' => 'Zamówienia Klientów',
+ 'Save' => 'Zapisz',
+ 'Save as new' => '',
+ 'Save to File' => 'Zapisz w zbiorze',
+ 'Screen' => 'Ekran',
+ 'Select a Dataset to delete and press "Continue"' => 'Wybierz Zbiór Danych do usuniêcia i naci¶nij "Kontynuj"',
+ 'Select all' => '',
+ 'Select from one of the items below' => 'Wybie¿ jeden z poni¿szych artyku³ów',
+ 'Select from one of the names below' => '',
+ 'Select from one of the projects below' => '',
+ 'Select postscript or PDF!' => '',
+ 'Sell Price' => 'Cena Sprzeda¿y',
+ 'Send by E-Mail' => 'Wys³ano przy u¿yciu E-Mail',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Service' => 'õÓÌÕÇÁ',
+ 'Service Items' => 'Artyku³y Us³ugowe',
+ 'Service Number missing!' => 'Brak Numeru Us³ugi!',
+ 'Services' => 'õÓÌÕÇÉ',
+ 'Setup Templates' => 'Ustaw Szablony',
+ 'Ship' => '',
+ 'Ship to' => '',
+ 'Ship via' => '',
+ 'Short' => 'Niedobór',
+ 'Signature' => 'ðÏÄÐÉÓØ',
+ 'Sold' => 'Sprzedano',
+ 'Source' => '¯ród³o',
+ 'Standard' => 'óÔÁÎÄÁÒÔÎÙÅ',
+ 'Statement' => '',
+ 'Statement Balance' => '',
+ 'Statement sent to' => '',
+ 'Statements sent to printer!' => '',
+ 'Stock Assembly' => 'Wstaw Z³o¿enie',
+ 'Stylesheet' => 'ïÆÏÒÍÌÅÎÉÅ',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'System' => 'óÉÓÔÅÍÁ',
+ 'Tax' => 'îÁÌÏÇ',
+ 'Tax Accounts' => 'Konta Podatkowe',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'Tax collected' => '',
+ 'Tax paid' => '',
+ 'Taxable' => 'Opodatkowane',
+ 'Template saved!' => '',
+ 'Templates' => 'æÏÒÍÙ',
+ 'Terms: Net' => 'Warunki: Netto',
+ 'The following Datasets are not in use and can be deleted' => 'Te Zbiory Danych s± nieu¿ywane i mo¿na je usun±æ',
+ 'The following Datasets need to be updated' => 'Zbiory Danych do uzupe³nienia',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Jest to wstêpne sprawdzenie istniej±cych ¿róde³. Narazie nic nie bêdzie utworzone lub usuniête.',
+ 'To' => 'do',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => '¯eby dodaæ do grupy u¿ytkownika zmieñ nazwê, nazwê zarejestrowania i zapisz. Nowy u¿ytkownik z tymi samymi zmiennymi warto¶ciami bêdzie zapisany pod now± nazw± rejestruj±c±',
+ 'Top Level' => '',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Transaction Date missing!' => 'Brak Daty Transakcji!',
+ 'Transaction deleted!' => '',
+ 'Transaction posted!' => '',
+ 'Transaction reversal enforced for all dates' => 'Zmiana transakcji narzucona dla wszystkich okresów',
+ 'Transaction reversal enforced up to' => 'Zmiana transakcji narzucona do',
+ 'Transactions' => 'Transakcje',
+ 'Transactions exist, cannot delete customer!' => 'Istniej± Transakcje, niemo¿na usun±æ odbiorcy',
+ 'Transactions exist, cannot delete vendor!' => 'Istniej± Transakcje, nie mo¿na usun±æ dostawcy',
+ 'Transactions exist; cannot delete account!' => 'Istniej± Transakcje, nie mo¿na usun±æ konta',
+ 'Trial Balance' => 'Bilans Porównawczy',
+ 'Unit' => 'Jednostka',
+ 'Unit of measure' => 'Jednostka miary',
+ 'Update' => '',
+ 'Update Dataset' => 'Uzupe³nij Zbiór Danych',
+ 'Updated' => '',
+ 'Use Templates' => 'U¿yj Szablony',
+ 'User' => 'U¿ytkownik',
+ 'User deleted!' => '',
+ 'User saved!' => '',
+ 'Vendor' => 'Dostawca',
+ 'Vendor deleted!' => '',
+ 'Vendor missing!' => '',
+ 'Vendor not on file!' => '',
+ 'Vendor saved!' => '',
+ 'Vendors' => '',
+ 'Version' => '÷ÅÒÓÉÑ',
+ 'Weight' => 'Waga',
+ 'Weight Unit' => 'Jednostka Wagi',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'Year End' => 'Koniec Roku Finansowego',
+ 'Yes' => 'Tak',
+ 'You are logged out!' => '',
+ 'You did not enter a name!' => 'Nie wstawiono nazwy!',
+ 'You must enter a host and port for local and remote connections!' => 'Wstaw wêze³ i port dla lokalnego i zdalnego po³±czenia',
+ 'as at' => '',
+ 'collected on sales' => 'zebranego przy sprzeda¿y',
+ 'days' => 'dni',
+ 'does not exist' => 'nie istnieje',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'for Period' => 'za Okres',
+ 'hr' => 'godz',
+ 'is already a member!' => 'Jest ju¿ cz³onkiem',
+ 'is not a member!' => 'Nie jest cz³onkiem',
+ 'localhost' => 'wêze³',
+ 'paid on purchases' => 'zap³aconego przy zakupach',
+ 'sent to printer' => 'wys³ano do drukarki',
+ 'successfully created!' => 'stworzone z powodzeniem',
+ 'successfully deleted!' => 'usuniête z powodzeniem',
+ 'to' => '',
+ 'website' => 'witryna WWW',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/am b/sql-ledger/locale/ru/am
new file mode 100644
index 0000000..204e1c3
--- /dev/null
+++ b/sql-ledger/locale/ru/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'òÁÓÈÏÄ',
+ 'AR' => 'äÏÈÏÄ',
+ 'Account' => 'óÞÅÔ',
+ 'Account Number' => 'ëÏÄ ÓÞÅÔÁ',
+ 'Account Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ!',
+ 'Account Type' => 'ôÉÐ ÓÞÅÔÁ',
+ 'Account Type missing!' => 'îÅ ÕËÁÚÁÎ ÔÉÐ ÓÞÅÔÁ!',
+ 'Account deleted!' => 'Account deleted!',
+ 'Account saved!' => 'Account saved!',
+ 'Add Account' => 'îÏ×ÙÊ ÓÞÅÔ',
+ 'Add GIFI' => 'îÏ×ÙÊ GIFI',
+ 'Address' => 'áÄÒÅÓ',
+ 'Asset' => 'áËÔÉ×',
+ 'Audit Control' => 'ëÏÎÔÒÏÌØ',
+ 'Backup sent to' => 'òÅÚÅÒ×ÎÁÑ ËÏÐÉÑ ÏÔÏÓÌÁÎÁ ÎÁ',
+ 'Books are open' => 'ëÎÉÇÁ ÏÔËÒÙÔÁ',
+ 'Business Number' => 'òîî',
+ 'COGS' => 'COGS',
+ 'Cannot delete account!' => 'Cannot delete account!',
+ 'Cannot delete default account!' => 'îÅÌØÚÑ ÕÄÁÌÉÔØ ÏÓÎÏ×ÎÏÊ ÓÞÅÔ!',
+ 'Cannot save account!' => 'Cannot save account!',
+ 'Cannot save preferences!' => 'Cannot save preferences!',
+ 'Character Set' => 'ëÏÄÉÒÏ×ËÁ',
+ 'Chart of Accounts' => 'ðÌÁÎ ÓÞÅÔÏ×',
+ 'Close Books up to' => 'Zamkniêcie Ksi±g do!',
+ 'Company' => 'ïÒÇÁÎÉÚÁÃÉÑ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Copy to COA' => 'ëÏÐÉÒÏ×ÁÔØ × çðó',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Date Format' => 'æÏÒÍÁÔ ÄÁÔÙ',
+ 'Debit' => 'äÅÂÅÔ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Delete Account' => 'õÄÁÌÍÔØ ÓÞÅÔ',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'E-mail',
+ 'Edit' => 'Edit',
+ 'Edit Account' => 'éÚÍÅÎÉÔØ ÓÞÅÔ',
+ 'Edit GIFI' => 'éÚÍÅÎÉÔØ GIFI',
+ 'Edit Preferences for' => 'Zmiany Preferencji dla',
+ 'Edit Template' => 'Zmiany Wzorca',
+ 'Enforce transaction reversal for all dates' => 'Egzekwuj zmiany transakcji dla wszystkich terminów',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies',
+ 'Equity' => 'Kapita³',
+ 'Expense' => 'òÁÓÈÏÄ',
+ 'Expense Account' => 'Konto Kosztów',
+ 'Expense/Asset' => 'Koszt/Aktywy',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Zysk przy Wymianie Walut',
+ 'Foreign Exchange Loss' => 'Strata przy Wymianie Walut',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI deleted!',
+ 'GIFI missing!' => 'Brakuje GIFI',
+ 'GIFI saved!' => 'GIFI saved!',
+ 'Heading' => 'òÁÚÄÅÌ',
+ 'Include in drop-down menus' => 'Do³±cz w menu rozwijanym',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Do³±cz Konto w formularzach Kontrachentów ¿eby wskazaæ ¿e podlegaj± opodatkowaniu',
+ 'Income' => 'äÏÈÏÄ',
+ 'Income Account' => 'Konto Przychodów',
+ 'Inventory' => 'éÎ×ÅÎÔÁÒÎÙÊ',
+ 'Inventory Account' => 'Konto Materia³owe',
+ 'Is this a summary account to record' => 'Czy jest to konto sumaryczne?',
+ 'Language' => 'ñÚÙË',
+ 'Last Invoice Number' => 'Ostatni Numer Faktury',
+ 'Last Numbers & Default Accounts' => 'Ostatnie Numery i Konta Domy¶lne',
+ 'Last Purchase Order Number' => 'Ostatni Numer Faktury Zamówienia',
+ 'Last Sales Order Number' => 'Ostatni Numer Faktury Sprzeda¿y',
+ 'Liability' => 'ðÁÓÓÉ×',
+ 'Link' => 'Dowi±zanie',
+ 'Name' => 'Nazwa',
+ 'No' => 'Nie',
+ 'No email address for' => 'Brak adresu email',
+ 'Number' => 'Numer Katalogu',
+ 'Number Format' => 'Format Numeru',
+ 'Parts Inventory' => 'Inwentarz',
+ 'Password' => 'Has³o',
+ 'Payables' => 'Zobowi±zania',
+ 'Payment' => 'P³atno¶æ',
+ 'Phone' => 'Tel.',
+ 'Preferences saved!' => 'Preferencje Zapisane!',
+ 'Rate' => 'Stawka',
+ 'Receivables' => 'Nale¿no¶ci',
+ 'Sales' => 'Sprzeda¿',
+ 'Save' => 'Zapisz',
+ 'Service Items' => 'Artyku³y Us³ugowe',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'ðÏÄÐÉÓØ',
+ 'Stylesheet' => 'ïÆÏÒÍÌÅÎÉÅ',
+ 'Tax' => 'îÁÌÏÇ',
+ 'Tax Accounts' => 'Konta Podatkowe',
+ 'Template saved!' => 'Template saved!',
+ 'Transaction reversal enforced for all dates' => 'Zmiana transakcji narzucona dla wszystkich okresów',
+ 'Transaction reversal enforced up to' => 'Zmiana transakcji narzucona do',
+ 'Transactions exist; cannot delete account!' => 'Istniej± Transakcje, nie mo¿na usun±æ konta',
+ 'Weight Unit' => 'Jednostka Wagi',
+ 'Year End' => 'Koniec Roku Finansowego',
+ 'Yes' => 'Tak',
+ 'does not exist' => 'nie istnieje',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'îÏ×ÙÊ_ÓÞÅÔ' => 'add_account',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'ëÏÐÉÒÏ×ÁÔØ_×_çðó' => 'copy_to_coa',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'edit' => 'edit',
+ 'éÚÍÅÎÉÔØ_ÓÞÅÔ' => 'edit_account',
+ 'zapisz' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/ap b/sql-ledger/locale/ru/ap
new file mode 100644
index 0000000..3c243eb
--- /dev/null
+++ b/sql-ledger/locale/ru/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AP Transactions' => 'ðÒÏ×ÏÄËÉ ÒÁÓÈÏÄÁ',
+ 'Account' => 'óÞÅÔ',
+ 'Add Accounts Payables Transaction' => 'Add Accounts Payables Transaction',
+ 'Address' => 'áÄÒÅÓ',
+ 'Amount' => 'óÕÍÍÁ',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Are you sure you want to delete Transaction' => '÷Ù Õ×ÅÒÅÎÙ, ÓÔÏ ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÄÁÎÎÕÀ ÐÒÏ×ÏÄËÕ?',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cannot post transaction for a closed period!' => 'Nie mo¿na zaksiêgowaæ transakcji w zamkniêtym okresie',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'úÁËÒÙÔ',
+ 'Confirm!' => 'ðÏÄÔ×ÅÒÄÉÔØ!',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'äÁÔÁ',
+ 'Date Paid' => 'äÁÔÁ ÏÐÌÁÔÙ',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Due Date' => 'ïÐÌÁÔÉÔØ ÄÏ',
+ 'Due Date missing!' => 'îÅ ÕËÁÚÁÎ ÓÒÏË ÏÐÌÁÔÙ!',
+ 'Edit Accounts Payables Transaction' => 'Edit Accounts Payables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'ID' => 'Identyfikator',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ',
+ 'Invoice Date missing!' => 'îÅ ÕËÁÚÁÎÁ ÄÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number' => 'îÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Open' => 'Otwórz',
+ 'Order' => 'Zamówienie',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Paid' => 'Zap³acono',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payments' => 'Rozliczenia P³atno¶ci',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Source' => '¯ród³o',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'Tax' => 'îÁÌÏÇ',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor' => 'Dostawca',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Tak',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'add_accounts_payables_transaction' => 'add_accounts_payables_transaction',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'edit_accounts_payables_transaction' => 'edit_accounts_payables_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'update' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/ar b/sql-ledger/locale/ru/ar
new file mode 100644
index 0000000..3970754
--- /dev/null
+++ b/sql-ledger/locale/ru/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'AR Transaction',
+ 'AR Transactions' => 'ðÒÏ×ÏÄËÉ ÄÏÈÏÄÁ',
+ 'Account' => 'óÞÅÔ',
+ 'Add Accounts Receivables Transaction' => 'Add Accounts Receivables Transaction',
+ 'Address' => 'áÄÒÅÓ',
+ 'Amount' => 'óÕÍÍÁ',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Are you sure you want to delete Transaction' => '÷Ù Õ×ÅÒÅÎÙ, ÓÔÏ ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÄÁÎÎÕÀ ÐÒÏ×ÏÄËÕ?',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cannot post transaction for a closed period!' => 'Nie mo¿na zaksiêgowaæ transakcji w zamkniêtym okresie',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'úÁËÒÙÔ',
+ 'Confirm!' => 'ðÏÄÔ×ÅÒÄÉÔØ!',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Credit Limit' => 'ìÉÍÉÔ ËÒÅÄÉÔÁ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer' => 'ëÌÉÅÎÔ',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'äÁÔÁ',
+ 'Date Paid' => 'äÁÔÁ ÏÐÌÁÔÙ',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Due Date' => 'ïÐÌÁÔÉÔØ ÄÏ',
+ 'Due Date missing!' => 'îÅ ÕËÁÚÁÎ ÓÒÏË ÏÐÌÁÔÙ!',
+ 'Edit Accounts Receivables Transaction' => 'Edit Accounts Receivables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'ID' => 'Identyfikator',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ',
+ 'Invoice Date missing!' => 'îÅ ÕËÁÚÁÎÁ ÄÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number' => 'îÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Open' => 'Otwórz',
+ 'Order' => 'Zamówienie',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Paid' => 'Zap³acono',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payments' => 'Rozliczenia P³atno¶ci',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Remaining' => 'Pozosta³e',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Source' => '¯ród³o',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'Tax' => 'îÁÌÏÇ',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Tak',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ar_transaction' => 'ar_transaction',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/arap b/sql-ledger/locale/ru/arap
new file mode 100644
index 0000000..24fe716
--- /dev/null
+++ b/sql-ledger/locale/ru/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'áÄÒÅÓ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Number' => 'Numer Katalogu',
+ 'Project not on file!' => 'Project not on file!',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/ca b/sql-ledger/locale/ru/ca
new file mode 100644
index 0000000..1b1b139
--- /dev/null
+++ b/sql-ledger/locale/ru/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'óÞÅÔ',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'ðÌÁÎ ÓÞÅÔÏ×',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Date' => 'äÁÔÁ',
+ 'Debit' => 'äÅÂÅÔ',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'List Transactions' => 'Wykaz Transakcji',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Reference' => 'Reference',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'To' => 'do',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'wykaz_transakcji' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/cp b/sql-ledger/locale/ru/cp
new file mode 100644
index 0000000..6ff1936
--- /dev/null
+++ b/sql-ledger/locale/ru/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'óÞÅÔ',
+ 'Address' => 'áÄÒÅÓ',
+ 'Amount' => 'óÕÍÍÁ',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Amount missing!',
+ 'Applied' => 'Applied',
+ 'Cannot post payment!' => 'Cannot post payment!',
+ 'Cannot process payment for a closed period!' => 'Cannot process payment for a closed period!',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check printed!',
+ 'Check printing failed!' => 'Check printing failed!',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer' => 'ëÌÉÅÎÔ',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'äÁÔÁ',
+ 'Date missing!' => 'Date missing!',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Due' => 'äÏ',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'From' => 'Od',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Invoices' => 'Invoices',
+ 'Nothing applied!' => 'Nothing applied!',
+ 'Number' => 'Numer Katalogu',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'P³atno¶æ',
+ 'Payment posted!' => 'Payment posted!',
+ 'Post' => 'Post',
+ 'Print' => 'Print',
+ 'Printer' => 'Drukarka',
+ 'Project not on file!' => 'Project not on file!',
+ 'Receipt' => 'Receipt',
+ 'Reference' => 'Reference',
+ 'Screen' => 'Ekran',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'To' => 'do',
+ 'Update' => 'Update',
+ 'Vendor' => 'Dostawca',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/ct b/sql-ledger/locale/ru/ct
new file mode 100644
index 0000000..7c39884
--- /dev/null
+++ b/sql-ledger/locale/ru/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'îÏ×ÙÊ',
+ 'Address' => 'áÄÒÅÓ',
+ 'All' => '÷ÓÅ',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Cannot delete customer!',
+ 'Cannot delete vendor!' => 'Cannot delete vendor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'ëÏÎÔÁËÔÎÏÅ ÌÉÃÏ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Credit Limit' => 'ìÉÍÉÔ ËÒÅÄÉÔÁ',
+ 'Customer deleted!' => 'Customer deleted!',
+ 'Customer saved!' => 'Customer saved!',
+ 'Customers' => 'Customers',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Discount' => 'óËÉÄËÁ',
+ 'E-mail' => 'E-mail',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Name' => 'Nazwa',
+ 'Name missing!' => 'Name missing!',
+ 'Notes' => 'Noty',
+ 'Number' => 'Numer Katalogu',
+ 'Order' => 'Zamówienie',
+ 'Orphaned' => 'Zbêdny',
+ 'Phone' => 'Tel.',
+ 'Save' => 'Zapisz',
+ 'Ship to' => 'Ship to',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'Taxable' => 'Opodatkowane',
+ 'Terms: Net' => 'Warunki: Netto',
+ 'Transactions exist, cannot delete customer!' => 'Istniej± Transakcje, niemo¿na usun±æ odbiorcy',
+ 'Transactions exist, cannot delete vendor!' => 'Istniej± Transakcje, nie mo¿na usun±æ dostawcy',
+ 'Vendor deleted!' => 'Vendor deleted!',
+ 'Vendor saved!' => 'Vendor saved!',
+ 'Vendors' => 'Vendors',
+ 'days' => 'dni',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'îÏ×ÙÊ' => 'add',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'óÞÅÔ_ÆÁËÔÕÒÁ' => 'invoice',
+ 'zamówienie' => 'order',
+ 'zapisz' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/gl b/sql-ledger/locale/ru/gl
new file mode 100644
index 0000000..28292ad
--- /dev/null
+++ b/sql-ledger/locale/ru/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AR Transaction' => 'AR Transaction',
+ 'Account' => 'óÞÅÔ',
+ 'Add General Ledger Transaction' => 'îÏ×ÁÑ ÐÒÏ×ÏÄËÁ',
+ 'Address' => 'áÄÒÅÓ',
+ 'All' => '÷ÓÅ',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Are you sure you want to delete Transaction' => '÷Ù Õ×ÅÒÅÎÙ, ÓÔÏ ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÄÁÎÎÕÀ ÐÒÏ×ÏÄËÕ?',
+ 'Asset' => 'áËÔÉ×',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot have a value in both Debit and Credit!' => 'Nie mo¿na wpisaæ warto¶ci w Debet i Kredyt równocze¶nie!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'Nie mo¿na zaksiêgowaæ transakcji w zamkniêtym okresie',
+ 'Confirm!' => 'ðÏÄÔ×ÅÒÄÉÔØ!',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'äÁÔÁ',
+ 'Debit' => 'äÅÂÅÔ',
+ 'Debit and credit out of balance!' => 'Debet i Kredyt siê niebalansuj±!',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Edit General Ledger Transaction' => 'Zmiany w Ksiêdze G³ównej',
+ 'Equity' => 'Kapita³',
+ 'Expense' => 'òÁÓÈÏÄ',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'GL Transaction',
+ 'General Ledger' => 'Ksiêga G³ówna',
+ 'ID' => 'Identyfikator',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Income' => 'äÏÈÏÄ',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'Liability' => 'ðÁÓÓÉ×',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference missing!',
+ 'Reports' => 'Sprawozdania',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Source' => '¯ród³o',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'To' => 'do',
+ 'Transaction Date missing!' => 'Brak Daty Transakcji!',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Tak',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'gl_transaction' => 'gl_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/ic b/sql-ledger/locale/ru/ic
new file mode 100644
index 0000000..b879e88
--- /dev/null
+++ b/sql-ledger/locale/ru/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Active',
+ 'Add' => 'îÏ×ÙÊ',
+ 'Add Assembly' => 'îÏ×ÙÊ ËÏÍÐÌÅËÔ',
+ 'Add Part' => 'îÏ×ÙÊ ÐÒÏÄÕËÔ',
+ 'Add Purchase Order' => 'îÏ×ÙÊ ÚÁËÁÚ ÐÏÓÔÁ×ÝÉËÁ',
+ 'Add Sales Order' => 'îÏ×ÙÊ ÚÁËÁÚ ËÌÉÅÎÔÁ',
+ 'Add Service' => 'îÏ×ÁÑ ÕÓÌÕÇÁ',
+ 'Address' => 'áÄÒÅÓ',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Assemblies' => 'ëÏÍÐÌÅËÔÙ',
+ 'Assemblies restocked!' => 'Assemblies restocked!',
+ 'Assembly Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ËÏÍÐÌÅËÔÁ!',
+ 'Attachment' => '÷ÌÏÖÅÎÉÅ',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Bought' => 'ëÕÐÌÅÎÏ',
+ 'COGS' => 'COGS',
+ 'Cannot delete item already invoiced!' => 'Nie mo¿na usun±æ pozycji zafakturowanej!',
+ 'Cannot delete item on order!' => 'Nie mo¿na usunac zamówionego produktu!',
+ 'Cannot delete item which is part of an assembly!' => 'Nie mo¿na usun±æ czê¶ci z zestawienia!',
+ 'Cannot delete item!' => 'Cannot delete item!',
+ 'Cannot stock assemblies!' => 'Cannot stock assemblies!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'ëÏÎÔÁËÔÎÏÅ ÌÉÃÏ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Copies' => 'ëÏÐÉÊ',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Drawing' => 'Drawing',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'îÅ ÕËÁÚÁÎ ÁÄÒÅÓ E-mail!',
+ 'Edit Assembly' => 'éÚÍÅÎÉÔØ ËÏÍÐÌÅËÔ',
+ 'Edit Part' => 'Zmiany Produktu',
+ 'Edit Service' => 'éÚÍÅÎÉÔØ ÕÓÌÕÇÕ',
+ 'Expense' => 'òÁÓÈÏÄ',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'Image' => 'Image',
+ 'In-line' => 'W³±czony',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Income' => 'äÏÈÏÄ',
+ 'Individual Items' => 'Indywidualne Czê¶ci',
+ 'Inventory' => 'éÎ×ÅÎÔÁÒÎÙÊ',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Ilo¶æ Inventarza musi byæ równa zero zanim bêdzie mozna zdezaktualizowaæ to z³o¿enie!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Ilo¶æ inventarza musi byæ równa zero zanim bêdzie mo¿na zdezaktualizowaæ t± czê¶æ!',
+ 'Inventory quantity must be zero!' => 'Ilo¶æc Inventarza musi byæ równa zero',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Invoice Date missing!' => 'îÅ ÕËÁÚÁÎÁ ÄÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number' => 'îÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Item deleted!' => 'Item deleted!',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'Last Cost' => 'Cena Zakupu',
+ 'Line Total' => 'Suma ca³kowita',
+ 'Link Accounts' => 'Konta dowi±zane',
+ 'List Price' => 'Cena',
+ 'Make' => 'Marka',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Model',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'Obsolete' => 'Zdezaktualizowany',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'On Hand' => 'Na Stanie',
+ 'On Order' => 'On Order',
+ 'Order' => 'Zamówienie',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'Ordered' => 'Ordered',
+ 'Orphaned' => 'Zbêdny',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Part Number missing!' => 'Brak Symbolu Produktu!',
+ 'Parts' => 'Produkty',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'ROP' => 'PPZ',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales' => 'Sprzeda¿',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Save' => 'Zapisz',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybie¿ jeden z poni¿szych artyku³ów',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sell Price' => 'Cena Sprzeda¿y',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Service' => 'õÓÌÕÇÁ',
+ 'Service Number missing!' => 'Brak Numeru Us³ugi!',
+ 'Services' => 'õÓÌÕÇÉ',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Short' => 'Niedobór',
+ 'Sold' => 'Sprzedano',
+ 'Stock Assembly' => 'Wstaw Z³o¿enie',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'Tax' => 'îÁÌÏÇ',
+ 'To' => 'do',
+ 'Top Level' => 'Top Level',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Unit' => 'Jednostka',
+ 'Unit of measure' => 'Jednostka miary',
+ 'Update' => 'Update',
+ 'Updated' => 'Updated',
+ 'Weight' => 'Waga',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'hr' => 'godz',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'îÏ×ÙÊ' => 'add',
+ 'îÏ×ÙÊ_ËÏÍÐÌÅËÔ' => 'add_assembly',
+ 'îÏ×ÙÊ_ÐÒÏÄÕËÔ' => 'add_part',
+ 'îÏ×ÁÑ_ÕÓÌÕÇÁ' => 'add_service',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'éÚÍÅÎÉÔØ_ËÏÍÐÌÅËÔ' => 'edit_assembly',
+ 'zmiany_produktu' => 'edit_part',
+ 'éÚÍÅÎÉÔØ_ÕÓÌÕÇÕ' => 'edit_service',
+ 'zapisz' => 'save',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/io b/sql-ledger/locale/ru/io
new file mode 100644
index 0000000..36137b2
--- /dev/null
+++ b/sql-ledger/locale/ru/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'îÏ×ÙÊ ÚÁËÁÚ ÐÏÓÔÁ×ÝÉËÁ',
+ 'Add Sales Order' => 'îÏ×ÙÊ ÚÁËÁÚ ËÌÉÅÎÔÁ',
+ 'Address' => 'áÄÒÅÓ',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Attachment' => '÷ÌÏÖÅÎÉÅ',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cc' => 'Cc',
+ 'Contact' => 'ëÏÎÔÁËÔÎÏÅ ÌÉÃÏ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Copies' => 'ëÏÐÉÊ',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'îÅ ÕËÁÚÁÎ ÁÄÒÅÓ E-mail!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'In-line' => 'W³±czony',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Invoice Date missing!' => 'îÅ ÕËÁÚÁÎÁ ÄÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Order' => 'Zamówienie',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybie¿ jeden z poni¿szych artyku³ów',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Service' => 'õÓÌÕÇÁ',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Subject' => 'ôÅÍÁ',
+ 'To' => 'do',
+ 'Unit' => 'Jednostka',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/ir b/sql-ledger/locale/ru/ir
new file mode 100644
index 0000000..67db203
--- /dev/null
+++ b/sql-ledger/locale/ru/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'óÞÅÔ',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'îÏ×ÙÊ ÚÁËÁÚ ÐÏÓÔÁ×ÝÉËÁ',
+ 'Add Sales Order' => 'îÏ×ÙÊ ÚÁËÁÚ ËÌÉÅÎÔÁ',
+ 'Address' => 'áÄÒÅÓ',
+ 'Amount' => 'óÕÍÍÁ',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Are you sure you want to delete Invoice Number' => '÷Ù Õ×ÅÒÅÎÙ, ÞÔÏ ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÄÁÎÎÙÊ ÓÞÅÔ?',
+ 'Attachment' => '÷ÌÏÖÅÎÉÅ',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Nie mo¿na zksiêgowaæ faktury pozamkniêciu okresu',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'ðÏÄÔ×ÅÒÄÉÔØ!',
+ 'Contact' => 'ëÏÎÔÁËÔÎÏÅ ÌÉÃÏ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Copies' => 'ëÏÐÉÊ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'äÁÔÁ',
+ 'Date Due' => 'ïÐÌÁÔÉÔØ ÄÏ',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'îÅ ÕËÁÚÁÎ ÁÄÒÅÓ E-mail!',
+ 'Edit Purchase Invoice' => 'Edit Purchase Invoice',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'In-line' => 'W³±czony',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ',
+ 'Invoice Date missing!' => 'îÅ ÕËÁÚÁÎÁ ÄÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number' => 'îÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Order' => 'Zamówienie',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payments' => 'Rozliczenia P³atno¶ci',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'Recd' => 'Recd',
+ 'Record in' => 'ïÔÎÅÓÔÉ ÎÁ ÓÞÅÔ',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybie¿ jeden z poni¿szych artyku³ów',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Service' => 'õÓÌÕÇÁ',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Source' => '¯ród³o',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Unit' => 'Jednostka',
+ 'Update' => 'Update',
+ 'Vendor' => 'Dostawca',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'Yes' => 'Tak',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'zamówienie' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'update' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/is b/sql-ledger/locale/ru/is
new file mode 100644
index 0000000..a4a4621
--- /dev/null
+++ b/sql-ledger/locale/ru/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'óÞÅÔ',
+ 'Add Purchase Order' => 'îÏ×ÙÊ ÚÁËÁÚ ÐÏÓÔÁ×ÝÉËÁ',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'îÏ×ÙÊ ÚÁËÁÚ ËÌÉÅÎÔÁ',
+ 'Address' => 'áÄÒÅÓ',
+ 'Amount' => 'óÕÍÍÁ',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Are you sure you want to delete Invoice Number' => '÷Ù Õ×ÅÒÅÎÙ, ÞÔÏ ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÄÁÎÎÙÊ ÓÞÅÔ?',
+ 'Attachment' => '÷ÌÏÖÅÎÉÅ',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Nie mo¿na zksiêgowaæ faktury pozamkniêciu okresu',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Nie mo¿na zaksiêgowaæ p³atno¶ci po zamkniêciu okresu!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'ðÏÄÔ×ÅÒÄÉÔØ!',
+ 'Contact' => 'ëÏÎÔÁËÔÎÏÅ ÌÉÃÏ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Copies' => 'ëÏÐÉÊ',
+ 'Credit Limit' => 'ìÉÍÉÔ ËÒÅÄÉÔÁ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer' => 'ëÌÉÅÎÔ',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'äÁÔÁ',
+ 'Date Due' => 'ïÐÌÁÔÉÔØ ÄÏ',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'îÅ ÕËÁÚÁÎ ÁÄÒÅÓ E-mail!',
+ 'Edit Sales Invoice' => 'Edit Sales Invoice',
+ 'Exch' => 'Kurs',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate for payment missing!' => 'Brakuje kursu wymiany dla p³atno¶ci!',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'In-line' => 'W³±czony',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ',
+ 'Invoice Date missing!' => 'îÅ ÕËÁÚÁÎÁ ÄÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number' => 'îÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Order' => 'Zamówienie',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Payment date missing!' => 'Brak Daty P³atno¶ci',
+ 'Payments' => 'Rozliczenia P³atno¶ci',
+ 'Phone' => 'Tel.',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Print' => 'Print',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'Recd' => 'Recd',
+ 'Record in' => 'ïÔÎÅÓÔÉ ÎÁ ÓÞÅÔ',
+ 'Remaining' => 'Pozosta³e',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybie¿ jeden z poni¿szych artyku³ów',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Service' => 'õÓÌÕÇÁ',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Source' => '¯ród³o',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Unit' => 'Jednostka',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'Yes' => 'Tak',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'zamówienie' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/login b/sql-ledger/locale/ru/login
new file mode 100644
index 0000000..4ff4eff
--- /dev/null
+++ b/sql-ledger/locale/ru/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'ï ÐÒÏÇÒÁÍÍÅ',
+ 'Accounting' => 'Accounting',
+ 'Database Host' => 'Wêze³ Bazy Danych',
+ 'Dataset' => 'Zbiór Danych',
+ 'Incorrect Dataset version!' => 'Nieprawid³owa wersja Zbioru Danych',
+ 'Incorrect Password!' => 'Nieprawid³owe Has³o',
+ 'Licensed to' => 'ìÉÃÅÎÚÉÅÊ ÏÂÌÁÄÁÅÔ:',
+ 'Login' => 'Zarejestrój siê',
+ 'Name' => 'Nazwa',
+ 'Password' => 'Has³o',
+ 'User' => 'U¿ytkownik',
+ 'Version' => '÷ÅÒÓÉÑ',
+ 'You are logged out!' => 'You are logged out!',
+ 'You did not enter a name!' => 'Nie wstawiono nazwy!',
+ 'is not a member!' => 'Nie jest cz³onkiem',
+ 'localhost' => 'wêze³',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'zarejestrój_siê' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/menu b/sql-ledger/locale/ru/menu
new file mode 100644
index 0000000..af96c02
--- /dev/null
+++ b/sql-ledger/locale/ru/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'òÁÓÈÏÄ',
+ 'AP Aging' => 'AP Aging',
+ 'AR' => 'äÏÈÏÄ',
+ 'AR Aging' => 'AR Aging',
+ 'Accounting Menu' => 'Accounting Menu',
+ 'Add Account' => 'îÏ×ÙÊ ÓÞÅÔ',
+ 'Add Assembly' => 'îÏ×ÙÊ ËÏÍÐÌÅËÔ',
+ 'Add Customer' => 'îÏ×ÙÊ ËÌÉÅÎÔ',
+ 'Add GIFI' => 'îÏ×ÙÊ GIFI',
+ 'Add Part' => 'îÏ×ÙÊ ÐÒÏÄÕËÔ',
+ 'Add Project' => 'Add Project',
+ 'Add Service' => 'îÏ×ÁÑ ÕÓÌÕÇÁ',
+ 'Add Transaction' => 'îÏ×ÁÑ ÐÒÏ×ÏÄËÁ',
+ 'Add Vendor' => 'îÏ×ÙÊ ÐÏÓÔÁ×ÝÉË',
+ 'Assemblies' => 'ëÏÍÐÌÅËÔÙ',
+ 'Audit Control' => 'ëÏÎÔÒÏÌØ',
+ 'Backup' => 'òÅÚÅÒ×ÎÁÑ ËÏÐÉÑ',
+ 'Balance Sheet' => 'âÁÌÁÎÓ',
+ 'Cash' => 'Cash',
+ 'Chart of Accounts' => 'ðÌÁÎ ÓÞÅÔÏ×',
+ 'Check' => 'Check',
+ 'Customers' => 'Customers',
+ 'General Ledger' => 'Ksiêga G³ówna',
+ 'Goods & Services' => 'Produkty i Us³ugi',
+ 'HTML Templates' => 'Szablony HTML',
+ 'Income Statement' => 'Rachunek Zysków i Strat',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'LaTeX Templates' => 'Szablony LaTeX',
+ 'List Accounts' => 'Spis Kont',
+ 'List GIFI' => 'Wykaz GIFI',
+ 'Logout' => 'Wyrejestrój siê',
+ 'Order Entry' => 'Wystawianie Zamówieñ',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Parts' => 'Produkty',
+ 'Payment' => 'P³atno¶æ',
+ 'Payments' => 'Rozliczenia P³atno¶ci',
+ 'Preferences' => 'Preferencje',
+ 'Projects' => 'Projects',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Purchase Orders' => 'Zamówienia Zakupu',
+ 'Receipt' => 'Receipt',
+ 'Receipts' => 'Receipts',
+ 'Reconciliation' => 'Reconciliation',
+ 'Reports' => 'Sprawozdania',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Sales Orders' => 'Zamówienia Klientów',
+ 'Save to File' => 'Zapisz w zbiorze',
+ 'Send by E-Mail' => 'Wys³ano przy u¿yciu E-Mail',
+ 'Services' => 'õÓÌÕÇÉ',
+ 'Statement' => 'Statement',
+ 'Stock Assembly' => 'Wstaw Z³o¿enie',
+ 'Stylesheet' => 'ïÆÏÒÍÌÅÎÉÅ',
+ 'System' => 'óÉÓÔÅÍÁ',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'Transactions' => 'Transakcje',
+ 'Trial Balance' => 'Bilans Porównawczy',
+ 'Vendors' => 'Vendors',
+ 'Version' => '÷ÅÒÓÉÑ',
+ 'localhost' => 'wêze³',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/oe b/sql-ledger/locale/ru/oe
new file mode 100644
index 0000000..24b26df
--- /dev/null
+++ b/sql-ledger/locale/ru/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'îÏ×ÙÊ',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'îÏ×ÙÊ ÚÁËÁÚ ÐÏÓÔÁ×ÝÉËÁ',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'îÏ×ÙÊ ÚÁËÁÚ ËÌÉÅÎÔÁ',
+ 'Address' => 'áÄÒÅÓ',
+ 'Amount' => 'óÕÍÍÁ',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Are you sure you want to delete Order Number' => '÷Ù Õ×ÅÒÅÎÙ, ÞÔÏ ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÄÁÎÎÙÊ ÚÁËÁÚ?',
+ 'Attachment' => '÷ÌÏÖÅÎÉÅ',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Cannot delete order!',
+ 'Cannot save order!' => 'Cannot save order!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'úÁËÒÙÔ',
+ 'Confirm!' => 'ðÏÄÔ×ÅÒÄÉÔØ!',
+ 'Contact' => 'ëÏÎÔÁËÔÎÏÅ ÌÉÃÏ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Copies' => 'ëÏÐÉÊ',
+ 'Credit Limit' => 'ìÉÍÉÔ ËÒÅÄÉÔÁ',
+ 'Curr' => '÷ÁÌÀÔÁ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer' => 'ëÌÉÅÎÔ',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'äÁÔÁ',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'îÅ ÕËÁÚÁÎ ÁÄÒÅÓ E-mail!',
+ 'Edit Purchase Order' => 'Zmiany Zamówienia Zakupu',
+ 'Edit Sales Order' => 'Zmiany Zamówienia Klienta',
+ 'Exchangerate' => 'Kurs Wymiany',
+ 'Exchangerate missing!' => 'Brakuje kursu wymiany',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'ID' => 'Identyfikator',
+ 'In-line' => 'W³±czony',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Invoice Date missing!' => 'îÅ ÕËÁÚÁÎÁ ÄÁÔÁ ×ÙÓÔÁ×ÌÅÎÉÑ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Invoice Number missing!' => 'îÅ ÕËÁÚÁÎ ÎÏÍÅÒ ÓÞÅÔÁ-ÆÁËÔÕÒÙ',
+ 'Item not on file!' => 'Produkt nie jest w zbiorze!',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'Name' => 'Nazwa',
+ 'No.' => 'No.',
+ 'Notes' => 'Noty',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Number' => 'Numer Katalogu',
+ 'Number missing in Row' => 'Brak Numeru w Rzêdzie',
+ 'O' => 'O',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'Open' => 'Otwórz',
+ 'Order' => 'Zamówienie',
+ 'Order Date' => 'Data Zamówienia',
+ 'Order Date missing!' => 'Brak Daty Zamówienia',
+ 'Order Number' => 'Numer Zamówienia',
+ 'Order Number missing!' => 'Brak Numeru Zamówienia',
+ 'Order deleted!' => 'Order deleted!',
+ 'Order saved!' => 'Order saved!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Wykaz Dostawy',
+ 'Packing List Date missing!' => 'Brak Daty Wykazu Dostawy',
+ 'Packing List Number missing!' => 'Brak Numeru Wykazu Dostawy',
+ 'Part' => 'Produkt',
+ 'Phone' => 'Tel.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Cena Netto',
+ 'Print' => 'Print',
+ 'Printer' => 'Drukarka',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Zamówienie Zakupu',
+ 'Purchase Orders' => 'Zamówienia Zakupu',
+ 'Qty' => 'Ilo¶æ',
+ 'Recd' => 'Recd',
+ 'Remaining' => 'Pozosta³e',
+ 'Required by' => 'Termin Dostawy',
+ 'Sales Order' => 'Zamówienie Klienta',
+ 'Sales Orders' => 'Zamówienia Klientów',
+ 'Save' => 'Zapisz',
+ 'Save as new' => 'Save as new',
+ 'Screen' => 'Ekran',
+ 'Select from one of the items below' => 'Wybie¿ jeden z poni¿szych artyku³ów',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Service' => 'õÓÌÕÇÁ',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'Tax' => 'îÁÌÏÇ',
+ 'Tax Included' => 'Podatek Wliczony',
+ 'Terms: Net' => 'Warunki: Netto',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Unit' => 'Jednostka',
+ 'Update' => 'Update',
+ 'Vendor' => 'Dostawca',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'Co to za rodzaj artyku³u',
+ 'Yes' => 'Tak',
+ 'days' => 'dni',
+ 'ea' => 'szt',
+ 'emailed to' => 'email do',
+ 'sent to printer' => 'wys³ano do drukarki',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'îÏ×ÙÊ' => 'add',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'óÞÅÔ_ÆÁËÔÕÒÁ' => 'invoice',
+ 'print' => 'print',
+ 'zapisz' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/pe b/sql-ledger/locale/ru/pe
new file mode 100644
index 0000000..2505a26
--- /dev/null
+++ b/sql-ledger/locale/ru/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'îÏ×ÙÊ',
+ 'Add Project' => 'Add Project',
+ 'All' => '÷ÓÅ',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Delete' => 'õÄÁÌÉÔØ',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Edit Project' => 'Edit Project',
+ 'Number' => 'Numer Katalogu',
+ 'Orphaned' => 'Zbêdny',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Project Number missing!',
+ 'Project deleted!' => 'Project deleted!',
+ 'Project saved!' => 'Project saved!',
+ 'Projects' => 'Projects',
+ 'Save' => 'Zapisz',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'îÏ×ÙÊ' => 'add',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'õÄÁÌÉÔØ' => 'delete',
+ 'zapisz' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/rc b/sql-ledger/locale/ru/rc
new file mode 100644
index 0000000..a14f22a
--- /dev/null
+++ b/sql-ledger/locale/ru/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'óÞÅÔ',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Date' => 'äÁÔÁ',
+ 'Deposit' => 'Deposit',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Difference' => 'Difference',
+ 'Done' => 'Done',
+ 'Exchangerate Difference' => 'Exchangerate Difference',
+ 'From' => 'Od',
+ 'Out of balance!' => 'Out of balance!',
+ 'Payment' => 'P³atno¶æ',
+ 'Reconciliation' => 'Reconciliation',
+ 'Select all' => 'Select all',
+ 'Source' => '¯ród³o',
+ 'Statement Balance' => 'Statement Balance',
+ 'To' => 'do',
+ 'Update' => 'Update',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'done' => 'done',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ru/rp b/sql-ledger/locale/ru/rp
new file mode 100644
index 0000000..acea23f
--- /dev/null
+++ b/sql-ledger/locale/ru/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'AP Aging',
+ 'AR Aging' => 'AR Aging',
+ 'Account' => 'óÞÅÔ',
+ 'Accounts' => 'óÞÅÔÁ',
+ 'Amount' => 'óÕÍÍÁ',
+ 'Apr' => 'áÐÒ',
+ 'April' => 'áÐÒÅÌØ',
+ 'Attachment' => '÷ÌÏÖÅÎÉÅ',
+ 'Aug' => 'á×Ç',
+ 'August' => 'á×ÇÕÓÔ',
+ 'Balance Sheet' => 'âÁÌÁÎÓ',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'óÒÁ×ÎÉÔØ Ó',
+ 'Continue' => 'ðÒÏÄÏÌÖÉÔØ',
+ 'Copies' => 'ëÏÐÉÊ',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Current' => 'Current',
+ 'Customer' => 'ëÌÉÅÎÔ',
+ 'Date' => 'äÁÔÁ',
+ 'Debit' => 'äÅÂÅÔ',
+ 'Dec' => 'äÅË',
+ 'December' => 'äÅËÁÂÒØ',
+ 'Decimalplaces' => 'Decimalplaces',
+ 'Description' => 'ïÐÉÓÁÎÉÅ',
+ 'Due' => 'äÏ',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'E-mail Statement to',
+ 'Feb' => 'Luty',
+ 'February' => 'Luty',
+ 'From' => 'Od',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'òÁÚÄÅÌ',
+ 'ID' => 'Identyfikator',
+ 'In-line' => 'W³±czony',
+ 'Include in Report' => 'Do³±cz w Sprawozdaniu',
+ 'Income Statement' => 'Rachunek Zysków i Strat',
+ 'Invoice' => 'óÞÅÔ-ÆÁËÔÕÒÁ',
+ 'Jan' => 'ñÎ×',
+ 'January' => 'ñÎ×ÁÒØ',
+ 'Jul' => 'éÀÌ',
+ 'July' => 'éÀÌØ',
+ 'Jun' => 'éÀÎ',
+ 'June' => 'éÀÎØ',
+ 'Mar' => 'Marzec',
+ 'March' => 'Marzec',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Wiadomo¶æ',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Nothing selected!',
+ 'Nov' => 'Listopad',
+ 'November' => 'Listopad',
+ 'Oct' => 'Pa¿dziernik',
+ 'October' => 'Pa¿dziernik',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Rozliczenia P³atno¶ci',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Print',
+ 'Printer' => 'Drukarka',
+ 'Receipts' => 'Receipts',
+ 'Report for' => 'Raport dla',
+ 'Retained Earnings' => 'Zysk',
+ 'Screen' => 'Ekran',
+ 'Select all' => 'Select all',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'óÅÎ',
+ 'September' => 'óÅÎÔÑÂÒØ',
+ 'Source' => '¯ród³o',
+ 'Standard' => 'óÔÁÎÄÁÒÔÎÙÅ',
+ 'Statement' => 'Statement',
+ 'Statement sent to' => 'Statement sent to',
+ 'Statements sent to printer!' => 'Statements sent to printer!',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'éÔÏÇÏ ÐÏ ÒÁÚÄÅÌÕ',
+ 'Tax' => 'îÁÌÏÇ',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'To' => 'do',
+ 'Total' => 'Warto¶æ Brutto',
+ 'Trial Balance' => 'Bilans Porównawczy',
+ 'Vendor' => 'Dostawca',
+ 'as at' => 'as at',
+ 'collected on sales' => 'zebranego przy sprzeda¿y',
+ 'for Period' => 'za Okres',
+ 'paid on purchases' => 'zap³aconego przy zakupach',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'ðÒÏÄÏÌÖÉÔØ' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'print' => 'print',
+ 'select_all' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/se/COPYING b/sql-ledger/locale/se/COPYING
new file mode 100644
index 0000000..5e4eee3
--- /dev/null
+++ b/sql-ledger/locale/se/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2002
+#
+# Swedish texts:
+#
+# Author: jonny@lernbo.com
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/se/LANGUAGE b/sql-ledger/locale/se/LANGUAGE
new file mode 100644
index 0000000..e375393
--- /dev/null
+++ b/sql-ledger/locale/se/LANGUAGE
@@ -0,0 +1 @@
+Swedish
diff --git a/sql-ledger/locale/se/admin b/sql-ledger/locale/se/admin
new file mode 100644
index 0000000..5b8e140
--- /dev/null
+++ b/sql-ledger/locale/se/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Accesskontroll',
+ 'Accounting' => 'Bokföring',
+ 'Add User' => 'Ny användare',
+ 'Address' => 'Adress',
+ 'Administration' => 'Administration',
+ 'Administrator' => 'Administratör',
+ 'All Datasets up to date!' => 'Alla dataset uppdaterade',
+ 'Change Admin Password' => 'Ändra lösenord för admin',
+ 'Change Password' => 'Ändra lösenord',
+ 'Character Set' => 'Teckenuppsättning',
+ 'Click on login name to edit!' => 'Klicka på användarnamn för att redigera!',
+ 'Company' => 'Företag',
+ 'Connect to' => 'Anslut till',
+ 'Continue' => 'Fortsätt',
+ 'Create Chart of Accounts' => 'Skapa kontoplan',
+ 'Create Dataset' => 'Skapa dataset',
+ 'DBI not installed!' => 'DBI inte installerad',
+ 'Database' => 'Databas',
+ 'Database Administration' => 'Administration av databas',
+ 'Database Driver not checked!' => 'Databasedriver icke kontrollerad',
+ 'Database User missing!' => 'Databasanvändare saknas',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Dataset saknas',
+ 'Dataset updated!' => 'Dataset uppdaterat',
+ 'Date Format' => 'Datumformat',
+ 'Delete' => 'Radera',
+ 'Delete Dataset' => 'Radera dataset',
+ 'Directory' => 'Katalog',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Dropdown gräns',
+ 'E-mail' => 'E-Post',
+ 'Edit User' => 'Redigera användare',
+ 'Existing Datasets' => 'Existerande Dataset',
+ 'Fax' => 'Fax',
+ 'File locked!' => 'Fil låst',
+ 'Host' => 'Värd',
+ 'Hostname missing!' => 'Värdnamn saknas',
+ 'Incorrect Password!' => 'Felaktigt lösenord',
+ 'Language' => 'Språk',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Lämna värd och port fälten tomma om du inte vill göra en fjärranslutning',
+ 'Login' => 'Logga in',
+ 'Multibyte Encoding' => 'Multibytekodning',
+ 'Name' => 'Namn',
+ 'New Templates' => 'Ny mall',
+ 'No Database Drivers available!' => 'Inga databasdrivers tillgängliga',
+ 'No Dataset selected!' => 'Inget Dataset valt',
+ 'Nothing to delete!' => 'Inget att radera',
+ 'Number Format' => 'Nummerformat',
+ 'Oracle Database Administration' => 'Oracle Databasadministration',
+ 'Password' => 'Lösenord',
+ 'Password changed!' => 'Lösenord ändrat',
+ 'Pg Database Administration' => 'Administration av databas PG',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port saknas',
+ 'Printer' => 'Skrivare',
+ 'Save' => 'Spara',
+ 'Select a Dataset to delete and press "Continue"' => 'Välj en databas att radera och klicka på "Fortsätt"',
+ 'Setup Templates' => 'Sätt upp mallar',
+ 'Ship via' => 'Skicka via',
+ 'Signature' => 'Signatur',
+ 'Stylesheet' => 'Stilmall',
+ 'Templates' => 'Mallar',
+ 'The following Datasets are not in use and can be deleted' => 'Följande Dataset är inte i bruk och kan raderas',
+ 'The following Datasets need to be updated' => 'Följande Dataset behöver uppdateras',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Det här är en preliminär kontroll av existerande källor. Ingenting kommer att sparas eller raderas vid detta tillfälle',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'För att lägga till en användare till en grupp, editera namnet, ändra login namnet och spara. En ny användare med samma variabler sparas då under det nya namnet.',
+ 'Update Dataset' => 'Uppdatera dataset',
+ 'Use Templates' => 'Använd mallar',
+ 'User' => 'Användare',
+ 'User deleted!' => 'Användare raderad',
+ 'User saved!' => 'Användare sparad',
+ 'Version' => 'Version',
+ 'You must enter a host and port for local and remote connections!' => 'Du måste ange en värd och en port för att göra en fjärrsnslutning',
+ 'does not exist' => 'finns inte',
+ 'is already a member!' => 'är redan medlem!',
+ 'localhost' => 'localhost',
+ 'successfully created!' => 'skapades',
+ 'successfully deleted!' => 'raderades',
+ 'website' => 'website',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'ny_användare' => 'add_user',
+ 'Ändra_lösenord_för_admin' => 'change_admin_password',
+ 'Ändra_lösenord' => 'change_password',
+ 'fortsätt' => 'continue',
+ 'skapa_dataset' => 'create_dataset',
+ 'radera' => 'delete',
+ 'radera_dataset' => 'delete_dataset',
+ 'logga_in' => 'login',
+ 'oracle_databasadministration' => 'oracle_database_administration',
+ 'administration_av_databas_pg' => 'pg_database_administration',
+ 'spara' => 'save',
+ 'uppdatera_dataset' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/se/all b/sql-ledger/locale/se/all
new file mode 100644
index 0000000..dc1dd2d
--- /dev/null
+++ b/sql-ledger/locale/se/all
@@ -0,0 +1,491 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Kredit',
+ 'AP Aging' => 'Kredit åldersfördeling',
+ 'AP Transaction' => 'Kredit verifikat',
+ 'AP Transactions' => 'Kredit verifikationer',
+ 'AR' => 'Debet',
+ 'AR Aging' => 'Debet åldersfördeling',
+ 'AR Transaction' => 'Debet verifikat',
+ 'AR Transactions' => 'Debet verifikationer',
+ 'About' => 'Om',
+ 'Access Control' => 'Accesskontroll',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Kontonummer',
+ 'Account Number missing!' => 'Kontonummer saknas',
+ 'Account Type' => 'Kontotyp',
+ 'Account Type missing!' => 'Kontotyp saknas!',
+ 'Account deleted!' => 'Konto raderat!',
+ 'Account saved!' => 'Konto sparat!',
+ 'Accounting' => 'Bokföring',
+ 'Accounting Menu' => 'Konto-meny',
+ 'Accounts' => 'Konton',
+ 'Active' => 'Aktiv',
+ 'Add' => 'Lägg til',
+ 'Add Account' => 'Nytt konto',
+ 'Add Accounts Payables Transaction' => 'Lägg till kreditverifikat',
+ 'Add Accounts Receivables Transaction' => 'Lägg till debetverifikat',
+ 'Add Assembly' => 'Ny sammansätting',
+ 'Add Customer' => 'Ny kund',
+ 'Add GIFI' => 'Ny GIFI',
+ 'Add General Ledger Transaction' => 'Ny post i huvudbok',
+ 'Add Part' => 'Ny vara',
+ 'Add Project' => 'Nytt projekt',
+ 'Add Purchase Invoice' => 'Ny inköpsfaktura',
+ 'Add Purchase Order' => 'Ny inköpsorder',
+ 'Add Sales Invoice' => 'Ny säljfaktura',
+ 'Add Sales Order' => 'Ny säljorder',
+ 'Add Service' => 'Ny tjänst',
+ 'Add Transaction' => 'Ny post',
+ 'Add User' => 'Ny användare',
+ 'Add Vendor' => 'Ny leverantör',
+ 'Address' => 'Adress',
+ 'Administration' => 'Administration',
+ 'Administrator' => 'Administratör',
+ 'All' => 'Alla',
+ 'All Datasets up to date!' => 'Alla dataset uppdaterade',
+ 'Amount' => 'Belopp',
+ 'Amount Due' => 'Belopp förfallet',
+ 'Amount does not equal applied!' => 'Förfallet belopp stämmer ej med det tillagda',
+ 'Amount missing!' => 'Summa saknas',
+ 'Applied' => 'Tillagt',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Invoice Number' => 'Är du säker på att du vill radera Faktura Nummer',
+ 'Are you sure you want to delete Order Number' => 'Är du säker på att du vill radera Order Nummer',
+ 'Are you sure you want to delete Transaction' => 'Är du säker på att du vill radera Transaktionen',
+ 'Assemblies' => 'Sammansättningar',
+ 'Assemblies restocked!' => 'Sammansättningar åter i lager',
+ 'Assembly Number missing!' => 'Sammansättningsnummer saknas',
+ 'Asset' => 'Tillgång',
+ 'Attachment' => 'Bilaga',
+ 'Audit Control' => 'Revisionskontroll',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'BOM' => 'BOM',
+ 'Backup' => 'Säkerhetkopia',
+ 'Backup sent to' => 'Säkerhetskopia har sänts till',
+ 'Balance' => 'Balans',
+ 'Balance Sheet' => 'Status',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Antal i lager',
+ 'Books are open' => 'Bokföringen är öppen för rättning',
+ 'Bought' => 'Köpt',
+ 'Business Number' => 'Organisationsnummer',
+ 'C' => 'C',
+ 'COGS' => 'Inköp',
+ 'Cannot delete account!' => 'Kan inte radera konto',
+ 'Cannot delete customer!' => 'Kan inte radera kund',
+ 'Cannot delete default account!' => 'Kan inte radera standardkonto',
+ 'Cannot delete invoice!' => 'Kan inte radera faktura',
+ 'Cannot delete item already invoiced!' => 'Kan inte radera redan fakturerade varor!',
+ 'Cannot delete item on order!' => 'Kan inte radera vara i order!',
+ 'Cannot delete item which is part of an assembly!' => 'Kan inte radera vara som är del av en sammansättning!',
+ 'Cannot delete item!' => 'Kan inte radera vara',
+ 'Cannot delete order!' => 'Kan inte radera order',
+ 'Cannot delete transaction!' => 'Kan inte radera händelse',
+ 'Cannot delete vendor!' => 'Kan inte radera Leverantör',
+ 'Cannot have a value in both Debit and Credit!' => 'Kan inte ha värde i både Debet och Kredit!',
+ 'Cannot post a transaction without a value!' => 'Kan inte lägga till en händelse utan ett värde',
+ 'Cannot post invoice for a closed period!' => 'Kan inte lägga till en faktura för en avslutad period',
+ 'Cannot post invoice!' => 'Kan inte lägga till faktura',
+ 'Cannot post payment for a closed period!' => 'Kan inte lägga till en betalning för en stängd period',
+ 'Cannot post payment!' => 'Kan inte lägga till betalning',
+ 'Cannot post transaction for a closed period!' => 'Kan inte bokföra för en stängd period',
+ 'Cannot post transaction!' => 'Kan inte lägga till händelsen',
+ 'Cannot process payment for a closed period!' => 'Kan inte processa betalning för en avslutad period',
+ 'Cannot save account!' => 'Kan inte spara konto',
+ 'Cannot save order!' => 'Kan inte spara order',
+ 'Cannot save preferences!' => 'Kan inte spara preferenser',
+ 'Cannot stock assemblies!' => 'Kan lagerföra sammansättningar',
+ 'Cash' => 'Kontant',
+ 'Cash based' => 'Kontantbaserad',
+ 'Cc' => 'Kopia',
+ 'Change Admin Password' => 'Ändra lösenord för admin',
+ 'Change Password' => 'Ändra lösenord',
+ 'Character Set' => 'Teckenuppsättning',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check utskriven',
+ 'Check printing failed!' => 'Utskrift av check misslyckades',
+ 'Cleared Balance' => 'Rensade balans',
+ 'Click on login name to edit!' => 'Klicka på användarnamn för att redigera!',
+ 'Close Books up to' => 'Avsluta bokföring fram till och med',
+ 'Closed' => 'Avslutad',
+ 'Company' => 'Företag',
+ 'Compare to' => 'Jämför med',
+ 'Confirm!' => 'Bekräfta',
+ 'Connect to' => 'Anslut till',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsätt',
+ 'Copies' => 'Kopior',
+ 'Copy to COA' => 'Kopiera till COA',
+ 'Create Chart of Accounts' => 'Skapa kontoplan',
+ 'Create Dataset' => 'Skapa dataset',
+ 'Credit' => 'Kredit',
+ 'Credit Limit' => 'Kreditgräns',
+ 'Curr' => 'Val',
+ 'Currency' => 'Valuta',
+ 'Current' => 'Nuvarande',
+ 'Customer' => 'Kund',
+ 'Customer deleted!' => 'Kund raderad',
+ 'Customer missing!' => 'Kund saknas',
+ 'Customer not on file!' => 'Kund finns ej',
+ 'Customer saved!' => 'Kund sparad',
+ 'Customers' => 'Kunder',
+ 'DBI not installed!' => 'DBI inte installerad',
+ 'Database' => 'Databas',
+ 'Database Administration' => 'Administration av databas',
+ 'Database Driver not checked!' => 'Databasedriver icke kontrollerad',
+ 'Database Host' => 'Databasvärd',
+ 'Database User missing!' => 'Databasanvändare saknas',
+ 'Dataset' => 'Dataset',
+ 'Dataset missing!' => 'Dataset saknas',
+ 'Dataset updated!' => 'Dataset uppdaterat',
+ 'Date' => 'Datum',
+ 'Date Due' => 'Förfallodatum',
+ 'Date Format' => 'Datumformat',
+ 'Date Paid' => 'Betalningsdatum',
+ 'Date missing!' => 'Datum saknas',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet och kredit måste vara lika!',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Decimalplaces' => 'Decimalplaceringar',
+ 'Delete' => 'Radera',
+ 'Delete Account' => 'Radera konto',
+ 'Delete Dataset' => 'Radera dataset',
+ 'Delivery Date' => 'Leveransdatum',
+ 'Deposit' => 'Säkerhet',
+ 'Description' => 'Beskrivning',
+ 'Difference' => 'Differens',
+ 'Directory' => 'Katalog',
+ 'Discount' => 'Rabatt',
+ 'Done' => 'Klart',
+ 'Drawing' => 'Ritning',
+ 'Driver' => 'Driver',
+ 'Dropdown Limit' => 'Dropdown gräns',
+ 'Due' => 'Förfallen',
+ 'Due Date' => 'Förfallodatum',
+ 'Due Date missing!' => 'Förfallodatum saknas',
+ 'E-mail' => 'E-Post',
+ 'E-mail Statement to' => 'E-Post anmaning till',
+ 'E-mail address missing!' => 'E-Postadress saknas',
+ 'Edit' => 'Redigera',
+ 'Edit Account' => 'Redigera konto',
+ 'Edit Accounts Payables Transaction' => 'Redigera kreditkonton',
+ 'Edit Accounts Receivables Transaction' => 'Redigera debetkonton',
+ 'Edit Assembly' => 'Redigera sammansättning',
+ 'Edit Customer' => 'Redigera kund',
+ 'Edit GIFI' => 'Redigera GIFI',
+ 'Edit General Ledger Transaction' => 'Redigera en post i Huvudboken',
+ 'Edit Part' => 'Redigera vara',
+ 'Edit Preferences for' => 'Redigera inställningar för',
+ 'Edit Project' => 'Redigera projekt',
+ 'Edit Purchase Invoice' => 'Redigera inköpsfakturor',
+ 'Edit Purchase Order' => 'Redigera inköpsorder',
+ 'Edit Sales Invoice' => 'Redigera säljfakturor',
+ 'Edit Sales Order' => 'Redigera säljorder',
+ 'Edit Service' => 'Redigera tjänster',
+ 'Edit Template' => 'Redigera mall',
+ 'Edit User' => 'Redigera användare',
+ 'Edit Vendor' => 'Redigera Leverantör',
+ 'Employee' => 'Anställd',
+ 'Enforce transaction reversal for all dates' => 'Tvinga rättelser för alla konton',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Ange upp till 3 bokstäver (SEK:EUR:USD) för egen och utländsk valuta',
+ 'Equity' => 'Eget kapital',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Växlingskurs',
+ 'Exchangerate Difference' => 'Differens Växlingskurs',
+ 'Exchangerate for payment missing!' => 'Växlingskurs för saknad betalning',
+ 'Exchangerate missing!' => 'Växelkurs saknas',
+ 'Existing Datasets' => 'Existerande Dataset',
+ 'Expense' => 'Utgift',
+ 'Expense Account' => 'Utgiftskonto',
+ 'Expense/Asset' => 'Utgift/Tillgång',
+ 'Extended' => 'Utökad',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'File locked!' => 'Fil låst',
+ 'Foreign Exchange Gain' => 'Vinst på valutahandel',
+ 'Foreign Exchange Loss' => 'Förlust på valutahandel',
+ 'From' => 'Från',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI raderad',
+ 'GIFI missing!' => 'GIFI saknas',
+ 'GIFI saved!' => 'GIFI sparad',
+ 'GL Transaction' => 'GL händelse',
+ 'General Ledger' => 'Huvudbok',
+ 'Goods & Services' => 'Varor och Tjänster',
+ 'HTML Templates' => 'HTML mallar',
+ 'Heading' => 'Överskrift',
+ 'Host' => 'Värd',
+ 'Hostname missing!' => 'Värdnamn saknas',
+ 'ID' => 'ID',
+ 'Image' => 'Bild',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Inkludera i rapport',
+ 'Include in drop-down menus' => 'Inkludera i rullgardinsmenyer',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Inkludera det här kontot för kund/leverantör för att markera kund/leverantör som momspliktig',
+ 'Income' => 'Intäkt',
+ 'Income Account' => 'Intäktskonto',
+ 'Income Statement' => 'Inkomstberäkning',
+ 'Incorrect Dataset version!' => 'Felaktig databasversion',
+ 'Incorrect Password!' => 'Felaktigt lösenord',
+ 'Individual Items' => 'Individuella enheter',
+ 'Inventory' => 'Lager',
+ 'Inventory Account' => 'Lagerkonto',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Lagerkvantitet måste vara noll innan du kan sätta sammansättningen som utgången!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Lagerkvantitet måste vara noll innan du kan sätta varan som utgången!',
+ 'Inventory quantity must be zero!' => 'Lagerkvantiteten måste vara noll!',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadatum',
+ 'Invoice Date missing!' => 'Fakturadatum saknas',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer saknas',
+ 'Invoice deleted!' => 'Faktura raderad',
+ 'Invoice posted!' => 'Faktura postad',
+ 'Invoices' => 'Fakturor',
+ 'Is this a summary account to record' => 'Samlingskonto för',
+ 'Item deleted!' => 'Vara raderad',
+ 'Item not on file!' => 'Varan finns inte i databasen',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'LaTeX Templates' => 'LaTeX Mallar',
+ 'Language' => 'Språk',
+ 'Last Cost' => 'Senaste kostnad',
+ 'Last Invoice Number' => 'Senaste fakturanummer',
+ 'Last Numbers & Default Accounts' => 'Senaste nummer och standardkonto',
+ 'Last Purchase Order Number' => 'Senaste inköpsordernummer',
+ 'Last Sales Order Number' => 'Senaste säljordernummer',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Lämna värd och port fälten tomma om du inte vill göra en fjärranslutning',
+ 'Liability' => 'Ansvar',
+ 'Licensed to' => 'Licensierad till',
+ 'Line Total' => 'Antal rader',
+ 'Link' => 'Referens',
+ 'Link Accounts' => 'Koppla konton',
+ 'List Accounts' => 'Lista konton',
+ 'List GIFI' => 'Lista GIFI',
+ 'List Price' => 'Inköpspris',
+ 'List Transactions' => 'Lista transaktioner',
+ 'Login' => 'Logga in',
+ 'Logout' => 'Logga ut',
+ 'Make' => 'Skapa',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Meddelande',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modell',
+ 'Multibyte Encoding' => 'Multibytekodning',
+ 'N/A' => 'N/A',
+ 'Name' => 'Namn',
+ 'Name missing!' => 'Namn saknas',
+ 'New Templates' => 'Ny mall',
+ 'No' => 'Rad',
+ 'No Database Drivers available!' => 'Inga databasdrivers tillgängliga',
+ 'No Dataset selected!' => 'Inget Dataset valt',
+ 'No email address for' => 'Ingen E-Postadress för',
+ 'No.' => 'Rad',
+ 'Notes' => 'Anmärkningar',
+ 'Nothing applied!' => 'Ingenting lades till',
+ 'Nothing selected!' => 'Ingenting valt',
+ 'Nothing to delete!' => 'Inget att radera',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Nummerformat',
+ 'Number missing in Row' => 'Nummer saknas i rad',
+ 'O' => 'O',
+ 'Obsolete' => 'Utgången',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'On Hand' => 'I lager',
+ 'On Order' => 'På order',
+ 'Open' => 'Öppen',
+ 'Oracle Database Administration' => 'Oracle Databasadministration',
+ 'Order' => 'Order',
+ 'Order Date' => 'Orderdatum',
+ 'Order Date missing!' => 'Orderdatum saknas',
+ 'Order Entry' => 'Orderingång',
+ 'Order Number' => 'Ordernummer',
+ 'Order Number missing!' => 'Ordernummer saknas',
+ 'Order deleted!' => 'Order raderad',
+ 'Order saved!' => 'Order sparad',
+ 'Ordered' => 'Beställt',
+ 'Orphaned' => 'Fristående',
+ 'Out of balance!' => 'Ej i balans',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packsedel',
+ 'Packing List Date missing!' => 'Packsedelsdatum saknas',
+ 'Packing List Number missing!' => 'Packsedelsnummer saknas',
+ 'Paid' => 'Betalt',
+ 'Paid in full' => 'Slutbetalt',
+ 'Part' => 'Vara',
+ 'Part Number missing!' => 'Artikelnummer saknas',
+ 'Parts' => 'Varor',
+ 'Parts Inventory' => 'Artikellista',
+ 'Password' => 'Lösenord',
+ 'Password changed!' => 'Lösenord ändrat',
+ 'Payables' => 'Utbetalningar',
+ 'Payment' => 'Betalning',
+ 'Payment date missing!' => 'Betalningsdatum saknas',
+ 'Payment posted!' => 'Betalning postad',
+ 'Payments' => 'Betalningar',
+ 'Pg Database Administration' => 'Administration av databas PG',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port saknas',
+ 'Post' => 'Lägg till',
+ 'Post as new' => 'Lägg till som ny',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Inställningar',
+ 'Preferences saved!' => 'Inställningar sparade',
+ 'Price' => 'Pris',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Skrivare',
+ 'Project' => 'Projekt',
+ 'Project Number missing!' => 'Projektnummer saknas',
+ 'Project deleted!' => 'Projekt raderat',
+ 'Project not on file!' => 'Projekt finns ej',
+ 'Project saved!' => 'Projekt sparat',
+ 'Projects' => 'Projekt',
+ 'Purchase Invoice' => 'Inköpsfaktura',
+ 'Purchase Order' => 'Inköpsorder',
+ 'Purchase Orders' => 'Inköpsordrar',
+ 'Qty' => 'Antal',
+ 'ROP' => 'Efterbeställning vid',
+ 'Rate' => 'Rate',
+ 'Recd' => 'Mottagen',
+ 'Receipt' => 'Kvitto',
+ 'Receipts' => 'Kvitton',
+ 'Receivables' => 'Inbetalningar',
+ 'Reconciliation' => 'Bankuppgörelse',
+ 'Record in' => 'Bokför på',
+ 'Reference' => 'Referens',
+ 'Reference missing!' => 'Referens saknas',
+ 'Remaining' => 'Resterar',
+ 'Report for' => 'Rapport för',
+ 'Reports' => 'Rapporter',
+ 'Required by' => 'Beställt den',
+ 'Retained Earnings' => 'Realiserat överskott',
+ 'Sales' => 'Försäljning',
+ 'Sales Invoice' => 'Säljfaktura',
+ 'Sales Order' => 'Säljorder',
+ 'Sales Orders' => 'Säljordrar',
+ 'Save' => 'Spara',
+ 'Save as new' => 'Spara som ny',
+ 'Save to File' => 'Spara till fil',
+ 'Screen' => 'Skärm',
+ 'Select a Dataset to delete and press "Continue"' => 'Välj en databas att radera och klicka på "Fortsätt"',
+ 'Select all' => 'Välj alla',
+ 'Select from one of the items below' => 'Välj en artikel nedan',
+ 'Select from one of the names below' => 'Välj ett av namnen nedan',
+ 'Select from one of the projects below' => 'Välj ett av projekten nedan',
+ 'Select postscript or PDF!' => 'Välj Postscript eller PDF',
+ 'Sell Price' => 'Försäljningspris',
+ 'Send by E-Mail' => 'Skicka via E-Post',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Tjänster',
+ 'Service Items' => 'Tjänsteartiklar',
+ 'Service Number missing!' => 'Tjänstenummer saknas',
+ 'Services' => 'Tjänster',
+ 'Setup Templates' => 'Sätt upp mallar',
+ 'Ship' => 'Skicka',
+ 'Ship to' => 'Skicka till',
+ 'Ship via' => 'Skicka via',
+ 'Short' => 'Kort',
+ 'Signature' => 'Signatur',
+ 'Sold' => 'Såld',
+ 'Source' => 'Källa',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Anmärkning',
+ 'Statement Balance' => 'Anmärkning status',
+ 'Statement sent to' => 'Anmärkning skickad till',
+ 'Statements sent to printer!' => 'Anmärkningar skickade till skrivare',
+ 'Stock Assembly' => 'Lagersammansättning',
+ 'Stylesheet' => 'Stilmall',
+ 'Subject' => 'Ämne',
+ 'Subtotal' => 'Subtotal',
+ 'System' => 'System',
+ 'Tax' => 'Moms',
+ 'Tax Accounts' => 'Momskonton',
+ 'Tax Included' => 'Moms ingår',
+ 'Tax collected' => 'Moms total',
+ 'Tax paid' => 'Moms betalad',
+ 'Taxable' => 'Momspliktigt',
+ 'Template saved!' => 'Mall sparad',
+ 'Templates' => 'Mallar',
+ 'Terms: Net' => 'Netto',
+ 'The following Datasets are not in use and can be deleted' => 'Följande Dataset är inte i bruk och kan raderas',
+ 'The following Datasets need to be updated' => 'Följande Dataset behöver uppdateras',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Det här är en preliminär kontroll av existerande källor. Ingenting kommer att sparas eller raderas vid detta tillfälle',
+ 'To' => 'Till',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'För att lägga till en användare till en grupp, editera namnet, ändra login namnet och spara. En ny användare med samma variabler sparas då under det nya namnet.',
+ 'Top Level' => 'Toppnivå',
+ 'Total' => 'Total',
+ 'Transaction Date missing!' => 'Transaktionsdatum saknas',
+ 'Transaction deleted!' => 'Transaktion raderad',
+ 'Transaction posted!' => 'Transaktion sparad',
+ 'Transaction reversal enforced for all dates' => 'Transaktion påtvingas för alla datum',
+ 'Transaction reversal enforced up to' => 'Transaktion påtvingas upp till',
+ 'Transactions' => 'Transaktioner',
+ 'Transactions exist, cannot delete customer!' => 'Transaktioner finns, kan inte radera kund',
+ 'Transactions exist, cannot delete vendor!' => 'Transaktioner finns, kan inte radera leverantör',
+ 'Transactions exist; cannot delete account!' => 'Transaktioner finns, kan inte radera konto',
+ 'Trial Balance' => 'Provbalans',
+ 'Unit' => 'Enhet',
+ 'Unit of measure' => 'Måttenhet',
+ 'Update' => 'Uppdatera',
+ 'Update Dataset' => 'Uppdatera dataset',
+ 'Updated' => 'Uppdaterad',
+ 'Use Templates' => 'Använd mallar',
+ 'User' => 'Användare',
+ 'User deleted!' => 'Användare raderad',
+ 'User saved!' => 'Användare sparad',
+ 'Vendor' => 'Leverantör',
+ 'Vendor deleted!' => 'Leverantör raderad',
+ 'Vendor missing!' => 'Leverantör saknas',
+ 'Vendor not on file!' => 'Leverantör finns ej',
+ 'Vendor saved!' => 'Leverantör sparad',
+ 'Vendors' => 'Leverantörer',
+ 'Version' => 'Version',
+ 'Weight' => 'Vikt',
+ 'Weight Unit' => 'Viktenhet',
+ 'What type of item is this?' => 'Vilken typ av artikel är detta?',
+ 'Year End' => 'Årsslut',
+ 'Yes' => 'Ja',
+ 'You are logged out!' => 'Du är utloggad',
+ 'You did not enter a name!' => 'Du skrev inte in något namn',
+ 'You must enter a host and port for local and remote connections!' => 'Du måste ange en värd och en port för att göra en fjärrsnslutning',
+ 'as at' => 'som vid',
+ 'collected on sales' => 'inbetalt på försäljning',
+ 'days' => 'dagar',
+ 'does not exist' => 'finns inte',
+ 'ea' => 'st',
+ 'emailed to' => 'E-Postat till',
+ 'for Period' => 'för perioden',
+ 'hr' => 'timme',
+ 'is already a member!' => 'är redan medlem!',
+ 'is not a member!' => 'är inte medlem!',
+ 'localhost' => 'localhost',
+ 'paid on purchases' => 'betalt vid köp',
+ 'sent to printer' => 'skickat till skrivare',
+ 'successfully created!' => 'skapades',
+ 'successfully deleted!' => 'raderades',
+ 'to' => 'till',
+ 'website' => 'website',
+};
+
+1;
diff --git a/sql-ledger/locale/se/am b/sql-ledger/locale/se/am
new file mode 100644
index 0000000..d8e084b
--- /dev/null
+++ b/sql-ledger/locale/se/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Kredit',
+ 'AR' => 'Debet',
+ 'Account' => 'Konto',
+ 'Account Number' => 'Kontonummer',
+ 'Account Number missing!' => 'Kontonummer saknas',
+ 'Account Type' => 'Kontotyp',
+ 'Account Type missing!' => 'Kontotyp saknas!',
+ 'Account deleted!' => 'Konto raderat!',
+ 'Account saved!' => 'Konto sparat!',
+ 'Add Account' => 'Nytt konto',
+ 'Add GIFI' => 'Ny GIFI',
+ 'Address' => 'Adress',
+ 'Asset' => 'Tillgång',
+ 'Audit Control' => 'Revisionskontroll',
+ 'Backup sent to' => 'Säkerhetskopia har sänts till',
+ 'Books are open' => 'Bokföringen är öppen för rättning',
+ 'Business Number' => 'Organisationsnummer',
+ 'COGS' => 'Inköp',
+ 'Cannot delete account!' => 'Kan inte radera konto',
+ 'Cannot delete default account!' => 'Kan inte radera standardkonto',
+ 'Cannot save account!' => 'Kan inte spara konto',
+ 'Cannot save preferences!' => 'Kan inte spara preferenser',
+ 'Character Set' => 'Teckenuppsättning',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Close Books up to' => 'Avsluta bokföring fram till och med',
+ 'Company' => 'Företag',
+ 'Continue' => 'Fortsätt',
+ 'Copy to COA' => 'Kopiera till COA',
+ 'Credit' => 'Kredit',
+ 'Date Format' => 'Datumformat',
+ 'Debit' => 'Debet',
+ 'Delete' => 'Radera',
+ 'Delete Account' => 'Radera konto',
+ 'Description' => 'Beskrivning',
+ 'Dropdown Limit' => 'Dropdown gräns',
+ 'E-mail' => 'E-Post',
+ 'Edit' => 'Redigera',
+ 'Edit Account' => 'Redigera konto',
+ 'Edit GIFI' => 'Redigera GIFI',
+ 'Edit Preferences for' => 'Redigera inställningar för',
+ 'Edit Template' => 'Redigera mall',
+ 'Enforce transaction reversal for all dates' => 'Tvinga rättelser för alla konton',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Ange upp till 3 bokstäver (SEK:EUR:USD) för egen och utländsk valuta',
+ 'Equity' => 'Eget kapital',
+ 'Expense' => 'Utgift',
+ 'Expense Account' => 'Utgiftskonto',
+ 'Expense/Asset' => 'Utgift/Tillgång',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Vinst på valutahandel',
+ 'Foreign Exchange Loss' => 'Förlust på valutahandel',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI raderad',
+ 'GIFI missing!' => 'GIFI saknas',
+ 'GIFI saved!' => 'GIFI sparad',
+ 'Heading' => 'Överskrift',
+ 'Include in drop-down menus' => 'Inkludera i rullgardinsmenyer',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Inkludera det här kontot för kund/leverantör för att markera kund/leverantör som momspliktig',
+ 'Income' => 'Intäkt',
+ 'Income Account' => 'Intäktskonto',
+ 'Inventory' => 'Lager',
+ 'Inventory Account' => 'Lagerkonto',
+ 'Is this a summary account to record' => 'Samlingskonto för',
+ 'Language' => 'Språk',
+ 'Last Invoice Number' => 'Senaste fakturanummer',
+ 'Last Numbers & Default Accounts' => 'Senaste nummer och standardkonto',
+ 'Last Purchase Order Number' => 'Senaste inköpsordernummer',
+ 'Last Sales Order Number' => 'Senaste säljordernummer',
+ 'Liability' => 'Ansvar',
+ 'Link' => 'Referens',
+ 'Name' => 'Namn',
+ 'No' => 'Rad',
+ 'No email address for' => 'Ingen E-Postadress för',
+ 'Number' => 'Nummer',
+ 'Number Format' => 'Nummerformat',
+ 'Parts Inventory' => 'Artikellista',
+ 'Password' => 'Lösenord',
+ 'Payables' => 'Utbetalningar',
+ 'Payment' => 'Betalning',
+ 'Phone' => 'Telefon',
+ 'Preferences saved!' => 'Inställningar sparade',
+ 'Rate' => 'Rate',
+ 'Receivables' => 'Inbetalningar',
+ 'Sales' => 'Försäljning',
+ 'Save' => 'Spara',
+ 'Service Items' => 'Tjänsteartiklar',
+ 'Ship via' => 'Skicka via',
+ 'Signature' => 'Signatur',
+ 'Stylesheet' => 'Stilmall',
+ 'Tax' => 'Moms',
+ 'Tax Accounts' => 'Momskonton',
+ 'Template saved!' => 'Mall sparad',
+ 'Transaction reversal enforced for all dates' => 'Transaktion påtvingas för alla datum',
+ 'Transaction reversal enforced up to' => 'Transaktion påtvingas upp till',
+ 'Transactions exist; cannot delete account!' => 'Transaktioner finns, kan inte radera konto',
+ 'Weight Unit' => 'Viktenhet',
+ 'Year End' => 'Årsslut',
+ 'Yes' => 'Ja',
+ 'does not exist' => 'finns inte',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'nytt_konto' => 'add_account',
+ 'fortsätt' => 'continue',
+ 'kopiera_till_coa' => 'copy_to_coa',
+ 'radera' => 'delete',
+ 'redigera' => 'edit',
+ 'redigera_konto' => 'edit_account',
+ 'spara' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/se/ap b/sql-ledger/locale/se/ap
new file mode 100644
index 0000000..94021c9
--- /dev/null
+++ b/sql-ledger/locale/se/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Kredit verifikat',
+ 'AP Transactions' => 'Kredit verifikationer',
+ 'Account' => 'Konto',
+ 'Add Accounts Payables Transaction' => 'Lägg till kreditverifikat',
+ 'Address' => 'Adress',
+ 'Amount' => 'Belopp',
+ 'Amount Due' => 'Belopp förfallet',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Transaction' => 'Är du säker på att du vill radera Transaktionen',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'Cannot delete transaction!' => 'Kan inte radera händelse',
+ 'Cannot post payment for a closed period!' => 'Kan inte lägga till en betalning för en stängd period',
+ 'Cannot post transaction for a closed period!' => 'Kan inte bokföra för en stängd period',
+ 'Cannot post transaction!' => 'Kan inte lägga till händelsen',
+ 'Closed' => 'Avslutad',
+ 'Confirm!' => 'Bekräfta',
+ 'Continue' => 'Fortsätt',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Kund finns ej',
+ 'Date' => 'Datum',
+ 'Date Paid' => 'Betalningsdatum',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Radera',
+ 'Description' => 'Beskrivning',
+ 'Due Date' => 'Förfallodatum',
+ 'Due Date missing!' => 'Förfallodatum saknas',
+ 'Edit Accounts Payables Transaction' => 'Redigera kreditkonton',
+ 'Employee' => 'Anställd',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Växlingskurs',
+ 'Exchangerate for payment missing!' => 'Växlingskurs för saknad betalning',
+ 'Exchangerate missing!' => 'Växelkurs saknas',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Från',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inkludera i rapport',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadatum',
+ 'Invoice Date missing!' => 'Fakturadatum saknas',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer saknas',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Notes' => 'Anmärkningar',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Open' => 'Öppen',
+ 'Order' => 'Order',
+ 'Order Number' => 'Ordernummer',
+ 'Paid' => 'Betalt',
+ 'Payment date missing!' => 'Betalningsdatum saknas',
+ 'Payments' => 'Betalningar',
+ 'Post' => 'Lägg till',
+ 'Post as new' => 'Lägg till som ny',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt finns ej',
+ 'Purchase Invoice' => 'Inköpsfaktura',
+ 'Select from one of the names below' => 'Välj ett av namnen nedan',
+ 'Select from one of the projects below' => 'Välj ett av projekten nedan',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Källa',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Moms',
+ 'Tax Included' => 'Moms ingår',
+ 'To' => 'Till',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaktion raderad',
+ 'Transaction posted!' => 'Transaktion sparad',
+ 'Update' => 'Uppdatera',
+ 'Vendor' => 'Leverantör',
+ 'Vendor missing!' => 'Leverantör saknas',
+ 'Vendor not on file!' => 'Leverantör finns ej',
+ 'Yes' => 'Ja',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'kredit_verifikat' => 'ap_transaction',
+ 'lägg_till_kreditverifikat' => 'add_accounts_payables_transaction',
+ 'fortsätt' => 'continue',
+ 'radera' => 'delete',
+ 'redigera_kreditkonton' => 'edit_accounts_payables_transaction',
+ 'lägg_till' => 'post',
+ 'lägg_till_som_ny' => 'post_as_new',
+ 'inköpsfaktura' => 'purchase_invoice',
+ 'uppdatera' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/se/ar b/sql-ledger/locale/se/ar
new file mode 100644
index 0000000..c72f7cf
--- /dev/null
+++ b/sql-ledger/locale/se/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Debet verifikat',
+ 'AR Transactions' => 'Debet verifikationer',
+ 'Account' => 'Konto',
+ 'Add Accounts Receivables Transaction' => 'Lägg till debetverifikat',
+ 'Address' => 'Adress',
+ 'Amount' => 'Belopp',
+ 'Amount Due' => 'Belopp förfallet',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Transaction' => 'Är du säker på att du vill radera Transaktionen',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'Cannot delete transaction!' => 'Kan inte radera händelse',
+ 'Cannot post payment for a closed period!' => 'Kan inte lägga till en betalning för en stängd period',
+ 'Cannot post transaction for a closed period!' => 'Kan inte bokföra för en stängd period',
+ 'Cannot post transaction!' => 'Kan inte lägga till händelsen',
+ 'Closed' => 'Avslutad',
+ 'Confirm!' => 'Bekräfta',
+ 'Continue' => 'Fortsätt',
+ 'Credit Limit' => 'Kreditgräns',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kund',
+ 'Customer missing!' => 'Kund saknas',
+ 'Customer not on file!' => 'Kund finns ej',
+ 'Date' => 'Datum',
+ 'Date Paid' => 'Betalningsdatum',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Radera',
+ 'Description' => 'Beskrivning',
+ 'Due Date' => 'Förfallodatum',
+ 'Due Date missing!' => 'Förfallodatum saknas',
+ 'Edit Accounts Receivables Transaction' => 'Redigera debetkonton',
+ 'Employee' => 'Anställd',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Växlingskurs',
+ 'Exchangerate for payment missing!' => 'Växlingskurs för saknad betalning',
+ 'Exchangerate missing!' => 'Växelkurs saknas',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Från',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inkludera i rapport',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadatum',
+ 'Invoice Date missing!' => 'Fakturadatum saknas',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer saknas',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Notes' => 'Anmärkningar',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Open' => 'Öppen',
+ 'Order' => 'Order',
+ 'Order Number' => 'Ordernummer',
+ 'Paid' => 'Betalt',
+ 'Payment date missing!' => 'Betalningsdatum saknas',
+ 'Payments' => 'Betalningar',
+ 'Post' => 'Lägg till',
+ 'Post as new' => 'Lägg till som ny',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt finns ej',
+ 'Remaining' => 'Resterar',
+ 'Sales Invoice' => 'Säljfaktura',
+ 'Select from one of the names below' => 'Välj ett av namnen nedan',
+ 'Select from one of the projects below' => 'Välj ett av projekten nedan',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Källa',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Moms',
+ 'Tax Included' => 'Moms ingår',
+ 'To' => 'Till',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transaktion raderad',
+ 'Transaction posted!' => 'Transaktion sparad',
+ 'Update' => 'Uppdatera',
+ 'Vendor not on file!' => 'Leverantör finns ej',
+ 'Yes' => 'Ja',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'debet_verifikat' => 'ar_transaction',
+ 'fortsätt' => 'continue',
+ 'radera' => 'delete',
+ 'lägg_till' => 'post',
+ 'lägg_till_som_ny' => 'post_as_new',
+ 'säljfaktura' => 'sales_invoice',
+ 'uppdatera' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/se/arap b/sql-ledger/locale/se/arap
new file mode 100644
index 0000000..51fa73a
--- /dev/null
+++ b/sql-ledger/locale/se/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adress',
+ 'Continue' => 'Fortsätt',
+ 'Customer not on file!' => 'Kund finns ej',
+ 'Description' => 'Beskrivning',
+ 'Number' => 'Nummer',
+ 'Project not on file!' => 'Projekt finns ej',
+ 'Select from one of the names below' => 'Välj ett av namnen nedan',
+ 'Select from one of the projects below' => 'Välj ett av projekten nedan',
+ 'Vendor not on file!' => 'Leverantör finns ej',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'fortsätt' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/se/ca b/sql-ledger/locale/se/ca
new file mode 100644
index 0000000..d186a62
--- /dev/null
+++ b/sql-ledger/locale/se/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'Balance' => 'Balans',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Credit' => 'Kredit',
+ 'Date' => 'Datum',
+ 'Debit' => 'Debet',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Description' => 'Beskrivning',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Från',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Inkludera i rapport',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'List Transactions' => 'Lista transaktioner',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Reference' => 'Referens',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Till',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'lista_transaktioner' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/se/cp b/sql-ledger/locale/se/cp
new file mode 100644
index 0000000..c6b1f47
--- /dev/null
+++ b/sql-ledger/locale/se/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Address' => 'Adress',
+ 'Amount' => 'Belopp',
+ 'Amount does not equal applied!' => 'Förfallet belopp stämmer ej med det tillagda',
+ 'Amount missing!' => 'Summa saknas',
+ 'Applied' => 'Tillagt',
+ 'Cannot post payment!' => 'Kan inte lägga till betalning',
+ 'Cannot process payment for a closed period!' => 'Kan inte processa betalning för en avslutad period',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check utskriven',
+ 'Check printing failed!' => 'Utskrift av check misslyckades',
+ 'Continue' => 'Fortsätt',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kund',
+ 'Customer not on file!' => 'Kund finns ej',
+ 'Date' => 'Datum',
+ 'Date missing!' => 'Datum saknas',
+ 'Description' => 'Beskrivning',
+ 'Due' => 'Förfallen',
+ 'Exchangerate' => 'Växlingskurs',
+ 'From' => 'Från',
+ 'Invoice' => 'Faktura',
+ 'Invoices' => 'Fakturor',
+ 'Nothing applied!' => 'Ingenting lades till',
+ 'Number' => 'Nummer',
+ 'Paid in full' => 'Slutbetalt',
+ 'Payment' => 'Betalning',
+ 'Payment posted!' => 'Betalning postad',
+ 'Post' => 'Lägg till',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Skrivare',
+ 'Project not on file!' => 'Projekt finns ej',
+ 'Receipt' => 'Kvitto',
+ 'Reference' => 'Referens',
+ 'Screen' => 'Skärm',
+ 'Select from one of the names below' => 'Välj ett av namnen nedan',
+ 'Select from one of the projects below' => 'Välj ett av projekten nedan',
+ 'To' => 'Till',
+ 'Update' => 'Uppdatera',
+ 'Vendor' => 'Leverantör',
+ 'Vendor not on file!' => 'Leverantör finns ej',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'fortsätt' => 'continue',
+ 'lägg_till' => 'post',
+ 'skriv_ut' => 'print',
+ 'uppdatera' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/se/ct b/sql-ledger/locale/se/ct
new file mode 100644
index 0000000..16d6b64
--- /dev/null
+++ b/sql-ledger/locale/se/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Lägg til',
+ 'Address' => 'Adress',
+ 'All' => 'Alla',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Kan inte radera kund',
+ 'Cannot delete vendor!' => 'Kan inte radera Leverantör',
+ 'Cc' => 'Kopia',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsätt',
+ 'Credit Limit' => 'Kreditgräns',
+ 'Customer deleted!' => 'Kund raderad',
+ 'Customer saved!' => 'Kund sparad',
+ 'Customers' => 'Kunder',
+ 'Delete' => 'Radera',
+ 'Discount' => 'Rabatt',
+ 'E-mail' => 'E-Post',
+ 'Edit Customer' => 'Redigera kund',
+ 'Edit Vendor' => 'Redigera Leverantör',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Inkludera i rapport',
+ 'Invoice' => 'Faktura',
+ 'Name' => 'Namn',
+ 'Name missing!' => 'Namn saknas',
+ 'Notes' => 'Anmärkningar',
+ 'Number' => 'Nummer',
+ 'Order' => 'Order',
+ 'Orphaned' => 'Fristående',
+ 'Phone' => 'Telefon',
+ 'Save' => 'Spara',
+ 'Ship to' => 'Skicka till',
+ 'Tax Included' => 'Moms ingår',
+ 'Taxable' => 'Momspliktigt',
+ 'Terms: Net' => 'Netto',
+ 'Transactions exist, cannot delete customer!' => 'Transaktioner finns, kan inte radera kund',
+ 'Transactions exist, cannot delete vendor!' => 'Transaktioner finns, kan inte radera leverantör',
+ 'Vendor deleted!' => 'Leverantör raderad',
+ 'Vendor saved!' => 'Leverantör sparad',
+ 'Vendors' => 'Leverantörer',
+ 'days' => 'dagar',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'lägg_til' => 'add',
+ 'fortsätt' => 'continue',
+ 'radera' => 'delete',
+ 'faktura' => 'invoice',
+ 'order' => 'order',
+ 'spara' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/se/gl b/sql-ledger/locale/se/gl
new file mode 100644
index 0000000..314839f
--- /dev/null
+++ b/sql-ledger/locale/se/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Kredit verifikat',
+ 'AR Transaction' => 'Debet verifikat',
+ 'Account' => 'Konto',
+ 'Add General Ledger Transaction' => 'Ny post i huvudbok',
+ 'Address' => 'Adress',
+ 'All' => 'Alla',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Transaction' => 'Är du säker på att du vill radera Transaktionen',
+ 'Asset' => 'Tillgång',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'Balance' => 'Balans',
+ 'Cannot delete transaction!' => 'Kan inte radera händelse',
+ 'Cannot have a value in both Debit and Credit!' => 'Kan inte ha värde i både Debet och Kredit!',
+ 'Cannot post a transaction without a value!' => 'Kan inte lägga till en händelse utan ett värde',
+ 'Cannot post transaction for a closed period!' => 'Kan inte bokföra för en stängd period',
+ 'Confirm!' => 'Bekräfta',
+ 'Continue' => 'Fortsätt',
+ 'Credit' => 'Kredit',
+ 'Customer not on file!' => 'Kund finns ej',
+ 'Date' => 'Datum',
+ 'Debit' => 'Debet',
+ 'Debit and credit out of balance!' => 'Debet och kredit måste vara lika!',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Radera',
+ 'Description' => 'Beskrivning',
+ 'Edit General Ledger Transaction' => 'Redigera en post i Huvudboken',
+ 'Equity' => 'Eget kapital',
+ 'Expense' => 'Utgift',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Från',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'GL händelse',
+ 'General Ledger' => 'Huvudbok',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Inkludera i rapport',
+ 'Income' => 'Intäkt',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Liability' => 'Ansvar',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Notes' => 'Anmärkningar',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Post' => 'Lägg till',
+ 'Post as new' => 'Lägg till som ny',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt finns ej',
+ 'Purchase Invoice' => 'Inköpsfaktura',
+ 'Reference' => 'Referens',
+ 'Reference missing!' => 'Referens saknas',
+ 'Reports' => 'Rapporter',
+ 'Sales Invoice' => 'Säljfaktura',
+ 'Select from one of the names below' => 'Välj ett av namnen nedan',
+ 'Select from one of the projects below' => 'Välj ett av projekten nedan',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Källa',
+ 'Subtotal' => 'Subtotal',
+ 'To' => 'Till',
+ 'Transaction Date missing!' => 'Transaktionsdatum saknas',
+ 'Transaction deleted!' => 'Transaktion raderad',
+ 'Transaction posted!' => 'Transaktion sparad',
+ 'Update' => 'Uppdatera',
+ 'Vendor not on file!' => 'Leverantör finns ej',
+ 'Yes' => 'Ja',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'kredit_verifikat' => 'ap_transaction',
+ 'debet_verifikat' => 'ar_transaction',
+ 'fortsätt' => 'continue',
+ 'radera' => 'delete',
+ 'gl_händelse' => 'gl_transaction',
+ 'lägg_till' => 'post',
+ 'lägg_till_som_ny' => 'post_as_new',
+ 'inköpsfaktura' => 'purchase_invoice',
+ 'säljfaktura' => 'sales_invoice',
+ 'uppdatera' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/se/ic b/sql-ledger/locale/se/ic
new file mode 100644
index 0000000..176b68b
--- /dev/null
+++ b/sql-ledger/locale/se/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Aktiv',
+ 'Add' => 'Lägg til',
+ 'Add Assembly' => 'Ny sammansätting',
+ 'Add Part' => 'Ny vara',
+ 'Add Purchase Order' => 'Ny inköpsorder',
+ 'Add Sales Order' => 'Ny säljorder',
+ 'Add Service' => 'Ny tjänst',
+ 'Address' => 'Adress',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Assemblies' => 'Sammansättningar',
+ 'Assemblies restocked!' => 'Sammansättningar åter i lager',
+ 'Assembly Number missing!' => 'Sammansättningsnummer saknas',
+ 'Attachment' => 'Bilaga',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Antal i lager',
+ 'Bought' => 'Köpt',
+ 'COGS' => 'Inköp',
+ 'Cannot delete item already invoiced!' => 'Kan inte radera redan fakturerade varor!',
+ 'Cannot delete item on order!' => 'Kan inte radera vara i order!',
+ 'Cannot delete item which is part of an assembly!' => 'Kan inte radera vara som är del av en sammansättning!',
+ 'Cannot delete item!' => 'Kan inte radera vara',
+ 'Cannot stock assemblies!' => 'Kan lagerföra sammansättningar',
+ 'Cc' => 'Kopia',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsätt',
+ 'Copies' => 'Kopior',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Radera',
+ 'Delivery Date' => 'Leveransdatum',
+ 'Description' => 'Beskrivning',
+ 'Drawing' => 'Ritning',
+ 'E-mail' => 'E-Post',
+ 'E-mail address missing!' => 'E-Postadress saknas',
+ 'Edit Assembly' => 'Redigera sammansättning',
+ 'Edit Part' => 'Redigera vara',
+ 'Edit Service' => 'Redigera tjänster',
+ 'Expense' => 'Utgift',
+ 'Extended' => 'Utökad',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Från',
+ 'Image' => 'Bild',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Inkludera i rapport',
+ 'Income' => 'Intäkt',
+ 'Individual Items' => 'Individuella enheter',
+ 'Inventory' => 'Lager',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Lagerkvantitet måste vara noll innan du kan sätta sammansättningen som utgången!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Lagerkvantitet måste vara noll innan du kan sätta varan som utgången!',
+ 'Inventory quantity must be zero!' => 'Lagerkvantiteten måste vara noll!',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Fakturadatum saknas',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer saknas',
+ 'Item deleted!' => 'Vara raderad',
+ 'Item not on file!' => 'Varan finns inte i databasen',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Last Cost' => 'Senaste kostnad',
+ 'Line Total' => 'Antal rader',
+ 'Link Accounts' => 'Koppla konton',
+ 'List Price' => 'Inköpspris',
+ 'Make' => 'Skapa',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Meddelande',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Modell',
+ 'Name' => 'Namn',
+ 'No.' => 'Rad',
+ 'Notes' => 'Anmärkningar',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer saknas i rad',
+ 'Obsolete' => 'Utgången',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'On Hand' => 'I lager',
+ 'On Order' => 'På order',
+ 'Order' => 'Order',
+ 'Order Date missing!' => 'Orderdatum saknas',
+ 'Order Number' => 'Ordernummer',
+ 'Order Number missing!' => 'Ordernummer saknas',
+ 'Ordered' => 'Beställt',
+ 'Orphaned' => 'Fristående',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packsedel',
+ 'Packing List Date missing!' => 'Packsedelsdatum saknas',
+ 'Packing List Number missing!' => 'Packsedelsnummer saknas',
+ 'Part' => 'Vara',
+ 'Part Number missing!' => 'Artikelnummer saknas',
+ 'Parts' => 'Varor',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Printer' => 'Skrivare',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Inköpsorder',
+ 'Qty' => 'Antal',
+ 'ROP' => 'Efterbeställning vid',
+ 'Recd' => 'Mottagen',
+ 'Required by' => 'Beställt den',
+ 'Sales' => 'Försäljning',
+ 'Sales Order' => 'Säljorder',
+ 'Save' => 'Spara',
+ 'Screen' => 'Skärm',
+ 'Select from one of the items below' => 'Välj en artikel nedan',
+ 'Select postscript or PDF!' => 'Välj Postscript eller PDF',
+ 'Sell Price' => 'Försäljningspris',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Tjänster',
+ 'Service Number missing!' => 'Tjänstenummer saknas',
+ 'Services' => 'Tjänster',
+ 'Ship' => 'Skicka',
+ 'Ship to' => 'Skicka till',
+ 'Short' => 'Kort',
+ 'Sold' => 'Såld',
+ 'Stock Assembly' => 'Lagersammansättning',
+ 'Subject' => 'Ämne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Moms',
+ 'To' => 'Till',
+ 'Top Level' => 'Toppnivå',
+ 'Total' => 'Total',
+ 'Unit' => 'Enhet',
+ 'Unit of measure' => 'Måttenhet',
+ 'Update' => 'Uppdatera',
+ 'Updated' => 'Uppdaterad',
+ 'Weight' => 'Vikt',
+ 'What type of item is this?' => 'Vilken typ av artikel är detta?',
+ 'ea' => 'st',
+ 'emailed to' => 'E-Postat till',
+ 'hr' => 'timme',
+ 'sent to printer' => 'skickat till skrivare',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'lägg_til' => 'add',
+ 'ny_sammansätting' => 'add_assembly',
+ 'ny_vara' => 'add_part',
+ 'ny_tjänst' => 'add_service',
+ 'fortsätt' => 'continue',
+ 'radera' => 'delete',
+ 'redigera_sammansättning' => 'edit_assembly',
+ 'redigera_vara' => 'edit_part',
+ 'redigera_tjänster' => 'edit_service',
+ 'spara' => 'save',
+ 'uppdatera' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/se/io b/sql-ledger/locale/se/io
new file mode 100644
index 0000000..68418c3
--- /dev/null
+++ b/sql-ledger/locale/se/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Ny inköpsorder',
+ 'Add Sales Order' => 'Ny säljorder',
+ 'Address' => 'Adress',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Attachment' => 'Bilaga',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Antal i lager',
+ 'Cc' => 'Kopia',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsätt',
+ 'Copies' => 'Kopior',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delivery Date' => 'Leveransdatum',
+ 'Description' => 'Beskrivning',
+ 'E-mail' => 'E-Post',
+ 'E-mail address missing!' => 'E-Postadress saknas',
+ 'Extended' => 'Utökad',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Fakturadatum saknas',
+ 'Invoice Number missing!' => 'Fakturanummer saknas',
+ 'Item not on file!' => 'Varan finns inte i databasen',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Meddelande',
+ 'Name' => 'Namn',
+ 'No.' => 'Rad',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer saknas i rad',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Order' => 'Order',
+ 'Order Date missing!' => 'Orderdatum saknas',
+ 'Order Number missing!' => 'Ordernummer saknas',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packsedel',
+ 'Packing List Date missing!' => 'Packsedelsdatum saknas',
+ 'Packing List Number missing!' => 'Packsedelsnummer saknas',
+ 'Part' => 'Vara',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Printer' => 'Skrivare',
+ 'Project' => 'Projekt',
+ 'Purchase Order' => 'Inköpsorder',
+ 'Qty' => 'Antal',
+ 'Recd' => 'Mottagen',
+ 'Required by' => 'Beställt den',
+ 'Sales Order' => 'Säljorder',
+ 'Screen' => 'Skärm',
+ 'Select from one of the items below' => 'Välj en artikel nedan',
+ 'Select postscript or PDF!' => 'Välj Postscript eller PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Tjänster',
+ 'Ship' => 'Skicka',
+ 'Ship to' => 'Skicka till',
+ 'Subject' => 'Ämne',
+ 'To' => 'Till',
+ 'Unit' => 'Enhet',
+ 'What type of item is this?' => 'Vilken typ av artikel är detta?',
+ 'emailed to' => 'E-Postat till',
+ 'sent to printer' => 'skickat till skrivare',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'fortsätt' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/se/ir b/sql-ledger/locale/se/ir
new file mode 100644
index 0000000..113fa9c
--- /dev/null
+++ b/sql-ledger/locale/se/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Invoice' => 'Ny inköpsfaktura',
+ 'Add Purchase Order' => 'Ny inköpsorder',
+ 'Add Sales Order' => 'Ny säljorder',
+ 'Address' => 'Adress',
+ 'Amount' => 'Belopp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Invoice Number' => 'Är du säker på att du vill radera Faktura Nummer',
+ 'Attachment' => 'Bilaga',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Antal i lager',
+ 'Cannot delete invoice!' => 'Kan inte radera faktura',
+ 'Cannot post invoice for a closed period!' => 'Kan inte lägga till en faktura för en avslutad period',
+ 'Cannot post invoice!' => 'Kan inte lägga till faktura',
+ 'Cannot post payment for a closed period!' => 'Kan inte lägga till en betalning för en stängd period',
+ 'Cc' => 'Kopia',
+ 'Confirm!' => 'Bekräfta',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsätt',
+ 'Copies' => 'Kopior',
+ 'Currency' => 'Valuta',
+ 'Customer not on file!' => 'Kund finns ej',
+ 'Date' => 'Datum',
+ 'Date Due' => 'Förfallodatum',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Radera',
+ 'Delivery Date' => 'Leveransdatum',
+ 'Description' => 'Beskrivning',
+ 'E-mail' => 'E-Post',
+ 'E-mail address missing!' => 'E-Postadress saknas',
+ 'Edit Purchase Invoice' => 'Redigera inköpsfakturor',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Växlingskurs',
+ 'Exchangerate for payment missing!' => 'Växlingskurs för saknad betalning',
+ 'Exchangerate missing!' => 'Växelkurs saknas',
+ 'Extended' => 'Utökad',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadatum',
+ 'Invoice Date missing!' => 'Fakturadatum saknas',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer saknas',
+ 'Invoice deleted!' => 'Faktura raderad',
+ 'Invoice posted!' => 'Faktura postad',
+ 'Item not on file!' => 'Varan finns inte i databasen',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Meddelande',
+ 'Name' => 'Namn',
+ 'No.' => 'Rad',
+ 'Notes' => 'Anmärkningar',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer saknas i rad',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Order' => 'Order',
+ 'Order Date missing!' => 'Orderdatum saknas',
+ 'Order Number' => 'Ordernummer',
+ 'Order Number missing!' => 'Ordernummer saknas',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packsedel',
+ 'Packing List Date missing!' => 'Packsedelsdatum saknas',
+ 'Packing List Number missing!' => 'Packsedelsnummer saknas',
+ 'Part' => 'Vara',
+ 'Payment date missing!' => 'Betalningsdatum saknas',
+ 'Payments' => 'Betalningar',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Lägg till',
+ 'Post as new' => 'Lägg till som ny',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Printer' => 'Skrivare',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt finns ej',
+ 'Purchase Order' => 'Inköpsorder',
+ 'Qty' => 'Antal',
+ 'Recd' => 'Mottagen',
+ 'Record in' => 'Bokför på',
+ 'Required by' => 'Beställt den',
+ 'Sales Order' => 'Säljorder',
+ 'Screen' => 'Skärm',
+ 'Select from one of the items below' => 'Välj en artikel nedan',
+ 'Select from one of the names below' => 'Välj ett av namnen nedan',
+ 'Select from one of the projects below' => 'Välj ett av projekten nedan',
+ 'Select postscript or PDF!' => 'Välj Postscript eller PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Tjänster',
+ 'Ship' => 'Skicka',
+ 'Ship to' => 'Skicka till',
+ 'Source' => 'Källa',
+ 'Subject' => 'Ämne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Moms ingår',
+ 'To' => 'Till',
+ 'Total' => 'Total',
+ 'Unit' => 'Enhet',
+ 'Update' => 'Uppdatera',
+ 'Vendor' => 'Leverantör',
+ 'Vendor missing!' => 'Leverantör saknas',
+ 'Vendor not on file!' => 'Leverantör finns ej',
+ 'What type of item is this?' => 'Vilken typ av artikel är detta?',
+ 'Yes' => 'Ja',
+ 'ea' => 'st',
+ 'emailed to' => 'E-Postat till',
+ 'sent to printer' => 'skickat till skrivare',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'fortsätt' => 'continue',
+ 'radera' => 'delete',
+ 'order' => 'order',
+ 'lägg_till' => 'post',
+ 'lägg_till_som_ny' => 'post_as_new',
+ 'uppdatera' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/se/is b/sql-ledger/locale/se/is
new file mode 100644
index 0000000..92f640a
--- /dev/null
+++ b/sql-ledger/locale/se/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Add Purchase Order' => 'Ny inköpsorder',
+ 'Add Sales Invoice' => 'Ny säljfaktura',
+ 'Add Sales Order' => 'Ny säljorder',
+ 'Address' => 'Adress',
+ 'Amount' => 'Belopp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Invoice Number' => 'Är du säker på att du vill radera Faktura Nummer',
+ 'Attachment' => 'Bilaga',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Antal i lager',
+ 'Cannot delete invoice!' => 'Kan inte radera faktura',
+ 'Cannot post invoice for a closed period!' => 'Kan inte lägga till en faktura för en avslutad period',
+ 'Cannot post invoice!' => 'Kan inte lägga till faktura',
+ 'Cannot post payment for a closed period!' => 'Kan inte lägga till en betalning för en stängd period',
+ 'Cc' => 'Kopia',
+ 'Confirm!' => 'Bekräfta',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsätt',
+ 'Copies' => 'Kopior',
+ 'Credit Limit' => 'Kreditgräns',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kund',
+ 'Customer missing!' => 'Kund saknas',
+ 'Customer not on file!' => 'Kund finns ej',
+ 'Date' => 'Datum',
+ 'Date Due' => 'Förfallodatum',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Radera',
+ 'Delivery Date' => 'Leveransdatum',
+ 'Description' => 'Beskrivning',
+ 'E-mail' => 'E-Post',
+ 'E-mail address missing!' => 'E-Postadress saknas',
+ 'Edit Sales Invoice' => 'Redigera säljfakturor',
+ 'Exch' => 'Vxl',
+ 'Exchangerate' => 'Växlingskurs',
+ 'Exchangerate for payment missing!' => 'Växlingskurs för saknad betalning',
+ 'Exchangerate missing!' => 'Växelkurs saknas',
+ 'Extended' => 'Utökad',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date' => 'Fakturadatum',
+ 'Invoice Date missing!' => 'Fakturadatum saknas',
+ 'Invoice Number' => 'Fakturanummer',
+ 'Invoice Number missing!' => 'Fakturanummer saknas',
+ 'Invoice deleted!' => 'Faktura raderad',
+ 'Invoice posted!' => 'Faktura postad',
+ 'Item not on file!' => 'Varan finns inte i databasen',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Meddelande',
+ 'Name' => 'Namn',
+ 'No.' => 'Rad',
+ 'Notes' => 'Anmärkningar',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer saknas i rad',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Order' => 'Order',
+ 'Order Date missing!' => 'Orderdatum saknas',
+ 'Order Number' => 'Ordernummer',
+ 'Order Number missing!' => 'Ordernummer saknas',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packsedel',
+ 'Packing List Date missing!' => 'Packsedelsdatum saknas',
+ 'Packing List Number missing!' => 'Packsedelsnummer saknas',
+ 'Part' => 'Vara',
+ 'Payment date missing!' => 'Betalningsdatum saknas',
+ 'Payments' => 'Betalningar',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Lägg till',
+ 'Post as new' => 'Lägg till som ny',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Skrivare',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt finns ej',
+ 'Purchase Order' => 'Inköpsorder',
+ 'Qty' => 'Antal',
+ 'Recd' => 'Mottagen',
+ 'Record in' => 'Bokför på',
+ 'Remaining' => 'Resterar',
+ 'Required by' => 'Beställt den',
+ 'Sales Order' => 'Säljorder',
+ 'Screen' => 'Skärm',
+ 'Select from one of the items below' => 'Välj en artikel nedan',
+ 'Select from one of the names below' => 'Välj ett av namnen nedan',
+ 'Select from one of the projects below' => 'Välj ett av projekten nedan',
+ 'Select postscript or PDF!' => 'Välj Postscript eller PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Tjänster',
+ 'Ship' => 'Skicka',
+ 'Ship to' => 'Skicka till',
+ 'Ship via' => 'Skicka via',
+ 'Source' => 'Källa',
+ 'Subject' => 'Ämne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Moms ingår',
+ 'To' => 'Till',
+ 'Total' => 'Total',
+ 'Unit' => 'Enhet',
+ 'Update' => 'Uppdatera',
+ 'Vendor not on file!' => 'Leverantör finns ej',
+ 'What type of item is this?' => 'Vilken typ av artikel är detta?',
+ 'Yes' => 'Ja',
+ 'ea' => 'st',
+ 'emailed to' => 'E-Postat till',
+ 'sent to printer' => 'skickat till skrivare',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'fortsätt' => 'continue',
+ 'radera' => 'delete',
+ 'e_post' => 'e_mail',
+ 'order' => 'order',
+ 'lägg_till' => 'post',
+ 'lägg_till_som_ny' => 'post_as_new',
+ 'skriv_ut' => 'print',
+ 'skicka_till' => 'ship_to',
+ 'uppdatera' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/se/login b/sql-ledger/locale/se/login
new file mode 100644
index 0000000..2fe34aa
--- /dev/null
+++ b/sql-ledger/locale/se/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Om',
+ 'Database Host' => 'Databasvärd',
+ 'Dataset' => 'Dataset',
+ 'Incorrect Dataset version!' => 'Felaktig databasversion',
+ 'Incorrect Password!' => 'Felaktigt lösenord',
+ 'Licensed to' => 'Licensierad till',
+ 'Login' => 'Logga in',
+ 'Name' => 'Namn',
+ 'Password' => 'Lösenord',
+ 'User' => 'Användare',
+ 'Version' => 'Version',
+ 'You are logged out!' => 'Du är utloggad',
+ 'You did not enter a name!' => 'Du skrev inte in något namn',
+ 'is not a member!' => 'är inte medlem!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'logga_in' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/se/menu b/sql-ledger/locale/se/menu
new file mode 100644
index 0000000..2e7ae34
--- /dev/null
+++ b/sql-ledger/locale/se/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'Kredit',
+ 'AP Aging' => 'Kredit åldersfördeling',
+ 'AR' => 'Debet',
+ 'AR Aging' => 'Debet åldersfördeling',
+ 'Accounting Menu' => 'Konto-meny',
+ 'Add Account' => 'Nytt konto',
+ 'Add Assembly' => 'Ny sammansätting',
+ 'Add Customer' => 'Ny kund',
+ 'Add GIFI' => 'Ny GIFI',
+ 'Add Part' => 'Ny vara',
+ 'Add Project' => 'Nytt projekt',
+ 'Add Service' => 'Ny tjänst',
+ 'Add Transaction' => 'Ny post',
+ 'Add Vendor' => 'Ny leverantör',
+ 'Assemblies' => 'Sammansättningar',
+ 'Audit Control' => 'Revisionskontroll',
+ 'Backup' => 'Säkerhetkopia',
+ 'Balance Sheet' => 'Status',
+ 'Cash' => 'Kontant',
+ 'Chart of Accounts' => 'Kontoplan',
+ 'Check' => 'Check',
+ 'Customers' => 'Kunder',
+ 'General Ledger' => 'Huvudbok',
+ 'Goods & Services' => 'Varor och Tjänster',
+ 'HTML Templates' => 'HTML mallar',
+ 'Income Statement' => 'Inkomstberäkning',
+ 'Invoice' => 'Faktura',
+ 'LaTeX Templates' => 'LaTeX Mallar',
+ 'List Accounts' => 'Lista konton',
+ 'List GIFI' => 'Lista GIFI',
+ 'Logout' => 'Logga ut',
+ 'Order Entry' => 'Orderingång',
+ 'Packing List' => 'Packsedel',
+ 'Parts' => 'Varor',
+ 'Payment' => 'Betalning',
+ 'Payments' => 'Betalningar',
+ 'Preferences' => 'Inställningar',
+ 'Projects' => 'Projekt',
+ 'Purchase Invoice' => 'Inköpsfaktura',
+ 'Purchase Order' => 'Inköpsorder',
+ 'Purchase Orders' => 'Inköpsordrar',
+ 'Receipt' => 'Kvitto',
+ 'Receipts' => 'Kvitton',
+ 'Reconciliation' => 'Bankuppgörelse',
+ 'Reports' => 'Rapporter',
+ 'Sales Invoice' => 'Säljfaktura',
+ 'Sales Order' => 'Säljorder',
+ 'Sales Orders' => 'Säljordrar',
+ 'Save to File' => 'Spara till fil',
+ 'Send by E-Mail' => 'Skicka via E-Post',
+ 'Services' => 'Tjänster',
+ 'Statement' => 'Anmärkning',
+ 'Stock Assembly' => 'Lagersammansättning',
+ 'Stylesheet' => 'Stilmall',
+ 'System' => 'System',
+ 'Tax collected' => 'Moms total',
+ 'Tax paid' => 'Moms betalad',
+ 'Transactions' => 'Transaktioner',
+ 'Trial Balance' => 'Provbalans',
+ 'Vendors' => 'Leverantörer',
+ 'Version' => 'Version',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/se/oe b/sql-ledger/locale/se/oe
new file mode 100644
index 0000000..2a62a15
--- /dev/null
+++ b/sql-ledger/locale/se/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Lägg til',
+ 'Add Purchase Invoice' => 'Ny inköpsfaktura',
+ 'Add Purchase Order' => 'Ny inköpsorder',
+ 'Add Sales Invoice' => 'Ny säljfaktura',
+ 'Add Sales Order' => 'Ny säljorder',
+ 'Address' => 'Adress',
+ 'Amount' => 'Belopp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Are you sure you want to delete Order Number' => 'Är du säker på att du vill radera Order Nummer',
+ 'Attachment' => 'Bilaga',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Antal i lager',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Kan inte radera order',
+ 'Cannot save order!' => 'Kan inte spara order',
+ 'Cc' => 'Kopia',
+ 'Closed' => 'Avslutad',
+ 'Confirm!' => 'Bekräfta',
+ 'Contact' => 'Kontakt',
+ 'Continue' => 'Fortsätt',
+ 'Copies' => 'Kopior',
+ 'Credit Limit' => 'Kreditgräns',
+ 'Curr' => 'Val',
+ 'Currency' => 'Valuta',
+ 'Customer' => 'Kund',
+ 'Customer missing!' => 'Kund saknas',
+ 'Customer not on file!' => 'Kund finns ej',
+ 'Date' => 'Datum',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Delete' => 'Radera',
+ 'Delivery Date' => 'Leveransdatum',
+ 'Description' => 'Beskrivning',
+ 'E-mail' => 'E-Post',
+ 'E-mail address missing!' => 'E-Postadress saknas',
+ 'Edit Purchase Order' => 'Redigera inköpsorder',
+ 'Edit Sales Order' => 'Redigera säljorder',
+ 'Exchangerate' => 'Växlingskurs',
+ 'Exchangerate missing!' => 'Växelkurs saknas',
+ 'Extended' => 'Utökad',
+ 'Fax' => 'Fax',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Från',
+ 'ID' => 'ID',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Inkludera i rapport',
+ 'Invoice' => 'Faktura',
+ 'Invoice Date missing!' => 'Fakturadatum saknas',
+ 'Invoice Number missing!' => 'Fakturanummer saknas',
+ 'Item not on file!' => 'Varan finns inte i databasen',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Meddelande',
+ 'Name' => 'Namn',
+ 'No.' => 'Rad',
+ 'Notes' => 'Anmärkningar',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Number' => 'Nummer',
+ 'Number missing in Row' => 'Nummer saknas i rad',
+ 'O' => 'O',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'Open' => 'Öppen',
+ 'Order' => 'Order',
+ 'Order Date' => 'Orderdatum',
+ 'Order Date missing!' => 'Orderdatum saknas',
+ 'Order Number' => 'Ordernummer',
+ 'Order Number missing!' => 'Ordernummer saknas',
+ 'Order deleted!' => 'Order raderad',
+ 'Order saved!' => 'Order sparad',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Packsedel',
+ 'Packing List Date missing!' => 'Packsedelsdatum saknas',
+ 'Packing List Number missing!' => 'Packsedelsnummer saknas',
+ 'Part' => 'Vara',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Pris',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Skrivare',
+ 'Project' => 'Projekt',
+ 'Project not on file!' => 'Projekt finns ej',
+ 'Purchase Order' => 'Inköpsorder',
+ 'Purchase Orders' => 'Inköpsordrar',
+ 'Qty' => 'Antal',
+ 'Recd' => 'Mottagen',
+ 'Remaining' => 'Resterar',
+ 'Required by' => 'Beställt den',
+ 'Sales Order' => 'Säljorder',
+ 'Sales Orders' => 'Säljordrar',
+ 'Save' => 'Spara',
+ 'Save as new' => 'Spara som ny',
+ 'Screen' => 'Skärm',
+ 'Select from one of the items below' => 'Välj en artikel nedan',
+ 'Select from one of the names below' => 'Välj ett av namnen nedan',
+ 'Select from one of the projects below' => 'Välj ett av projekten nedan',
+ 'Select postscript or PDF!' => 'Välj Postscript eller PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Service' => 'Tjänster',
+ 'Ship' => 'Skicka',
+ 'Ship to' => 'Skicka till',
+ 'Ship via' => 'Skicka via',
+ 'Subject' => 'Ämne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Moms',
+ 'Tax Included' => 'Moms ingår',
+ 'Terms: Net' => 'Netto',
+ 'To' => 'Till',
+ 'Total' => 'Total',
+ 'Unit' => 'Enhet',
+ 'Update' => 'Uppdatera',
+ 'Vendor' => 'Leverantör',
+ 'Vendor missing!' => 'Leverantör saknas',
+ 'Vendor not on file!' => 'Leverantör finns ej',
+ 'What type of item is this?' => 'Vilken typ av artikel är detta?',
+ 'Yes' => 'Ja',
+ 'days' => 'dagar',
+ 'ea' => 'st',
+ 'emailed to' => 'E-Postat till',
+ 'sent to printer' => 'skickat till skrivare',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'lägg_til' => 'add',
+ 'fortsätt' => 'continue',
+ 'radera' => 'delete',
+ 'e_post' => 'e_mail',
+ 'faktura' => 'invoice',
+ 'skriv_ut' => 'print',
+ 'spara' => 'save',
+ 'spara_som_ny' => 'save_as_new',
+ 'skicka_till' => 'ship_to',
+ 'uppdatera' => 'update',
+ 'ja' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/se/pe b/sql-ledger/locale/se/pe
new file mode 100644
index 0000000..c8d5b42
--- /dev/null
+++ b/sql-ledger/locale/se/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Lägg til',
+ 'Add Project' => 'Nytt projekt',
+ 'All' => 'Alla',
+ 'Continue' => 'Fortsätt',
+ 'Delete' => 'Radera',
+ 'Description' => 'Beskrivning',
+ 'Edit Project' => 'Redigera projekt',
+ 'Number' => 'Nummer',
+ 'Orphaned' => 'Fristående',
+ 'Project' => 'Projekt',
+ 'Project Number missing!' => 'Projektnummer saknas',
+ 'Project deleted!' => 'Projekt raderat',
+ 'Project saved!' => 'Projekt sparat',
+ 'Projects' => 'Projekt',
+ 'Save' => 'Spara',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'lägg_til' => 'add',
+ 'fortsätt' => 'continue',
+ 'radera' => 'delete',
+ 'spara' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/se/rc b/sql-ledger/locale/se/rc
new file mode 100644
index 0000000..84df25d
--- /dev/null
+++ b/sql-ledger/locale/se/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Konto',
+ 'Balance' => 'Balans',
+ 'Cleared Balance' => 'Rensade balans',
+ 'Continue' => 'Fortsätt',
+ 'Date' => 'Datum',
+ 'Deposit' => 'Säkerhet',
+ 'Description' => 'Beskrivning',
+ 'Difference' => 'Differens',
+ 'Done' => 'Klart',
+ 'Exchangerate Difference' => 'Differens Växlingskurs',
+ 'From' => 'Från',
+ 'Out of balance!' => 'Ej i balans',
+ 'Payment' => 'Betalning',
+ 'Reconciliation' => 'Bankuppgörelse',
+ 'Select all' => 'Välj alla',
+ 'Source' => 'Källa',
+ 'Statement Balance' => 'Anmärkning status',
+ 'To' => 'Till',
+ 'Update' => 'Uppdatera',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'fortsätt' => 'continue',
+ 'klart' => 'done',
+ 'välj_alla' => 'select_all',
+ 'uppdatera' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/se/rp b/sql-ledger/locale/se/rp
new file mode 100644
index 0000000..da93e1b
--- /dev/null
+++ b/sql-ledger/locale/se/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Kredit åldersfördeling',
+ 'AR Aging' => 'Debet åldersfördeling',
+ 'Account' => 'Konto',
+ 'Accounts' => 'Konton',
+ 'Amount' => 'Belopp',
+ 'Apr' => 'apr',
+ 'April' => 'april',
+ 'Attachment' => 'Bilaga',
+ 'Aug' => 'aug',
+ 'August' => 'augusti',
+ 'Balance Sheet' => 'Status',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Kontantbaserad',
+ 'Cc' => 'Kopia',
+ 'Compare to' => 'Jämför med',
+ 'Continue' => 'Fortsätt',
+ 'Copies' => 'Kopior',
+ 'Credit' => 'Kredit',
+ 'Current' => 'Nuvarande',
+ 'Customer' => 'Kund',
+ 'Date' => 'Datum',
+ 'Debit' => 'Debet',
+ 'Dec' => 'dec',
+ 'December' => 'december',
+ 'Decimalplaces' => 'Decimalplaceringar',
+ 'Description' => 'Beskrivning',
+ 'Due' => 'Förfallen',
+ 'E-mail' => 'E-Post',
+ 'E-mail Statement to' => 'E-Post anmaning till',
+ 'Feb' => 'Feb',
+ 'February' => 'Februari',
+ 'From' => 'Från',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Överskrift',
+ 'ID' => 'ID',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Inkludera i rapport',
+ 'Income Statement' => 'Inkomstberäkning',
+ 'Invoice' => 'Faktura',
+ 'Jan' => 'Jan',
+ 'January' => 'Januari',
+ 'Jul' => 'Jul',
+ 'July' => 'Juli',
+ 'Jun' => 'Jun',
+ 'June' => 'Juni',
+ 'Mar' => 'Mar',
+ 'March' => 'Mars',
+ 'May' => 'Maj',
+ 'May ' => 'Maj',
+ 'Message' => 'Meddelande',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Ingenting valt',
+ 'Nov' => 'Nov',
+ 'November' => 'November',
+ 'Oct' => 'Okt',
+ 'October' => 'Oktober',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Betalningar',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Skriv ut',
+ 'Printer' => 'Skrivare',
+ 'Receipts' => 'Kvitton',
+ 'Report for' => 'Rapport för',
+ 'Retained Earnings' => 'Realiserat överskott',
+ 'Screen' => 'Skärm',
+ 'Select all' => 'Välj alla',
+ 'Select postscript or PDF!' => 'Välj Postscript eller PDF',
+ 'Sep' => 'Sep',
+ 'September' => 'September',
+ 'Source' => 'Källa',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Anmärkning',
+ 'Statement sent to' => 'Anmärkning skickad till',
+ 'Statements sent to printer!' => 'Anmärkningar skickade till skrivare',
+ 'Subject' => 'Ämne',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'Moms',
+ 'Tax collected' => 'Moms total',
+ 'Tax paid' => 'Moms betalad',
+ 'To' => 'Till',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Provbalans',
+ 'Vendor' => 'Leverantör',
+ 'as at' => 'som vid',
+ 'collected on sales' => 'inbetalt på försäljning',
+ 'for Period' => 'för perioden',
+ 'paid on purchases' => 'betalt vid köp',
+ 'to' => 'till',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'fortsätt' => 'continue',
+ 'e_post' => 'e_mail',
+ 'skriv_ut' => 'print',
+ 'välj_alla' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/COPYING b/sql-ledger/locale/tr/COPYING
new file mode 100644
index 0000000..523dffa
--- /dev/null
+++ b/sql-ledger/locale/tr/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Turkish texts:
+#
+# Author: Mufit Eribol <meribol@deltagrup.com.tr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/tr/LANGUAGE b/sql-ledger/locale/tr/LANGUAGE
new file mode 100644
index 0000000..d7b2f1f
--- /dev/null
+++ b/sql-ledger/locale/tr/LANGUAGE
@@ -0,0 +1 @@
+Turkish
diff --git a/sql-ledger/locale/tr/admin b/sql-ledger/locale/tr/admin
new file mode 100644
index 0000000..5d0b0fd
--- /dev/null
+++ b/sql-ledger/locale/tr/admin
@@ -0,0 +1,122 @@
+$self{texts} = {
+ 'Access Control' => 'Giriþ Kontrol',
+ 'Accounting' => 'Muhasebe',
+ 'Add User' => 'Kullanýcý Ekle',
+ 'Address' => 'Adres',
+ 'Administration' => 'Yönetim',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => 'All Datasets up to date!',
+ 'Change Admin Password' => 'Yönetici Þifresini Deðiþtir',
+ 'Change Password' => 'Þifre Deðiþtir',
+ 'Character Set' => 'Karakter Seti',
+ 'Click on login name to edit!' => 'Düzenlemek için giriþ ismini týklayýn.',
+ 'Company' => 'Þirket',
+ 'Connect to' => 'Baðlan',
+ 'Continue' => 'Devam',
+ 'Create Chart of Accounts' => 'Hesap Planý Oluþtur',
+ 'Create Dataset' => 'Veriseti Oluþtur',
+ 'DBI not installed!' => 'DBJ kurulu deðil',
+ 'Database' => 'Veritabaný',
+ 'Database Administration' => 'Veritabani Yonetimi',
+ 'Database Driver not checked!' => 'Database Driver not checked!',
+ 'Database User missing!' => 'Veritabaný Kullanýcýsý yok!',
+ 'Dataset' => 'Veriseti',
+ 'Dataset missing!' => 'Veriseti Yok!',
+ 'Dataset updated!' => 'Dataset updated!',
+ 'Date Format' => 'Tarih Formatý',
+ 'Delete' => 'Sil',
+ 'Delete Dataset' => 'Verisetini Sil',
+ 'Directory' => 'Dizin',
+ 'Driver' => 'Sürücü',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'Posta',
+ 'Edit User' => 'Kullanýcý Bilgilerini Düzenle',
+ 'Existing Datasets' => 'Verisetleri',
+ 'Fax' => 'Faks',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Host yok!',
+ 'Incorrect Password!' => 'Yanlýþ Þifre!',
+ 'Language' => 'Dil',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Uzakta baglantý yapmak istemiyorsanýz host ve port alanlarýný boþ býrakýnýz.',
+ 'Login' => 'Giriþ',
+ 'Name' => 'Ýsim',
+ 'New Templates' => 'Yeni Þablonlar',
+ 'No Database Drivers available!' => 'Veritabaný Sürücüsü yok!',
+ 'No Dataset selected!' => 'Veriseti seçilmedi!',
+ 'Nothing to delete!' => 'Nothing to delete!',
+ 'Number Format' => 'Rakam Formatý',
+ 'Oracle Database Administration' => 'Oracle Veritabaný Yönetimi',
+ 'Password' => 'Þifre',
+ 'Password changed!' => 'Password changed!',
+ 'Pg Database Administration' => 'Pg Veritabaný Yönetimi',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port yok!',
+ 'Printer' => 'Yazýcý',
+ 'Save' => 'Kaydet',
+ 'Select a Dataset to delete and press "Continue"' => 'Silmek için bir Veriseti seçin ve "Devam"ý týklayýn.',
+ 'Setup Templates' => 'Þablon Kur',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Ýmza',
+ 'Stylesheet' => 'Düzen Sayfasý',
+ 'Templates' => 'Þablonlar',
+ 'The following Datasets are not in use and can be deleted' => 'Aþaðýdaki Verisetleri kullanýlmamaktadýr ve silinebilir',
+ 'The following Datasets need to be updated' => 'The following Datasets need to be updated',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Mevcut fiþ bilgileri için bu bir ön kontroldür. Bu aþamada hiçbirþey oluþturulmaz ve silinemez',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Gruba yeni kullanýcý eklemek için, giriþ ismini deðiþtirin ve kaydedin. Yeni kullanýcý yeni giriþ altýnda ayný parametrelerle kaydedilecektir.',
+ 'Update Dataset' => 'Update Dataset',
+ 'Use Templates' => 'Þablon Kullan',
+ 'User' => 'Kullanýcý',
+ 'User deleted!' => 'User deleted!',
+ 'User saved!' => 'User saved!',
+ 'Version' => 'Versiyon',
+ 'You must enter a host and port for local and remote connections!' => 'Yerel ve uzak baðlantýlar için bir host ve port girmek zorundasýnýz!',
+ 'does not exist' => 'mevcut deðil',
+ 'is already a member!' => 'üyedir!',
+ 'localhost' => 'Yerelhost',
+ 'successfully created!' => 'baþarýyla oluþturuldu!',
+ 'successfully deleted!' => 'baþarýyla silindi!',
+ 'website' => 'Websitesi',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'kullanýcý_ekle' => 'add_user',
+ 'yönetici_Þifresini_deðiþtir' => 'change_admin_password',
+ 'Þifre_deðiþtir' => 'change_password',
+ 'devam' => 'continue',
+ 'veriseti_oluþtur' => 'create_dataset',
+ 'sil' => 'delete',
+ 'verisetini_sil' => 'delete_dataset',
+ 'giriþ' => 'login',
+ 'oracle_veritabaný_yönetimi' => 'oracle_database_administration',
+ 'pg_veritabaný_yönetimi' => 'pg_database_administration',
+ 'kaydet' => 'save',
+ 'update_dataset' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/all b/sql-ledger/locale/tr/all
new file mode 100644
index 0000000..2eefc62
--- /dev/null
+++ b/sql-ledger/locale/tr/all
@@ -0,0 +1,487 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'Borçlar',
+ 'AP Aging' => 'Gecikmiþ Borçlar',
+ 'AP Transaction' => '',
+ 'AP Transactions' => 'Borç Ýþlemleri',
+ 'AR' => 'Alacaklar',
+ 'AR Aging' => 'Gecikmiþ Alacaklar',
+ 'AR Transaction' => '',
+ 'AR Transactions' => 'Alacak Ýþlemleri',
+ 'About' => 'Program bilgileri',
+ 'Access Control' => 'Giriþ Kontrol',
+ 'Account' => 'Hesap',
+ 'Account Number' => 'Hesap Numarasý',
+ 'Account Number missing!' => 'Hesap Numarasý yok!',
+ 'Account Type' => 'Hesap Türü',
+ 'Account Type missing!' => 'Hesap Türü yok!',
+ 'Account deleted!' => '',
+ 'Account saved!' => '',
+ 'Accounting' => 'Muhasebe',
+ 'Accounting Menu' => 'Muhasebe Menüsü',
+ 'Accounts' => '',
+ 'Active' => '',
+ 'Add' => 'Ekle',
+ 'Add Account' => 'Hesap Ekle',
+ 'Add Accounts Payables Transaction' => '',
+ 'Add Accounts Receivables Transaction' => '',
+ 'Add Assembly' => 'Grup Ekle',
+ 'Add Customer' => 'Alýcý Ekle',
+ 'Add GIFI' => '',
+ 'Add General Ledger Transaction' => 'Defteri Kebire Ýþlem Ekle',
+ 'Add Part' => 'Parça Ekle',
+ 'Add Project' => '',
+ 'Add Purchase Invoice' => '',
+ 'Add Purchase Order' => 'Satýnalma Sip. Ekle',
+ 'Add Sales Invoice' => '',
+ 'Add Sales Order' => 'Satýþ Sipariþi Ekle',
+ 'Add Service' => 'Hizmet Ekle',
+ 'Add Transaction' => 'Ýþlem Ekle',
+ 'Add User' => 'Kullanýcý Ekle',
+ 'Add Vendor' => 'Satýcý Ekle',
+ 'Address' => 'Adres',
+ 'Administration' => 'Yönetim',
+ 'Administrator' => '',
+ 'All' => 'Hepsi',
+ 'All Datasets up to date!' => '',
+ 'Amount' => 'Miktar',
+ 'Amount Due' => '',
+ 'Amount does not equal applied!' => '',
+ 'Amount missing!' => '',
+ 'Applied' => '',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Are you sure you want to delete Invoice Number' => 'Fatura Numarasýný silmek istediðinizden emin misiniz? Fiþ: ',
+ 'Are you sure you want to delete Order Number' => 'Sipariþ Numarasýný silmek istediðinizden emin misiniz? Fiþ: ',
+ 'Are you sure you want to delete Transaction' => 'Ýþlemi silmek istediðinizden emin misiniz? Fiþ: ',
+ 'Assemblies' => 'Gruplar',
+ 'Assemblies restocked!' => '',
+ 'Assembly Number missing!' => 'Grup Numarasý yok!',
+ 'Asset' => 'Aktif',
+ 'Attachment' => '',
+ 'Audit Control' => '',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'BOM' => '',
+ 'Backup' => 'Yedekleme',
+ 'Backup sent to' => '',
+ 'Balance' => '',
+ 'Balance Sheet' => 'Bilanço',
+ 'Bcc' => '',
+ 'Bin' => '',
+ 'Books are open' => '',
+ 'Bought' => 'Alýnan',
+ 'Business Number' => 'ÞirketNo',
+ 'C' => '',
+ 'COGS' => 'SMM',
+ 'Cannot delete account!' => '',
+ 'Cannot delete customer!' => '',
+ 'Cannot delete default account!' => 'Öntanýmlý hesap silinmez!',
+ 'Cannot delete invoice!' => '',
+ 'Cannot delete item already invoiced!' => 'Faturalanmýþ kalem silinemez!',
+ 'Cannot delete item on order!' => '',
+ 'Cannot delete item which is part of an assembly!' => 'Grubun parçasý olan kalem silinemez!',
+ 'Cannot delete item!' => '',
+ 'Cannot delete order!' => '',
+ 'Cannot delete transaction!' => '',
+ 'Cannot delete vendor!' => '',
+ 'Cannot have a value in both Debit and Credit!' => 'Borç ve Alacak hanelerine ayný anda deðer yazýlamaz!',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => '',
+ 'Cannot post invoice!' => '',
+ 'Cannot post payment for a closed period!' => '',
+ 'Cannot post payment!' => '',
+ 'Cannot post transaction for a closed period!' => '',
+ 'Cannot post transaction!' => '',
+ 'Cannot process payment for a closed period!' => '',
+ 'Cannot save account!' => '',
+ 'Cannot save order!' => '',
+ 'Cannot save preferences!' => '',
+ 'Cannot stock assemblies!' => '',
+ 'Cash' => '',
+ 'Cash based' => '',
+ 'Cc' => '',
+ 'Change Admin Password' => 'Yönetici Þifresini Deðiþtir',
+ 'Change Password' => 'Þifre Deðiþtir',
+ 'Character Set' => 'Karakter Seti',
+ 'Chart of Accounts' => 'Hesap Planý',
+ 'Check' => '',
+ 'Check printed!' => '',
+ 'Check printing failed!' => '',
+ 'Cleared Balance' => '',
+ 'Click on login name to edit!' => 'Düzenlemek için giriþ ismini týklayýn.',
+ 'Close Books up to' => '',
+ 'Closed' => '',
+ 'Company' => 'Þirket',
+ 'Compare to' => '...kýyasla',
+ 'Confirm!' => 'Onayla!',
+ 'Connect to' => 'Baðlan',
+ 'Contact' => 'Kontak',
+ 'Continue' => 'Devam',
+ 'Copies' => '',
+ 'Copy to COA' => '',
+ 'Create Chart of Accounts' => 'Hesap Planý Oluþtur',
+ 'Create Dataset' => 'Veriseti Oluþtur',
+ 'Credit' => 'Alacak',
+ 'Credit Limit' => 'Kredi Limiti',
+ 'Curr' => '',
+ 'Currency' => 'Para Birimi',
+ 'Current' => '',
+ 'Customer' => 'Alýcý',
+ 'Customer deleted!' => '',
+ 'Customer missing!' => '',
+ 'Customer not on file!' => '',
+ 'Customer saved!' => '',
+ 'Customers' => '',
+ 'DBI not installed!' => 'DBJ kurulu deðil',
+ 'Database' => 'Veritabaný',
+ 'Database Administration' => 'Veritabani Yonetimi',
+ 'Database Driver not checked!' => '',
+ 'Database Host' => 'Veritabaný Hostu',
+ 'Database User missing!' => 'Veritabaný Kullanýcýsý yok!',
+ 'Dataset' => 'Veriseti',
+ 'Dataset missing!' => 'Veriseti Yok!',
+ 'Dataset updated!' => '',
+ 'Date' => 'Tarih',
+ 'Date Due' => 'Vade Tarihi',
+ 'Date Format' => 'Tarih Formatý',
+ 'Date Paid' => 'Ödendiði Tarih',
+ 'Date missing!' => '',
+ 'Debit' => 'Borç',
+ 'Debit and credit out of balance!' => 'Borç ve alacak eþit deðil!',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Decimalplaces' => '',
+ 'Delete' => 'Sil',
+ 'Delete Account' => 'Hesabý Sil',
+ 'Delete Dataset' => 'Verisetini Sil',
+ 'Delivery Date' => '',
+ 'Deposit' => '',
+ 'Description' => 'Açýklama',
+ 'Difference' => '',
+ 'Directory' => 'Dizin',
+ 'Discount' => 'Ýndirim',
+ 'Done' => '',
+ 'Drawing' => '',
+ 'Driver' => 'Sürücü',
+ 'Dropdown Limit' => '',
+ 'Due' => 'Vade',
+ 'Due Date' => 'Vade Tarihi',
+ 'Due Date missing!' => 'Vade Tarihi yok!',
+ 'E-mail' => 'Posta',
+ 'E-mail Statement to' => '',
+ 'E-mail address missing!' => 'Posta adresi yok!',
+ 'Edit' => '',
+ 'Edit Account' => 'Hesabý Düzenle',
+ 'Edit Accounts Payables Transaction' => '',
+ 'Edit Accounts Receivables Transaction' => '',
+ 'Edit Assembly' => 'Grubu Düzenle',
+ 'Edit GIFI' => '',
+ 'Edit General Ledger Transaction' => 'Defteri Kebir Ýþlemini Düzenle',
+ 'Edit Part' => 'Parçayý Düzenle',
+ 'Edit Preferences for' => 'Tercihleri Düzenle: ',
+ 'Edit Project' => '',
+ 'Edit Purchase Invoice' => '',
+ 'Edit Purchase Order' => 'Alýþ Sipariþini Düzenle',
+ 'Edit Sales Invoice' => '',
+ 'Edit Sales Order' => 'Satýþ Sipariþini Düzenle',
+ 'Edit Service' => 'Hizmeti Düzenle',
+ 'Edit Template' => 'Þablonu Düzenle',
+ 'Edit User' => 'Kullanýcý Bilgilerini Düzenle',
+ 'Employee' => '',
+ 'Enforce transaction reversal for all dates' => '',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Yerel ve yabancý para birimleri için 3 harfli tanýmlama giriniz yi týklayýnýz (USD:TRL:EUR)',
+ 'Equity' => 'Sermaye',
+ 'Exch' => 'D.Kuru',
+ 'Exchangerate' => 'Döviz Kuru',
+ 'Exchangerate Difference' => '',
+ 'Exchangerate for payment missing!' => '',
+ 'Exchangerate missing!' => '',
+ 'Existing Datasets' => 'Verisetleri',
+ 'Expense' => 'Gider',
+ 'Expense Account' => 'Gider Hesabý',
+ 'Expense/Asset' => 'Gider/Varlýklar',
+ 'Extended' => '',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'Foreign Exchange Gain' => 'Kur Kazancý',
+ 'Foreign Exchange Loss' => 'Kur Kaybý',
+ 'From' => 'Baþlangýç',
+ 'GIFI' => '',
+ 'GIFI deleted!' => '',
+ 'GIFI missing!' => '',
+ 'GIFI saved!' => '',
+ 'GL Transaction' => '',
+ 'General Ledger' => 'Defteri Kebir',
+ 'Goods & Services' => '',
+ 'HTML Templates' => '',
+ 'Heading' => 'Baþlýk',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Host yok!',
+ 'ID' => '',
+ 'Image' => '',
+ 'In-line' => '',
+ 'Include in Report' => 'Raporla',
+ 'Include in drop-down menus' => 'Seçmeli Menüye dahil et',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Vergiye tabi alýcý/satýcý belirlemek için bu hesabý alýcý/aatýcý formlarýna dahil ediniz?',
+ 'Income' => 'Gelirler',
+ 'Income Account' => 'Gelir Hesabý',
+ 'Income Statement' => 'Gelir Tablosu',
+ 'Incorrect Dataset version!' => '',
+ 'Incorrect Password!' => 'Yanlýþ Þifre!',
+ 'Individual Items' => 'Farklý Kalemler',
+ 'Inventory' => 'Stok',
+ 'Inventory Account' => 'Stok Hesabý',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Bu grubu çýkarmadan önce stok miktarý sýfýr olmalýdýr',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Bu Parçayý çýkarmadan önce stok miktarý sýfýr olmalýdýr',
+ 'Inventory quantity must be zero!' => 'Stok miktarý sýfýr olmalý!',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Fatura Tarihi',
+ 'Invoice Date missing!' => 'Fatura Tarihi yok!',
+ 'Invoice Number' => 'Fatura No',
+ 'Invoice Number missing!' => 'Fatura Numarasý yok!',
+ 'Invoice deleted!' => '',
+ 'Invoice posted!' => '',
+ 'Invoices' => '',
+ 'Is this a summary account to record' => 'Bu kaydedilecek hesap özeti mi',
+ 'Item deleted!' => '',
+ 'Item not on file!' => 'Bu kalem dosyada yok!',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'LaTeX Templates' => '',
+ 'Language' => 'Dil',
+ 'Last Cost' => 'Son Maliyet',
+ 'Last Invoice Number' => 'Son Fatura Numarasý',
+ 'Last Numbers & Default Accounts' => 'Son Numaralar ve Öntanýmlý Hesaplar',
+ 'Last Purchase Order Number' => 'Son Satýnalma Sipariþ Numarasý',
+ 'Last Sales Order Number' => '',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Uzakta baglantý yapmak istemiyorsanýz host ve port alanlarýný boþ býrakýnýz.',
+ 'Liability' => 'Pasif',
+ 'Licensed to' => 'Lisans Sahibi:',
+ 'Line Total' => '',
+ 'Link' => 'Baðla',
+ 'Link Accounts' => 'Baðlý Hesaplar',
+ 'List Accounts' => '',
+ 'List GIFI' => '',
+ 'List Price' => 'Liste Fiyatý',
+ 'List Transactions' => 'Ýþlemleri Listele',
+ 'Login' => 'Giriþ',
+ 'Logout' => '',
+ 'Make' => 'Marka',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Message' => '',
+ 'Microfiche' => '',
+ 'Model' => 'Model',
+ 'N/A' => '',
+ 'Name' => 'Ýsim',
+ 'Name missing!' => '',
+ 'New Templates' => 'Yeni Þablonlar',
+ 'No' => 'Hayýr',
+ 'No Database Drivers available!' => 'Veritabaný Sürücüsü yok!',
+ 'No Dataset selected!' => 'Veriseti seçilmedi!',
+ 'No email address for' => 'E-posta adresi yok: ',
+ 'No.' => '',
+ 'Notes' => 'Notlar:',
+ 'Nothing applied!' => '',
+ 'Nothing selected!' => '',
+ 'Nothing to delete!' => '',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Number' => 'Numara',
+ 'Number Format' => 'Rakam Formatý',
+ 'Number missing in Row' => 'Sýrada Numara yok!',
+ 'O' => '',
+ 'Obsolete' => 'Eski',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'On Hand' => 'Stok:',
+ 'On Order' => '',
+ 'Open' => '',
+ 'Oracle Database Administration' => 'Oracle Veritabaný Yönetimi',
+ 'Order' => 'Sipariþ',
+ 'Order Date' => 'Sipariþ Tarihi',
+ 'Order Date missing!' => 'Sipariþ Tarihi yok!',
+ 'Order Entry' => 'Sipariþ Giriþi',
+ 'Order Number' => 'Sipariþ No',
+ 'Order Number missing!' => 'Sipariþ Numarasý yok!',
+ 'Order deleted!' => '',
+ 'Order saved!' => '',
+ 'Ordered' => '',
+ 'Orphaned' => '',
+ 'Out of balance!' => '',
+ 'PDF' => '',
+ 'Packing List' => 'Paketleme Listesi',
+ 'Packing List Date missing!' => '',
+ 'Packing List Number missing!' => '',
+ 'Paid' => 'Ödendi',
+ 'Paid in full' => '',
+ 'Part' => 'Parça',
+ 'Part Number missing!' => 'Parça Numarasý yok!',
+ 'Parts' => 'Parçalar',
+ 'Parts Inventory' => 'Parça Stoðu',
+ 'Password' => 'Þifre',
+ 'Password changed!' => '',
+ 'Payables' => 'Borçlar',
+ 'Payment' => 'Ödeme',
+ 'Payment date missing!' => 'Ödeme Tarihi yok',
+ 'Payment posted!' => '',
+ 'Payments' => 'Ödemeler',
+ 'Pg Database Administration' => 'Pg Veritabaný Yönetimi',
+ 'Phone' => 'Telefon',
+ 'Port' => 'Port',
+ 'Port missing!' => 'Port yok!',
+ 'Post' => '',
+ 'Post as new' => '',
+ 'Postscript' => '',
+ 'Preferences' => 'Tercihler',
+ 'Preferences saved!' => 'Tercihler kaydedildi!',
+ 'Price' => 'Fiyat',
+ 'Print' => '',
+ 'Printer' => 'Yazýcý',
+ 'Project' => '',
+ 'Project Number missing!' => '',
+ 'Project deleted!' => '',
+ 'Project not on file!' => '',
+ 'Project saved!' => '',
+ 'Projects' => '',
+ 'Purchase Invoice' => '',
+ 'Purchase Order' => 'Satýnalma Sipariþi',
+ 'Purchase Orders' => 'Satýnalma Sipariþleri',
+ 'Qty' => 'Adet',
+ 'ROP' => '',
+ 'Rate' => 'Oran',
+ 'Recd' => '',
+ 'Receipt' => '',
+ 'Receipts' => '',
+ 'Receivables' => 'Alacaklar',
+ 'Reconciliation' => '',
+ 'Record in' => 'Kaydet',
+ 'Reference' => '',
+ 'Reference missing!' => '',
+ 'Remaining' => '',
+ 'Report for' => '',
+ 'Reports' => 'Raporlar',
+ 'Required by' => 'Talep tarihi:',
+ 'Retained Earnings' => 'Net Dönem Karý (Zararý)',
+ 'Sales' => 'Satýþlar',
+ 'Sales Invoice' => '',
+ 'Sales Order' => 'Satýþ Sipariþi',
+ 'Sales Orders' => 'Satýþ Sipariþleri',
+ 'Save' => 'Kaydet',
+ 'Save as new' => '',
+ 'Save to File' => 'Dosyaya Kaydet',
+ 'Screen' => '',
+ 'Select a Dataset to delete and press "Continue"' => 'Silmek için bir Veriseti seçin ve "Devam"ý týklayýn.',
+ 'Select all' => '',
+ 'Select from one of the items below' => 'Aþaðýdaki kalemlerden birini seç',
+ 'Select from one of the names below' => '',
+ 'Select from one of the projects below' => '',
+ 'Select postscript or PDF!' => '',
+ 'Sell Price' => 'Satýþ Fiyatý',
+ 'Send by E-Mail' => 'E-postayla gönder',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Service' => 'servis',
+ 'Service Items' => 'Hizmet Kalemleri',
+ 'Service Number missing!' => 'Hizmet Numarasý yok!',
+ 'Services' => 'Servisler',
+ 'Setup Templates' => 'Þablon Kur',
+ 'Ship' => '',
+ 'Ship to' => '',
+ 'Ship via' => '',
+ 'Short' => 'Kýsa',
+ 'Signature' => 'Ýmza',
+ 'Sold' => 'satýlan',
+ 'Source' => 'Kaynak',
+ 'Standard' => '',
+ 'Statement' => '',
+ 'Statement Balance' => '',
+ 'Statement sent to' => '',
+ 'Statements sent to printer!' => '',
+ 'Stock Assembly' => 'Grubu Stokla',
+ 'Stylesheet' => 'Düzen Sayfasý',
+ 'Subject' => '',
+ 'Subtotal' => 'Aratoplam',
+ 'System' => '',
+ 'Tax' => 'Vergi',
+ 'Tax Accounts' => 'Vergi Hesaplarý',
+ 'Tax Included' => 'Vergi Dahil',
+ 'Tax collected' => '',
+ 'Tax paid' => '',
+ 'Taxable' => 'Vergiye tabi',
+ 'Template saved!' => '',
+ 'Templates' => 'Þablonlar',
+ 'Terms: Net' => 'Þartlar: Net',
+ 'The following Datasets are not in use and can be deleted' => 'Aþaðýdaki Verisetleri kullanýlmamaktadýr ve silinebilir',
+ 'The following Datasets need to be updated' => '',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Mevcut fiþ bilgileri için bu bir ön kontroldür. Bu aþamada hiçbirþey oluþturulmaz ve silinemez',
+ 'To' => 'Bitiþ',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Gruba yeni kullanýcý eklemek için, giriþ ismini deðiþtirin ve kaydedin. Yeni kullanýcý yeni giriþ altýnda ayný parametrelerle kaydedilecektir.',
+ 'Top Level' => '',
+ 'Total' => 'Toplam',
+ 'Transaction Date missing!' => 'Ýþlem Tarihi yok!',
+ 'Transaction deleted!' => '',
+ 'Transaction posted!' => '',
+ 'Transaction reversal enforced for all dates' => '',
+ 'Transaction reversal enforced up to' => '',
+ 'Transactions' => 'Ýþlemler',
+ 'Transactions exist, cannot delete customer!' => 'Ýþlem var, alýcý silinemez!',
+ 'Transactions exist, cannot delete vendor!' => 'Ýþlem var, satýcý silinemez!',
+ 'Transactions exist; cannot delete account!' => 'Ýþlem var, hesap silinemez!',
+ 'Trial Balance' => 'Proforma Bilanço',
+ 'Unit' => 'Birim',
+ 'Unit of measure' => 'Ölçme Birimi',
+ 'Update' => '',
+ 'Update Dataset' => '',
+ 'Updated' => '',
+ 'Use Templates' => 'Þablon Kullan',
+ 'User' => 'Kullanýcý',
+ 'User deleted!' => '',
+ 'User saved!' => '',
+ 'Vendor' => 'Satýcý',
+ 'Vendor deleted!' => '',
+ 'Vendor missing!' => '',
+ 'Vendor not on file!' => '',
+ 'Vendor saved!' => '',
+ 'Vendors' => '',
+ 'Version' => 'Versiyon',
+ 'Weight' => 'Aðýrlýk',
+ 'Weight Unit' => 'Aðýrlýk Birimi',
+ 'What type of item is this?' => 'Bu ne çeþit bir kalemdir?',
+ 'Year End' => 'Sene Sonu',
+ 'Yes' => 'Evet',
+ 'You are logged out!' => '',
+ 'You did not enter a name!' => 'Ýsim girmediniz!',
+ 'You must enter a host and port for local and remote connections!' => 'Yerel ve uzak baðlantýlar için bir host ve port girmek zorundasýnýz!',
+ 'as at' => '',
+ 'collected on sales' => '',
+ 'days' => 'gün. ',
+ 'does not exist' => 'mevcut deðil',
+ 'ea' => 'ad',
+ 'emailed to' => '',
+ 'for Period' => 'Dönem:',
+ 'hr' => 'sa',
+ 'is already a member!' => 'üyedir!',
+ 'is not a member!' => '',
+ 'localhost' => 'Yerelhost',
+ 'paid on purchases' => '',
+ 'sent to printer' => '',
+ 'successfully created!' => 'baþarýyla oluþturuldu!',
+ 'successfully deleted!' => 'baþarýyla silindi!',
+ 'to' => '',
+ 'website' => 'Websitesi',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/am b/sql-ledger/locale/tr/am
new file mode 100644
index 0000000..1ce2de0
--- /dev/null
+++ b/sql-ledger/locale/tr/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'Borçlar',
+ 'AR' => 'Alacaklar',
+ 'Account' => 'Hesap',
+ 'Account Number' => 'Hesap Numarasý',
+ 'Account Number missing!' => 'Hesap Numarasý yok!',
+ 'Account Type' => 'Hesap Türü',
+ 'Account Type missing!' => 'Hesap Türü yok!',
+ 'Account deleted!' => 'Account deleted!',
+ 'Account saved!' => 'Account saved!',
+ 'Add Account' => 'Hesap Ekle',
+ 'Add GIFI' => 'Add GIFI',
+ 'Address' => 'Adres',
+ 'Asset' => 'Aktif',
+ 'Audit Control' => 'Audit Control',
+ 'Backup sent to' => 'Backup sent to',
+ 'Books are open' => 'Books are open',
+ 'Business Number' => 'ÞirketNo',
+ 'COGS' => 'SMM',
+ 'Cannot delete account!' => 'Cannot delete account!',
+ 'Cannot delete default account!' => 'Öntanýmlý hesap silinmez!',
+ 'Cannot save account!' => 'Cannot save account!',
+ 'Cannot save preferences!' => 'Cannot save preferences!',
+ 'Character Set' => 'Karakter Seti',
+ 'Chart of Accounts' => 'Hesap Planý',
+ 'Close Books up to' => 'Close Books up to',
+ 'Company' => 'Þirket',
+ 'Continue' => 'Devam',
+ 'Copy to COA' => 'Copy to COA',
+ 'Credit' => 'Alacak',
+ 'Date Format' => 'Tarih Formatý',
+ 'Debit' => 'Borç',
+ 'Delete' => 'Sil',
+ 'Delete Account' => 'Hesabý Sil',
+ 'Description' => 'Açýklama',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => 'Posta',
+ 'Edit' => 'Edit',
+ 'Edit Account' => 'Hesabý Düzenle',
+ 'Edit GIFI' => 'Edit GIFI',
+ 'Edit Preferences for' => 'Tercihleri Düzenle: ',
+ 'Edit Template' => 'Þablonu Düzenle',
+ 'Enforce transaction reversal for all dates' => 'Enforce transaction reversal for all dates',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Yerel ve yabancý para birimleri için 3 harfli tanýmlama giriniz yi týklayýnýz (USD:TRL:EUR)',
+ 'Equity' => 'Sermaye',
+ 'Expense' => 'Gider',
+ 'Expense Account' => 'Gider Hesabý',
+ 'Expense/Asset' => 'Gider/Varlýklar',
+ 'Fax' => 'Faks',
+ 'Foreign Exchange Gain' => 'Kur Kazancý',
+ 'Foreign Exchange Loss' => 'Kur Kaybý',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI deleted!',
+ 'GIFI missing!' => 'GIFI missing!',
+ 'GIFI saved!' => 'GIFI saved!',
+ 'Heading' => 'Baþlýk',
+ 'Include in drop-down menus' => 'Seçmeli Menüye dahil et',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Vergiye tabi alýcý/satýcý belirlemek için bu hesabý alýcý/aatýcý formlarýna dahil ediniz?',
+ 'Income' => 'Gelirler',
+ 'Income Account' => 'Gelir Hesabý',
+ 'Inventory' => 'Stok',
+ 'Inventory Account' => 'Stok Hesabý',
+ 'Is this a summary account to record' => 'Bu kaydedilecek hesap özeti mi',
+ 'Language' => 'Dil',
+ 'Last Invoice Number' => 'Son Fatura Numarasý',
+ 'Last Numbers & Default Accounts' => 'Son Numaralar ve Öntanýmlý Hesaplar',
+ 'Last Purchase Order Number' => 'Son Satýnalma Sipariþ Numarasý',
+ 'Last Sales Order Number' => 'Last Sales Order Number',
+ 'Liability' => 'Pasif',
+ 'Link' => 'Baðla',
+ 'Name' => 'Ýsim',
+ 'No' => 'Hayýr',
+ 'No email address for' => 'E-posta adresi yok: ',
+ 'Number' => 'Numara',
+ 'Number Format' => 'Rakam Formatý',
+ 'Parts Inventory' => 'Parça Stoðu',
+ 'Password' => 'Þifre',
+ 'Payables' => 'Borçlar',
+ 'Payment' => 'Ödeme',
+ 'Phone' => 'Telefon',
+ 'Preferences saved!' => 'Tercihler kaydedildi!',
+ 'Rate' => 'Oran',
+ 'Receivables' => 'Alacaklar',
+ 'Sales' => 'Satýþlar',
+ 'Save' => 'Kaydet',
+ 'Service Items' => 'Hizmet Kalemleri',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'Ýmza',
+ 'Stylesheet' => 'Düzen Sayfasý',
+ 'Tax' => 'Vergi',
+ 'Tax Accounts' => 'Vergi Hesaplarý',
+ 'Template saved!' => 'Template saved!',
+ 'Transaction reversal enforced for all dates' => 'Transaction reversal enforced for all dates',
+ 'Transaction reversal enforced up to' => 'Transaction reversal enforced up to',
+ 'Transactions exist; cannot delete account!' => 'Ýþlem var, hesap silinemez!',
+ 'Weight Unit' => 'Aðýrlýk Birimi',
+ 'Year End' => 'Sene Sonu',
+ 'Yes' => 'Evet',
+ 'does not exist' => 'mevcut deðil',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'hesap_ekle' => 'add_account',
+ 'devam' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'sil' => 'delete',
+ 'edit' => 'edit',
+ 'hesabý_düzenle' => 'edit_account',
+ 'kaydet' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/ap b/sql-ledger/locale/tr/ap
new file mode 100644
index 0000000..f6c817f
--- /dev/null
+++ b/sql-ledger/locale/tr/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AP Transactions' => 'Borç Ýþlemleri',
+ 'Account' => 'Hesap',
+ 'Add Accounts Payables Transaction' => 'Add Accounts Payables Transaction',
+ 'Address' => 'Adres',
+ 'Amount' => 'Miktar',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Are you sure you want to delete Transaction' => 'Ýþlemi silmek istediðinizden emin misiniz? Fiþ: ',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'Cannot post transaction for a closed period!',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Closed',
+ 'Confirm!' => 'Onayla!',
+ 'Continue' => 'Devam',
+ 'Currency' => 'Para Birimi',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Tarih',
+ 'Date Paid' => 'Ödendiði Tarih',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Delete' => 'Sil',
+ 'Description' => 'Açýklama',
+ 'Due Date' => 'Vade Tarihi',
+ 'Due Date missing!' => 'Vade Tarihi yok!',
+ 'Edit Accounts Payables Transaction' => 'Edit Accounts Payables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'D.Kuru',
+ 'Exchangerate' => 'Döviz Kuru',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'From' => 'Baþlangýç',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Raporla',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Fatura Tarihi',
+ 'Invoice Date missing!' => 'Fatura Tarihi yok!',
+ 'Invoice Number' => 'Fatura No',
+ 'Invoice Number missing!' => 'Fatura Numarasý yok!',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Notes' => 'Notlar:',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Number' => 'Numara',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'Open' => 'Open',
+ 'Order' => 'Sipariþ',
+ 'Order Number' => 'Sipariþ No',
+ 'Paid' => 'Ödendi',
+ 'Payment date missing!' => 'Ödeme Tarihi yok',
+ 'Payments' => 'Ödemeler',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Source' => 'Kaynak',
+ 'Subtotal' => 'Aratoplam',
+ 'Tax' => 'Vergi',
+ 'Tax Included' => 'Vergi Dahil',
+ 'To' => 'Bitiþ',
+ 'Total' => 'Toplam',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor' => 'Satýcý',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Evet',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'add_accounts_payables_transaction' => 'add_accounts_payables_transaction',
+ 'devam' => 'continue',
+ 'sil' => 'delete',
+ 'edit_accounts_payables_transaction' => 'edit_accounts_payables_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'update' => 'update',
+ 'evet' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/ar b/sql-ledger/locale/tr/ar
new file mode 100644
index 0000000..642c556
--- /dev/null
+++ b/sql-ledger/locale/tr/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'AR Transaction',
+ 'AR Transactions' => 'Alacak Ýþlemleri',
+ 'Account' => 'Hesap',
+ 'Add Accounts Receivables Transaction' => 'Add Accounts Receivables Transaction',
+ 'Address' => 'Adres',
+ 'Amount' => 'Miktar',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Are you sure you want to delete Transaction' => 'Ýþlemi silmek istediðinizden emin misiniz? Fiþ: ',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'Cannot post transaction for a closed period!',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => 'Closed',
+ 'Confirm!' => 'Onayla!',
+ 'Continue' => 'Devam',
+ 'Credit Limit' => 'Kredi Limiti',
+ 'Currency' => 'Para Birimi',
+ 'Customer' => 'Alýcý',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Tarih',
+ 'Date Paid' => 'Ödendiði Tarih',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Delete' => 'Sil',
+ 'Description' => 'Açýklama',
+ 'Due Date' => 'Vade Tarihi',
+ 'Due Date missing!' => 'Vade Tarihi yok!',
+ 'Edit Accounts Receivables Transaction' => 'Edit Accounts Receivables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => 'D.Kuru',
+ 'Exchangerate' => 'Döviz Kuru',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'From' => 'Baþlangýç',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Raporla',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Fatura Tarihi',
+ 'Invoice Date missing!' => 'Fatura Tarihi yok!',
+ 'Invoice Number' => 'Fatura No',
+ 'Invoice Number missing!' => 'Fatura Numarasý yok!',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Notes' => 'Notlar:',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Number' => 'Numara',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'Open' => 'Open',
+ 'Order' => 'Sipariþ',
+ 'Order Number' => 'Sipariþ No',
+ 'Paid' => 'Ödendi',
+ 'Payment date missing!' => 'Ödeme Tarihi yok',
+ 'Payments' => 'Ödemeler',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Remaining' => 'Remaining',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Source' => 'Kaynak',
+ 'Subtotal' => 'Aratoplam',
+ 'Tax' => 'Vergi',
+ 'Tax Included' => 'Vergi Dahil',
+ 'To' => 'Bitiþ',
+ 'Total' => 'Toplam',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Evet',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ar_transaction' => 'ar_transaction',
+ 'devam' => 'continue',
+ 'sil' => 'delete',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'evet' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/arap b/sql-ledger/locale/tr/arap
new file mode 100644
index 0000000..fb56368
--- /dev/null
+++ b/sql-ledger/locale/tr/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Adres',
+ 'Continue' => 'Devam',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Description' => 'Açýklama',
+ 'Number' => 'Numara',
+ 'Project not on file!' => 'Project not on file!',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'devam' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/ca b/sql-ledger/locale/tr/ca
new file mode 100644
index 0000000..f379cd6
--- /dev/null
+++ b/sql-ledger/locale/tr/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Hesap',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'Hesap Planý',
+ 'Credit' => 'Alacak',
+ 'Date' => 'Tarih',
+ 'Debit' => 'Borç',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Description' => 'Açýklama',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'From' => 'Baþlangýç',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Raporla',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'List Transactions' => 'Ýþlemleri Listele',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'Reference' => 'Reference',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Subtotal' => 'Aratoplam',
+ 'To' => 'Bitiþ',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'Ýþlemleri_listele' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/cp b/sql-ledger/locale/tr/cp
new file mode 100644
index 0000000..a08a0b7
--- /dev/null
+++ b/sql-ledger/locale/tr/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Hesap',
+ 'Address' => 'Adres',
+ 'Amount' => 'Miktar',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Amount missing!',
+ 'Applied' => 'Applied',
+ 'Cannot post payment!' => 'Cannot post payment!',
+ 'Cannot process payment for a closed period!' => 'Cannot process payment for a closed period!',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check printed!',
+ 'Check printing failed!' => 'Check printing failed!',
+ 'Continue' => 'Devam',
+ 'Currency' => 'Para Birimi',
+ 'Customer' => 'Alýcý',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Tarih',
+ 'Date missing!' => 'Date missing!',
+ 'Description' => 'Açýklama',
+ 'Due' => 'Vade',
+ 'Exchangerate' => 'Döviz Kuru',
+ 'From' => 'Baþlangýç',
+ 'Invoice' => 'Fatura',
+ 'Invoices' => 'Invoices',
+ 'Nothing applied!' => 'Nothing applied!',
+ 'Number' => 'Numara',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => 'Ödeme',
+ 'Payment posted!' => 'Payment posted!',
+ 'Post' => 'Post',
+ 'Print' => 'Print',
+ 'Printer' => 'Yazýcý',
+ 'Project not on file!' => 'Project not on file!',
+ 'Receipt' => 'Receipt',
+ 'Reference' => 'Reference',
+ 'Screen' => 'Screen',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'To' => 'Bitiþ',
+ 'Update' => 'Update',
+ 'Vendor' => 'Satýcý',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'devam' => 'continue',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/ct b/sql-ledger/locale/tr/ct
new file mode 100644
index 0000000..b7b0e4f
--- /dev/null
+++ b/sql-ledger/locale/tr/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => 'Ekle',
+ 'Address' => 'Adres',
+ 'All' => 'Hepsi',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Cannot delete customer!',
+ 'Cannot delete vendor!' => 'Cannot delete vendor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontak',
+ 'Continue' => 'Devam',
+ 'Credit Limit' => 'Kredi Limiti',
+ 'Customer deleted!' => 'Customer deleted!',
+ 'Customer saved!' => 'Customer saved!',
+ 'Customers' => 'Customers',
+ 'Delete' => 'Sil',
+ 'Discount' => 'Ýndirim',
+ 'E-mail' => 'Posta',
+ 'Fax' => 'Faks',
+ 'Include in Report' => 'Raporla',
+ 'Invoice' => 'Fatura',
+ 'Name' => 'Ýsim',
+ 'Name missing!' => 'Name missing!',
+ 'Notes' => 'Notlar:',
+ 'Number' => 'Numara',
+ 'Order' => 'Sipariþ',
+ 'Orphaned' => 'Orphaned',
+ 'Phone' => 'Telefon',
+ 'Save' => 'Kaydet',
+ 'Ship to' => 'Ship to',
+ 'Tax Included' => 'Vergi Dahil',
+ 'Taxable' => 'Vergiye tabi',
+ 'Terms: Net' => 'Þartlar: Net',
+ 'Transactions exist, cannot delete customer!' => 'Ýþlem var, alýcý silinemez!',
+ 'Transactions exist, cannot delete vendor!' => 'Ýþlem var, satýcý silinemez!',
+ 'Vendor deleted!' => 'Vendor deleted!',
+ 'Vendor saved!' => 'Vendor saved!',
+ 'Vendors' => 'Vendors',
+ 'days' => 'gün. ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'ekle' => 'add',
+ 'devam' => 'continue',
+ 'sil' => 'delete',
+ 'fatura' => 'invoice',
+ 'sipariþ' => 'order',
+ 'kaydet' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/gl b/sql-ledger/locale/tr/gl
new file mode 100644
index 0000000..7370def
--- /dev/null
+++ b/sql-ledger/locale/tr/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AR Transaction' => 'AR Transaction',
+ 'Account' => 'Hesap',
+ 'Add General Ledger Transaction' => 'Defteri Kebire Ýþlem Ekle',
+ 'Address' => 'Adres',
+ 'All' => 'Hepsi',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Are you sure you want to delete Transaction' => 'Ýþlemi silmek istediðinizden emin misiniz? Fiþ: ',
+ 'Asset' => 'Aktif',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot have a value in both Debit and Credit!' => 'Borç ve Alacak hanelerine ayný anda deðer yazýlamaz!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'Cannot post transaction for a closed period!',
+ 'Confirm!' => 'Onayla!',
+ 'Continue' => 'Devam',
+ 'Credit' => 'Alacak',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Tarih',
+ 'Debit' => 'Borç',
+ 'Debit and credit out of balance!' => 'Borç ve alacak eþit deðil!',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Delete' => 'Sil',
+ 'Description' => 'Açýklama',
+ 'Edit General Ledger Transaction' => 'Defteri Kebir Ýþlemini Düzenle',
+ 'Equity' => 'Sermaye',
+ 'Expense' => 'Gider',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'From' => 'Baþlangýç',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'GL Transaction',
+ 'General Ledger' => 'Defteri Kebir',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Raporla',
+ 'Income' => 'Gelirler',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'Liability' => 'Pasif',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Notes' => 'Notlar:',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Number' => 'Numara',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference missing!',
+ 'Reports' => 'Raporlar',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Source' => 'Kaynak',
+ 'Subtotal' => 'Aratoplam',
+ 'To' => 'Bitiþ',
+ 'Transaction Date missing!' => 'Ýþlem Tarihi yok!',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => 'Evet',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'devam' => 'continue',
+ 'sil' => 'delete',
+ 'gl_transaction' => 'gl_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ 'evet' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/ic b/sql-ledger/locale/tr/ic
new file mode 100644
index 0000000..b069b81
--- /dev/null
+++ b/sql-ledger/locale/tr/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Active',
+ 'Add' => 'Ekle',
+ 'Add Assembly' => 'Grup Ekle',
+ 'Add Part' => 'Parça Ekle',
+ 'Add Purchase Order' => 'Satýnalma Sip. Ekle',
+ 'Add Sales Order' => 'Satýþ Sipariþi Ekle',
+ 'Add Service' => 'Hizmet Ekle',
+ 'Address' => 'Adres',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Assemblies' => 'Gruplar',
+ 'Assemblies restocked!' => 'Assemblies restocked!',
+ 'Assembly Number missing!' => 'Grup Numarasý yok!',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Bought' => 'Alýnan',
+ 'COGS' => 'SMM',
+ 'Cannot delete item already invoiced!' => 'Faturalanmýþ kalem silinemez!',
+ 'Cannot delete item on order!' => 'Cannot delete item on order!',
+ 'Cannot delete item which is part of an assembly!' => 'Grubun parçasý olan kalem silinemez!',
+ 'Cannot delete item!' => 'Cannot delete item!',
+ 'Cannot stock assemblies!' => 'Cannot stock assemblies!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontak',
+ 'Continue' => 'Devam',
+ 'Copies' => 'Copies',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Delete' => 'Sil',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Açýklama',
+ 'Drawing' => 'Drawing',
+ 'E-mail' => 'Posta',
+ 'E-mail address missing!' => 'Posta adresi yok!',
+ 'Edit Assembly' => 'Grubu Düzenle',
+ 'Edit Part' => 'Parçayý Düzenle',
+ 'Edit Service' => 'Hizmeti Düzenle',
+ 'Expense' => 'Gider',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'From' => 'Baþlangýç',
+ 'Image' => 'Image',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Raporla',
+ 'Income' => 'Gelirler',
+ 'Individual Items' => 'Farklý Kalemler',
+ 'Inventory' => 'Stok',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Bu grubu çýkarmadan önce stok miktarý sýfýr olmalýdýr',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Bu Parçayý çýkarmadan önce stok miktarý sýfýr olmalýdýr',
+ 'Inventory quantity must be zero!' => 'Stok miktarý sýfýr olmalý!',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date missing!' => 'Fatura Tarihi yok!',
+ 'Invoice Number' => 'Fatura No',
+ 'Invoice Number missing!' => 'Fatura Numarasý yok!',
+ 'Item deleted!' => 'Item deleted!',
+ 'Item not on file!' => 'Bu kalem dosyada yok!',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'Last Cost' => 'Son Maliyet',
+ 'Line Total' => 'Line Total',
+ 'Link Accounts' => 'Baðlý Hesaplar',
+ 'List Price' => 'Liste Fiyatý',
+ 'Make' => 'Marka',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Message' => 'Message',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => 'Model',
+ 'Name' => 'Ýsim',
+ 'No.' => 'No.',
+ 'Notes' => 'Notlar:',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Number' => 'Numara',
+ 'Number missing in Row' => 'Sýrada Numara yok!',
+ 'Obsolete' => 'Eski',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'On Hand' => 'Stok:',
+ 'On Order' => 'On Order',
+ 'Order' => 'Sipariþ',
+ 'Order Date missing!' => 'Sipariþ Tarihi yok!',
+ 'Order Number' => 'Sipariþ No',
+ 'Order Number missing!' => 'Sipariþ Numarasý yok!',
+ 'Ordered' => 'Ordered',
+ 'Orphaned' => 'Orphaned',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Paketleme Listesi',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Parça',
+ 'Part Number missing!' => 'Parça Numarasý yok!',
+ 'Parts' => 'Parçalar',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Fiyat',
+ 'Printer' => 'Yazýcý',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Satýnalma Sipariþi',
+ 'Qty' => 'Adet',
+ 'ROP' => 'ROP',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Talep tarihi:',
+ 'Sales' => 'Satýþlar',
+ 'Sales Order' => 'Satýþ Sipariþi',
+ 'Save' => 'Kaydet',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Aþaðýdaki kalemlerden birini seç',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sell Price' => 'Satýþ Fiyatý',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Service' => 'servis',
+ 'Service Number missing!' => 'Hizmet Numarasý yok!',
+ 'Services' => 'Servisler',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Short' => 'Kýsa',
+ 'Sold' => 'satýlan',
+ 'Stock Assembly' => 'Grubu Stokla',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Aratoplam',
+ 'Tax' => 'Vergi',
+ 'To' => 'Bitiþ',
+ 'Top Level' => 'Top Level',
+ 'Total' => 'Toplam',
+ 'Unit' => 'Birim',
+ 'Unit of measure' => 'Ölçme Birimi',
+ 'Update' => 'Update',
+ 'Updated' => 'Updated',
+ 'Weight' => 'Aðýrlýk',
+ 'What type of item is this?' => 'Bu ne çeþit bir kalemdir?',
+ 'ea' => 'ad',
+ 'emailed to' => 'emailed to',
+ 'hr' => 'sa',
+ 'sent to printer' => 'sent to printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'ekle' => 'add',
+ 'grup_ekle' => 'add_assembly',
+ 'parça_ekle' => 'add_part',
+ 'hizmet_ekle' => 'add_service',
+ 'devam' => 'continue',
+ 'sil' => 'delete',
+ 'grubu_düzenle' => 'edit_assembly',
+ 'parçayý_düzenle' => 'edit_part',
+ 'hizmeti_düzenle' => 'edit_service',
+ 'kaydet' => 'save',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/io b/sql-ledger/locale/tr/io
new file mode 100644
index 0000000..8ce89dd
--- /dev/null
+++ b/sql-ledger/locale/tr/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Satýnalma Sip. Ekle',
+ 'Add Sales Order' => 'Satýþ Sipariþi Ekle',
+ 'Address' => 'Adres',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Kontak',
+ 'Continue' => 'Devam',
+ 'Copies' => 'Copies',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Açýklama',
+ 'E-mail' => 'Posta',
+ 'E-mail address missing!' => 'Posta adresi yok!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date missing!' => 'Fatura Tarihi yok!',
+ 'Invoice Number missing!' => 'Fatura Numarasý yok!',
+ 'Item not on file!' => 'Bu kalem dosyada yok!',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Message' => 'Message',
+ 'Name' => 'Ýsim',
+ 'No.' => 'No.',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Number' => 'Numara',
+ 'Number missing in Row' => 'Sýrada Numara yok!',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'Order' => 'Sipariþ',
+ 'Order Date missing!' => 'Sipariþ Tarihi yok!',
+ 'Order Number missing!' => 'Sipariþ Numarasý yok!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Paketleme Listesi',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Parça',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Fiyat',
+ 'Printer' => 'Yazýcý',
+ 'Project' => 'Project',
+ 'Purchase Order' => 'Satýnalma Sipariþi',
+ 'Qty' => 'Adet',
+ 'Recd' => 'Recd',
+ 'Required by' => 'Talep tarihi:',
+ 'Sales Order' => 'Satýþ Sipariþi',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Aþaðýdaki kalemlerden birini seç',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Service' => 'servis',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Subject' => 'Subject',
+ 'To' => 'Bitiþ',
+ 'Unit' => 'Birim',
+ 'What type of item is this?' => 'Bu ne çeþit bir kalemdir?',
+ 'emailed to' => 'emailed to',
+ 'sent to printer' => 'sent to printer',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'devam' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/ir b/sql-ledger/locale/tr/ir
new file mode 100644
index 0000000..c62536a
--- /dev/null
+++ b/sql-ledger/locale/tr/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Hesap',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Satýnalma Sip. Ekle',
+ 'Add Sales Order' => 'Satýþ Sipariþi Ekle',
+ 'Address' => 'Adres',
+ 'Amount' => 'Miktar',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Are you sure you want to delete Invoice Number' => 'Fatura Numarasýný silmek istediðinizden emin misiniz? Fiþ: ',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Onayla!',
+ 'Contact' => 'Kontak',
+ 'Continue' => 'Devam',
+ 'Copies' => 'Copies',
+ 'Currency' => 'Para Birimi',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Tarih',
+ 'Date Due' => 'Vade Tarihi',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Delete' => 'Sil',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Açýklama',
+ 'E-mail' => 'Posta',
+ 'E-mail address missing!' => 'Posta adresi yok!',
+ 'Edit Purchase Invoice' => 'Edit Purchase Invoice',
+ 'Exch' => 'D.Kuru',
+ 'Exchangerate' => 'Döviz Kuru',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Fatura Tarihi',
+ 'Invoice Date missing!' => 'Fatura Tarihi yok!',
+ 'Invoice Number' => 'Fatura No',
+ 'Invoice Number missing!' => 'Fatura Numarasý yok!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'Bu kalem dosyada yok!',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Message' => 'Message',
+ 'Name' => 'Ýsim',
+ 'No.' => 'No.',
+ 'Notes' => 'Notlar:',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Number' => 'Numara',
+ 'Number missing in Row' => 'Sýrada Numara yok!',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'Order' => 'Sipariþ',
+ 'Order Date missing!' => 'Sipariþ Tarihi yok!',
+ 'Order Number' => 'Sipariþ No',
+ 'Order Number missing!' => 'Sipariþ Numarasý yok!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Paketleme Listesi',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Parça',
+ 'Payment date missing!' => 'Ödeme Tarihi yok',
+ 'Payments' => 'Ödemeler',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Fiyat',
+ 'Printer' => 'Yazýcý',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Satýnalma Sipariþi',
+ 'Qty' => 'Adet',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Kaydet',
+ 'Required by' => 'Talep tarihi:',
+ 'Sales Order' => 'Satýþ Sipariþi',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Aþaðýdaki kalemlerden birini seç',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Service' => 'servis',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Source' => 'Kaynak',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Aratoplam',
+ 'Tax Included' => 'Vergi Dahil',
+ 'To' => 'Bitiþ',
+ 'Total' => 'Toplam',
+ 'Unit' => 'Birim',
+ 'Update' => 'Update',
+ 'Vendor' => 'Satýcý',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'Bu ne çeþit bir kalemdir?',
+ 'Yes' => 'Evet',
+ 'ea' => 'ad',
+ 'emailed to' => 'emailed to',
+ 'sent to printer' => 'sent to printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'devam' => 'continue',
+ 'sil' => 'delete',
+ 'sipariþ' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'update' => 'update',
+ 'evet' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/is b/sql-ledger/locale/tr/is
new file mode 100644
index 0000000..29342c3
--- /dev/null
+++ b/sql-ledger/locale/tr/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Hesap',
+ 'Add Purchase Order' => 'Satýnalma Sip. Ekle',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Satýþ Sipariþi Ekle',
+ 'Address' => 'Adres',
+ 'Amount' => 'Miktar',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Are you sure you want to delete Invoice Number' => 'Fatura Numarasýný silmek istediðinizden emin misiniz? Fiþ: ',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Onayla!',
+ 'Contact' => 'Kontak',
+ 'Continue' => 'Devam',
+ 'Copies' => 'Copies',
+ 'Credit Limit' => 'Kredi Limiti',
+ 'Currency' => 'Para Birimi',
+ 'Customer' => 'Alýcý',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Tarih',
+ 'Date Due' => 'Vade Tarihi',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Delete' => 'Sil',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Açýklama',
+ 'E-mail' => 'Posta',
+ 'E-mail address missing!' => 'Posta adresi yok!',
+ 'Edit Sales Invoice' => 'Edit Sales Invoice',
+ 'Exch' => 'D.Kuru',
+ 'Exchangerate' => 'Döviz Kuru',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'In-line' => 'In-line',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date' => 'Fatura Tarihi',
+ 'Invoice Date missing!' => 'Fatura Tarihi yok!',
+ 'Invoice Number' => 'Fatura No',
+ 'Invoice Number missing!' => 'Fatura Numarasý yok!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => 'Bu kalem dosyada yok!',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Message' => 'Message',
+ 'Name' => 'Ýsim',
+ 'No.' => 'No.',
+ 'Notes' => 'Notlar:',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Number' => 'Numara',
+ 'Number missing in Row' => 'Sýrada Numara yok!',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'Order' => 'Sipariþ',
+ 'Order Date missing!' => 'Sipariþ Tarihi yok!',
+ 'Order Number' => 'Sipariþ No',
+ 'Order Number missing!' => 'Sipariþ Numarasý yok!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Paketleme Listesi',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Parça',
+ 'Payment date missing!' => 'Ödeme Tarihi yok',
+ 'Payments' => 'Ödemeler',
+ 'Phone' => 'Telefon',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Fiyat',
+ 'Print' => 'Print',
+ 'Printer' => 'Yazýcý',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Satýnalma Sipariþi',
+ 'Qty' => 'Adet',
+ 'Recd' => 'Recd',
+ 'Record in' => 'Kaydet',
+ 'Remaining' => 'Remaining',
+ 'Required by' => 'Talep tarihi:',
+ 'Sales Order' => 'Satýþ Sipariþi',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Aþaðýdaki kalemlerden birini seç',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Service' => 'servis',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Source' => 'Kaynak',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Aratoplam',
+ 'Tax Included' => 'Vergi Dahil',
+ 'To' => 'Bitiþ',
+ 'Total' => 'Toplam',
+ 'Unit' => 'Birim',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'Bu ne çeþit bir kalemdir?',
+ 'Yes' => 'Evet',
+ 'ea' => 'ad',
+ 'emailed to' => 'emailed to',
+ 'sent to printer' => 'sent to printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'devam' => 'continue',
+ 'sil' => 'delete',
+ 'posta' => 'e_mail',
+ 'sipariþ' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'evet' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/login b/sql-ledger/locale/tr/login
new file mode 100644
index 0000000..3c6fb0b
--- /dev/null
+++ b/sql-ledger/locale/tr/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'Program bilgileri',
+ 'Accounting' => 'Muhasebe',
+ 'Database Host' => 'Veritabaný Hostu',
+ 'Dataset' => 'Veriseti',
+ 'Incorrect Dataset version!' => 'Incorrect Dataset version!',
+ 'Incorrect Password!' => 'Yanlýþ Þifre!',
+ 'Licensed to' => 'Lisans Sahibi:',
+ 'Login' => 'Giriþ',
+ 'Name' => 'Ýsim',
+ 'Password' => 'Þifre',
+ 'User' => 'Kullanýcý',
+ 'Version' => 'Versiyon',
+ 'You are logged out!' => 'You are logged out!',
+ 'You did not enter a name!' => 'Ýsim girmediniz!',
+ 'is not a member!' => 'is not a member!',
+ 'localhost' => 'Yerelhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'giriþ' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/menu b/sql-ledger/locale/tr/menu
new file mode 100644
index 0000000..45a4296
--- /dev/null
+++ b/sql-ledger/locale/tr/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'Borçlar',
+ 'AP Aging' => 'Gecikmiþ Borçlar',
+ 'AR' => 'Alacaklar',
+ 'AR Aging' => 'Gecikmiþ Alacaklar',
+ 'Accounting Menu' => 'Muhasebe Menüsü',
+ 'Add Account' => 'Hesap Ekle',
+ 'Add Assembly' => 'Grup Ekle',
+ 'Add Customer' => 'Alýcý Ekle',
+ 'Add GIFI' => 'Add GIFI',
+ 'Add Part' => 'Parça Ekle',
+ 'Add Project' => 'Add Project',
+ 'Add Service' => 'Hizmet Ekle',
+ 'Add Transaction' => 'Ýþlem Ekle',
+ 'Add Vendor' => 'Satýcý Ekle',
+ 'Assemblies' => 'Gruplar',
+ 'Audit Control' => 'Audit Control',
+ 'Backup' => 'Yedekleme',
+ 'Balance Sheet' => 'Bilanço',
+ 'Cash' => 'Cash',
+ 'Chart of Accounts' => 'Hesap Planý',
+ 'Check' => 'Check',
+ 'Customers' => 'Customers',
+ 'General Ledger' => 'Defteri Kebir',
+ 'Goods & Services' => 'Goods & Services',
+ 'HTML Templates' => 'HTML Templates',
+ 'Income Statement' => 'Gelir Tablosu',
+ 'Invoice' => 'Fatura',
+ 'LaTeX Templates' => 'LaTeX Templates',
+ 'List Accounts' => 'List Accounts',
+ 'List GIFI' => 'List GIFI',
+ 'Logout' => 'Logout',
+ 'Order Entry' => 'Sipariþ Giriþi',
+ 'Packing List' => 'Paketleme Listesi',
+ 'Parts' => 'Parçalar',
+ 'Payment' => 'Ödeme',
+ 'Payments' => 'Ödemeler',
+ 'Preferences' => 'Tercihler',
+ 'Projects' => 'Projects',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Purchase Order' => 'Satýnalma Sipariþi',
+ 'Purchase Orders' => 'Satýnalma Sipariþleri',
+ 'Receipt' => 'Receipt',
+ 'Receipts' => 'Receipts',
+ 'Reconciliation' => 'Reconciliation',
+ 'Reports' => 'Raporlar',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Sales Order' => 'Satýþ Sipariþi',
+ 'Sales Orders' => 'Satýþ Sipariþleri',
+ 'Save to File' => 'Dosyaya Kaydet',
+ 'Send by E-Mail' => 'E-postayla gönder',
+ 'Services' => 'Servisler',
+ 'Statement' => 'Statement',
+ 'Stock Assembly' => 'Grubu Stokla',
+ 'Stylesheet' => 'Düzen Sayfasý',
+ 'System' => 'System',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'Transactions' => 'Ýþlemler',
+ 'Trial Balance' => 'Proforma Bilanço',
+ 'Vendors' => 'Vendors',
+ 'Version' => 'Versiyon',
+ 'localhost' => 'Yerelhost',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/oe b/sql-ledger/locale/tr/oe
new file mode 100644
index 0000000..31415c6
--- /dev/null
+++ b/sql-ledger/locale/tr/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => 'Ekle',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => 'Satýnalma Sip. Ekle',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => 'Satýþ Sipariþi Ekle',
+ 'Address' => 'Adres',
+ 'Amount' => 'Miktar',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Are you sure you want to delete Order Number' => 'Sipariþ Numarasýný silmek istediðinizden emin misiniz? Fiþ: ',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Bin',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Cannot delete order!',
+ 'Cannot save order!' => 'Cannot save order!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Closed',
+ 'Confirm!' => 'Onayla!',
+ 'Contact' => 'Kontak',
+ 'Continue' => 'Devam',
+ 'Copies' => 'Copies',
+ 'Credit Limit' => 'Kredi Limiti',
+ 'Curr' => 'Curr',
+ 'Currency' => 'Para Birimi',
+ 'Customer' => 'Alýcý',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => 'Tarih',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Delete' => 'Sil',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => 'Açýklama',
+ 'E-mail' => 'Posta',
+ 'E-mail address missing!' => 'Posta adresi yok!',
+ 'Edit Purchase Order' => 'Alýþ Sipariþini Düzenle',
+ 'Edit Sales Order' => 'Satýþ Sipariþini Düzenle',
+ 'Exchangerate' => 'Döviz Kuru',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => 'Faks',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'From' => 'Baþlangýç',
+ 'ID' => 'ID',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Raporla',
+ 'Invoice' => 'Fatura',
+ 'Invoice Date missing!' => 'Fatura Tarihi yok!',
+ 'Invoice Number missing!' => 'Fatura Numarasý yok!',
+ 'Item not on file!' => 'Bu kalem dosyada yok!',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Message' => 'Message',
+ 'Name' => 'Ýsim',
+ 'No.' => 'No.',
+ 'Notes' => 'Notlar:',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Number' => 'Numara',
+ 'Number missing in Row' => 'Sýrada Numara yok!',
+ 'O' => 'O',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'Open' => 'Open',
+ 'Order' => 'Sipariþ',
+ 'Order Date' => 'Sipariþ Tarihi',
+ 'Order Date missing!' => 'Sipariþ Tarihi yok!',
+ 'Order Number' => 'Sipariþ No',
+ 'Order Number missing!' => 'Sipariþ Numarasý yok!',
+ 'Order deleted!' => 'Order deleted!',
+ 'Order saved!' => 'Order saved!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Paketleme Listesi',
+ 'Packing List Date missing!' => 'Packing List Date missing!',
+ 'Packing List Number missing!' => 'Packing List Number missing!',
+ 'Part' => 'Parça',
+ 'Phone' => 'Telefon',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Fiyat',
+ 'Print' => 'Print',
+ 'Printer' => 'Yazýcý',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => 'Satýnalma Sipariþi',
+ 'Purchase Orders' => 'Satýnalma Sipariþleri',
+ 'Qty' => 'Adet',
+ 'Recd' => 'Recd',
+ 'Remaining' => 'Remaining',
+ 'Required by' => 'Talep tarihi:',
+ 'Sales Order' => 'Satýþ Sipariþi',
+ 'Sales Orders' => 'Satýþ Sipariþleri',
+ 'Save' => 'Kaydet',
+ 'Save as new' => 'Save as new',
+ 'Screen' => 'Screen',
+ 'Select from one of the items below' => 'Aþaðýdaki kalemlerden birini seç',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Service' => 'servis',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Aratoplam',
+ 'Tax' => 'Vergi',
+ 'Tax Included' => 'Vergi Dahil',
+ 'Terms: Net' => 'Þartlar: Net',
+ 'To' => 'Bitiþ',
+ 'Total' => 'Toplam',
+ 'Unit' => 'Birim',
+ 'Update' => 'Update',
+ 'Vendor' => 'Satýcý',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => 'Bu ne çeþit bir kalemdir?',
+ 'Yes' => 'Evet',
+ 'days' => 'gün. ',
+ 'ea' => 'ad',
+ 'emailed to' => 'emailed to',
+ 'sent to printer' => 'sent to printer',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'ekle' => 'add',
+ 'devam' => 'continue',
+ 'sil' => 'delete',
+ 'posta' => 'e_mail',
+ 'fatura' => 'invoice',
+ 'print' => 'print',
+ 'kaydet' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'evet' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/pe b/sql-ledger/locale/tr/pe
new file mode 100644
index 0000000..d010eca
--- /dev/null
+++ b/sql-ledger/locale/tr/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Ekle',
+ 'Add Project' => 'Add Project',
+ 'All' => 'Hepsi',
+ 'Continue' => 'Devam',
+ 'Delete' => 'Sil',
+ 'Description' => 'Açýklama',
+ 'Edit Project' => 'Edit Project',
+ 'Number' => 'Numara',
+ 'Orphaned' => 'Orphaned',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Project Number missing!',
+ 'Project deleted!' => 'Project deleted!',
+ 'Project saved!' => 'Project saved!',
+ 'Projects' => 'Projects',
+ 'Save' => 'Kaydet',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'ekle' => 'add',
+ 'devam' => 'continue',
+ 'sil' => 'delete',
+ 'kaydet' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/rc b/sql-ledger/locale/tr/rc
new file mode 100644
index 0000000..4e71d0c
--- /dev/null
+++ b/sql-ledger/locale/tr/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Hesap',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'Devam',
+ 'Date' => 'Tarih',
+ 'Deposit' => 'Deposit',
+ 'Description' => 'Açýklama',
+ 'Difference' => 'Difference',
+ 'Done' => 'Done',
+ 'Exchangerate Difference' => 'Exchangerate Difference',
+ 'From' => 'Baþlangýç',
+ 'Out of balance!' => 'Out of balance!',
+ 'Payment' => 'Ödeme',
+ 'Reconciliation' => 'Reconciliation',
+ 'Select all' => 'Select all',
+ 'Source' => 'Kaynak',
+ 'Statement Balance' => 'Statement Balance',
+ 'To' => 'Bitiþ',
+ 'Update' => 'Update',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'devam' => 'continue',
+ 'done' => 'done',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/tr/rp b/sql-ledger/locale/tr/rp
new file mode 100644
index 0000000..7807262
--- /dev/null
+++ b/sql-ledger/locale/tr/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'Gecikmiþ Borçlar',
+ 'AR Aging' => 'Gecikmiþ Alacaklar',
+ 'Account' => 'Hesap',
+ 'Accounts' => 'Accounts',
+ 'Amount' => 'Miktar',
+ 'Apr' => 'Nis',
+ 'April' => 'Nisan',
+ 'Attachment' => 'Attachment',
+ 'Aug' => 'Aðu',
+ 'August' => 'Aðustos',
+ 'Balance Sheet' => 'Bilanço',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => '...kýyasla',
+ 'Continue' => 'Devam',
+ 'Copies' => 'Copies',
+ 'Credit' => 'Alacak',
+ 'Current' => 'Current',
+ 'Customer' => 'Alýcý',
+ 'Date' => 'Tarih',
+ 'Debit' => 'Borç',
+ 'Dec' => 'Ara',
+ 'December' => 'Aralýk',
+ 'Decimalplaces' => 'Decimalplaces',
+ 'Description' => 'Açýklama',
+ 'Due' => 'Vade',
+ 'E-mail' => 'Posta',
+ 'E-mail Statement to' => 'E-mail Statement to',
+ 'Feb' => 'Þub',
+ 'February' => 'Þubat',
+ 'From' => 'Baþlangýç',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Baþlýk',
+ 'ID' => 'ID',
+ 'In-line' => 'In-line',
+ 'Include in Report' => 'Raporla',
+ 'Income Statement' => 'Gelir Tablosu',
+ 'Invoice' => 'Fatura',
+ 'Jan' => 'Oca',
+ 'January' => 'Ocak',
+ 'Jul' => 'Tem',
+ 'July' => 'Temmuz',
+ 'Jun' => 'Haz',
+ 'June' => 'Haziran',
+ 'Mar' => 'Mar',
+ 'March' => 'Mart',
+ 'May' => 'May',
+ 'May ' => 'Mayýs',
+ 'Message' => 'Message',
+ 'N/A' => 'N/A',
+ 'Nothing selected!' => 'Nothing selected!',
+ 'Nov' => 'Kas',
+ 'November' => 'Kasým',
+ 'Oct' => 'Eki',
+ 'October' => 'Ekim',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Ödemeler',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Print',
+ 'Printer' => 'Yazýcý',
+ 'Receipts' => 'Receipts',
+ 'Report for' => 'Report for',
+ 'Retained Earnings' => 'Net Dönem Karý (Zararý)',
+ 'Screen' => 'Screen',
+ 'Select all' => 'Select all',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => 'Eyl',
+ 'September' => 'Eylül',
+ 'Source' => 'Kaynak',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Statement',
+ 'Statement sent to' => 'Statement sent to',
+ 'Statements sent to printer!' => 'Statements sent to printer!',
+ 'Subject' => 'Subject',
+ 'Subtotal' => 'Aratoplam',
+ 'Tax' => 'Vergi',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'To' => 'Bitiþ',
+ 'Total' => 'Toplam',
+ 'Trial Balance' => 'Proforma Bilanço',
+ 'Vendor' => 'Satýcý',
+ 'as at' => 'as at',
+ 'collected on sales' => 'collected on sales',
+ 'for Period' => 'Dönem:',
+ 'paid on purchases' => 'paid on purchases',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'devam' => 'continue',
+ 'posta' => 'e_mail',
+ 'print' => 'print',
+ 'select_all' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/COPYING b/sql-ledger/locale/tw/COPYING
new file mode 100644
index 0000000..835a214
--- /dev/null
+++ b/sql-ledger/locale/tw/COPYING
@@ -0,0 +1,25 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2001
+#
+# Traditional Chinese texts:
+#
+# Author: ¤è²»³Ç (Jacky Fang) <jackyf@5star.com.tw>
+# Chien Hsin Chang <werther@elixus.org>
+# Autrijus Tang <autrijus@autrijus.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/tw/LANGUAGE b/sql-ledger/locale/tw/LANGUAGE
new file mode 100644
index 0000000..b8ba9c3
--- /dev/null
+++ b/sql-ledger/locale/tw/LANGUAGE
@@ -0,0 +1 @@
+Traditional Chinese
diff --git a/sql-ledger/locale/tw/admin b/sql-ledger/locale/tw/admin
new file mode 100644
index 0000000..6c19c11
--- /dev/null
+++ b/sql-ledger/locale/tw/admin
@@ -0,0 +1,122 @@
+$self{texts} = {
+ 'Access Control' => 'Åv­­±±¨î',
+ 'Accounting' => '·|­p',
+ 'Add User' => '·s¼W¨Ï¥ÎªÌ',
+ 'Address' => '¦a§}',
+ 'Administration' => '¨t²ÎºÞ²z',
+ 'Administrator' => 'Administrator',
+ 'All Datasets up to date!' => '©Ò¦³¸ê®Æ¬Ò¤w§ó·s!',
+ 'Change Admin Password' => '§ó§ïºÞ²z­û±K½X',
+ 'Change Password' => '§ó§ï±K½X',
+ 'Character Set' => '¦r¤¸¶°',
+ 'Click on login name to edit!' => '½Ð«öµn¤J¦WºÙ¥H¶i¦æ­×§ï!',
+ 'Company' => '¤½¥q¦WºÙ',
+ 'Connect to' => '³sµ²¨ì',
+ 'Continue' => 'Ä~Äò',
+ 'Create Chart of Accounts' => '«Ø¥ß±b¤á¹Ïªí',
+ 'Create Dataset' => '«Ø¥ß¸ê®Æ¶°',
+ 'DBI not installed!' => '¥¼¦w¸Ë DBI ¼Ò²Õ!',
+ 'Database' => '¸ê®Æ®w',
+ 'Database Administration' => '¸ê®Æ®wºÞ²z',
+ 'Database Driver not checked!' => '¥¼¿ï©w¸ê®Æ®wÅX°Êµ{¦¡!',
+ 'Database User missing!' => '¥¼«ü©ú¸ê®Æ®w¨Ï¥ÎªÌ!',
+ 'Dataset' => '¸ê®Æ¶°',
+ 'Dataset missing!' => '¥¼«ü©ú¸ê®Æ¶°!',
+ 'Dataset updated!' => 'Dataset updated!',
+ 'Date Format' => '¤é´Á®æ¦¡',
+ 'Delete' => '§R°£',
+ 'Delete Dataset' => '§R°£¸ê®Æ¶°',
+ 'Directory' => '¥Ø¿ý',
+ 'Driver' => 'ÅX°Êµ{¦¡',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'Edit User' => '½s¿è¨Ï¥ÎªÌ',
+ 'Existing Datasets' => '¬J¦³ªº¸ê®Æ¶°',
+ 'Fax' => '¶Ç¯u',
+ 'Host' => '¥D¾÷',
+ 'Hostname missing!' => '¥¼«ü©ú¥D¾÷¦WºÙ!',
+ 'Incorrect Password!' => '±K½X¿ù»~!',
+ 'Language' => '»y¨t',
+ 'Leave host and port field empty unless you want to make a remote connection.' => '°£«D±z·Q­n¶i¦æ»·ºÝ³s½u, §_«h½Ð±N¥D¾÷¤Î°ð¸¹¯d¥Õ.',
+ 'Login' => 'µn¤J',
+ 'Name' => '¦WºÙ',
+ 'New Templates' => '·s¼W¼Òª©',
+ 'No Database Drivers available!' => '¨S¦³¥i¥ÎªºÅX°Êµ{¦¡!',
+ 'No Dataset selected!' => '¥¼¿ï©w¸ê®Æ¶°!',
+ 'Nothing to delete!' => '¨S¦³¥i§R°£ªº¶µ¥Ø',
+ 'Number Format' => '¼Æ¦r®æ¦¡',
+ 'Oracle Database Administration' => 'Oracle ¸ê®Æ®wºÞ²z',
+ 'Password' => '±K½X',
+ 'Password changed!' => 'Password changed!',
+ 'Pg Database Administration' => 'Pg ¸ê®Æ®wºÞ²z',
+ 'Phone' => '¹q¸Ü¸¹½X',
+ 'Port' => '°ð¸¹',
+ 'Port missing!' => '¥¼«ü©ú°ð¸¹!',
+ 'Printer' => '¦Lªí¾÷',
+ 'Save' => 'Àx¦s',
+ 'Select a Dataset to delete and press "Continue"' => '½Ð¿ï¾Ü±ý§R°£ªº¸ê®Æ¶°, ¦A«ö "Ä~Äò"',
+ 'Setup Templates' => '³]©w¼Òª©',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'ñ¦W',
+ 'Stylesheet' => '¼Ë¦¡ªí',
+ 'Templates' => '¼Òª©',
+ 'The following Datasets are not in use and can be deleted' => '¤U¦C¸ê®Æ¶°¨Ã¥¼¨Ï¥Î, ¥i¥H§R°£',
+ 'The following Datasets need to be updated' => '¤U¦C¸ê®Æ¶°»Ý­n§ó·s',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => '³o¬O¹ï¬J¦s¸ê®Æ¨Ó·½ªºªì¨BÀˬd. ¦b¦¹¶¥¬q, ¤£·|§R°£©Î·s¼W¥ô¦ó¸ê®Æ!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => '­Y­n·s¼W¸s²Õ¤ºªº¨Ï¥ÎªÌ, ½Ð½s¿è¦WºÙ, §ó§ïµn¤J¦W, µM«áÀx¦s. ³o¼Ë¤@¨Ó, ·s¨Ï¥ÎªÌ·|«O¯d¬Û¦PªºÅܼÆ, ¨Ã¥H·sªºµn¤J¦W¦s¤J.',
+ 'Update Dataset' => '§ó·s¸ê®Æ¶°',
+ 'Use Templates' => '¨Ï¥Î¼Òª©',
+ 'User' => '¨Ï¥ÎªÌ',
+ 'User deleted!' => 'User deleted!',
+ 'User saved!' => 'User saved!',
+ 'Version' => 'ª©¥»',
+ 'You must enter a host and port for local and remote connections!' => '±z¥²»ÝÁä¤J¥D¾÷¤Î°ð¸¹, ¥H¶i¦æ¥»¾÷©Î»·ºÝ³s½u!',
+ 'does not exist' => '¤£¦s¦b',
+ 'is already a member!' => '¤w¸g¬O¦¨­û¤F!',
+ 'localhost' => 'localhost',
+ 'successfully created!' => '¦¨¥\«Ø¥ß!',
+ 'successfully deleted!' => '¦¨¥\§R°£!',
+ 'website' => 'ºô¯¸',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ '·s¼w¨Ï¥ÎªÌ' => 'add_user',
+ '§ó§ïºÞ²z­û±k½x' => 'change_admin_password',
+ '§ó§ï±k½x' => 'change_password',
+ 'Ä~Äò' => 'continue',
+ '«Ø¥ß¸ê®Æ¶°' => 'create_dataset',
+ '§r°£' => 'delete',
+ '§r°£¸ê®Æ¶°' => 'delete_dataset',
+ 'µn¤j' => 'login',
+ 'oracle_¸ê®Æ®wºÞ²z' => 'oracle_database_administration',
+ 'pg_¸ê®Æ®wºÞ²z' => 'pg_database_administration',
+ 'Àx¦s' => 'save',
+ '§ó·s¸ê®Æ¶°' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/all b/sql-ledger/locale/tw/all
new file mode 100644
index 0000000..016df2c
--- /dev/null
+++ b/sql-ledger/locale/tw/all
@@ -0,0 +1,487 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'À³¥I±b´Ú',
+ 'AP Aging' => 'À³¥I±bÄÖ¤ÀªR',
+ 'AP Transaction' => '',
+ 'AP Transactions' => 'À³¥I±b¥Ø',
+ 'AR' => 'À³¦¬±b´Ú',
+ 'AR Aging' => 'À³¦¬±bÄÖ¤ÀªR',
+ 'AR Transaction' => '',
+ 'AR Transactions' => 'À³¦¬±b¥Ø',
+ 'About' => 'Ãö©ó',
+ 'Access Control' => 'Åv­­±±¨î',
+ 'Account' => '¬ì¥Ø',
+ 'Account Number' => '¬ì¥Ø½s¸¹',
+ 'Account Number missing!' => 'º|¶ñ¬ì¥Ø½s¸¹!',
+ 'Account Type' => '¬ì¥ØÃþ§O',
+ 'Account Type missing!' => 'º|¶ñ¬ì¥ØÃþ§O!',
+ 'Account deleted!' => '',
+ 'Account saved!' => '',
+ 'Accounting' => '·|­p',
+ 'Accounting Menu' => '·|­p¿ï³æ',
+ 'Accounts' => '±b¤á',
+ 'Active' => '',
+ 'Add' => '·s¼W',
+ 'Add Account' => '·s¼W¬ì¥Ø',
+ 'Add Accounts Payables Transaction' => '',
+ 'Add Accounts Receivables Transaction' => '',
+ 'Add Assembly' => '·s¼W°Ó«~',
+ 'Add Customer' => '·s¼W«È¤á',
+ 'Add GIFI' => '·s¼W GIFI',
+ 'Add General Ledger Transaction' => '·s¼WÁ`±b',
+ 'Add Part' => '·s¼W­ì®Æ',
+ 'Add Project' => '',
+ 'Add Purchase Invoice' => '',
+ 'Add Purchase Order' => '·s¼W±ÄÁʳæ',
+ 'Add Sales Invoice' => '',
+ 'Add Sales Order' => '·s¼W¾P³f³æ',
+ 'Add Service' => '·s¼WªA°È',
+ 'Add Transaction' => '·s¼W±b¥Ø',
+ 'Add User' => '·s¼W¨Ï¥ÎªÌ',
+ 'Add Vendor' => '·s¼W¼t°Ó',
+ 'Address' => '¦a§}',
+ 'Administration' => '¨t²ÎºÞ²z',
+ 'Administrator' => '',
+ 'All' => '¥þ³¡',
+ 'All Datasets up to date!' => '©Ò¦³¸ê®Æ¬Ò¤w§ó·s!',
+ 'Amount' => 'Á`­p',
+ 'Amount Due' => '',
+ 'Amount does not equal applied!' => '',
+ 'Amount missing!' => '',
+ 'Applied' => '',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Are you sure you want to delete Invoice Number' => '±z½T©w­n§R°£µo²¼½s¸¹',
+ 'Are you sure you want to delete Order Number' => '±z¬O§_½T©w­n§R°£­q³æ',
+ 'Are you sure you want to delete Transaction' => '±z½T©w­n§R°£±b¥Ø',
+ 'Assemblies' => '°Ó«~',
+ 'Assemblies restocked!' => '',
+ 'Assembly Number missing!' => '¬dµL¦¹°Ó«~!',
+ 'Asset' => '¸ê²£',
+ 'Attachment' => 'ªþÀÉ',
+ 'Audit Control' => '½]®Ö±±¨î',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'BOM' => '',
+ 'Backup' => '³Æ¥÷',
+ 'Backup sent to' => '³Æ¥÷±H°e¨ì',
+ 'Balance' => '',
+ 'Balance Sheet' => '¸ê²£­t¶Åªí',
+ 'Bcc' => '',
+ 'Bin' => '½c',
+ 'Books are open' => '±bï¤w¶}±Ò',
+ 'Bought' => '¤wÁʶR',
+ 'Business Number' => '²Î¤@½s¸¹',
+ 'C' => '',
+ 'COGS' => '³f¾P¦¨¥»',
+ 'Cannot delete account!' => '',
+ 'Cannot delete customer!' => '',
+ 'Cannot delete default account!' => '',
+ 'Cannot delete invoice!' => '',
+ 'Cannot delete item already invoiced!' => '',
+ 'Cannot delete item on order!' => 'µLªk§R°£³æ¤Wªº¶µ¥Ø!',
+ 'Cannot delete item which is part of an assembly!' => '',
+ 'Cannot delete item!' => '',
+ 'Cannot delete order!' => '',
+ 'Cannot delete transaction!' => '',
+ 'Cannot delete vendor!' => '',
+ 'Cannot have a value in both Debit and Credit!' => '',
+ 'Cannot post a transaction without a value!' => '',
+ 'Cannot post invoice for a closed period!' => '',
+ 'Cannot post invoice!' => '',
+ 'Cannot post payment for a closed period!' => '',
+ 'Cannot post payment!' => '',
+ 'Cannot post transaction for a closed period!' => 'µLªk¦b¤wÃö³¬ªº®É¬q¤º¥[¤J¥æ©ö!',
+ 'Cannot post transaction!' => '',
+ 'Cannot process payment for a closed period!' => '',
+ 'Cannot save account!' => '',
+ 'Cannot save order!' => '',
+ 'Cannot save preferences!' => '',
+ 'Cannot stock assemblies!' => '',
+ 'Cash' => '',
+ 'Cash based' => '',
+ 'Cc' => '',
+ 'Change Admin Password' => '§ó§ïºÞ²z­û±K½X',
+ 'Change Password' => '§ó§ï±K½X',
+ 'Character Set' => '¦r¤¸¶°',
+ 'Chart of Accounts' => '·|­p¬ì¥Øªí',
+ 'Check' => '',
+ 'Check printed!' => '',
+ 'Check printing failed!' => '',
+ 'Cleared Balance' => '',
+ 'Click on login name to edit!' => '½Ð«öµn¤J¦WºÙ¥H¶i¦æ­×§ï!',
+ 'Close Books up to' => 'Ãö³¬¨ì¦¹¬°¤îªº±bï',
+ 'Closed' => '¤wÃö³¬',
+ 'Company' => '¤½¥q¦WºÙ',
+ 'Compare to' => '¹ï·Ó',
+ 'Confirm!' => '¤J±b¦¨¥\!',
+ 'Connect to' => '³sµ²¨ì',
+ 'Contact' => '³sµ¸¤H',
+ 'Continue' => 'Ä~Äò',
+ 'Copies' => '«þ¨©',
+ 'Copy to COA' => '½Æ»s¨ì COA',
+ 'Create Chart of Accounts' => '«Ø¥ß±b¤á¹Ïªí',
+ 'Create Dataset' => '«Ø¥ß¸ê®Æ¶°',
+ 'Credit' => '¶U¤è',
+ 'Credit Limit' => '«H¥ÎÃB«×',
+ 'Curr' => '¥Ø«e',
+ 'Currency' => '¹ô§O',
+ 'Current' => '',
+ 'Customer' => '«È¤á',
+ 'Customer deleted!' => '',
+ 'Customer missing!' => '',
+ 'Customer not on file!' => '',
+ 'Customer saved!' => '',
+ 'Customers' => '',
+ 'DBI not installed!' => '¥¼¦w¸Ë DBI ¼Ò²Õ!',
+ 'Database' => '¸ê®Æ®w',
+ 'Database Administration' => '¸ê®Æ®wºÞ²z',
+ 'Database Driver not checked!' => '¥¼¿ï©w¸ê®Æ®wÅX°Êµ{¦¡!',
+ 'Database Host' => '¸ê®Æ®w¥D¾÷',
+ 'Database User missing!' => '¥¼«ü©ú¸ê®Æ®w¨Ï¥ÎªÌ!',
+ 'Dataset' => '¸ê®Æ¶°',
+ 'Dataset missing!' => '¥¼«ü©ú¸ê®Æ¶°!',
+ 'Dataset updated!' => '',
+ 'Date' => '¤é´Á',
+ 'Date Due' => 'À³¥I¤é´Á',
+ 'Date Format' => '¤é´Á®æ¦¡',
+ 'Date Paid' => '¥I´Ú¤é´Á',
+ 'Date missing!' => '',
+ 'Debit' => '­É¤è',
+ 'Debit and credit out of balance!' => '­É¶U¤£¥­¿Å!',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Decimalplaces' => '',
+ 'Delete' => '§R°£',
+ 'Delete Account' => '§R°£¬ì¥Ø',
+ 'Delete Dataset' => '§R°£¸ê®Æ¶°',
+ 'Delivery Date' => '',
+ 'Deposit' => '',
+ 'Description' => '»¡©ú',
+ 'Difference' => '',
+ 'Directory' => '¥Ø¿ý',
+ 'Discount' => '§é¦©',
+ 'Done' => '',
+ 'Drawing' => '',
+ 'Driver' => 'ÅX°Êµ{¦¡',
+ 'Dropdown Limit' => '',
+ 'Due' => '¨ì´Á',
+ 'Due Date' => '¨ì´Á¤é',
+ 'Due Date missing!' => 'º|¶ñ¨ì´Á¤é!',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'E-mail Statement to' => '',
+ 'E-mail address missing!' => 'º|¶ñ¹q¤l¶l¥ó¦ì§}!',
+ 'Edit' => '',
+ 'Edit Account' => '½s¿è¬ì¥Ø',
+ 'Edit Accounts Payables Transaction' => '',
+ 'Edit Accounts Receivables Transaction' => '',
+ 'Edit Assembly' => '½s¿è°Ó«~',
+ 'Edit GIFI' => '½s¿è GIFI',
+ 'Edit General Ledger Transaction' => '½s¿èÁ`±b',
+ 'Edit Part' => '½s¿è­ì®Æ',
+ 'Edit Preferences for' => '³]©w¨Ï¥ÎªÌ',
+ 'Edit Project' => '',
+ 'Edit Purchase Invoice' => '',
+ 'Edit Purchase Order' => '½s¿è±ÄÁʳæ',
+ 'Edit Sales Invoice' => '',
+ 'Edit Sales Order' => '½s¿è¾P³f³æ',
+ 'Edit Service' => '½s¿èªA°È',
+ 'Edit Template' => '½s¿è¼Òª©',
+ 'Edit User' => '½s¿è¨Ï¥ÎªÌ',
+ 'Employee' => '',
+ 'Enforce transaction reversal for all dates' => '±j¨î©Ò¦³¤é´Áªº¥æ©ö¦^´_',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => '½ÐÁä¤J¥H«_¸¹¤À¹jªº­^¤å¦r¥À, ¨C¶µ¤£¶W¹L¤T­Ó¦r (¦p CAD:USD:EUR), §@¬°±zªº¥»°ê¤Î¥~°ê³f¹ô',
+ 'Equity' => 'ªÑÅv',
+ 'Exch' => '¶×²v',
+ 'Exchangerate' => '¶×²v',
+ 'Exchangerate Difference' => '',
+ 'Exchangerate for payment missing!' => '',
+ 'Exchangerate missing!' => '',
+ 'Existing Datasets' => '¬J¦³ªº¸ê®Æ¶°',
+ 'Expense' => '¶O¥Î',
+ 'Expense Account' => '¶O¥Î¬ì¥Ø',
+ 'Expense/Asset' => '¶O¥Î/¸ê²£',
+ 'Extended' => '',
+ 'Fax' => '¶Ç¯u',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'Foreign Exchange Gain' => '¥~¶×¦¬¯q',
+ 'Foreign Exchange Loss' => '¥~¶×·l¥¢',
+ 'From' => '±q',
+ 'GIFI' => '',
+ 'GIFI deleted!' => '',
+ 'GIFI missing!' => '¥¼«ü©ú GIFI!',
+ 'GIFI saved!' => '',
+ 'GL Transaction' => '',
+ 'General Ledger' => 'Á`±b',
+ 'Goods & Services' => '³fª«¤ÎªA°È',
+ 'HTML Templates' => 'HTML ªí³æ',
+ 'Heading' => 'ªíÀY',
+ 'Host' => '¥D¾÷',
+ 'Hostname missing!' => '¥¼«ü©ú¥D¾÷¦WºÙ!',
+ 'ID' => '½s¸¹',
+ 'Image' => '',
+ 'In-line' => '¦æ¤º',
+ 'Include in Report' => '¤@¨ÖÅã¥Ü',
+ 'Include in drop-down menus' => '¥]§t¦b¤U©Ô¦¡¿ï³æ¤¤',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => '­n±N³o­Ó«È¤á/¼t°Ó¥[¤JÀ³¥[µ|²M³æ?',
+ 'Income' => '¦¬¯q',
+ 'Income Account' => '·l¯q¬ì¥Ø',
+ 'Income Statement' => '·l¯qªí',
+ 'Incorrect Dataset version!' => '¸ê®Æ¶°ª©¥»¿ù»~!',
+ 'Incorrect Password!' => '±K½X¿ù»~!',
+ 'Individual Items' => '²Õ¦¨¶µ¥Ø',
+ 'Inventory' => '®w¦s',
+ 'Inventory Account' => '¦s³f¬ì¥Ø',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => '¦b°±¥Î¦¹¶µ²Õ¦X«~¤§«e, ¦s³f¼Æ¶q¥²»Ý¬°¹s!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => '°±¥Î¦¹¶µ¹s¥ó¤§«e, ¦s³f¼Æ¶q¥²»Ý¬°¹s!',
+ 'Inventory quantity must be zero!' => '¦s³f¼Æ¶q¥²»Ý¬°¹s!',
+ 'Invoice' => 'µo²¼',
+ 'Invoice Date' => 'µo²¼¤é´Á',
+ 'Invoice Date missing!' => 'µo²¼¤é´Á¿ù»~!',
+ 'Invoice Number' => 'µo²¼½s¸¹',
+ 'Invoice Number missing!' => 'µo²¼½s¸¹¿ù»~!',
+ 'Invoice deleted!' => '',
+ 'Invoice posted!' => '',
+ 'Invoices' => '',
+ 'Is this a summary account to record' => '¦¹¬°Á`µ²¬ì¥Ø¶Ü?',
+ 'Item deleted!' => '',
+ 'Item not on file!' => '¬dµL¦¹¶µ¥Ø',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'LaTeX Templates' => 'LaTex ¼Òª©',
+ 'Language' => '»y¨t',
+ 'Last Cost' => '¤W¤@µ§¦¨¥»',
+ 'Last Invoice Number' => '¤W¤@µ§µo²¼½s¸¹',
+ 'Last Numbers & Default Accounts' => '¤W¤@µ§½s¸¹¤Î¹w³]¬ì¥Ø',
+ 'Last Purchase Order Number' => '«e¦¸±ÄÁʳ渹',
+ 'Last Sales Order Number' => '«e¦¸¾P',
+ 'Leave host and port field empty unless you want to make a remote connection.' => '°£«D±z·Q­n¶i¦æ»·ºÝ³s½u, §_«h½Ð±N¥D¾÷¤Î°ð¸¹¯d¥Õ.',
+ 'Liability' => '­t¶Å',
+ 'Licensed to' => '±ÂÅv¤©',
+ 'Line Total' => 'Á`¦C¼Æ',
+ 'Link' => '³sµ²',
+ 'Link Accounts' => '³sµ²¬ì¥Ø',
+ 'List Accounts' => '¦C¥X±b¸¹',
+ 'List GIFI' => '¦C¥X GIFI',
+ 'List Price' => '¶i»ù',
+ 'List Transactions' => '¦C¥X±b¥Ø',
+ 'Login' => 'µn¤J',
+ 'Logout' => 'µn¥X',
+ 'Make' => '»s³y',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Message' => '°T®§',
+ 'Microfiche' => '',
+ 'Model' => '«¬¸¹',
+ 'N/A' => '¤£¾A¥Î',
+ 'Name' => '¦WºÙ',
+ 'Name missing!' => '',
+ 'New Templates' => '·s¼W¼Òª©',
+ 'No' => '§_',
+ 'No Database Drivers available!' => '¨S¦³¥i¥ÎªºÅX°Êµ{¦¡!',
+ 'No Dataset selected!' => '¥¼¿ï©w¸ê®Æ¶°!',
+ 'No email address for' => '¥¼«ü©ú¹q¤l¶l¥ó¦ì¸m',
+ 'No.' => '',
+ 'Notes' => '³Æµù',
+ 'Nothing applied!' => '',
+ 'Nothing selected!' => '',
+ 'Nothing to delete!' => '¨S¦³¥i§R°£ªº¶µ¥Ø',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Number' => '½s¸¹',
+ 'Number Format' => '¼Æ¦r®æ¦¡',
+ 'Number missing in Row' => '¦¹¦C¤¤¯Ê¤Ö¼Æ­È',
+ 'O' => '',
+ 'Obsolete' => '°±¥Î',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'On Hand' => '¦s¶q',
+ 'On Order' => '',
+ 'Open' => '¶}±Ò',
+ 'Oracle Database Administration' => 'Oracle ¸ê®Æ®wºÞ²z',
+ 'Order' => '­q³æ',
+ 'Order Date' => '¤U³æ¤é´Á',
+ 'Order Date missing!' => '¥¼«ü©ú¤U³æ¤é´Á!',
+ 'Order Entry' => '¤U³æ¶µ¥Ø',
+ 'Order Number' => '­q³æ½s¸¹',
+ 'Order Number missing!' => '¥¼«ü©ú­q³æ½s¸¹!',
+ 'Order deleted!' => '',
+ 'Order saved!' => '',
+ 'Ordered' => '',
+ 'Orphaned' => 'µL¥D',
+ 'Out of balance!' => '',
+ 'PDF' => '',
+ 'Packing List' => '¥X³f³æ',
+ 'Packing List Date missing!' => '¥¼«ü©ú¥]¸Ë²M³æ¤é´Á!',
+ 'Packing List Number missing!' => '¥¼«ü©ú¥]¸Ë²M³æ½s¸¹!',
+ 'Paid' => '¤w¥I',
+ 'Paid in full' => '',
+ 'Part' => '­ì®Æ',
+ 'Part Number missing!' => 'º|¶ñ­ì®Æ½s¸¹!',
+ 'Parts' => '­ì®Æ',
+ 'Parts Inventory' => '®w¦s­ì®Æ',
+ 'Password' => '±K½X',
+ 'Password changed!' => '',
+ 'Payables' => 'À³¥I¬ì¥Ø',
+ 'Payment' => '¥I´Ú¤è¦¡',
+ 'Payment date missing!' => '¥¼«ü©ú¥I´Ú¤é´Á!',
+ 'Payment posted!' => '',
+ 'Payments' => '¥I´Ú',
+ 'Pg Database Administration' => 'Pg ¸ê®Æ®wºÞ²z',
+ 'Phone' => '¹q¸Ü¸¹½X',
+ 'Port' => '°ð¸¹',
+ 'Port missing!' => '¥¼«ü©ú°ð¸¹!',
+ 'Post' => '',
+ 'Post as new' => '',
+ 'Postscript' => '',
+ 'Preferences' => '­Ó¤H³]©w',
+ 'Preferences saved!' => '­Ó¤H³]©w¤wÀx¦s!',
+ 'Price' => '»ù®æ',
+ 'Print' => '',
+ 'Printer' => '¦Lªí¾÷',
+ 'Project' => '',
+ 'Project Number missing!' => '',
+ 'Project deleted!' => '',
+ 'Project not on file!' => '',
+ 'Project saved!' => '',
+ 'Projects' => '',
+ 'Purchase Invoice' => '',
+ 'Purchase Order' => '±ÄÁʳæ',
+ 'Purchase Orders' => '±ÄÁʳæ',
+ 'Qty' => '¼Æ¶q',
+ 'ROP' => '¦A­qÂI',
+ 'Rate' => 'µ|²v',
+ 'Recd' => '',
+ 'Receipt' => '',
+ 'Receipts' => '',
+ 'Receivables' => 'À³¦¬¬ì¥Ø',
+ 'Reconciliation' => '',
+ 'Record in' => '°O¿ý©ó',
+ 'Reference' => '',
+ 'Reference missing!' => '',
+ 'Remaining' => '©|¾l',
+ 'Report for' => '³øªí¨Ó·½',
+ 'Reports' => '³øªí',
+ 'Required by' => '¤l¶µ¥Ø',
+ 'Retained Earnings' => '«O¯d¬Õ¾l',
+ 'Sales' => '·~°È',
+ 'Sales Invoice' => '',
+ 'Sales Order' => '¾P³f³æ',
+ 'Sales Orders' => '¾P³f³æ',
+ 'Save' => 'Àx¦s',
+ 'Save as new' => '',
+ 'Save to File' => 'Àx¦s¦ÜÀÉ®×',
+ 'Screen' => '¿Ã¹õ',
+ 'Select a Dataset to delete and press "Continue"' => '½Ð¿ï¾Ü±ý§R°£ªº¸ê®Æ¶°, ¦A«ö "Ä~Äò"',
+ 'Select all' => '',
+ 'Select from one of the items below' => '©ó¤U¦C¶µ¥Ø¤¤¿ï¾Ü¤@¶µ',
+ 'Select from one of the names below' => '',
+ 'Select from one of the projects below' => '',
+ 'Select postscript or PDF!' => '',
+ 'Sell Price' => '°â»ù',
+ 'Send by E-Mail' => '¥H¹q¤l¶l¥ó±H°e',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Service' => 'ªA°È',
+ 'Service Items' => 'ªA°È¶µ¥Ø',
+ 'Service Number missing!' => 'º|¶ñªA°È½s¸¹!',
+ 'Services' => 'ªA°È',
+ 'Setup Templates' => '³]©w¼Òª©',
+ 'Ship' => '',
+ 'Ship to' => '',
+ 'Ship via' => '',
+ 'Short' => 'µu',
+ 'Signature' => 'ñ¦W',
+ 'Sold' => '¤w½æ¥X',
+ 'Source' => '¨Ó·½',
+ 'Standard' => '¼Ð·Ç',
+ 'Statement' => '',
+ 'Statement Balance' => '',
+ 'Statement sent to' => '',
+ 'Statements sent to printer!' => '',
+ 'Stock Assembly' => '½LÂI',
+ 'Stylesheet' => '¼Ë¦¡ªí',
+ 'Subject' => '¼ÐÃD',
+ 'Subtotal' => '¤p­p',
+ 'System' => '¨t²Î',
+ 'Tax' => 'µ|ª÷',
+ 'Tax Accounts' => 'µ|ª÷¬ì¥Ø',
+ 'Tax Included' => '¤£¦¬ªA°È¶O',
+ 'Tax collected' => '',
+ 'Tax paid' => '',
+ 'Taxable' => 'À³µ|',
+ 'Template saved!' => '',
+ 'Templates' => '¼Òª©',
+ 'Terms: Net' => '²¼´Á²b­p',
+ 'The following Datasets are not in use and can be deleted' => '¤U¦C¸ê®Æ¶°¨Ã¥¼¨Ï¥Î, ¥i¥H§R°£',
+ 'The following Datasets need to be updated' => '¤U¦C¸ê®Æ¶°»Ý­n§ó·s',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => '³o¬O¹ï¬J¦s¸ê®Æ¨Ó·½ªºªì¨BÀˬd. ¦b¦¹¶¥¬q, ¤£·|§R°£©Î·s¼W¥ô¦ó¸ê®Æ!',
+ 'To' => '¦Ü',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => '­Y­n·s¼W¸s²Õ¤ºªº¨Ï¥ÎªÌ, ½Ð½s¿è¦WºÙ, §ó§ïµn¤J¦W, µM«áÀx¦s. ³o¼Ë¤@¨Ó, ·s¨Ï¥ÎªÌ·|«O¯d¬Û¦PªºÅܼÆ, ¨Ã¥H·sªºµn¤J¦W¦s¤J.',
+ 'Top Level' => '',
+ 'Total' => 'Á`­p',
+ 'Transaction Date missing!' => 'º|¶ñ±b¥Ø¤é´Á!',
+ 'Transaction deleted!' => '',
+ 'Transaction posted!' => '',
+ 'Transaction reversal enforced for all dates' => '±j¨î¦^´_©Ò¦³¤é´Áªº¥æ©ö',
+ 'Transaction reversal enforced up to' => '±j¨î¦^´_¥æ©öª½¨ì',
+ 'Transactions' => '±b¥Ø',
+ 'Transactions exist, cannot delete customer!' => '¦¹«È¤á¤w¦³±b¥Ø, ¤£¯à§R°£!',
+ 'Transactions exist, cannot delete vendor!' => '¦¹¼t°Ó¤w¦³±b¥Ø, ¤£¯à§R°£!',
+ 'Transactions exist; cannot delete account!' => '©|¦³¥æ©ö¦s¦b; µLªk§R°£±b¤á!',
+ 'Trial Balance' => '¸Õºâªí',
+ 'Unit' => '³æ¦ì',
+ 'Unit of measure' => '«×¶q³æ¦ì',
+ 'Update' => '',
+ 'Update Dataset' => '§ó·s¸ê®Æ¶°',
+ 'Updated' => '',
+ 'Use Templates' => '¨Ï¥Î¼Òª©',
+ 'User' => '¨Ï¥ÎªÌ',
+ 'User deleted!' => '',
+ 'User saved!' => '',
+ 'Vendor' => '¼t°Ó',
+ 'Vendor deleted!' => '',
+ 'Vendor missing!' => '',
+ 'Vendor not on file!' => '',
+ 'Vendor saved!' => '',
+ 'Vendors' => '',
+ 'Version' => 'ª©¥»',
+ 'Weight' => '­«¶q',
+ 'Weight Unit' => '­«¶q³æ¦ì',
+ 'What type of item is this?' => '¦¹¶µ¥Øªº«¬ºA?',
+ 'Year End' => '·|­p¦~«×',
+ 'Yes' => '¬O',
+ 'You are logged out!' => '',
+ 'You did not enter a name!' => '±z¨Ã¥¼Áä¤J¦WºÙ!',
+ 'You must enter a host and port for local and remote connections!' => '±z¥²»ÝÁä¤J¥D¾÷¤Î°ð¸¹, ¥H¶i¦æ¥»¾÷©Î»·ºÝ³s½u!',
+ 'as at' => '',
+ 'collected on sales' => '¦b¾P³f®Éµ²²M',
+ 'days' => '¤é',
+ 'does not exist' => '¤£¦s¦b',
+ 'ea' => '­Ó',
+ 'emailed to' => '¤w±H¦Ü',
+ 'for Period' => '´Á¶¡',
+ 'hr' => 'hr',
+ 'is already a member!' => '¤w¸g¬O¦¨­û¤F!',
+ 'is not a member!' => '¨Ã¤£¬O¦¨­û!',
+ 'localhost' => 'localhost',
+ 'paid on purchases' => '¦b±ÄÁʮɵ²²M',
+ 'sent to printer' => '°e¦Ü¦Lªí¾÷',
+ 'successfully created!' => '¦¨¥\«Ø¥ß!',
+ 'successfully deleted!' => '¦¨¥\§R°£!',
+ 'to' => '',
+ 'website' => 'ºô¯¸',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/am b/sql-ledger/locale/tw/am
new file mode 100644
index 0000000..77df0d3
--- /dev/null
+++ b/sql-ledger/locale/tw/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'À³¥I±b´Ú',
+ 'AR' => 'À³¦¬±b´Ú',
+ 'Account' => '¬ì¥Ø',
+ 'Account Number' => '¬ì¥Ø½s¸¹',
+ 'Account Number missing!' => 'º|¶ñ¬ì¥Ø½s¸¹!',
+ 'Account Type' => '¬ì¥ØÃþ§O',
+ 'Account Type missing!' => 'º|¶ñ¬ì¥ØÃþ§O!',
+ 'Account deleted!' => 'Account deleted!',
+ 'Account saved!' => 'Account saved!',
+ 'Add Account' => '·s¼W¬ì¥Ø',
+ 'Add GIFI' => '·s¼W GIFI',
+ 'Address' => '¦a§}',
+ 'Asset' => '¸ê²£',
+ 'Audit Control' => '½]®Ö±±¨î',
+ 'Backup sent to' => '³Æ¥÷±H°e¨ì',
+ 'Books are open' => '±bï¤w¶}±Ò',
+ 'Business Number' => '²Î¤@½s¸¹',
+ 'COGS' => '³f¾P¦¨¥»',
+ 'Cannot delete account!' => 'Cannot delete account!',
+ 'Cannot delete default account!' => 'Cannot delete default account!',
+ 'Cannot save account!' => 'Cannot save account!',
+ 'Cannot save preferences!' => 'Cannot save preferences!',
+ 'Character Set' => '¦r¤¸¶°',
+ 'Chart of Accounts' => '·|­p¬ì¥Øªí',
+ 'Close Books up to' => 'Ãö³¬¨ì¦¹¬°¤îªº±bï',
+ 'Company' => '¤½¥q¦WºÙ',
+ 'Continue' => 'Ä~Äò',
+ 'Copy to COA' => '½Æ»s¨ì COA',
+ 'Credit' => '¶U¤è',
+ 'Date Format' => '¤é´Á®æ¦¡',
+ 'Debit' => '­É¤è',
+ 'Delete' => '§R°£',
+ 'Delete Account' => '§R°£¬ì¥Ø',
+ 'Description' => '»¡©ú',
+ 'Dropdown Limit' => 'Dropdown Limit',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'Edit' => 'Edit',
+ 'Edit Account' => '½s¿è¬ì¥Ø',
+ 'Edit GIFI' => '½s¿è GIFI',
+ 'Edit Preferences for' => '³]©w¨Ï¥ÎªÌ',
+ 'Edit Template' => '½s¿è¼Òª©',
+ 'Enforce transaction reversal for all dates' => '±j¨î©Ò¦³¤é´Áªº¥æ©ö¦^´_',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => '½ÐÁä¤J¥H«_¸¹¤À¹jªº­^¤å¦r¥À, ¨C¶µ¤£¶W¹L¤T­Ó¦r (¦p CAD:USD:EUR), §@¬°±zªº¥»°ê¤Î¥~°ê³f¹ô',
+ 'Equity' => 'ªÑÅv',
+ 'Expense' => '¶O¥Î',
+ 'Expense Account' => '¶O¥Î¬ì¥Ø',
+ 'Expense/Asset' => '¶O¥Î/¸ê²£',
+ 'Fax' => '¶Ç¯u',
+ 'Foreign Exchange Gain' => '¥~¶×¦¬¯q',
+ 'Foreign Exchange Loss' => '¥~¶×·l¥¢',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI deleted!',
+ 'GIFI missing!' => '¥¼«ü©ú GIFI!',
+ 'GIFI saved!' => 'GIFI saved!',
+ 'Heading' => 'ªíÀY',
+ 'Include in drop-down menus' => '¥]§t¦b¤U©Ô¦¡¿ï³æ¤¤',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => '­n±N³o­Ó«È¤á/¼t°Ó¥[¤JÀ³¥[µ|²M³æ?',
+ 'Income' => '¦¬¯q',
+ 'Income Account' => '·l¯q¬ì¥Ø',
+ 'Inventory' => '®w¦s',
+ 'Inventory Account' => '¦s³f¬ì¥Ø',
+ 'Is this a summary account to record' => '¦¹¬°Á`µ²¬ì¥Ø¶Ü?',
+ 'Language' => '»y¨t',
+ 'Last Invoice Number' => '¤W¤@µ§µo²¼½s¸¹',
+ 'Last Numbers & Default Accounts' => '¤W¤@µ§½s¸¹¤Î¹w³]¬ì¥Ø',
+ 'Last Purchase Order Number' => '«e¦¸±ÄÁʳ渹',
+ 'Last Sales Order Number' => '«e¦¸¾P',
+ 'Liability' => '­t¶Å',
+ 'Link' => '³sµ²',
+ 'Name' => '¦WºÙ',
+ 'No' => '§_',
+ 'No email address for' => '¥¼«ü©ú¹q¤l¶l¥ó¦ì¸m',
+ 'Number' => '½s¸¹',
+ 'Number Format' => '¼Æ¦r®æ¦¡',
+ 'Parts Inventory' => '®w¦s­ì®Æ',
+ 'Password' => '±K½X',
+ 'Payables' => 'À³¥I¬ì¥Ø',
+ 'Payment' => '¥I´Ú¤è¦¡',
+ 'Phone' => '¹q¸Ü¸¹½X',
+ 'Preferences saved!' => '­Ó¤H³]©w¤wÀx¦s!',
+ 'Rate' => 'µ|²v',
+ 'Receivables' => 'À³¦¬¬ì¥Ø',
+ 'Sales' => '·~°È',
+ 'Save' => 'Àx¦s',
+ 'Service Items' => 'ªA°È¶µ¥Ø',
+ 'Ship via' => 'Ship via',
+ 'Signature' => 'ñ¦W',
+ 'Stylesheet' => '¼Ë¦¡ªí',
+ 'Tax' => 'µ|ª÷',
+ 'Tax Accounts' => 'µ|ª÷¬ì¥Ø',
+ 'Template saved!' => 'Template saved!',
+ 'Transaction reversal enforced for all dates' => '±j¨î¦^´_©Ò¦³¤é´Áªº¥æ©ö',
+ 'Transaction reversal enforced up to' => '±j¨î¦^´_¥æ©öª½¨ì',
+ 'Transactions exist; cannot delete account!' => '©|¦³¥æ©ö¦s¦b; µLªk§R°£±b¤á!',
+ 'Weight Unit' => '­«¶q³æ¦ì',
+ 'Year End' => '·|­p¦~«×',
+ 'Yes' => '¬O',
+ 'does not exist' => '¤£¦s¦b',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ '·s¼w¬ì¥Ø' => 'add_account',
+ 'Ä~Äò' => 'continue',
+ '½Æ»s¨ì_coa' => 'copy_to_coa',
+ '§r°£' => 'delete',
+ 'edit' => 'edit',
+ '½s¿è¬ì¥Ø' => 'edit_account',
+ 'Àx¦s' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/ap b/sql-ledger/locale/tw/ap
new file mode 100644
index 0000000..c251797
--- /dev/null
+++ b/sql-ledger/locale/tw/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AP Transactions' => 'À³¥I±b¥Ø',
+ 'Account' => '¬ì¥Ø',
+ 'Add Accounts Payables Transaction' => 'Add Accounts Payables Transaction',
+ 'Address' => '¦a§}',
+ 'Amount' => 'Á`­p',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Are you sure you want to delete Transaction' => '±z½T©w­n§R°£±b¥Ø',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'µLªk¦b¤wÃö³¬ªº®É¬q¤º¥[¤J¥æ©ö!',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => '¤wÃö³¬',
+ 'Confirm!' => '¤J±b¦¨¥\!',
+ 'Continue' => 'Ä~Äò',
+ 'Currency' => '¹ô§O',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => '¤é´Á',
+ 'Date Paid' => '¥I´Ú¤é´Á',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Delete' => '§R°£',
+ 'Description' => '»¡©ú',
+ 'Due Date' => '¨ì´Á¤é',
+ 'Due Date missing!' => 'º|¶ñ¨ì´Á¤é!',
+ 'Edit Accounts Payables Transaction' => 'Edit Accounts Payables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => '¶×²v',
+ 'Exchangerate' => '¶×²v',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'From' => '±q',
+ 'ID' => '½s¸¹',
+ 'Include in Report' => '¤@¨ÖÅã¥Ü',
+ 'Invoice' => 'µo²¼',
+ 'Invoice Date' => 'µo²¼¤é´Á',
+ 'Invoice Date missing!' => 'µo²¼¤é´Á¿ù»~!',
+ 'Invoice Number' => 'µo²¼½s¸¹',
+ 'Invoice Number missing!' => 'µo²¼½s¸¹¿ù»~!',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Notes' => '³Æµù',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Number' => '½s¸¹',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'Open' => '¶}±Ò',
+ 'Order' => '­q³æ',
+ 'Order Number' => '­q³æ½s¸¹',
+ 'Paid' => '¤w¥I',
+ 'Payment date missing!' => '¥¼«ü©ú¥I´Ú¤é´Á!',
+ 'Payments' => '¥I´Ú',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Source' => '¨Ó·½',
+ 'Subtotal' => '¤p­p',
+ 'Tax' => 'µ|ª÷',
+ 'Tax Included' => '¤£¦¬ªA°È¶O',
+ 'To' => '¦Ü',
+ 'Total' => 'Á`­p',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor' => '¼t°Ó',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => '¬O',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'add_accounts_payables_transaction' => 'add_accounts_payables_transaction',
+ 'Ä~Äò' => 'continue',
+ '§r°£' => 'delete',
+ 'edit_accounts_payables_transaction' => 'edit_accounts_payables_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'update' => 'update',
+ '¬o' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/ar b/sql-ledger/locale/tw/ar
new file mode 100644
index 0000000..a864b41
--- /dev/null
+++ b/sql-ledger/locale/tw/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'AR Transaction',
+ 'AR Transactions' => 'À³¦¬±b¥Ø',
+ 'Account' => '¬ì¥Ø',
+ 'Add Accounts Receivables Transaction' => 'Add Accounts Receivables Transaction',
+ 'Address' => '¦a§}',
+ 'Amount' => 'Á`­p',
+ 'Amount Due' => 'Amount Due',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Are you sure you want to delete Transaction' => '±z½T©w­n§R°£±b¥Ø',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cannot post transaction for a closed period!' => 'µLªk¦b¤wÃö³¬ªº®É¬q¤º¥[¤J¥æ©ö!',
+ 'Cannot post transaction!' => 'Cannot post transaction!',
+ 'Closed' => '¤wÃö³¬',
+ 'Confirm!' => '¤J±b¦¨¥\!',
+ 'Continue' => 'Ä~Äò',
+ 'Credit Limit' => '«H¥ÎÃB«×',
+ 'Currency' => '¹ô§O',
+ 'Customer' => '«È¤á',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => '¤é´Á',
+ 'Date Paid' => '¥I´Ú¤é´Á',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Delete' => '§R°£',
+ 'Description' => '»¡©ú',
+ 'Due Date' => '¨ì´Á¤é',
+ 'Due Date missing!' => 'º|¶ñ¨ì´Á¤é!',
+ 'Edit Accounts Receivables Transaction' => 'Edit Accounts Receivables Transaction',
+ 'Employee' => 'Employee',
+ 'Exch' => '¶×²v',
+ 'Exchangerate' => '¶×²v',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'From' => '±q',
+ 'ID' => '½s¸¹',
+ 'Include in Report' => '¤@¨ÖÅã¥Ü',
+ 'Invoice' => 'µo²¼',
+ 'Invoice Date' => 'µo²¼¤é´Á',
+ 'Invoice Date missing!' => 'µo²¼¤é´Á¿ù»~!',
+ 'Invoice Number' => 'µo²¼½s¸¹',
+ 'Invoice Number missing!' => 'µo²¼½s¸¹¿ù»~!',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Notes' => '³Æµù',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Number' => '½s¸¹',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'Open' => '¶}±Ò',
+ 'Order' => '­q³æ',
+ 'Order Number' => '­q³æ½s¸¹',
+ 'Paid' => '¤w¥I',
+ 'Payment date missing!' => '¥¼«ü©ú¥I´Ú¤é´Á!',
+ 'Payments' => '¥I´Ú',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Remaining' => '©|¾l',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Source' => '¨Ó·½',
+ 'Subtotal' => '¤p­p',
+ 'Tax' => 'µ|ª÷',
+ 'Tax Included' => '¤£¦¬ªA°È¶O',
+ 'To' => '¦Ü',
+ 'Total' => 'Á`­p',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => '¬O',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ar_transaction' => 'ar_transaction',
+ 'Ä~Äò' => 'continue',
+ '§r°£' => 'delete',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ '¬o' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/arap b/sql-ledger/locale/tw/arap
new file mode 100644
index 0000000..e82552c
--- /dev/null
+++ b/sql-ledger/locale/tw/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => '¦a§}',
+ 'Continue' => 'Ä~Äò',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Description' => '»¡©ú',
+ 'Number' => '½s¸¹',
+ 'Project not on file!' => 'Project not on file!',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'Ä~Äò' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/ca b/sql-ledger/locale/tw/ca
new file mode 100644
index 0000000..677a41f
--- /dev/null
+++ b/sql-ledger/locale/tw/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => '¬ì¥Ø',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => '·|­p¬ì¥Øªí',
+ 'Credit' => '¶U¤è',
+ 'Date' => '¤é´Á',
+ 'Debit' => '­É¤è',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Description' => '»¡©ú',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'From' => '±q',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => '¤@¨ÖÅã¥Ü',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'List Transactions' => '¦C¥X±b¥Ø',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'Reference' => 'Reference',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Subtotal' => '¤p­p',
+ 'To' => '¦Ü',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ '¦c¥x±b¥Ø' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/cp b/sql-ledger/locale/tw/cp
new file mode 100644
index 0000000..af8421a
--- /dev/null
+++ b/sql-ledger/locale/tw/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => '¬ì¥Ø',
+ 'Address' => '¦a§}',
+ 'Amount' => 'Á`­p',
+ 'Amount does not equal applied!' => 'Amount does not equal applied!',
+ 'Amount missing!' => 'Amount missing!',
+ 'Applied' => 'Applied',
+ 'Cannot post payment!' => 'Cannot post payment!',
+ 'Cannot process payment for a closed period!' => 'Cannot process payment for a closed period!',
+ 'Check' => 'Check',
+ 'Check printed!' => 'Check printed!',
+ 'Check printing failed!' => 'Check printing failed!',
+ 'Continue' => 'Ä~Äò',
+ 'Currency' => '¹ô§O',
+ 'Customer' => '«È¤á',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => '¤é´Á',
+ 'Date missing!' => 'Date missing!',
+ 'Description' => '»¡©ú',
+ 'Due' => '¨ì´Á',
+ 'Exchangerate' => '¶×²v',
+ 'From' => '±q',
+ 'Invoice' => 'µo²¼',
+ 'Invoices' => 'Invoices',
+ 'Nothing applied!' => 'Nothing applied!',
+ 'Number' => '½s¸¹',
+ 'Paid in full' => 'Paid in full',
+ 'Payment' => '¥I´Ú¤è¦¡',
+ 'Payment posted!' => 'Payment posted!',
+ 'Post' => 'Post',
+ 'Print' => 'Print',
+ 'Printer' => '¦Lªí¾÷',
+ 'Project not on file!' => 'Project not on file!',
+ 'Receipt' => 'Receipt',
+ 'Reference' => 'Reference',
+ 'Screen' => '¿Ã¹õ',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'To' => '¦Ü',
+ 'Update' => 'Update',
+ 'Vendor' => '¼t°Ó',
+ 'Vendor not on file!' => 'Vendor not on file!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'Ä~Äò' => 'continue',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/ct b/sql-ledger/locale/tw/ct
new file mode 100644
index 0000000..1597c9f
--- /dev/null
+++ b/sql-ledger/locale/tw/ct
@@ -0,0 +1,69 @@
+$self{texts} = {
+ 'Add' => '·s¼W',
+ 'Address' => '¦a§}',
+ 'All' => '¥þ³¡',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'Cannot delete customer!',
+ 'Cannot delete vendor!' => 'Cannot delete vendor!',
+ 'Cc' => 'Cc',
+ 'Contact' => '³sµ¸¤H',
+ 'Continue' => 'Ä~Äò',
+ 'Credit Limit' => '«H¥ÎÃB«×',
+ 'Customer deleted!' => 'Customer deleted!',
+ 'Customer saved!' => 'Customer saved!',
+ 'Customers' => 'Customers',
+ 'Delete' => '§R°£',
+ 'Discount' => '§é¦©',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'Fax' => '¶Ç¯u',
+ 'Include in Report' => '¤@¨ÖÅã¥Ü',
+ 'Invoice' => 'µo²¼',
+ 'Name' => '¦WºÙ',
+ 'Name missing!' => 'Name missing!',
+ 'Notes' => '³Æµù',
+ 'Number' => '½s¸¹',
+ 'Order' => '­q³æ',
+ 'Orphaned' => 'µL¥D',
+ 'Phone' => '¹q¸Ü¸¹½X',
+ 'Save' => 'Àx¦s',
+ 'Ship to' => 'Ship to',
+ 'Tax Included' => '¤£¦¬ªA°È¶O',
+ 'Taxable' => 'À³µ|',
+ 'Terms: Net' => '²¼´Á²b­p',
+ 'Transactions exist, cannot delete customer!' => '¦¹«È¤á¤w¦³±b¥Ø, ¤£¯à§R°£!',
+ 'Transactions exist, cannot delete vendor!' => '¦¹¼t°Ó¤w¦³±b¥Ø, ¤£¯à§R°£!',
+ 'Vendor deleted!' => 'Vendor deleted!',
+ 'Vendor saved!' => 'Vendor saved!',
+ 'Vendors' => 'Vendors',
+ 'days' => '¤é',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ '·s¼w' => 'add',
+ 'Ä~Äò' => 'continue',
+ '§r°£' => 'delete',
+ 'µo²¼' => 'invoice',
+ '­q³æ' => 'order',
+ 'Àx¦s' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/gl b/sql-ledger/locale/tw/gl
new file mode 100644
index 0000000..ce671a9
--- /dev/null
+++ b/sql-ledger/locale/tw/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'AP Transaction',
+ 'AR Transaction' => 'AR Transaction',
+ 'Account' => '¬ì¥Ø',
+ 'Add General Ledger Transaction' => '·s¼WÁ`±b',
+ 'Address' => '¦a§}',
+ 'All' => '¥þ³¡',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Are you sure you want to delete Transaction' => '±z½T©w­n§R°£±b¥Ø',
+ 'Asset' => '¸ê²£',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'Cannot delete transaction!',
+ 'Cannot have a value in both Debit and Credit!' => 'Cannot have a value in both Debit and Credit!',
+ 'Cannot post a transaction without a value!' => 'Cannot post a transaction without a value!',
+ 'Cannot post transaction for a closed period!' => 'µLªk¦b¤wÃö³¬ªº®É¬q¤º¥[¤J¥æ©ö!',
+ 'Confirm!' => '¤J±b¦¨¥\!',
+ 'Continue' => 'Ä~Äò',
+ 'Credit' => '¶U¤è',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => '¤é´Á',
+ 'Debit' => '­É¤è',
+ 'Debit and credit out of balance!' => '­É¶U¤£¥­¿Å!',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Delete' => '§R°£',
+ 'Description' => '»¡©ú',
+ 'Edit General Ledger Transaction' => '½s¿èÁ`±b',
+ 'Equity' => 'ªÑÅv',
+ 'Expense' => '¶O¥Î',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'From' => '±q',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'GL Transaction',
+ 'General Ledger' => 'Á`±b',
+ 'ID' => '½s¸¹',
+ 'Include in Report' => '¤@¨ÖÅã¥Ü',
+ 'Income' => '¦¬¯q',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'Liability' => '­t¶Å',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Notes' => '³Æµù',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Number' => '½s¸¹',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Reference' => 'Reference',
+ 'Reference missing!' => 'Reference missing!',
+ 'Reports' => '³øªí',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Source' => '¨Ó·½',
+ 'Subtotal' => '¤p­p',
+ 'To' => '¦Ü',
+ 'Transaction Date missing!' => 'º|¶ñ±b¥Ø¤é´Á!',
+ 'Transaction deleted!' => 'Transaction deleted!',
+ 'Transaction posted!' => 'Transaction posted!',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'Yes' => '¬O',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'Ä~Äò' => 'continue',
+ '§r°£' => 'delete',
+ 'gl_transaction' => 'gl_transaction',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'update' => 'update',
+ '¬o' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/ic b/sql-ledger/locale/tw/ic
new file mode 100644
index 0000000..7be481d
--- /dev/null
+++ b/sql-ledger/locale/tw/ic
@@ -0,0 +1,205 @@
+$self{texts} = {
+ 'Active' => 'Active',
+ 'Add' => '·s¼W',
+ 'Add Assembly' => '·s¼W°Ó«~',
+ 'Add Part' => '·s¼W­ì®Æ',
+ 'Add Purchase Order' => '·s¼W±ÄÁʳæ',
+ 'Add Sales Order' => '·s¼W¾P³f³æ',
+ 'Add Service' => '·s¼WªA°È',
+ 'Address' => '¦a§}',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Assemblies' => '°Ó«~',
+ 'Assemblies restocked!' => 'Assemblies restocked!',
+ 'Assembly Number missing!' => '¬dµL¦¹°Ó«~!',
+ 'Attachment' => 'ªþÀÉ',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'Bcc',
+ 'Bin' => '½c',
+ 'Bought' => '¤wÁʶR',
+ 'COGS' => '³f¾P¦¨¥»',
+ 'Cannot delete item already invoiced!' => 'Cannot delete item already invoiced!',
+ 'Cannot delete item on order!' => 'µLªk§R°£³æ¤Wªº¶µ¥Ø!',
+ 'Cannot delete item which is part of an assembly!' => 'Cannot delete item which is part of an assembly!',
+ 'Cannot delete item!' => 'Cannot delete item!',
+ 'Cannot stock assemblies!' => 'Cannot stock assemblies!',
+ 'Cc' => 'Cc',
+ 'Contact' => '³sµ¸¤H',
+ 'Continue' => 'Ä~Äò',
+ 'Copies' => '«þ¨©',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Delete' => '§R°£',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => '»¡©ú',
+ 'Drawing' => 'Drawing',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'E-mail address missing!' => 'º|¶ñ¹q¤l¶l¥ó¦ì§}!',
+ 'Edit Assembly' => '½s¿è°Ó«~',
+ 'Edit Part' => '½s¿è­ì®Æ',
+ 'Edit Service' => '½s¿èªA°È',
+ 'Expense' => '¶O¥Î',
+ 'Extended' => 'Extended',
+ 'Fax' => '¶Ç¯u',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'From' => '±q',
+ 'Image' => 'Image',
+ 'In-line' => '¦æ¤º',
+ 'Include in Report' => '¤@¨ÖÅã¥Ü',
+ 'Income' => '¦¬¯q',
+ 'Individual Items' => '²Õ¦¨¶µ¥Ø',
+ 'Inventory' => '®w¦s',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => '¦b°±¥Î¦¹¶µ²Õ¦X«~¤§«e, ¦s³f¼Æ¶q¥²»Ý¬°¹s!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => '°±¥Î¦¹¶µ¹s¥ó¤§«e, ¦s³f¼Æ¶q¥²»Ý¬°¹s!',
+ 'Inventory quantity must be zero!' => '¦s³f¼Æ¶q¥²»Ý¬°¹s!',
+ 'Invoice' => 'µo²¼',
+ 'Invoice Date missing!' => 'µo²¼¤é´Á¿ù»~!',
+ 'Invoice Number' => 'µo²¼½s¸¹',
+ 'Invoice Number missing!' => 'µo²¼½s¸¹¿ù»~!',
+ 'Item deleted!' => 'Item deleted!',
+ 'Item not on file!' => '¬dµL¦¹¶µ¥Ø',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'Last Cost' => '¤W¤@µ§¦¨¥»',
+ 'Line Total' => 'Á`¦C¼Æ',
+ 'Link Accounts' => '³sµ²¬ì¥Ø',
+ 'List Price' => '¶i»ù',
+ 'Make' => '»s³y',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Message' => '°T®§',
+ 'Microfiche' => 'Microfiche',
+ 'Model' => '«¬¸¹',
+ 'Name' => '¦WºÙ',
+ 'No.' => 'No.',
+ 'Notes' => '³Æµù',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Number' => '½s¸¹',
+ 'Number missing in Row' => '¦¹¦C¤¤¯Ê¤Ö¼Æ­È',
+ 'Obsolete' => '°±¥Î',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'On Hand' => '¦s¶q',
+ 'On Order' => 'On Order',
+ 'Order' => '­q³æ',
+ 'Order Date missing!' => '¥¼«ü©ú¤U³æ¤é´Á!',
+ 'Order Number' => '­q³æ½s¸¹',
+ 'Order Number missing!' => '¥¼«ü©ú­q³æ½s¸¹!',
+ 'Ordered' => 'Ordered',
+ 'Orphaned' => 'µL¥D',
+ 'PDF' => 'PDF',
+ 'Packing List' => '¥X³f³æ',
+ 'Packing List Date missing!' => '¥¼«ü©ú¥]¸Ë²M³æ¤é´Á!',
+ 'Packing List Number missing!' => '¥¼«ü©ú¥]¸Ë²M³æ½s¸¹!',
+ 'Part' => '­ì®Æ',
+ 'Part Number missing!' => 'º|¶ñ­ì®Æ½s¸¹!',
+ 'Parts' => '­ì®Æ',
+ 'Phone' => '¹q¸Ü¸¹½X',
+ 'Postscript' => 'Postscript',
+ 'Price' => '»ù®æ',
+ 'Printer' => '¦Lªí¾÷',
+ 'Project' => 'Project',
+ 'Purchase Order' => '±ÄÁʳæ',
+ 'Qty' => '¼Æ¶q',
+ 'ROP' => '¦A­qÂI',
+ 'Recd' => 'Recd',
+ 'Required by' => '¤l¶µ¥Ø',
+ 'Sales' => '·~°È',
+ 'Sales Order' => '¾P³f³æ',
+ 'Save' => 'Àx¦s',
+ 'Screen' => '¿Ã¹õ',
+ 'Select from one of the items below' => '©ó¤U¦C¶µ¥Ø¤¤¿ï¾Ü¤@¶µ',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sell Price' => '°â»ù',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Service' => 'ªA°È',
+ 'Service Number missing!' => 'º|¶ñªA°È½s¸¹!',
+ 'Services' => 'ªA°È',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Short' => 'µu',
+ 'Sold' => '¤w½æ¥X',
+ 'Stock Assembly' => '½LÂI',
+ 'Subject' => '¼ÐÃD',
+ 'Subtotal' => '¤p­p',
+ 'Tax' => 'µ|ª÷',
+ 'To' => '¦Ü',
+ 'Top Level' => 'Top Level',
+ 'Total' => 'Á`­p',
+ 'Unit' => '³æ¦ì',
+ 'Unit of measure' => '«×¶q³æ¦ì',
+ 'Update' => 'Update',
+ 'Updated' => 'Updated',
+ 'Weight' => '­«¶q',
+ 'What type of item is this?' => '¦¹¶µ¥Øªº«¬ºA?',
+ 'ea' => '­Ó',
+ 'emailed to' => '¤w±H¦Ü',
+ 'hr' => 'hr',
+ 'sent to printer' => '°e¦Ü¦Lªí¾÷',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ '·s¼w' => 'add',
+ '·s¼w°Ó«~' => 'add_assembly',
+ '·s¼w­ì®Æ' => 'add_part',
+ '·s¼wªa°È' => 'add_service',
+ 'Ä~Äò' => 'continue',
+ '§r°£' => 'delete',
+ '½s¿è°Ó«~' => 'edit_assembly',
+ '½s¿è­ì®Æ' => 'edit_part',
+ '½s¿èªa°È' => 'edit_service',
+ 'Àx¦s' => 'save',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/io b/sql-ledger/locale/tw/io
new file mode 100644
index 0000000..64c8ed7
--- /dev/null
+++ b/sql-ledger/locale/tw/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => '·s¼W±ÄÁʳæ',
+ 'Add Sales Order' => '·s¼W¾P³f³æ',
+ 'Address' => '¦a§}',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Attachment' => 'ªþÀÉ',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'Bcc' => 'Bcc',
+ 'Bin' => '½c',
+ 'Cc' => 'Cc',
+ 'Contact' => '³sµ¸¤H',
+ 'Continue' => 'Ä~Äò',
+ 'Copies' => '«þ¨©',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => '»¡©ú',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'E-mail address missing!' => 'º|¶ñ¹q¤l¶l¥ó¦ì§}!',
+ 'Extended' => 'Extended',
+ 'Fax' => '¶Ç¯u',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'In-line' => '¦æ¤º',
+ 'Invoice' => 'µo²¼',
+ 'Invoice Date missing!' => 'µo²¼¤é´Á¿ù»~!',
+ 'Invoice Number missing!' => 'µo²¼½s¸¹¿ù»~!',
+ 'Item not on file!' => '¬dµL¦¹¶µ¥Ø',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Message' => '°T®§',
+ 'Name' => '¦WºÙ',
+ 'No.' => 'No.',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Number' => '½s¸¹',
+ 'Number missing in Row' => '¦¹¦C¤¤¯Ê¤Ö¼Æ­È',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'Order' => '­q³æ',
+ 'Order Date missing!' => '¥¼«ü©ú¤U³æ¤é´Á!',
+ 'Order Number missing!' => '¥¼«ü©ú­q³æ½s¸¹!',
+ 'PDF' => 'PDF',
+ 'Packing List' => '¥X³f³æ',
+ 'Packing List Date missing!' => '¥¼«ü©ú¥]¸Ë²M³æ¤é´Á!',
+ 'Packing List Number missing!' => '¥¼«ü©ú¥]¸Ë²M³æ½s¸¹!',
+ 'Part' => '­ì®Æ',
+ 'Phone' => '¹q¸Ü¸¹½X',
+ 'Postscript' => 'Postscript',
+ 'Price' => '»ù®æ',
+ 'Printer' => '¦Lªí¾÷',
+ 'Project' => 'Project',
+ 'Purchase Order' => '±ÄÁʳæ',
+ 'Qty' => '¼Æ¶q',
+ 'Recd' => 'Recd',
+ 'Required by' => '¤l¶µ¥Ø',
+ 'Sales Order' => '¾P³f³æ',
+ 'Screen' => '¿Ã¹õ',
+ 'Select from one of the items below' => '©ó¤U¦C¶µ¥Ø¤¤¿ï¾Ü¤@¶µ',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Service' => 'ªA°È',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Subject' => '¼ÐÃD',
+ 'To' => '¦Ü',
+ 'Unit' => '³æ¦ì',
+ 'What type of item is this?' => '¦¹¶µ¥Øªº«¬ºA?',
+ 'emailed to' => '¤w±H¦Ü',
+ 'sent to printer' => '°e¦Ü¦Lªí¾÷',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'Ä~Äò' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/ir b/sql-ledger/locale/tw/ir
new file mode 100644
index 0000000..daa90e4
--- /dev/null
+++ b/sql-ledger/locale/tw/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => '¬ì¥Ø',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => '·s¼W±ÄÁʳæ',
+ 'Add Sales Order' => '·s¼W¾P³f³æ',
+ 'Address' => '¦a§}',
+ 'Amount' => 'Á`­p',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Are you sure you want to delete Invoice Number' => '±z½T©w­n§R°£µo²¼½s¸¹',
+ 'Attachment' => 'ªþÀÉ',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'Bcc' => 'Bcc',
+ 'Bin' => '½c',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => '¤J±b¦¨¥\!',
+ 'Contact' => '³sµ¸¤H',
+ 'Continue' => 'Ä~Äò',
+ 'Copies' => '«þ¨©',
+ 'Currency' => '¹ô§O',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => '¤é´Á',
+ 'Date Due' => 'À³¥I¤é´Á',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Delete' => '§R°£',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => '»¡©ú',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'E-mail address missing!' => 'º|¶ñ¹q¤l¶l¥ó¦ì§}!',
+ 'Edit Purchase Invoice' => 'Edit Purchase Invoice',
+ 'Exch' => '¶×²v',
+ 'Exchangerate' => '¶×²v',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => '¶Ç¯u',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'In-line' => '¦æ¤º',
+ 'Invoice' => 'µo²¼',
+ 'Invoice Date' => 'µo²¼¤é´Á',
+ 'Invoice Date missing!' => 'µo²¼¤é´Á¿ù»~!',
+ 'Invoice Number' => 'µo²¼½s¸¹',
+ 'Invoice Number missing!' => 'µo²¼½s¸¹¿ù»~!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => '¬dµL¦¹¶µ¥Ø',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Message' => '°T®§',
+ 'Name' => '¦WºÙ',
+ 'No.' => 'No.',
+ 'Notes' => '³Æµù',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Number' => '½s¸¹',
+ 'Number missing in Row' => '¦¹¦C¤¤¯Ê¤Ö¼Æ­È',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'Order' => '­q³æ',
+ 'Order Date missing!' => '¥¼«ü©ú¤U³æ¤é´Á!',
+ 'Order Number' => '­q³æ½s¸¹',
+ 'Order Number missing!' => '¥¼«ü©ú­q³æ½s¸¹!',
+ 'PDF' => 'PDF',
+ 'Packing List' => '¥X³f³æ',
+ 'Packing List Date missing!' => '¥¼«ü©ú¥]¸Ë²M³æ¤é´Á!',
+ 'Packing List Number missing!' => '¥¼«ü©ú¥]¸Ë²M³æ½s¸¹!',
+ 'Part' => '­ì®Æ',
+ 'Payment date missing!' => '¥¼«ü©ú¥I´Ú¤é´Á!',
+ 'Payments' => '¥I´Ú',
+ 'Phone' => '¹q¸Ü¸¹½X',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => '»ù®æ',
+ 'Printer' => '¦Lªí¾÷',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => '±ÄÁʳæ',
+ 'Qty' => '¼Æ¶q',
+ 'Recd' => 'Recd',
+ 'Record in' => '°O¿ý©ó',
+ 'Required by' => '¤l¶µ¥Ø',
+ 'Sales Order' => '¾P³f³æ',
+ 'Screen' => '¿Ã¹õ',
+ 'Select from one of the items below' => '©ó¤U¦C¶µ¥Ø¤¤¿ï¾Ü¤@¶µ',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Service' => 'ªA°È',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Source' => '¨Ó·½',
+ 'Subject' => '¼ÐÃD',
+ 'Subtotal' => '¤p­p',
+ 'Tax Included' => '¤£¦¬ªA°È¶O',
+ 'To' => '¦Ü',
+ 'Total' => 'Á`­p',
+ 'Unit' => '³æ¦ì',
+ 'Update' => 'Update',
+ 'Vendor' => '¼t°Ó',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => '¦¹¶µ¥Øªº«¬ºA?',
+ 'Yes' => '¬O',
+ 'ea' => '­Ó',
+ 'emailed to' => '¤w±H¦Ü',
+ 'sent to printer' => '°e¦Ü¦Lªí¾÷',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'Ä~Äò' => 'continue',
+ '§r°£' => 'delete',
+ '­q³æ' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'update' => 'update',
+ '¬o' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/is b/sql-ledger/locale/tw/is
new file mode 100644
index 0000000..1b0c6ec
--- /dev/null
+++ b/sql-ledger/locale/tw/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => '¬ì¥Ø',
+ 'Add Purchase Order' => '·s¼W±ÄÁʳæ',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => '·s¼W¾P³f³æ',
+ 'Address' => '¦a§}',
+ 'Amount' => 'Á`­p',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Are you sure you want to delete Invoice Number' => '±z½T©w­n§R°£µo²¼½s¸¹',
+ 'Attachment' => 'ªþÀÉ',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'Bcc' => 'Bcc',
+ 'Bin' => '½c',
+ 'Cannot delete invoice!' => 'Cannot delete invoice!',
+ 'Cannot post invoice for a closed period!' => 'Cannot post invoice for a closed period!',
+ 'Cannot post invoice!' => 'Cannot post invoice!',
+ 'Cannot post payment for a closed period!' => 'Cannot post payment for a closed period!',
+ 'Cc' => 'Cc',
+ 'Confirm!' => '¤J±b¦¨¥\!',
+ 'Contact' => '³sµ¸¤H',
+ 'Continue' => 'Ä~Äò',
+ 'Copies' => '«þ¨©',
+ 'Credit Limit' => '«H¥ÎÃB«×',
+ 'Currency' => '¹ô§O',
+ 'Customer' => '«È¤á',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => '¤é´Á',
+ 'Date Due' => 'À³¥I¤é´Á',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Delete' => '§R°£',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => '»¡©ú',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'E-mail address missing!' => 'º|¶ñ¹q¤l¶l¥ó¦ì§}!',
+ 'Edit Sales Invoice' => 'Edit Sales Invoice',
+ 'Exch' => '¶×²v',
+ 'Exchangerate' => '¶×²v',
+ 'Exchangerate for payment missing!' => 'Exchangerate for payment missing!',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => '¶Ç¯u',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'In-line' => '¦æ¤º',
+ 'Invoice' => 'µo²¼',
+ 'Invoice Date' => 'µo²¼¤é´Á',
+ 'Invoice Date missing!' => 'µo²¼¤é´Á¿ù»~!',
+ 'Invoice Number' => 'µo²¼½s¸¹',
+ 'Invoice Number missing!' => 'µo²¼½s¸¹¿ù»~!',
+ 'Invoice deleted!' => 'Invoice deleted!',
+ 'Invoice posted!' => 'Invoice posted!',
+ 'Item not on file!' => '¬dµL¦¹¶µ¥Ø',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Message' => '°T®§',
+ 'Name' => '¦WºÙ',
+ 'No.' => 'No.',
+ 'Notes' => '³Æµù',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Number' => '½s¸¹',
+ 'Number missing in Row' => '¦¹¦C¤¤¯Ê¤Ö¼Æ­È',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'Order' => '­q³æ',
+ 'Order Date missing!' => '¥¼«ü©ú¤U³æ¤é´Á!',
+ 'Order Number' => '­q³æ½s¸¹',
+ 'Order Number missing!' => '¥¼«ü©ú­q³æ½s¸¹!',
+ 'PDF' => 'PDF',
+ 'Packing List' => '¥X³f³æ',
+ 'Packing List Date missing!' => '¥¼«ü©ú¥]¸Ë²M³æ¤é´Á!',
+ 'Packing List Number missing!' => '¥¼«ü©ú¥]¸Ë²M³æ½s¸¹!',
+ 'Part' => '­ì®Æ',
+ 'Payment date missing!' => '¥¼«ü©ú¥I´Ú¤é´Á!',
+ 'Payments' => '¥I´Ú',
+ 'Phone' => '¹q¸Ü¸¹½X',
+ 'Post' => 'Post',
+ 'Post as new' => 'Post as new',
+ 'Postscript' => 'Postscript',
+ 'Price' => '»ù®æ',
+ 'Print' => 'Print',
+ 'Printer' => '¦Lªí¾÷',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => '±ÄÁʳæ',
+ 'Qty' => '¼Æ¶q',
+ 'Recd' => 'Recd',
+ 'Record in' => '°O¿ý©ó',
+ 'Remaining' => '©|¾l',
+ 'Required by' => '¤l¶µ¥Ø',
+ 'Sales Order' => '¾P³f³æ',
+ 'Screen' => '¿Ã¹õ',
+ 'Select from one of the items below' => '©ó¤U¦C¶µ¥Ø¤¤¿ï¾Ü¤@¶µ',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Service' => 'ªA°È',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Source' => '¨Ó·½',
+ 'Subject' => '¼ÐÃD',
+ 'Subtotal' => '¤p­p',
+ 'Tax Included' => '¤£¦¬ªA°È¶O',
+ 'To' => '¦Ü',
+ 'Total' => 'Á`­p',
+ 'Unit' => '³æ¦ì',
+ 'Update' => 'Update',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => '¦¹¶µ¥Øªº«¬ºA?',
+ 'Yes' => '¬O',
+ 'ea' => '­Ó',
+ 'emailed to' => '¤w±H¦Ü',
+ 'sent to printer' => '°e¦Ü¦Lªí¾÷',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'Ä~Äò' => 'continue',
+ '§r°£' => 'delete',
+ '¹q¤l¶l¥ó' => 'e_mail',
+ '­q³æ' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ '¬o' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/login b/sql-ledger/locale/tw/login
new file mode 100644
index 0000000..d934f5a
--- /dev/null
+++ b/sql-ledger/locale/tw/login
@@ -0,0 +1,28 @@
+$self{texts} = {
+ 'About' => 'Ãö©ó',
+ 'Accounting' => '·|­p',
+ 'Database Host' => '¸ê®Æ®w¥D¾÷',
+ 'Dataset' => '¸ê®Æ¶°',
+ 'Incorrect Dataset version!' => '¸ê®Æ¶°ª©¥»¿ù»~!',
+ 'Incorrect Password!' => '±K½X¿ù»~!',
+ 'Licensed to' => '±ÂÅv¤©',
+ 'Login' => 'µn¤J',
+ 'Name' => '¦WºÙ',
+ 'Password' => '±K½X',
+ 'User' => '¨Ï¥ÎªÌ',
+ 'Version' => 'ª©¥»',
+ 'You are logged out!' => 'You are logged out!',
+ 'You did not enter a name!' => '±z¨Ã¥¼Áä¤J¦WºÙ!',
+ 'is not a member!' => '¨Ã¤£¬O¦¨­û!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'µn¤j' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/menu b/sql-ledger/locale/tw/menu
new file mode 100644
index 0000000..54a3f07
--- /dev/null
+++ b/sql-ledger/locale/tw/menu
@@ -0,0 +1,72 @@
+$self{texts} = {
+ 'AP' => 'À³¥I±b´Ú',
+ 'AP Aging' => 'À³¥I±bÄÖ¤ÀªR',
+ 'AR' => 'À³¦¬±b´Ú',
+ 'AR Aging' => 'À³¦¬±bÄÖ¤ÀªR',
+ 'Accounting Menu' => '·|­p¿ï³æ',
+ 'Add Account' => '·s¼W¬ì¥Ø',
+ 'Add Assembly' => '·s¼W°Ó«~',
+ 'Add Customer' => '·s¼W«È¤á',
+ 'Add GIFI' => '·s¼W GIFI',
+ 'Add Part' => '·s¼W­ì®Æ',
+ 'Add Project' => 'Add Project',
+ 'Add Service' => '·s¼WªA°È',
+ 'Add Transaction' => '·s¼W±b¥Ø',
+ 'Add Vendor' => '·s¼W¼t°Ó',
+ 'Assemblies' => '°Ó«~',
+ 'Audit Control' => '½]®Ö±±¨î',
+ 'Backup' => '³Æ¥÷',
+ 'Balance Sheet' => '¸ê²£­t¶Åªí',
+ 'Cash' => 'Cash',
+ 'Chart of Accounts' => '·|­p¬ì¥Øªí',
+ 'Check' => 'Check',
+ 'Customers' => 'Customers',
+ 'General Ledger' => 'Á`±b',
+ 'Goods & Services' => '³fª«¤ÎªA°È',
+ 'HTML Templates' => 'HTML ªí³æ',
+ 'Income Statement' => '·l¯qªí',
+ 'Invoice' => 'µo²¼',
+ 'LaTeX Templates' => 'LaTex ¼Òª©',
+ 'List Accounts' => '¦C¥X±b¸¹',
+ 'List GIFI' => '¦C¥X GIFI',
+ 'Logout' => 'µn¥X',
+ 'Order Entry' => '¤U³æ¶µ¥Ø',
+ 'Packing List' => '¥X³f³æ',
+ 'Parts' => '­ì®Æ',
+ 'Payment' => '¥I´Ú¤è¦¡',
+ 'Payments' => '¥I´Ú',
+ 'Preferences' => '­Ó¤H³]©w',
+ 'Projects' => 'Projects',
+ 'Purchase Invoice' => 'Purchase Invoice',
+ 'Purchase Order' => '±ÄÁʳæ',
+ 'Purchase Orders' => '±ÄÁʳæ',
+ 'Receipt' => 'Receipt',
+ 'Receipts' => 'Receipts',
+ 'Reconciliation' => 'Reconciliation',
+ 'Reports' => '³øªí',
+ 'Sales Invoice' => 'Sales Invoice',
+ 'Sales Order' => '¾P³f³æ',
+ 'Sales Orders' => '¾P³f³æ',
+ 'Save to File' => 'Àx¦s¦ÜÀÉ®×',
+ 'Send by E-Mail' => '¥H¹q¤l¶l¥ó±H°e',
+ 'Services' => 'ªA°È',
+ 'Statement' => 'Statement',
+ 'Stock Assembly' => '½LÂI',
+ 'Stylesheet' => '¼Ë¦¡ªí',
+ 'System' => '¨t²Î',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'Transactions' => '±b¥Ø',
+ 'Trial Balance' => '¸Õºâªí',
+ 'Vendors' => 'Vendors',
+ 'Version' => 'ª©¥»',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/oe b/sql-ledger/locale/tw/oe
new file mode 100644
index 0000000..57dd382
--- /dev/null
+++ b/sql-ledger/locale/tw/oe
@@ -0,0 +1,199 @@
+$self{texts} = {
+ 'Add' => '·s¼W',
+ 'Add Purchase Invoice' => 'Add Purchase Invoice',
+ 'Add Purchase Order' => '·s¼W±ÄÁʳæ',
+ 'Add Sales Invoice' => 'Add Sales Invoice',
+ 'Add Sales Order' => '·s¼W¾P³f³æ',
+ 'Address' => '¦a§}',
+ 'Amount' => 'Á`­p',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Are you sure you want to delete Order Number' => '±z¬O§_½T©w­n§R°£­q³æ',
+ 'Attachment' => 'ªþÀÉ',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'Bcc' => 'Bcc',
+ 'Bin' => '½c',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'Cannot delete order!',
+ 'Cannot save order!' => 'Cannot save order!',
+ 'Cc' => 'Cc',
+ 'Closed' => '¤wÃö³¬',
+ 'Confirm!' => '¤J±b¦¨¥\!',
+ 'Contact' => '³sµ¸¤H',
+ 'Continue' => 'Ä~Äò',
+ 'Copies' => '«þ¨©',
+ 'Credit Limit' => '«H¥ÎÃB«×',
+ 'Curr' => '¥Ø«e',
+ 'Currency' => '¹ô§O',
+ 'Customer' => '«È¤á',
+ 'Customer missing!' => 'Customer missing!',
+ 'Customer not on file!' => 'Customer not on file!',
+ 'Date' => '¤é´Á',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Delete' => '§R°£',
+ 'Delivery Date' => 'Delivery Date',
+ 'Description' => '»¡©ú',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'E-mail address missing!' => 'º|¶ñ¹q¤l¶l¥ó¦ì§}!',
+ 'Edit Purchase Order' => '½s¿è±ÄÁʳæ',
+ 'Edit Sales Order' => '½s¿è¾P³f³æ',
+ 'Exchangerate' => '¶×²v',
+ 'Exchangerate missing!' => 'Exchangerate missing!',
+ 'Extended' => 'Extended',
+ 'Fax' => '¶Ç¯u',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'From' => '±q',
+ 'ID' => '½s¸¹',
+ 'In-line' => '¦æ¤º',
+ 'Include in Report' => '¤@¨ÖÅã¥Ü',
+ 'Invoice' => 'µo²¼',
+ 'Invoice Date missing!' => 'µo²¼¤é´Á¿ù»~!',
+ 'Invoice Number missing!' => 'µo²¼½s¸¹¿ù»~!',
+ 'Item not on file!' => '¬dµL¦¹¶µ¥Ø',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Message' => '°T®§',
+ 'Name' => '¦WºÙ',
+ 'No.' => 'No.',
+ 'Notes' => '³Æµù',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Number' => '½s¸¹',
+ 'Number missing in Row' => '¦¹¦C¤¤¯Ê¤Ö¼Æ­È',
+ 'O' => 'O',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'Open' => '¶}±Ò',
+ 'Order' => '­q³æ',
+ 'Order Date' => '¤U³æ¤é´Á',
+ 'Order Date missing!' => '¥¼«ü©ú¤U³æ¤é´Á!',
+ 'Order Number' => '­q³æ½s¸¹',
+ 'Order Number missing!' => '¥¼«ü©ú­q³æ½s¸¹!',
+ 'Order deleted!' => 'Order deleted!',
+ 'Order saved!' => 'Order saved!',
+ 'PDF' => 'PDF',
+ 'Packing List' => '¥X³f³æ',
+ 'Packing List Date missing!' => '¥¼«ü©ú¥]¸Ë²M³æ¤é´Á!',
+ 'Packing List Number missing!' => '¥¼«ü©ú¥]¸Ë²M³æ½s¸¹!',
+ 'Part' => '­ì®Æ',
+ 'Phone' => '¹q¸Ü¸¹½X',
+ 'Postscript' => 'Postscript',
+ 'Price' => '»ù®æ',
+ 'Print' => 'Print',
+ 'Printer' => '¦Lªí¾÷',
+ 'Project' => 'Project',
+ 'Project not on file!' => 'Project not on file!',
+ 'Purchase Order' => '±ÄÁʳæ',
+ 'Purchase Orders' => '±ÄÁʳæ',
+ 'Qty' => '¼Æ¶q',
+ 'Recd' => 'Recd',
+ 'Remaining' => '©|¾l',
+ 'Required by' => '¤l¶µ¥Ø',
+ 'Sales Order' => '¾P³f³æ',
+ 'Sales Orders' => '¾P³f³æ',
+ 'Save' => 'Àx¦s',
+ 'Save as new' => 'Save as new',
+ 'Screen' => '¿Ã¹õ',
+ 'Select from one of the items below' => '©ó¤U¦C¶µ¥Ø¤¤¿ï¾Ü¤@¶µ',
+ 'Select from one of the names below' => 'Select from one of the names below',
+ 'Select from one of the projects below' => 'Select from one of the projects below',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Service' => 'ªA°È',
+ 'Ship' => 'Ship',
+ 'Ship to' => 'Ship to',
+ 'Ship via' => 'Ship via',
+ 'Subject' => '¼ÐÃD',
+ 'Subtotal' => '¤p­p',
+ 'Tax' => 'µ|ª÷',
+ 'Tax Included' => '¤£¦¬ªA°È¶O',
+ 'Terms: Net' => '²¼´Á²b­p',
+ 'To' => '¦Ü',
+ 'Total' => 'Á`­p',
+ 'Unit' => '³æ¦ì',
+ 'Update' => 'Update',
+ 'Vendor' => '¼t°Ó',
+ 'Vendor missing!' => 'Vendor missing!',
+ 'Vendor not on file!' => 'Vendor not on file!',
+ 'What type of item is this?' => '¦¹¶µ¥Øªº«¬ºA?',
+ 'Yes' => '¬O',
+ 'days' => '¤é',
+ 'ea' => '­Ó',
+ 'emailed to' => '¤w±H¦Ü',
+ 'sent to printer' => '°e¦Ü¦Lªí¾÷',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ '·s¼w' => 'add',
+ 'Ä~Äò' => 'continue',
+ '§r°£' => 'delete',
+ '¹q¤l¶l¥ó' => 'e_mail',
+ 'µo²¼' => 'invoice',
+ 'print' => 'print',
+ 'Àx¦s' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ '¬o' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/pe b/sql-ledger/locale/tw/pe
new file mode 100644
index 0000000..6e7b638
--- /dev/null
+++ b/sql-ledger/locale/tw/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => '·s¼W',
+ 'Add Project' => 'Add Project',
+ 'All' => '¥þ³¡',
+ 'Continue' => 'Ä~Äò',
+ 'Delete' => '§R°£',
+ 'Description' => '»¡©ú',
+ 'Edit Project' => 'Edit Project',
+ 'Number' => '½s¸¹',
+ 'Orphaned' => 'µL¥D',
+ 'Project' => 'Project',
+ 'Project Number missing!' => 'Project Number missing!',
+ 'Project deleted!' => 'Project deleted!',
+ 'Project saved!' => 'Project saved!',
+ 'Projects' => 'Projects',
+ 'Save' => 'Àx¦s',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ '·s¼w' => 'add',
+ 'Ä~Äò' => 'continue',
+ '§r°£' => 'delete',
+ 'Àx¦s' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/rc b/sql-ledger/locale/tw/rc
new file mode 100644
index 0000000..2f813ab
--- /dev/null
+++ b/sql-ledger/locale/tw/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => '¬ì¥Ø',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'Ä~Äò',
+ 'Date' => '¤é´Á',
+ 'Deposit' => 'Deposit',
+ 'Description' => '»¡©ú',
+ 'Difference' => 'Difference',
+ 'Done' => 'Done',
+ 'Exchangerate Difference' => 'Exchangerate Difference',
+ 'From' => '±q',
+ 'Out of balance!' => 'Out of balance!',
+ 'Payment' => '¥I´Ú¤è¦¡',
+ 'Reconciliation' => 'Reconciliation',
+ 'Select all' => 'Select all',
+ 'Source' => '¨Ó·½',
+ 'Statement Balance' => 'Statement Balance',
+ 'To' => '¦Ü',
+ 'Update' => 'Update',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'Ä~Äò' => 'continue',
+ 'done' => 'done',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/tw/rp b/sql-ledger/locale/tw/rp
new file mode 100644
index 0000000..603745b
--- /dev/null
+++ b/sql-ledger/locale/tw/rp
@@ -0,0 +1,117 @@
+$self{texts} = {
+ 'AP Aging' => 'À³¥I±bÄÖ¤ÀªR',
+ 'AR Aging' => 'À³¦¬±bÄÖ¤ÀªR',
+ 'Account' => '¬ì¥Ø',
+ 'Accounts' => '±b¤á',
+ 'Amount' => 'Á`­p',
+ 'Apr' => '¥|¤ë',
+ 'April' => '¥|¤ë',
+ 'Attachment' => 'ªþÀÉ',
+ 'Aug' => '¤K¤ë',
+ 'August' => '¤K¤ë',
+ 'Balance Sheet' => '¸ê²£­t¶Åªí',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => '¹ï·Ó',
+ 'Continue' => 'Ä~Äò',
+ 'Copies' => '«þ¨©',
+ 'Credit' => '¶U¤è',
+ 'Current' => 'Current',
+ 'Customer' => '«È¤á',
+ 'Date' => '¤é´Á',
+ 'Debit' => '­É¤è',
+ 'Dec' => '¤Q¤G¤ë',
+ 'December' => '¤Q¤G¤ë',
+ 'Decimalplaces' => 'Decimalplaces',
+ 'Description' => '»¡©ú',
+ 'Due' => '¨ì´Á',
+ 'E-mail' => '¹q¤l¶l¥ó',
+ 'E-mail Statement to' => 'E-mail Statement to',
+ 'Feb' => '¤G¤ë',
+ 'February' => '¤G¤ë',
+ 'From' => '±q',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'ªíÀY',
+ 'ID' => '½s¸¹',
+ 'In-line' => '¦æ¤º',
+ 'Include in Report' => '¤@¨ÖÅã¥Ü',
+ 'Income Statement' => '·l¯qªí',
+ 'Invoice' => 'µo²¼',
+ 'Jan' => '¤@¤ë',
+ 'January' => '¤@¤ë',
+ 'Jul' => '¤C¤ë',
+ 'July' => '¤C¤ë',
+ 'Jun' => '¤»¤ë',
+ 'June' => '¤»¤ë',
+ 'Mar' => '¤T¤ë',
+ 'March' => '¤T¤ë',
+ 'May' => '¤­¤ë',
+ 'May ' => '¤­¤ë',
+ 'Message' => '°T®§',
+ 'N/A' => '¤£¾A¥Î',
+ 'Nothing selected!' => 'Nothing selected!',
+ 'Nov' => '¤Q¤@¤ë',
+ 'November' => '¤Q¤@¤ë',
+ 'Oct' => '¤Q¤ë',
+ 'October' => '¤Q¤ë',
+ 'PDF' => 'PDF',
+ 'Payments' => '¥I´Ú',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Print',
+ 'Printer' => '¦Lªí¾÷',
+ 'Receipts' => 'Receipts',
+ 'Report for' => '³øªí¨Ó·½',
+ 'Retained Earnings' => '«O¯d¬Õ¾l',
+ 'Screen' => '¿Ã¹õ',
+ 'Select all' => 'Select all',
+ 'Select postscript or PDF!' => 'Select postscript or PDF!',
+ 'Sep' => '¤E¤ë',
+ 'September' => '¤E¤ë',
+ 'Source' => '¨Ó·½',
+ 'Standard' => '¼Ð·Ç',
+ 'Statement' => 'Statement',
+ 'Statement sent to' => 'Statement sent to',
+ 'Statements sent to printer!' => 'Statements sent to printer!',
+ 'Subject' => '¼ÐÃD',
+ 'Subtotal' => '¤p­p',
+ 'Tax' => 'µ|ª÷',
+ 'Tax collected' => 'Tax collected',
+ 'Tax paid' => 'Tax paid',
+ 'To' => '¦Ü',
+ 'Total' => 'Á`­p',
+ 'Trial Balance' => '¸Õºâªí',
+ 'Vendor' => '¼t°Ó',
+ 'as at' => 'as at',
+ 'collected on sales' => '¦b¾P³f®Éµ²²M',
+ 'for Period' => '´Á¶¡',
+ 'paid on purchases' => '¦b±ÄÁʮɵ²²M',
+ 'to' => 'to',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'Ä~Äò' => 'continue',
+ '¹q¤l¶l¥ó' => 'e_mail',
+ 'print' => 'print',
+ 'select_all' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/COPYING b/sql-ledger/locale/ua/COPYING
new file mode 100644
index 0000000..001a4f8
--- /dev/null
+++ b/sql-ledger/locale/ua/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (c) 2003
+#
+# Ukrainian texts:
+#
+# Author: Ivan Petrouchtchak <impe@telus.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/ua/LANGUAGE b/sql-ledger/locale/ua/LANGUAGE
new file mode 100644
index 0000000..368ad3b
--- /dev/null
+++ b/sql-ledger/locale/ua/LANGUAGE
@@ -0,0 +1 @@
+Ukrainian
diff --git a/sql-ledger/locale/ua/admin b/sql-ledger/locale/ua/admin
new file mode 100644
index 0000000..2ba71b0
--- /dev/null
+++ b/sql-ledger/locale/ua/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'ëÏÎÔÒÏÌØ äÏÓÔÕÐÕ',
+ 'Accounting' => 'ïÂ̦Ë',
+ 'Add User' => 'îÏ×ÉÊ ËÏÒÉÓÔÕ×ÁÞ',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Administration' => 'áÄͦΦÓÔÒÕ×ÁÎÎÑ',
+ 'Administrator' => 'áÄͦΦÓÔÒÁÔÏÒ',
+ 'All Datasets up to date!' => 'âÁÚÉ äÁÎÉÈ ÎÅ ÐÏÔÒÅÂÕÀÔØ ÐÏÎÏ×ÌÅÎÎÑ!',
+ 'Change Admin Password' => 'úͦÎÉÔÉ ÐÁÒÏÌØ áÄͦΦÓÔÒÁÔÏÒÁ',
+ 'Change Password' => 'úͦÎÉÔÉ ÐÁÒÏÌØ',
+ 'Character Set' => 'ëÏÄÉÒÏ×ËÁ',
+ 'Click on login name to edit!' => 'îÁÔÉÓΦÔØ ÎÁ ÎÁÚ×Õ ËÏÒÉÓÔÕ×ÁÞÁ, ÝÏ ÚÒÏÂÉÔÉ ÚͦÎÉ!',
+ 'Company' => 'ð¦ÄÐÒɤÍÓÔ×Ï',
+ 'Connect to' => 'ð¦ÄËÌÀÞÉÔÉÓØ ÄÏ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Create Chart of Accounts' => 'óÔ×ÏÒÉÔÉ ðÌÁÎ òÁÈÕÎ˦×',
+ 'Create Dataset' => 'óÔ×ÏÒÉÔÉ âÁÚÕ äÁÎÉÈ',
+ 'DBI not installed!' => 'îÅ ×ÓÔÁÎÏ×ÌÅÎÉÊ ÄÒÁÊ×ÅÒ DBI!',
+ 'Database' => 'âÁÚÁ äÁÎÉÈ',
+ 'Database Administration' => 'áÄͦΦÓÔÒÕ×ÁÎÎÑ ÂÁÚÉ ÄÁÎÉÈ',
+ 'Database Driver not checked!' => 'îÅ ÚÁÚÎÁÞÅÎÉÊ ÄÒÁÊ×ÅÒ âÁÚÉ äÁÎÉÈ (Pg)!',
+ 'Database User missing!' => 'îÅ ×ËÁÚÁÎÉÊ ëÏÒÉÓÔÕ×ÁÞ âÁÚÉ äÁÎÉÈ!',
+ 'Dataset' => 'âÁÚÁ äÁÎÉÈ',
+ 'Dataset missing!' => 'îÅ ×ËÁÚÁÎÁ âÁÚÁ äÁÎÉÈ!',
+ 'Dataset updated!' => 'âÁÚÁ äÁÎÉÈ ÐÏÎÏ×ÌÅÎÁ!',
+ 'Date Format' => 'æÏÒÍÁÔ ÄÁÔÉ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Delete Dataset' => '÷ÉÄÁÌÉÔÉ âÁÚÕ äÁÎÉÈ',
+ 'Directory' => 'ëÁÔÁÌÏÇ',
+ 'Driver' => 'äÒÁÊ×ÅÒ',
+ 'Dropdown Limit' => 'ïÂÍÅÖÅÎÎÑ ÌÉÓÔÏ×ÏÇÏ ÍÅÎÀ',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'Edit User' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ëÏÒÉÓÔÕ×ÁÞÁ',
+ 'Existing Datasets' => '¶ÓÎÕÀÞ¦ âÁÚÉ äÁÎÉÈ',
+ 'Fax' => 'æÁÈ',
+ 'Host' => 'íÁÛÉÎÁ/Host',
+ 'Hostname missing!' => 'îÅ ×ËÁÚÁÎÁ ÎÁÚ×Á ÍÁÛÉÎÉ!',
+ 'Incorrect Password!' => 'îÅצÒÎÉÊ ðÁÒÏÌØ!',
+ 'Language' => 'íÏ×Á',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'ñËÝÏ ×É ÎÅ ÂÁÖÁ¤ÔÅ ×ÓÔÁÎÏ×ÉÔÉ ×¦ÄÄÁÌÅÎÉÊ Ú×ÑÚÏË, ÎÅ ÚÁÐÏ×ÎÀÊÔÅ ÐÏÌÑ ÍÁÛÉÎÉ ¦ ÐÏÒÔÕ.',
+ 'Login' => 'ðÏÞÁÔÏË óÅÁÎÓÕ',
+ 'Multibyte Encoding' => 'íÕÌØÔÉÂÉÔÎÅ ëÏÄÕ×ÁÎÎÑ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'New Templates' => 'îÏצ ûÁÂÌÏÎÉ',
+ 'No Database Drivers available!' => 'îÅÄÏÓÔÕÐÎÉÊ ÄÒÁÊ×ÅÒ âÁÚÉ äÁÎÉÈ!',
+ 'No Dataset selected!' => 'îÅ ÐÏÚÎÁÞÅÎÏ ×ÉÂÒÁÎÕ âÁÚÕ äÁÎÉÈ!',
+ 'Nothing to delete!' => 'îÅÍÁ ÝÏ ×ÉÄÁÌÉÔÉ!',
+ 'Number Format' => 'æÏÒÍÁÔ þÉÓÌÁ',
+ 'Oracle Database Administration' => 'áÄͦΦÓÔÒÁÃ¦Ñ âÁÚÉ äÁÎÉÈ Oracle',
+ 'Password' => 'ðÁÒÏÌØ',
+ 'Password changed!' => 'ðÁÒÏÌØ ÚͦÎÅÎÏ!',
+ 'Pg Database Administration' => 'áÄͦΦÓÔÒÁÃ¦Ñ âÁÚÉ äÁÎÉÈ Pg',
+ 'Phone' => 'ôÅÌ.',
+ 'Port' => 'ðÏÒÔ',
+ 'Port missing!' => 'ðÏÒÔ ÎÅ ×ËÁÚÁÎÏ!',
+ 'Printer' => 'ðÒÉÎÔÅÒ',
+ 'Save' => 'úÂÅÒÅÇÔÉ',
+ 'Select a Dataset to delete and press "Continue"' => '÷ÉÂÅÒ¦ÔØ âÁÚÕ äÁÎÉÈ ÄÌÑ ×ÉÄÁÌÅÎÎÑ ¦ ÎÁÔÉÓΦÔØ "ðÒÏÄÏ×ÖÉÔÉ"',
+ 'Setup Templates' => 'îÁÌÁÛÔÕ×ÁÔÉ ûÁÂÌÏÎÉ',
+ 'Ship via' => 'ðÏÓÌÁÔÉ ÞÅÒÅÚ',
+ 'Signature' => 'ð¦ÄÐÉÓ',
+ 'Stylesheet' => 'ïÆÏÒÍÌÅÎÎÎÑ',
+ 'Templates' => 'ûÁÂÌÏÎÉ',
+ 'The following Datasets are not in use and can be deleted' => 'îÁÓÔÕÐΦ âÁÚÉ äÁÎÉÈ ÎÅ ×ÉËÏÒÉÓÔÏ×ÕÀÔØÓÑ ¦ ÍÏÖÕÔØ ÂÕÔÉ ×ÉÄÁÌÅΦ',
+ 'The following Datasets need to be updated' => 'îÁÓÔÕÐΦ âÁÚÉ äÁÎÉÈ ÐÏ×ÉÎΦ ÂÕÔÉ ÐÏÎÏ×ÌÅΦ',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'ðÏÐÅÒÅÄÎÑ ÐÅÒÅצÒËÁ ¦ÓÎÕÀÞÉÈ ÄÖÅÒÅÌ. ðÏËÉ ÝÏ Î¦ÞÏÇÏ ÎÅ ÂÕÄÅ ÓÔ×ÏÒÅÎÏ ÁÂÏ ×ÉÄÁÌÅÎÏ!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'ýÏ ÄÏÄÁÔÉ ËÏÒÉÓÔÕ×ÁÞÁ ÄÏ ÇÒÕÐÉ, ÔÒÅÂÁ ÐÏͦÎÑÔÉ ¦Í\'Ñ, login/××ÏÄÎÅ ¦ÍÑ ¦ ÚÂÅÒÅÇÔÉ. îÏ×ÉÊ ËÏÒÉÓÔÕ×ÁÞÁ ¦Ú ÏÄÎÁËÏ×ÉÍÉ ÐÁÒÁÍÅÔÒÁÍÉ ÂÕÄÅ ÚÂÅÒÅÖÅÎÏ Ð¦Ä ÎÏ×ÉÍ login/××ÏÄÎÉÍ ¦Í\'ÑÍ.',
+ 'Update Dataset' => 'ðÏÎÏ×ÉÔÉ âÁÚÕ äÁÎÉÈ',
+ 'Use Templates' => '÷ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ûÁÂÌÏÎÉ',
+ 'User' => 'ëÏÒÉÓÔÕ×ÁÞ',
+ 'User deleted!' => 'ëÏÒÉÓÔÕ×ÁÞ ÷ÉÄÁÌÅÎÉÊ',
+ 'User saved!' => 'ëÏÒÉÓÔÕ×ÁÞ ÚÂÅÒÅÖÅÎÉÊ',
+ 'Version' => '÷ÅÒÓ¦Ñ',
+ 'You must enter a host and port for local and remote connections!' => 'íÕÓÉÔÅ ××ÅÓÔÉ ÎÁÚ×Õ ÍÁÛÉÎÉ ¦ ÐÏÒÔÁ ÄÌÑ Í¦ÓÃÅ×ÏÇÏ ¦ צÄÄÁÌÅÎÏÇÏ Ú×ÑÚËÕ!',
+ 'does not exist' => 'ÎÅ ¦ÓÎÕ¤',
+ 'is already a member!' => '×ÖÅ ¤ ÞÌÅÎÏÍ!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'ÚÁÍËÎÕÔÉÊ!',
+ 'successfully created!' => 'ÕÓЦÛÎÏ ÓÔ×ÏÒÅÎÏ!',
+ 'successfully deleted!' => 'ÕÓЦÛÎÏ ×ÉÄÁÌÅÎÏ!',
+ 'website' => '×ÅÂ-ÓÔÏÒ¦ÎËÁ',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'îÏ×ÉÊ_ËÏÒÉÓÔÕ×ÁÞ' => 'add_user',
+ 'úͦÎÉÔÉ_ÐÁÒÏÌØ_áÄͦΦÓÔÒÁÔÏÒÁ' => 'change_admin_password',
+ 'úͦÎÉÔÉ_ÐÁÒÏÌØ' => 'change_password',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ 'óÔ×ÏÒÉÔÉ_âÁÚÕ_äÁÎÉÈ' => 'create_dataset',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ '÷ÉÄÁÌÉÔÉ_âÁÚÕ_äÁÎÉÈ' => 'delete_dataset',
+ 'ðÏÞÁÔÏË_óÅÁÎÓÕ' => 'login',
+ 'áÄͦΦÓÔÒÁæÑ_âÁÚÉ_äÁÎÉÈ_oracle' => 'oracle_database_administration',
+ 'áÄͦΦÓÔÒÁæÑ_âÁÚÉ_äÁÎÉÈ_pg' => 'pg_database_administration',
+ 'úÂÅÒÅÇÔÉ' => 'save',
+ 'ðÏÎÏ×ÉÔÉ_âÁÚÕ_äÁÎÉÈ' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/all b/sql-ledger/locale/ua/all
new file mode 100644
index 0000000..c863ea3
--- /dev/null
+++ b/sql-ledger/locale/ua/all
@@ -0,0 +1,495 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => '÷ÉÔÒÁÔÉ',
+ 'AP Aging' => 'AP Aging (×ÉÔÒÁÔÉ)',
+ 'AP Transaction' => 'ïÐÅÒÁæ§ ÷ÉÔÒÁÔ',
+ 'AP Transactions' => 'ïÐÅÒÁæ§ ÷ÉÔÒÁÔ',
+ 'AR' => 'äÏÈÏÄÉ',
+ 'AR Aging' => 'AR Aging (ÄÏÈÏÄÉ)',
+ 'AR Transaction' => 'ïÐÅÒÁÃ¦Ñ äÏÈÏĦ×',
+ 'AR Transactions' => 'ïÐÅÒÁÃ¦Ñ äÏÈÏĦ×',
+ 'About' => 'ðÒÏ ÐÒÏÇÒÁÍÕ',
+ 'Access Control' => 'ëÏÎÔÒÏÌØ äÏÓÔÕÐÕ',
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Account Number' => 'îÏÍÅÒ òÁÈÕÎËÕ',
+ 'Account Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÕ!',
+ 'Account Type' => '÷ÉÄ ÒÁÈÕÎËÕ',
+ 'Account Type missing!' => 'îÅ ×ËÁÚÁÎÉÊ ×ÉÄ ÒÁÈÕÎËÕ!',
+ 'Account deleted!' => 'òÁÈÕÎÏË ×ÉÄÁÌÅÎÉÊ',
+ 'Account saved!' => 'òÁÈÕÎÏË ÚÂÅÒÅÖÅÎÏ',
+ 'Accounting' => 'ïÂ̦Ë',
+ 'Accounting Menu' => 'íÅÎÀ ïÂ̦ËÕ',
+ 'Accounts' => 'òÁÈÕÎËÉ',
+ 'Active' => 'áËÔÉ×ÎÉÊ',
+ 'Add' => 'îÏ×ÉÊ',
+ 'Add Account' => 'îÏ×ÉÊ ÒÁÈÕÎÏË',
+ 'Add Accounts Payables Transaction' => 'îÏ×Á ÏÐÅÒÁÃ¦Ñ ×ÉÔÒÁÔ',
+ 'Add Accounts Receivables Transaction' => 'îÏ×Á ÏÐÅÒÁÃ¦Ñ ÄÏÈÏĦ×',
+ 'Add Assembly' => 'îÏ×ÉÊ ËÏÍÐÌÅËÔ',
+ 'Add Customer' => 'îÏ×ÉÊ Ë̦¤ÎÔ',
+ 'Add GIFI' => 'îÏ×ÉÊ GIFI',
+ 'Add General Ledger Transaction' => 'îÏ×Á ÏÐÅÒÁæÑ',
+ 'Add Part' => 'îÏ×ÉÊ ôÏ×ÁÒ',
+ 'Add Project' => 'îÏ×ÉÊ ðÒÏÅËÔ',
+ 'Add Purchase Invoice' => 'îÏ×ÉÊ ëÕЦ×ÅÌØÎÉÊ òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Add Purchase Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ËÕЦ×ÌÀ',
+ 'Add Sales Invoice' => 'îÏ×ÉÊ òÁÈÕÎÏ-ÆÁËÔÕÒÁ',
+ 'Add Sales Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ÐÒÏÄÁÖ',
+ 'Add Service' => 'îÏ×Á ÐÏÓÌÕÇÁ',
+ 'Add Transaction' => 'îÏ×Á ÏÐÅÒÁæÑ',
+ 'Add User' => 'îÏ×ÉÊ ËÏÒÉÓÔÕ×ÁÞ',
+ 'Add Vendor' => 'îÏ×ÉÊ ÐÏÓÔÁÞÁÌØÎÉË',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Administration' => 'áÄͦΦÓÔÒÕ×ÁÎÎÑ',
+ 'Administrator' => 'áÄͦΦÓÔÒÁÔÏÒ',
+ 'All' => '÷Ó¦',
+ 'All Datasets up to date!' => 'âÁÚÉ äÁÎÉÈ ÎÅ ÐÏÔÒÅÂÕÀÔØ ÐÏÎÏ×ÌÅÎÎÑ!',
+ 'Amount' => 'óÕÍÁ',
+ 'Amount Due' => 'úÁÐÌÁÔÉÔÉ óÕÍÕ',
+ 'Amount does not equal applied!' => 'óÕÍÁ ÎÅ ÄÏÒ¦×ÎÀ¤ ÚÁÓÔÏÓÏ×ÁΦÊ!',
+ 'Amount missing!' => 'îÅ ×ËÁÚÁÎÁ ÓÕÍÁ!',
+ 'Applied' => 'úÁÓÔÏÓÏ×ÁÎÏ',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Are you sure you want to delete Invoice Number' => '÷É ÐÅ×Φ, ÝÏ ÈÏÞÅÔÅ ×ÉÄÁÌÉÔÉ ÄÁÎÉÊ ÒÁÈÕÎÏË?',
+ 'Are you sure you want to delete Order Number' => '÷É ÐÅ×Φ, ÝÏ ÈÏÞÅÔÅ ×ÉÄÁÌÉÔÉ ÄÁÎÅ ÚÁÍÏ×ÌÅÎÎÑ?',
+ 'Are you sure you want to delete Transaction' => '÷É ÐÅ×Φ, ÝÏ ÈÏÞÅÔÅ ×ÉÄÁÌÉÔÉ ÄÁÎÕ ÏÐÅÒÁæÀ?',
+ 'Assemblies' => 'ëÏÍÐÌÅËÔÉ',
+ 'Assemblies restocked!' => 'ëÏÍÐÌÅËÔÉ ¦Î×ÅÎÔÁÒÉÚÏ×ÁΦ!',
+ 'Assembly Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ËÏÍÐÌÅËÔÕ!',
+ 'Asset' => 'áËÔÉ×',
+ 'Attachment' => 'äÏÄÁÔÏË',
+ 'Audit Control' => 'ëÏÎÔÒÏÌØ',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'BOM' => 'BOM',
+ 'Backup' => 'òÅÚÅÒ×ÎÁ ËÏЦÑ',
+ 'Backup sent to' => 'òÅÚÅÒ×ÎÁ ËÏÐ¦Ñ ÐÏÓÌÁÎÁ ÄÏ',
+ 'Balance' => 'âÁÌÁÎÓ',
+ 'Balance Sheet' => 'âÁÌÁÎÓ',
+ 'Bcc' => 'ðÒÉ×ÁÔÎÁ ËÏÐ¦Ñ ÄÏ',
+ 'Bin' => 'Bin',
+ 'Books are open' => 'ëÎÉÇÁ צÄËÒÉÔÁ',
+ 'Bought' => 'ëÕÐÌÅÎÏ',
+ 'Business Number' => 'â¦ÚÎÅÓ-ÎÏÍÅÒ',
+ 'C' => 'ó',
+ 'COGS' => 'COGS',
+ 'Cannot delete account!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÁÈÕÎÏË',
+ 'Cannot delete customer!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ Ë̦¤ÎÔÁ',
+ 'Cannot delete default account!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÏÓÎÏ×ÎÉÊ ÒÁÈÕÎÏË!',
+ 'Cannot delete invoice!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÁÈÕÎÏË-ÆÁËÔÕÒÕ',
+ 'Cannot delete item already invoiced!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÔÏ×ÁÒ, ÎÁ ÑËÉÊ ×ÖÅ ×ÉÐÉÓÁÎÁ ÒÁÈÕÎÏË-ÆÁËÔÕÒÁ!',
+ 'Cannot delete item on order!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ Ò¦Þ ¦Ú ÚÁÍÏ×ÌÅÎÎÑ!',
+ 'Cannot delete item which is part of an assembly!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÔÏ×ÁÒ, ÑËÉÊ ¤ ÞÁÓÔÉÎÏÀ ËÏÍÐÌÅËÔÕ!',
+ 'Cannot delete item!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÃÅÊ ÅÌÅÍÅÎÔ',
+ 'Cannot delete order!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÚÁÍÏ×ÌÅÎÎÑ!',
+ 'Cannot delete transaction!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÏÒÅ!',
+ 'Cannot delete vendor!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÐÏÓÔÁÞÁÌØÎÉËÁ!',
+ 'Cannot have a value in both Debit and Credit!' => 'îÅ ÍÏÖÎÁ ÏÄÎÏÞÁÓÎÏ ÍÁÔÉ ÓÕÍÉ × äÅÂÉÔ¦ ¦ ëÒÅÄÉÔ¦',
+ 'Cannot post a transaction without a value!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÏÐÅÒÁæÀ ÂÅÚ ×ÁÒÔÏÓÔ¦!',
+ 'Cannot post invoice for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÒÁÈÕÎÏË-ÆÁËÔÕÒÕ ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot post invoice!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÒÁÈÕÎÏË-ÆÁËÔÕÒÕ!',
+ 'Cannot post payment for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÐÌÁÔ¦Ö ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot post payment!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÐÌÁÔ¦Ö!',
+ 'Cannot post transaction for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÏÐÅÒÁæÀ ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot post transaction!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÏÐÅÒÁæÀ!',
+ 'Cannot process payment for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ÐÒÏ×ÅÓÔÉ ÐÌÁÔ¦Ö ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot save account!' => 'îÅ ÍÏÖÌÉ×Ï ÚÂÅÒÅÇÔÉ ÒÁÈÕÎÏË!',
+ 'Cannot save order!' => 'îÅ ÍÏÖÌÉ×Ï ÚÂÅÒÅÇÔÉ ÚÁÍÏ×ÌÅÎÎÑ!',
+ 'Cannot save preferences!' => 'îÅ ÍÏÖÌÉ×Ï ÚÂÅÒÅÇÔÉ ÎÁÓÔÒÏÊËÉ!',
+ 'Cannot stock assemblies!' => 'îÅ ÍÏÖÌÉ×Ï ¦Î×ÅÎÔÁÒÉÚÕ×ÁÔÉ ËÏÍÐÌÅËÔÉ!',
+ 'Cash' => 'çÏÔ¦×ËÁ',
+ 'Cash based' => 'çÏÔ¦×ËÏ×ÉÊ',
+ 'Cc' => 'ëÏÐ¦Ñ ÄÏ',
+ 'Change Admin Password' => 'úͦÎÉÔÉ ÐÁÒÏÌØ áÄͦΦÓÔÒÁÔÏÒÁ',
+ 'Change Password' => 'úͦÎÉÔÉ ÐÁÒÏÌØ',
+ 'Character Set' => 'ëÏÄÉÒÏ×ËÁ',
+ 'Chart of Accounts' => 'ðÌÁÎ òÁÈÕÎ˦×',
+ 'Check' => 'þÅË',
+ 'Check printed!' => 'þÅË ÎÁÄÒÕËÏ×ÁÎÏ!',
+ 'Check printing failed!' => 'äÒÕË ÞÅËÕ ÎÅ ×ÄÁ×ÓÑ!',
+ 'Cleared Balance' => 'ë¦ÎÃÅ×Å óÁÌØÄÏ',
+ 'Click on login name to edit!' => 'îÁÔÉÓΦÔØ ÎÁ ÎÁÚ×Õ ËÏÒÉÓÔÕ×ÁÞÁ, ÝÏ ÚÒÏÂÉÔÉ ÚͦÎÉ!',
+ 'Close Books up to' => 'úÁËÒÉÔÉ ëÎÉÇÉ ÄÏ',
+ 'Closed' => 'úÁËÒÉÔÏ',
+ 'Company' => 'ð¦ÄÐÒɤÍÓÔ×Ï',
+ 'Compare to' => 'ðÏÒ¦×ÎÑÔÉ Ú',
+ 'Confirm!' => 'ð¦ÄÔ×ÅÒĦÔØ!',
+ 'Connect to' => 'ð¦ÄËÌÀÞÉÔÉÓØ ÄÏ',
+ 'Contact' => 'ëÏÎÔÁËÔÎÁ ÏÓÏÂÁ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Copies' => 'ëÏЦÊ',
+ 'Copy to COA' => 'óËÏЦÀ×ÁÔÉ ÄÏ ðÌÁÎÕ òÁÈÕÎ˦×',
+ 'Create Chart of Accounts' => 'óÔ×ÏÒÉÔÉ ðÌÁÎ òÁÈÕÎ˦×',
+ 'Create Dataset' => 'óÔ×ÏÒÉÔÉ âÁÚÕ äÁÎÉÈ',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Credit Limit' => 'ì¦Í¦Ô ËÒÅÄÉÔÕ',
+ 'Curr' => '÷ÁÌÀÔÁ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Current' => 'ðÏÔÏÞÎÉÊ',
+ 'Customer' => 'ë̦¤ÎÔ',
+ 'Customer deleted!' => 'ë̦¤ÎÔÁ ×ÉÄÁÌÅÎÏ!',
+ 'Customer missing!' => 'îÅ ×ËÁÚÁÎÉÊ Ë̦¤ÎÔ!',
+ 'Customer not on file!' => 'ë̦¤ÎÔÁ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Customer saved!' => 'ë̦¤ÎÔÁ ÚÂÅÒÅÖÅÎÏ!',
+ 'Customers' => 'ë̦¤ÎÔÉ',
+ 'DBI not installed!' => 'îÅ ×ÓÔÁÎÏ×ÌÅÎÉÊ ÄÒÁÊ×ÅÒ DBI!',
+ 'Database' => 'âÁÚÁ äÁÎÉÈ',
+ 'Database Administration' => 'áÄͦΦÓÔÒÕ×ÁÎÎÑ ÂÁÚÉ ÄÁÎÉÈ',
+ 'Database Driver not checked!' => 'îÅ ÚÁÚÎÁÞÅÎÉÊ ÄÒÁÊ×ÅÒ âÁÚÉ äÁÎÉÈ (Pg)!',
+ 'Database Host' => 'íÁÛÉÎÁ âÁÚÉ äÁÎÉÈ',
+ 'Database User missing!' => 'îÅ ×ËÁÚÁÎÉÊ ëÏÒÉÓÔÕ×ÁÞ âÁÚÉ äÁÎÉÈ!',
+ 'Dataset' => 'âÁÚÁ äÁÎÉÈ',
+ 'Dataset missing!' => 'îÅ ×ËÁÚÁÎÁ âÁÚÁ äÁÎÉÈ!',
+ 'Dataset updated!' => 'âÁÚÁ äÁÎÉÈ ÐÏÎÏ×ÌÅÎÁ!',
+ 'Date' => 'äÁÔÁ',
+ 'Date Due' => 'úÁÐÌÁÔÉÔÉ ÄÏ',
+ 'Date Format' => 'æÏÒÍÁÔ ÄÁÔÉ',
+ 'Date Paid' => 'äÁÔÁ ÏÐÌÁÔÉ',
+ 'Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ!',
+ 'Debit' => 'äÅÂÉÔ',
+ 'Debit and credit out of balance!' => 'äÅÂÉÔ ¦ ËÒÅÄÉÔ ÎÅ ÚÂÁÌÁÎÓÏ×ÁΦ!',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Decimalplaces' => 'äÅÓÑÔÉÞΦ ͦÓÃÑ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Delete Account' => '÷ÉÄÁÌÉÔÉ ÒÁÈÕÎÏË',
+ 'Delete Dataset' => '÷ÉÄÁÌÉÔÉ âÁÚÕ äÁÎÉÈ',
+ 'Delivery Date' => 'äÁÔÁ ÄÏÓÔÁ×ËÉ',
+ 'Department' => '',
+ 'Deposit' => 'äÅÐÏÚÉÔ/÷ËÌÁÄ',
+ 'Description' => 'ïÐÉÓ',
+ 'Difference' => 'ò¦ÚÎÉÃÑ',
+ 'Directory' => 'ëÁÔÁÌÏÇ',
+ 'Discount' => 'óËÉÄËÁ',
+ 'Done' => 'úÒÏÂÌÅÎÏ',
+ 'Drawing' => 'íÁÌÀÎÏË',
+ 'Driver' => 'äÒÁÊ×ÅÒ',
+ 'Dropdown Limit' => 'ïÂÍÅÖÅÎÎÑ ÌÉÓÔÏ×ÏÇÏ ÍÅÎÀ',
+ 'Due' => 'äÏ',
+ 'Due Date' => 'úÁÐÌÁÔÉÔÉ ÄÏ',
+ 'Due Date missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÔÅÒͦΠÏÐÌÁÔÉ!',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'E-mail Statement to' => 'ðÏÓÌÁÔÉ ÐÏ ÅÌ. ÐÏÛÔ¦ ÄÏ',
+ 'E-mail address missing!' => 'îÅ ×ËÁÚÁÎÁ ÁÄÒÅÓÁ ÅÌ. ÐÏÛÔÉ!',
+ 'Edit' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ',
+ 'Edit Account' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ òÁÈÕÎÏË',
+ 'Edit Accounts Payables Transaction' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ðÒÏ×ÏÄËÕ ÷ÉÔÒÁÔ',
+ 'Edit Accounts Receivables Transaction' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ðÒÏ×ÏÄËÕ äÏÈÏĦ×',
+ 'Edit Assembly' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ËÏÍÐÌÅËÔ',
+ 'Edit Customer' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ë̦¤ÎÔÁ',
+ 'Edit GIFI' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ GIFI',
+ 'Edit General Ledger Transaction' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ïÐÅÒÁæÀ çÏÌÏ×Îϧ ëÎÉÇÉ',
+ 'Edit Part' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ôÏ×ÁÒ',
+ 'Edit Preferences for' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ îÁÓÔÒÏÊËÉ',
+ 'Edit Project' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ðÒÏÅËÔ',
+ 'Edit Purchase Invoice' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ëÕЦ×ÅÌØÎÉÊ òÁÈÕÎÏË-ÆÁËÔÕÒÕ',
+ 'Edit Purchase Order' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ëÕЦ×ÅÌØÎÅ úÁÍÏ×ÌÅÎÎÑ',
+ 'Edit Sales Invoice' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ òÁÈÕÎÏË-ÆÁËÔÕÒÕ',
+ 'Edit Sales Order' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ îÁËÌÁÄÎÕ ðÒÏÄÁÖÕ',
+ 'Edit Service' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ÐÏÓÌÕÇÕ',
+ 'Edit Template' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ûÁÂÌÏÎ',
+ 'Edit User' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ëÏÒÉÓÔÕ×ÁÞÁ',
+ 'Edit Vendor' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ðÏÓÔÁÞÁÌØÎÉËÁ',
+ 'Employee' => 'ðÒÁæ×ÎÉË',
+ 'Enforce transaction reversal for all dates' => 'úÁÓÔÁ×ÉÔÉ Ú×ÏÒÏÔÎÕ ÚͦÎÕ ÐÒÏ×ÏÄÏË ÄÌÑ ×Ó¦È ÄÁÔ',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => '÷×ÅĦÔØ ÄÏ 3 ̦ÔÅÒ ÒÏÚĦÌÅÎÉÈ Ä×ÏËÒÁÐËÁÍÉ (i.e CAD:USD:EUR) ÄÌÑ ÐÏÚÎÁÞÅÎÎÑ Í¦ÓÃÅ×ϧ ¦ ¦ÎÏÚÅÍÎÉÈ ÇÒÏÛÏ×ÉÈ ÏÄÉÎÉÃØ',
+ 'Equity' => 'ëÁЦÔÁÌ',
+ 'Exch' => 'ëÕÒÓ',
+ 'Exchangerate' => 'ëÕÒÓ ×ÁÌÀÔÉ',
+ 'Exchangerate Difference' => 'ò¦ÚÎÉÃÑ ëÕÒÓÕ ×ÁÌÀÔÉ',
+ 'Exchangerate for payment missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ ÄÌÑ ÐÌÁÔÅÖÕ!',
+ 'Exchangerate missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ!',
+ 'Existing Datasets' => '¶ÓÎÕÀÞ¦ âÁÚÉ äÁÎÉÈ',
+ 'Expense' => '÷ÉÄÁÔËÉ',
+ 'Expense Account' => 'òÁÈÕÎÏË ÷ÉÄÁÔ˦×',
+ 'Expense/Asset' => '÷ÉÄÁÔÏË/áËÔÉ×',
+ 'Extended' => 'ðÒÏÄÏ×ÖÅÎÏ',
+ 'Fax' => 'æÁÈ',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'Foreign Exchange Gain' => 'ðÒÉÂÕÔÏË Ú ïÂͦÎÕ ÷ÁÌÀÔÉ',
+ 'Foreign Exchange Loss' => '÷ÔÒÁÔÁ ÎÁ ïÂͦΦ ÷ÁÌÀÔÉ',
+ 'From' => '÷¦Ä / Ú',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI ×ÉÄÁÌÅÎÏ!',
+ 'GIFI missing!' => 'îÅ ×ËÁÚÁÎÏ GIFI!',
+ 'GIFI saved!' => 'GIFI ÚÂÅÒÅÖÅÎÏ!',
+ 'GL Transaction' => 'çë ïÐÅÒÁæÑ',
+ 'General Ledger' => 'çÏÌÏ×ÎÁ ëÎÉÇÁ',
+ 'Goods & Services' => 'ôÏ×ÁÒÉ ¦ ðÏÓÌÕÇÉ',
+ 'HTML Templates' => 'HTML ûÁÂÌÏÎÉ ',
+ 'Heading' => 'òÏÚĦÌ',
+ 'Host' => 'íÁÛÉÎÁ/Host',
+ 'Hostname missing!' => 'îÅ ×ËÁÚÁÎÁ ÎÁÚ×Á ÍÁÛÉÎÉ!',
+ 'ID' => '¶ÄÅÎÔÉƦËÁæÊÎÉÊ ÎÏÍÅÒ',
+ 'Image' => 'úÏÂÒÁÖÅÎÎÑ',
+ 'In-line' => '÷ËÌÀÞÅÎÏ (In-line)',
+ 'Include in Report' => 'äÏÄÁÔÉ ÄÏ úצÔÕ',
+ 'Include in drop-down menus' => 'äÏÄÁÔÉ ÄÏ ÌÉÓÔÏ×ÉÈ ÍÅÎÀ',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'äÏÄÁÔÉ ÒÁÈÕÎÏË ÄÏ ÆÏÒÍ Ë̦¤ÎÔ¦×/ÐÏÓÔÁÞÁÌØÎÉ˦×, ÝÏ ÐÏÚÎÁÞÁÔÉ Ë̦¤ÎÔ¦×/ÐÏÓÔÁÞÁÌØÎÉË¦× Ú ÑËÉÈ ÓÔÑÇÕÀÔØÓÑ ÐÏÄÁÔËÉ?',
+ 'Income' => 'ðÒÉÂÕÔÏË',
+ 'Income Account' => 'òÁÈÕÎÏË ðÒÉÂÕÔ˦×',
+ 'Income Statement' => 'ú×¦Ô ÐÒÏ ÄÏÈÏÄÉ ¦ ×ÉÄÁÔËÉ',
+ 'Incorrect Dataset version!' => 'îÅצÒÎÁ ×ÅÒÓ¦Ñ âÁÚÉ äÁÎÉÈ!',
+ 'Incorrect Password!' => 'îÅצÒÎÉÊ ðÁÒÏÌØ!',
+ 'Individual Items' => '¶ÎÄÉצÄÕÁÌØΦ þÁÓÔÉÎÉ',
+ 'Inventory' => '¶Î×ÅÎÔÁÒ',
+ 'Inventory Account' => '¶Î×ÅÎÔÁÒÎÉÊ ÒÁÈÕÎÏË',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'ë¦ÌØ˦ÓÔØ × ¦Î×ÅÎÔÁÒ¦ ÐÏ×ÉÎÎÁ ÂÕÔÉ ÎÕÌØ, ÐÅÒÛ Î¦Ö ÍÏÖÎÁ ÐÏÚÎÁÞÉÔÉ ËÏÍÐÌÅËÔ ÚÁÓÔÁÒ¦ÌÉÍ!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'ë¦ÌØ˦ÓÔØ × ¦Î×ÅÎÔÁÒ¦ ÐÏ×ÉÎÎÁ ÂÕÔÉ ÎÕÌØ, ÐÅÒÛ Î¦Ö ÍÏÖÎÁ ÐÏÚÎÁÞÉÔÉ ÃÉÊ ÔÏ×ÁÒ ÚÁÓÔÁÒ¦ÌÉÍ!',
+ 'Inventory quantity must be zero!' => 'ë¦ÌØ˦ÓÔØ × ¦Î×ÅÎÔÁÒ¦ ÐÏ×ÉÎÎÁ ÂÕÔÉ ÎÕÌØ!',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ',
+ 'Invoice Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice Number' => 'îÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ',
+ 'Invoice Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice deleted!' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ ×ÉÄÁÌÅÎÉÊ!',
+ 'Invoice posted!' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ ×ÉÓÔÁ×ÌÅÎÉÊ!',
+ 'Invoices' => 'òÁÈÕÎËÉ-ÆÁËÔÕÒÉ',
+ 'Is this a summary account to record' => 'þÉ ÃŠЦÄÓÕÍËÏ×ÉÊ ÒÁÈÕÎÏË ÄÌÑ ÚÁÐÉÓÕ?',
+ 'Item deleted!' => 'ò¦Þ ×ÉÄÁÌÅÎÏ!',
+ 'Item not on file!' => 'òÅÞ¦ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'LaTeX Templates' => 'LaTeX ûÁÂÌÏÎÉ',
+ 'Language' => 'íÏ×Á',
+ 'Last Cost' => 'ëÕЦ×ÅÌØÎÁ ã¦ÎÁ',
+ 'Last Invoice Number' => 'îÏÍÅÒ ïÓÔÁÎÎØÏÇÏ òÁÈÕÎËÕ-æÁËÔÕÒÉ',
+ 'Last Numbers & Default Accounts' => 'ïÓÔÁÎΦ îÏÍÅÒÉ ¦ ôÉÐÏצ òÁÈÕÎËÉ',
+ 'Last Purchase Order Number' => 'îÏÍÅÒ ÏÓÔÁÎÎØÏÇÏ úÁÍÏ×ÌÅÎÎÑ ÎÁ ðÏÓÔÁÞÕ',
+ 'Last Sales Order Number' => 'îÏÍÅÒ ÏÓÔÁÎÎØϧ ðÒÏÄÁÖÎϧ îÁËÌÁÄÎϧ',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'ñËÝÏ ×É ÎÅ ÂÁÖÁ¤ÔÅ ×ÓÔÁÎÏ×ÉÔÉ ×¦ÄÄÁÌÅÎÉÊ Ú×ÑÚÏË, ÎÅ ÚÁÐÏ×ÎÀÊÔÅ ÐÏÌÑ ÍÁÛÉÎÉ ¦ ÐÏÒÔÕ.',
+ 'Liability' => 'ðÁÓÓÉ×',
+ 'Licensed to' => 'ì¦ÃÅÎÚ¦¤À ×ÏÌÏĦ¤:',
+ 'Line Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Link' => 'ðÏÓÉÌÁÎÎÑ',
+ 'Link Accounts' => 'ðÏ×ÑÚÁÔÉ òÁÈÕÎËÉ',
+ 'List Accounts' => 'óÐÉÓÏË òÁÈÕÎ˦×',
+ 'List GIFI' => 'óÐÉÓÏË GIFI',
+ 'List Price' => 'ã¦ÎÁ',
+ 'List Transactions' => 'óÐÉÓÏË ðÒÏ×ÏÄÏË',
+ 'Login' => 'ðÏÞÁÔÏË óÅÁÎÓÕ',
+ 'Logout' => 'ë¦ÎÅÃØ óÅÁÎÓÕ',
+ 'Make' => '÷ÉÒÏÂÎÉÃÔ×Ï',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Message' => 'ðÏצÄÏÍÌÅÎÎÑ',
+ 'Microfiche' => 'í¦ËÒÏƦÛÁ',
+ 'Model' => 'íÏÄÅÌØ',
+ 'Multibyte Encoding' => 'íÕÌØÔÉÂÉÔÎÅ ëÏÄÕ×ÁÎÎÑ',
+ 'N/A' => 'îÅ óÔÏÓÕ¤ÔØÓÑ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'Name missing!' => 'îÅ ×ËÁÚÁÎÅ ¦Í\'Ñ (ÎÁÚ×Á)!',
+ 'New Templates' => 'îÏצ ûÁÂÌÏÎÉ',
+ 'No' => 'î¦',
+ 'No Database Drivers available!' => 'îÅÄÏÓÔÕÐÎÉÊ ÄÒÁÊ×ÅÒ âÁÚÉ äÁÎÉÈ!',
+ 'No Dataset selected!' => 'îÅ ÐÏÚÎÁÞÅÎÏ ×ÉÂÒÁÎÕ âÁÚÕ äÁÎÉÈ!',
+ 'No email address for' => 'îÅ ×ËÁÚÁÎÁ ÁÄÒÅÓÁ ÅÌ. ÐÏÛÔÉ ÄÌÑ',
+ 'No.' => 'No.',
+ 'Notes' => 'ðÒÉͦÔËÉ',
+ 'Nothing applied!' => 'î¦ÞÏÇÏ ÎÅ ÚÁÓÔÏÓÏ×ÁÎÏ!',
+ 'Nothing selected!' => 'î¦ÞÏÇÏ ÎÅ ×ÉÂÒÁÎÏ!',
+ 'Nothing to delete!' => 'îÅÍÁ ÝÏ ×ÉÄÁÌÉÔÉ!',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Number Format' => 'æÏÒÍÁÔ þÉÓÌÁ',
+ 'Number missing in Row' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ Õ ÒÑÄËÕ',
+ 'O' => 'ï',
+ 'Obsolete' => 'úÁÓÔÁÒ¦ÌÅ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'On Hand' => 'îÁ òÕËÁÈ',
+ 'On Order' => 'îÁ úÁÍÏ×ÌÅÎΦ',
+ 'Open' => '÷¦ÄËÒÉÔÏ',
+ 'Oracle Database Administration' => 'áÄͦΦÓÔÒÁÃ¦Ñ âÁÚÉ äÁÎÉÈ Oracle',
+ 'Order' => 'úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Date' => 'äÁÔÁ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ úÁÍÏ×ÌÅÎÎÑ!',
+ 'Order Entry' => '÷ÉÓÔÁ×ÌÅÎÎÑ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Number' => 'îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Number missing!' => 'îÅ ×ËÁÚÁÎÏ îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order deleted!' => 'úÁÍÏ×ÌÅÎÎÑ ×ÉÄÁÌÅÎÏ!',
+ 'Order saved!' => 'úÁÍÏ×ÌÅÎÎÑ ÚÂÅÒÅÖÅÎÏ!',
+ 'Ordered' => 'úÁÍÏ×ÌÅÎÏ',
+ 'Orphaned' => '÷¦ÄÏËÒÅÍÌÅÎÉÊ/ïÓÉÒÏÔ¦ÌÉÊ',
+ 'Out of balance!' => 'îÅ ÚÂÁÌÁÎÓÏ×ÁÎÏ!',
+ 'PDF' => 'PDF ÆÏÒÍÁÔ',
+ 'Packing List' => 'ðÁËÕ×ÁÌØÎÉÊ óÐÉÓÏË',
+ 'Packing List Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Packing List Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ îÏÍÅÒ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Paid' => 'úÁÐÌÁÞÅÎÏ',
+ 'Paid in full' => 'úÁÐÌÁÞÅÎÏ ×ÐÏ×Φ',
+ 'Part' => 'ôÏ×ÁÒ',
+ 'Part Number missing!' => 'îÅ ×ËÁÚÁÎÏ îÏÍÅÒ ôÏ×ÁÒÕ!',
+ 'Parts' => 'ÔÏ×ÁÒÉ',
+ 'Parts Inventory' => '¶Î×ÅÎÔÁÒ ôÏ×ÁÒ¦×',
+ 'Password' => 'ðÁÒÏÌØ',
+ 'Password changed!' => 'ðÁÒÏÌØ ÚͦÎÅÎÏ!',
+ 'Payables' => 'úÏÂÏ×ÑÚÁÎÎÑ (ÐÌÁÔ¦ÖΦ)',
+ 'Payment' => 'ðÌÁÔ¦Ö',
+ 'Payment date missing!' => 'îÅ ×ËÁÚÁÎÏ ÄÁÔÕ ðÌÁÔÅÖÕ!',
+ 'Payment posted!' => 'ðÌÁÔ¦Ö ×ÉÓÔÁ×ÌÅÎÏ!',
+ 'Payments' => 'ðÌÁÔÅÖ¦',
+ 'Pg Database Administration' => 'áÄͦΦÓÔÒÁÃ¦Ñ âÁÚÉ äÁÎÉÈ Pg',
+ 'Phone' => 'ôÅÌ.',
+ 'Port' => 'ðÏÒÔ',
+ 'Port missing!' => 'ðÏÒÔ ÎÅ ×ËÁÚÁÎÏ!',
+ 'Post' => '÷ÉÓÔÁ×ÉÔÉ',
+ 'Post as new' => '÷ÉÓÔÁ×ÉÔÉ ÑË ÎÏ×ÉÊ',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'îÁÓÔÒÏÊËÉ',
+ 'Preferences saved!' => 'îÁÓÔÒÏÊËÉ ÚÂÅÒÅÖÅÎÏ!',
+ 'Price' => 'ã¦ÎÁ',
+ 'Print' => 'îÁÄÒÕËÕ×ÁÔÉ',
+ 'Printer' => 'ðÒÉÎÔÅÒ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Project Number' => '',
+ 'Project Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÐÒÏÅËÔÕ!',
+ 'Project deleted!' => 'ðÒÏÅËÔ ×ÉÄÁÌÅÎÏ!',
+ 'Project not on file!' => 'ðÒÏÅËÔÕ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Project saved!' => 'ðÒÏÅËÔ ÚÂÅÒÅÖÅÎÏ!',
+ 'Projects' => 'ðÒÏÅËÔÉ',
+ 'Purchase Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Purchase Order' => 'ëÕЦ×ÅÌØÎÅ úÁÍÏ×ÌÅÎÎÑ',
+ 'Purchase Orders' => 'ëÕЦ×ÅÌØΦ úÁÍÏ×ÌÅÎÎÑ',
+ 'Qty' => 'ë¦ÌØ˦ÓÔØ',
+ 'ROP' => 'ROP',
+ 'Rate' => 'òÏÚæÎËÁ',
+ 'Recd' => 'ïÔÒÉÍÁÎÏ',
+ 'Receipt' => 'ë×ÉÔÁÎæÑ',
+ 'Receipt printed!' => '',
+ 'Receipt printing failed!' => '',
+ 'Receipts' => 'ë×ÉÔÁÎæ§',
+ 'Receivables' => 'îÁÌÅÖÎÏÓÔ¦ (ÄÅÂÉÔÉ)',
+ 'Reconciliation' => 'õÚÇÏÄÖÅÎÎÑ',
+ 'Record in' => '÷ÎÅÓÔÉ ×',
+ 'Reference' => 'úÓÉÌËÁ',
+ 'Reference missing!' => 'îÅ ×ËÁÚÁÎÁ ÚÓÉÌËÁ!',
+ 'Remaining' => 'úÁÌÉÛÉÌÏÓØ',
+ 'Report for' => 'ú×¦Ô ÄÌÑ',
+ 'Reports' => 'úצÔÉ',
+ 'Required by' => 'ôÅÒͦΠÄÏÓÔÁ×ËÉ',
+ 'Retained Earnings' => 'ðÒÉÂÕÔÏË (ÎÅÒÏÚÐÏĦÌÅÎÉÊ)',
+ 'Sales' => 'úÂÕÔ',
+ 'Sales Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Sales Order' => 'îÁËÌÁÄÎÁ ðÒÏÄÁÖÕ ',
+ 'Sales Orders' => 'îÁËÌÁÄΦ ðÒÏÄÁÖÕ',
+ 'Save' => 'úÂÅÒÅÇÔÉ',
+ 'Save as new' => 'úÂÅÒÅÇÔÉ ÑË ÎÏ×Å',
+ 'Save to File' => 'úÂÅÒÅÇÔÉ Õ æÁÊ̦',
+ 'Screen' => 'åËÒÁÎ',
+ 'Select a Dataset to delete and press "Continue"' => '÷ÉÂÅÒ¦ÔØ âÁÚÕ äÁÎÉÈ ÄÌÑ ×ÉÄÁÌÅÎÎÑ ¦ ÎÁÔÉÓΦÔØ "ðÒÏÄÏ×ÖÉÔÉ"',
+ 'Select all' => '÷ÉÂÒÁÔÉ ×ÓÅ',
+ 'Select from one of the items below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÕ ¦Ú ÎÁÓÔÕÐÎÉÈ ÒÅÞÅÊ',
+ 'Select from one of the names below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÅ ¦Ú ÎÁÓÔÕÐÎÉÈ ¦ÍÅÎ/ÎÁÚ×',
+ 'Select from one of the projects below' => '÷ÉÂÅÒ¦ÔØ ÏÄÉÎ ¦Ú ÎÁÓÔÕÐÎÉÈ ÐÒÏÅËÔ¦×',
+ 'Select postscript or PDF!' => '÷ÉÂÅÒ¦ÔØ postscript ÁÂÏ PDF ÆÏÒÍÁÔ!',
+ 'Sell Price' => '÷¦ÄÐÕÓËÎÁ ã¦ÎÁ',
+ 'Send by E-Mail' => '÷ÉÓÌÁÔÉ ÐÏ ÅÌ. ÐÏÛÔ¦',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Service' => 'ðÏÓÌÕÇÁ',
+ 'Service Items' => 'ðÏÓÌÕÇÉ',
+ 'Service Number missing!' => 'îÏÍÅÒ ðÏÓÌÕÇÉ ÎÅ ×ËÁÚÁÎÏ',
+ 'Services' => 'ðÏÓÌÕÇÉ',
+ 'Setup Templates' => 'îÁÌÁÛÔÕ×ÁÔÉ ûÁÂÌÏÎÉ',
+ 'Ship' => 'ðÏÓÌÁÔÉ',
+ 'Ship to' => 'ðÏÓÌÁÔÉ ÄÏ',
+ 'Ship via' => 'ðÏÓÌÁÔÉ ÞÅÒÅÚ',
+ 'Short' => 'óËÏÒÏÞÅÎÏ',
+ 'Signature' => 'ð¦ÄÐÉÓ',
+ 'Sold' => 'ðÒÏÄÁÎÏ',
+ 'Source' => 'äÖÅÒÅÌÏ',
+ 'Standard' => 'óÔÁÎÄÁÒÔΦ',
+ 'Statement' => 'úצÔ',
+ 'Statement Balance' => 'âÁÌÁÎÓÏ×ÉÊ úצÔ',
+ 'Statement sent to' => 'ú×¦Ô ÐÏÓÌÁÎÏ ÄÏ',
+ 'Statements sent to printer!' => 'ú×¦Ô ÐÏÓÌÁÎÏ ÄÏ ÐÒÉÎÔÅÒÁ!',
+ 'Stock Assembly' => '¶Î×ÅÎÔÁÒ ëÏÍÐÌÅËÔÕ',
+ 'Stylesheet' => 'ïÆÏÒÍÌÅÎÎÎÑ',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'System' => 'óÉÓÔÅÍÁ',
+ 'Tax' => 'ðÏÄÁÔÏË',
+ 'Tax Accounts' => 'ðÏÄÁÔËÏצ òÁÈÕÎËÉ',
+ 'Tax Included' => 'ðÏÄÁÔÏË ×ËÌÀÞÅÎÏ',
+ 'Tax collected' => 'ú¦ÂÒÁÎÏ ÐÏÄÁÔË¦× ',
+ 'Tax paid' => 'ðÏÄÁÔÏË ÚÁÐÌÁÞÅÎÏ',
+ 'Taxable' => 'ïÐÏÄÁÔËÏ×Õ¤ÔØÓÑ',
+ 'Template saved!' => 'ûÁÂÌÏÎ ÚÂÅÒÅÖÅÎÏ!',
+ 'Templates' => 'ûÁÂÌÏÎÉ',
+ 'Terms: Net' => 'õÍÏ×É: úÁÐÌÁÔÉÔÉ',
+ 'The following Datasets are not in use and can be deleted' => 'îÁÓÔÕÐΦ âÁÚÉ äÁÎÉÈ ÎÅ ×ÉËÏÒÉÓÔÏ×ÕÀÔØÓÑ ¦ ÍÏÖÕÔØ ÂÕÔÉ ×ÉÄÁÌÅΦ',
+ 'The following Datasets need to be updated' => 'îÁÓÔÕÐΦ âÁÚÉ äÁÎÉÈ ÐÏ×ÉÎΦ ÂÕÔÉ ÐÏÎÏ×ÌÅΦ',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'ðÏÐÅÒÅÄÎÑ ÐÅÒÅצÒËÁ ¦ÓÎÕÀÞÉÈ ÄÖÅÒÅÌ. ðÏËÉ ÝÏ Î¦ÞÏÇÏ ÎÅ ÂÕÄÅ ÓÔ×ÏÒÅÎÏ ÁÂÏ ×ÉÄÁÌÅÎÏ!',
+ 'To' => 'äÏ',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'ýÏ ÄÏÄÁÔÉ ËÏÒÉÓÔÕ×ÁÞÁ ÄÏ ÇÒÕÐÉ, ÔÒÅÂÁ ÐÏͦÎÑÔÉ ¦Í\'Ñ, login/××ÏÄÎÅ ¦ÍÑ ¦ ÚÂÅÒÅÇÔÉ. îÏ×ÉÊ ËÏÒÉÓÔÕ×ÁÞÁ ¦Ú ÏÄÎÁËÏ×ÉÍÉ ÐÁÒÁÍÅÔÒÁÍÉ ÂÕÄÅ ÚÂÅÒÅÖÅÎÏ Ð¦Ä ÎÏ×ÉÍ login/××ÏÄÎÉÍ ¦Í\'ÑÍ.',
+ 'Top Level' => '÷ÅÒÈÎ¦Ê ò¦×ÅÎØ',
+ 'Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Transaction Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ÏÐÅÒÁæ§',
+ 'Transaction deleted!' => 'ïÐÅÒÁÃ¦Ñ ×ÉÄÁÌÅÎÁ',
+ 'Transaction posted!' => 'ïÐÅÒÁÃ¦Ñ ÚĦÊÓÎÅÎÁ',
+ 'Transaction reversal enforced for all dates' => 'ðÒÉÚÎÁÞÅÎÏ ÒÅ×ÅÓÉ×ÎÕ ÚͦÎÕ ÏÐÅÒÁÃ¦Ê ÄÌÑ ×Ó¦È ÄÁÔ',
+ 'Transaction reversal enforced up to' => ' ðÒÉÚÎÁÞÅÎÏ ÒÅ×ÅÓÉ×ÎÕ ÚͦÎÁ ÏÐÅÒÁÃ¦Ê ÁÖ ÄÏ',
+ 'Transactions' => 'ïÐÅÒÁæ§',
+ 'Transactions exist, cannot delete customer!' => '¶ÓÎÕÀÔØ ÏÐÅÒÁæ§, ÎÅ ÍÏÖÎÁ ×ÉÄÁÌÉÔÉ Ë̦¤ÎÔÁ',
+ 'Transactions exist, cannot delete vendor!' => '¶ÓÎÕÀÔØ ÏÐÅÒÁæ§, ÎÅ ÍÏÖÎÁ ×ÉÄÁÌÉÔÉ ÐÏÓÔÁÞÁÌØÎÉËÁ',
+ 'Transactions exist; cannot delete account!' => '¶ÓÎÕÀÔØ ÏÐÅÒÁæ§, ÎÅ ÍÏÖÎÁ ×ÉÄÁÌÉÔÉ ÒÁÈÕÎÏË',
+ 'Trial Balance' => 'ðÒÏÂÎÉÊ âÁÌÁÎÓ',
+ 'Unit' => 'ïÄÉÎÉÃÑ',
+ 'Unit of measure' => 'ïÄÉÎÉÃÑ ×ÉͦÒÕ',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'Update Dataset' => 'ðÏÎÏ×ÉÔÉ âÁÚÕ äÁÎÉÈ',
+ 'Updated' => 'ðÏÎÏ×ÌÅÎÏ',
+ 'Use Templates' => '÷ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ûÁÂÌÏÎÉ',
+ 'User' => 'ëÏÒÉÓÔÕ×ÁÞ',
+ 'User deleted!' => 'ëÏÒÉÓÔÕ×ÁÞ ÷ÉÄÁÌÅÎÉÊ',
+ 'User saved!' => 'ëÏÒÉÓÔÕ×ÁÞ ÚÂÅÒÅÖÅÎÉÊ',
+ 'Vendor' => 'ðÏÓÔÁÞÁÌØÎÉË',
+ 'Vendor deleted!' => 'ðÏÓÔÁÞÁÌØÎÉË ×ÉÄÁÌÅÎÉÊ',
+ 'Vendor missing!' => 'ðÏÓÔÁÞÁÌØÎÉË ÎÅ ¦ÓÎÕ¤',
+ 'Vendor not on file!' => 'ðÏÔÁÞÁÌØÎÉËÁ ÎÅÍÁ Õ ÓÐÉÓËÕ ',
+ 'Vendor saved!' => 'ðÏÓÔÁÞÁÌØÎÉËÁ ÚÂÅÒÅÖÅÎÏ',
+ 'Vendors' => 'ðÏÓÔÁÞÁÌØÎÉËÉ',
+ 'Version' => '÷ÅÒÓ¦Ñ',
+ 'Weight' => '÷ÁÇÁ',
+ 'Weight Unit' => 'ïÄÉÎÉÃÑ ÷ÁÇÉ',
+ 'What type of item is this?' => 'ñËÉÊ ÃÅ ×ÉÄ/ÔÉÐ ÔÏ×ÁÒÕ',
+ 'Year End' => 'ë¦ÎÅÃØ æ¦ÎÁÎÓÏ×ÏÇÏ òÏËÕ',
+ 'Yes' => 'Tak',
+ 'You are logged out!' => '÷ÁÛ ÓÅÁÎÓ ÚÁ˦ÎÞÉ×ÓÑ!',
+ 'You did not enter a name!' => 'îÅ ××ÅÄÅÎÏ ¦Í\'Ñ/ÎÁÚ×Õ',
+ 'You must enter a host and port for local and remote connections!' => 'íÕÓÉÔÅ ××ÅÓÔÉ ÎÁÚ×Õ ÍÁÛÉÎÉ ¦ ÐÏÒÔÁ ÄÌÑ Í¦ÓÃÅ×ÏÇÏ ¦ צÄÄÁÌÅÎÏÇÏ Ú×ÑÚËÕ!',
+ 'as at' => 'ÑË ×',
+ 'collected on sales' => 'Ú¦ÂÒÁÎÏ ÐÒÉ ÐÒÏÄÁÖÕ',
+ 'days' => 'ÄΦ×',
+ 'does not exist' => 'ÎÅ ¦ÓÎÕ¤',
+ 'ea' => 'ÛÔ.',
+ 'emailed to' => 'ÐÏÓÌÁÎÏ ÐÏ ÅÌ. ÐÏÛÔ¦ ÄÏ',
+ 'for Period' => 'ÚÁ ðÅÒ¦ÏÄ',
+ 'hr' => 'ÇÏÄ.',
+ 'is already a member!' => '×ÖÅ ¤ ÞÌÅÎÏÍ!',
+ 'is not a member!' => 'ÎÅ ¤ ÞÌÅÎÏÍ!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'ÚÁÍËÎÕÔÉÊ!',
+ 'paid on purchases' => 'ÚÁÐÌÁÞÅÎÏ ÎÁ ÐÏËÕÐËÉ',
+ 'sent to printer' => 'ÐÏÓÌÁÎÏ ÄÏ ÐÒÉÎÔÅÒÁ',
+ 'successfully created!' => 'ÕÓЦÛÎÏ ÓÔ×ÏÒÅÎÏ!',
+ 'successfully deleted!' => 'ÕÓЦÛÎÏ ×ÉÄÁÌÅÎÏ!',
+ 'to' => 'ÄÏ',
+ 'website' => '×ÅÂ-ÓÔÏÒ¦ÎËÁ',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/am b/sql-ledger/locale/ua/am
new file mode 100644
index 0000000..9064301
--- /dev/null
+++ b/sql-ledger/locale/ua/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => '÷ÉÔÒÁÔÉ',
+ 'AR' => 'äÏÈÏÄÉ',
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Account Number' => 'îÏÍÅÒ òÁÈÕÎËÕ',
+ 'Account Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÕ!',
+ 'Account Type' => '÷ÉÄ ÒÁÈÕÎËÕ',
+ 'Account Type missing!' => 'îÅ ×ËÁÚÁÎÉÊ ×ÉÄ ÒÁÈÕÎËÕ!',
+ 'Account deleted!' => 'òÁÈÕÎÏË ×ÉÄÁÌÅÎÉÊ',
+ 'Account saved!' => 'òÁÈÕÎÏË ÚÂÅÒÅÖÅÎÏ',
+ 'Add Account' => 'îÏ×ÉÊ ÒÁÈÕÎÏË',
+ 'Add GIFI' => 'îÏ×ÉÊ GIFI',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Asset' => 'áËÔÉ×',
+ 'Audit Control' => 'ëÏÎÔÒÏÌØ',
+ 'Backup sent to' => 'òÅÚÅÒ×ÎÁ ËÏÐ¦Ñ ÐÏÓÌÁÎÁ ÄÏ',
+ 'Books are open' => 'ëÎÉÇÁ צÄËÒÉÔÁ',
+ 'Business Number' => 'â¦ÚÎÅÓ-ÎÏÍÅÒ',
+ 'COGS' => 'COGS',
+ 'Cannot delete account!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÁÈÕÎÏË',
+ 'Cannot delete default account!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÏÓÎÏ×ÎÉÊ ÒÁÈÕÎÏË!',
+ 'Cannot save account!' => 'îÅ ÍÏÖÌÉ×Ï ÚÂÅÒÅÇÔÉ ÒÁÈÕÎÏË!',
+ 'Cannot save preferences!' => 'îÅ ÍÏÖÌÉ×Ï ÚÂÅÒÅÇÔÉ ÎÁÓÔÒÏÊËÉ!',
+ 'Character Set' => 'ëÏÄÉÒÏ×ËÁ',
+ 'Chart of Accounts' => 'ðÌÁÎ òÁÈÕÎ˦×',
+ 'Close Books up to' => 'úÁËÒÉÔÉ ëÎÉÇÉ ÄÏ',
+ 'Company' => 'ð¦ÄÐÒɤÍÓÔ×Ï',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Copy to COA' => 'óËÏЦÀ×ÁÔÉ ÄÏ ðÌÁÎÕ òÁÈÕÎ˦×',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Date Format' => 'æÏÒÍÁÔ ÄÁÔÉ',
+ 'Debit' => 'äÅÂÉÔ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Delete Account' => '÷ÉÄÁÌÉÔÉ ÒÁÈÕÎÏË',
+ 'Description' => 'ïÐÉÓ',
+ 'Dropdown Limit' => 'ïÂÍÅÖÅÎÎÑ ÌÉÓÔÏ×ÏÇÏ ÍÅÎÀ',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'Edit' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ',
+ 'Edit Account' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ òÁÈÕÎÏË',
+ 'Edit GIFI' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ GIFI',
+ 'Edit Preferences for' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ îÁÓÔÒÏÊËÉ',
+ 'Edit Template' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ûÁÂÌÏÎ',
+ 'Enforce transaction reversal for all dates' => 'úÁÓÔÁ×ÉÔÉ Ú×ÏÒÏÔÎÕ ÚͦÎÕ ÐÒÏ×ÏÄÏË ÄÌÑ ×Ó¦È ÄÁÔ',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => '÷×ÅĦÔØ ÄÏ 3 ̦ÔÅÒ ÒÏÚĦÌÅÎÉÈ Ä×ÏËÒÁÐËÁÍÉ (i.e CAD:USD:EUR) ÄÌÑ ÐÏÚÎÁÞÅÎÎÑ Í¦ÓÃÅ×ϧ ¦ ¦ÎÏÚÅÍÎÉÈ ÇÒÏÛÏ×ÉÈ ÏÄÉÎÉÃØ',
+ 'Equity' => 'ëÁЦÔÁÌ',
+ 'Expense' => '÷ÉÄÁÔËÉ',
+ 'Expense Account' => 'òÁÈÕÎÏË ÷ÉÄÁÔ˦×',
+ 'Expense/Asset' => '÷ÉÄÁÔÏË/áËÔÉ×',
+ 'Fax' => 'æÁÈ',
+ 'Foreign Exchange Gain' => 'ðÒÉÂÕÔÏË Ú ïÂͦÎÕ ÷ÁÌÀÔÉ',
+ 'Foreign Exchange Loss' => '÷ÔÒÁÔÁ ÎÁ ïÂͦΦ ÷ÁÌÀÔÉ',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI ×ÉÄÁÌÅÎÏ!',
+ 'GIFI missing!' => 'îÅ ×ËÁÚÁÎÏ GIFI!',
+ 'GIFI saved!' => 'GIFI ÚÂÅÒÅÖÅÎÏ!',
+ 'Heading' => 'òÏÚĦÌ',
+ 'Include in drop-down menus' => 'äÏÄÁÔÉ ÄÏ ÌÉÓÔÏ×ÉÈ ÍÅÎÀ',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'äÏÄÁÔÉ ÒÁÈÕÎÏË ÄÏ ÆÏÒÍ Ë̦¤ÎÔ¦×/ÐÏÓÔÁÞÁÌØÎÉ˦×, ÝÏ ÐÏÚÎÁÞÁÔÉ Ë̦¤ÎÔ¦×/ÐÏÓÔÁÞÁÌØÎÉË¦× Ú ÑËÉÈ ÓÔÑÇÕÀÔØÓÑ ÐÏÄÁÔËÉ?',
+ 'Income' => 'ðÒÉÂÕÔÏË',
+ 'Income Account' => 'òÁÈÕÎÏË ðÒÉÂÕÔ˦×',
+ 'Inventory' => '¶Î×ÅÎÔÁÒ',
+ 'Inventory Account' => '¶Î×ÅÎÔÁÒÎÉÊ ÒÁÈÕÎÏË',
+ 'Is this a summary account to record' => 'þÉ ÃŠЦÄÓÕÍËÏ×ÉÊ ÒÁÈÕÎÏË ÄÌÑ ÚÁÐÉÓÕ?',
+ 'Language' => 'íÏ×Á',
+ 'Last Invoice Number' => 'îÏÍÅÒ ïÓÔÁÎÎØÏÇÏ òÁÈÕÎËÕ-æÁËÔÕÒÉ',
+ 'Last Numbers & Default Accounts' => 'ïÓÔÁÎΦ îÏÍÅÒÉ ¦ ôÉÐÏצ òÁÈÕÎËÉ',
+ 'Last Purchase Order Number' => 'îÏÍÅÒ ÏÓÔÁÎÎØÏÇÏ úÁÍÏ×ÌÅÎÎÑ ÎÁ ðÏÓÔÁÞÕ',
+ 'Last Sales Order Number' => 'îÏÍÅÒ ÏÓÔÁÎÎØϧ ðÒÏÄÁÖÎϧ îÁËÌÁÄÎϧ',
+ 'Liability' => 'ðÁÓÓÉ×',
+ 'Link' => 'ðÏÓÉÌÁÎÎÑ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'No' => 'î¦',
+ 'No email address for' => 'îÅ ×ËÁÚÁÎÁ ÁÄÒÅÓÁ ÅÌ. ÐÏÛÔÉ ÄÌÑ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Number Format' => 'æÏÒÍÁÔ þÉÓÌÁ',
+ 'Parts Inventory' => '¶Î×ÅÎÔÁÒ ôÏ×ÁÒ¦×',
+ 'Password' => 'ðÁÒÏÌØ',
+ 'Payables' => 'úÏÂÏ×ÑÚÁÎÎÑ (ÐÌÁÔ¦ÖΦ)',
+ 'Payment' => 'ðÌÁÔ¦Ö',
+ 'Phone' => 'ôÅÌ.',
+ 'Preferences saved!' => 'îÁÓÔÒÏÊËÉ ÚÂÅÒÅÖÅÎÏ!',
+ 'Rate' => 'òÏÚæÎËÁ',
+ 'Receivables' => 'îÁÌÅÖÎÏÓÔ¦ (ÄÅÂÉÔÉ)',
+ 'Sales' => 'úÂÕÔ',
+ 'Save' => 'úÂÅÒÅÇÔÉ',
+ 'Service Items' => 'ðÏÓÌÕÇÉ',
+ 'Ship via' => 'ðÏÓÌÁÔÉ ÞÅÒÅÚ',
+ 'Signature' => 'ð¦ÄÐÉÓ',
+ 'Stylesheet' => 'ïÆÏÒÍÌÅÎÎÎÑ',
+ 'Tax' => 'ðÏÄÁÔÏË',
+ 'Tax Accounts' => 'ðÏÄÁÔËÏצ òÁÈÕÎËÉ',
+ 'Template saved!' => 'ûÁÂÌÏÎ ÚÂÅÒÅÖÅÎÏ!',
+ 'Transaction reversal enforced for all dates' => 'ðÒÉÚÎÁÞÅÎÏ ÒÅ×ÅÓÉ×ÎÕ ÚͦÎÕ ÏÐÅÒÁÃ¦Ê ÄÌÑ ×Ó¦È ÄÁÔ',
+ 'Transaction reversal enforced up to' => ' ðÒÉÚÎÁÞÅÎÏ ÒÅ×ÅÓÉ×ÎÕ ÚͦÎÁ ÏÐÅÒÁÃ¦Ê ÁÖ ÄÏ',
+ 'Transactions exist; cannot delete account!' => '¶ÓÎÕÀÔØ ÏÐÅÒÁæ§, ÎÅ ÍÏÖÎÁ ×ÉÄÁÌÉÔÉ ÒÁÈÕÎÏË',
+ 'Weight Unit' => 'ïÄÉÎÉÃÑ ÷ÁÇÉ',
+ 'Year End' => 'ë¦ÎÅÃØ æ¦ÎÁÎÓÏ×ÏÇÏ òÏËÕ',
+ 'Yes' => 'Tak',
+ 'does not exist' => 'ÎÅ ¦ÓÎÕ¤',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'îÏ×ÉÊ_ÒÁÈÕÎÏË' => 'add_account',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ 'óËÏЦÀ×ÁÔÉ_ÄÏ_ðÌÁÎÕ_òÁÈÕÎ˦×' => 'copy_to_coa',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ' => 'edit',
+ '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ_òÁÈÕÎÏË' => 'edit_account',
+ 'úÂÅÒÅÇÔÉ' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/ap b/sql-ledger/locale/ua/ap
new file mode 100644
index 0000000..a5ec52d
--- /dev/null
+++ b/sql-ledger/locale/ua/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'ïÐÅÒÁæ§ ÷ÉÔÒÁÔ',
+ 'AP Transactions' => 'ïÐÅÒÁæ§ ÷ÉÔÒÁÔ',
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Add Accounts Payables Transaction' => 'îÏ×Á ÏÐÅÒÁÃ¦Ñ ×ÉÔÒÁÔ',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Amount' => 'óÕÍÁ',
+ 'Amount Due' => 'úÁÐÌÁÔÉÔÉ óÕÍÕ',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Are you sure you want to delete Transaction' => '÷É ÐÅ×Φ, ÝÏ ÈÏÞÅÔÅ ×ÉÄÁÌÉÔÉ ÄÁÎÕ ÏÐÅÒÁæÀ?',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'Cannot delete transaction!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÏÒÅ!',
+ 'Cannot post payment for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÐÌÁÔ¦Ö ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot post transaction for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÏÐÅÒÁæÀ ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot post transaction!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÏÐÅÒÁæÀ!',
+ 'Closed' => 'úÁËÒÉÔÏ',
+ 'Confirm!' => 'ð¦ÄÔ×ÅÒĦÔØ!',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer not on file!' => 'ë̦¤ÎÔÁ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Date' => 'äÁÔÁ',
+ 'Date Paid' => 'äÁÔÁ ÏÐÌÁÔÉ',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Description' => 'ïÐÉÓ',
+ 'Due Date' => 'úÁÐÌÁÔÉÔÉ ÄÏ',
+ 'Due Date missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÔÅÒͦΠÏÐÌÁÔÉ!',
+ 'Edit Accounts Payables Transaction' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ðÒÏ×ÏÄËÕ ÷ÉÔÒÁÔ',
+ 'Employee' => 'ðÒÁæ×ÎÉË',
+ 'Exch' => 'ëÕÒÓ',
+ 'Exchangerate' => 'ëÕÒÓ ×ÁÌÀÔÉ',
+ 'Exchangerate for payment missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ ÄÌÑ ÐÌÁÔÅÖÕ!',
+ 'Exchangerate missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ!',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'From' => '÷¦Ä / Ú',
+ 'ID' => '¶ÄÅÎÔÉƦËÁæÊÎÉÊ ÎÏÍÅÒ',
+ 'Include in Report' => 'äÏÄÁÔÉ ÄÏ úצÔÕ',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ',
+ 'Invoice Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice Number' => 'îÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ',
+ 'Invoice Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Notes' => 'ðÒÉͦÔËÉ',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'Open' => '÷¦ÄËÒÉÔÏ',
+ 'Order' => 'úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Number' => 'îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Paid' => 'úÁÐÌÁÞÅÎÏ',
+ 'Payment date missing!' => 'îÅ ×ËÁÚÁÎÏ ÄÁÔÕ ðÌÁÔÅÖÕ!',
+ 'Payments' => 'ðÌÁÔÅÖ¦',
+ 'Post' => '÷ÉÓÔÁ×ÉÔÉ',
+ 'Post as new' => '÷ÉÓÔÁ×ÉÔÉ ÑË ÎÏ×ÉÊ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Project not on file!' => 'ðÒÏÅËÔÕ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Purchase Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Select from one of the names below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÅ ¦Ú ÎÁÓÔÕÐÎÉÈ ¦ÍÅÎ/ÎÁÚ×',
+ 'Select from one of the projects below' => '÷ÉÂÅÒ¦ÔØ ÏÄÉÎ ¦Ú ÎÁÓÔÕÐÎÉÈ ÐÒÏÅËÔ¦×',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Source' => 'äÖÅÒÅÌÏ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'Tax' => 'ðÏÄÁÔÏË',
+ 'Tax Included' => 'ðÏÄÁÔÏË ×ËÌÀÞÅÎÏ',
+ 'Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Transaction deleted!' => 'ïÐÅÒÁÃ¦Ñ ×ÉÄÁÌÅÎÁ',
+ 'Transaction posted!' => 'ïÐÅÒÁÃ¦Ñ ÚĦÊÓÎÅÎÁ',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'Vendor' => 'ðÏÓÔÁÞÁÌØÎÉË',
+ 'Vendor missing!' => 'ðÏÓÔÁÞÁÌØÎÉË ÎÅ ¦ÓÎÕ¤',
+ 'Vendor not on file!' => 'ðÏÔÁÞÁÌØÎÉËÁ ÎÅÍÁ Õ ÓÐÉÓËÕ ',
+ 'Yes' => 'Tak',
+ 'to' => 'ÄÏ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ïÐÅÒÁæ§_÷ÉÔÒÁÔ' => 'ap_transaction',
+ 'îÏ×Á_ÏÐÅÒÁæÑ_×ÉÔÒÁÔ' => 'add_accounts_payables_transaction',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ_ðÒÏ×ÏÄËÕ_÷ÉÔÒÁÔ' => 'edit_accounts_payables_transaction',
+ '÷ÉÓÔÁ×ÉÔÉ' => 'post',
+ '÷ÉÓÔÁ×ÉÔÉ_ÑË_ÎÏ×ÉÊ' => 'post_as_new',
+ 'òÁÈÕÎÏË_ÆÁËÔÕÒÁ' => 'purchase_invoice',
+ 'ðÏÎÏ×ÉÔÉ' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/ar b/sql-ledger/locale/ua/ar
new file mode 100644
index 0000000..cbbc5b1
--- /dev/null
+++ b/sql-ledger/locale/ua/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'ïÐÅÒÁÃ¦Ñ äÏÈÏĦ×',
+ 'AR Transactions' => 'ïÐÅÒÁÃ¦Ñ äÏÈÏĦ×',
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Add Accounts Receivables Transaction' => 'îÏ×Á ÏÐÅÒÁÃ¦Ñ ÄÏÈÏĦ×',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Amount' => 'óÕÍÁ',
+ 'Amount Due' => 'úÁÐÌÁÔÉÔÉ óÕÍÕ',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Are you sure you want to delete Transaction' => '÷É ÐÅ×Φ, ÝÏ ÈÏÞÅÔÅ ×ÉÄÁÌÉÔÉ ÄÁÎÕ ÏÐÅÒÁæÀ?',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'Cannot delete transaction!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÏÒÅ!',
+ 'Cannot post payment for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÐÌÁÔ¦Ö ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot post transaction for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÏÐÅÒÁæÀ ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot post transaction!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÏÐÅÒÁæÀ!',
+ 'Closed' => 'úÁËÒÉÔÏ',
+ 'Confirm!' => 'ð¦ÄÔ×ÅÒĦÔØ!',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Credit Limit' => 'ì¦Í¦Ô ËÒÅÄÉÔÕ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer' => 'ë̦¤ÎÔ',
+ 'Customer missing!' => 'îÅ ×ËÁÚÁÎÉÊ Ë̦¤ÎÔ!',
+ 'Customer not on file!' => 'ë̦¤ÎÔÁ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Date' => 'äÁÔÁ',
+ 'Date Paid' => 'äÁÔÁ ÏÐÌÁÔÉ',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Description' => 'ïÐÉÓ',
+ 'Due Date' => 'úÁÐÌÁÔÉÔÉ ÄÏ',
+ 'Due Date missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÔÅÒͦΠÏÐÌÁÔÉ!',
+ 'Edit Accounts Receivables Transaction' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ðÒÏ×ÏÄËÕ äÏÈÏĦ×',
+ 'Employee' => 'ðÒÁæ×ÎÉË',
+ 'Exch' => 'ëÕÒÓ',
+ 'Exchangerate' => 'ëÕÒÓ ×ÁÌÀÔÉ',
+ 'Exchangerate for payment missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ ÄÌÑ ÐÌÁÔÅÖÕ!',
+ 'Exchangerate missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ!',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'From' => '÷¦Ä / Ú',
+ 'ID' => '¶ÄÅÎÔÉƦËÁæÊÎÉÊ ÎÏÍÅÒ',
+ 'Include in Report' => 'äÏÄÁÔÉ ÄÏ úצÔÕ',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ',
+ 'Invoice Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice Number' => 'îÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ',
+ 'Invoice Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Notes' => 'ðÒÉͦÔËÉ',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'Open' => '÷¦ÄËÒÉÔÏ',
+ 'Order' => 'úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Number' => 'îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Paid' => 'úÁÐÌÁÞÅÎÏ',
+ 'Payment date missing!' => 'îÅ ×ËÁÚÁÎÏ ÄÁÔÕ ðÌÁÔÅÖÕ!',
+ 'Payments' => 'ðÌÁÔÅÖ¦',
+ 'Post' => '÷ÉÓÔÁ×ÉÔÉ',
+ 'Post as new' => '÷ÉÓÔÁ×ÉÔÉ ÑË ÎÏ×ÉÊ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Project not on file!' => 'ðÒÏÅËÔÕ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Remaining' => 'úÁÌÉÛÉÌÏÓØ',
+ 'Sales Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Select from one of the names below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÅ ¦Ú ÎÁÓÔÕÐÎÉÈ ¦ÍÅÎ/ÎÁÚ×',
+ 'Select from one of the projects below' => '÷ÉÂÅÒ¦ÔØ ÏÄÉÎ ¦Ú ÎÁÓÔÕÐÎÉÈ ÐÒÏÅËÔ¦×',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Source' => 'äÖÅÒÅÌÏ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'Tax' => 'ðÏÄÁÔÏË',
+ 'Tax Included' => 'ðÏÄÁÔÏË ×ËÌÀÞÅÎÏ',
+ 'Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Transaction deleted!' => 'ïÐÅÒÁÃ¦Ñ ×ÉÄÁÌÅÎÁ',
+ 'Transaction posted!' => 'ïÐÅÒÁÃ¦Ñ ÚĦÊÓÎÅÎÁ',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'Vendor not on file!' => 'ðÏÔÁÞÁÌØÎÉËÁ ÎÅÍÁ Õ ÓÐÉÓËÕ ',
+ 'Yes' => 'Tak',
+ 'to' => 'ÄÏ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ïÐÅÒÁæÑ_äÏÈÏĦ×' => 'ar_transaction',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ '÷ÉÓÔÁ×ÉÔÉ' => 'post',
+ '÷ÉÓÔÁ×ÉÔÉ_ÑË_ÎÏ×ÉÊ' => 'post_as_new',
+ 'òÁÈÕÎÏË_ÆÁËÔÕÒÁ' => 'sales_invoice',
+ 'ðÏÎÏ×ÉÔÉ' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/arap b/sql-ledger/locale/ua/arap
new file mode 100644
index 0000000..64f47c5
--- /dev/null
+++ b/sql-ledger/locale/ua/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Customer not on file!' => 'ë̦¤ÎÔÁ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Description' => 'ïÐÉÓ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Project not on file!' => 'ðÒÏÅËÔÕ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Select from one of the names below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÅ ¦Ú ÎÁÓÔÕÐÎÉÈ ¦ÍÅÎ/ÎÁÚ×',
+ 'Select from one of the projects below' => '÷ÉÂÅÒ¦ÔØ ÏÄÉÎ ¦Ú ÎÁÓÔÕÐÎÉÈ ÐÒÏÅËÔ¦×',
+ 'Vendor not on file!' => 'ðÏÔÁÞÁÌØÎÉËÁ ÎÅÍÁ Õ ÓÐÉÓËÕ ',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/ca b/sql-ledger/locale/ua/ca
new file mode 100644
index 0000000..64f42dd
--- /dev/null
+++ b/sql-ledger/locale/ua/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'Balance' => 'âÁÌÁÎÓ',
+ 'Chart of Accounts' => 'ðÌÁÎ òÁÈÕÎ˦×',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Date' => 'äÁÔÁ',
+ 'Debit' => 'äÅÂÉÔ',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Description' => 'ïÐÉÓ',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'From' => '÷¦Ä / Ú',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'äÏÄÁÔÉ ÄÏ úצÔÕ',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'List Transactions' => 'óÐÉÓÏË ðÒÏ×ÏÄÏË',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'Reference' => 'úÓÉÌËÁ',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'to' => 'ÄÏ',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'óÐÉÓÏË_ðÒÏ×ÏÄÏË' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/cp b/sql-ledger/locale/ua/cp
new file mode 100644
index 0000000..0a74130
--- /dev/null
+++ b/sql-ledger/locale/ua/cp
@@ -0,0 +1,77 @@
+$self{texts} = {
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Amount' => 'óÕÍÁ',
+ 'Amount does not equal applied!' => 'óÕÍÁ ÎÅ ÄÏÒ¦×ÎÀ¤ ÚÁÓÔÏÓÏ×ÁΦÊ!',
+ 'Amount missing!' => 'îÅ ×ËÁÚÁÎÁ ÓÕÍÁ!',
+ 'Applied' => 'úÁÓÔÏÓÏ×ÁÎÏ',
+ 'Cannot post payment!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÐÌÁÔ¦Ö!',
+ 'Cannot process payment for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ÐÒÏ×ÅÓÔÉ ÐÌÁÔ¦Ö ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Check' => 'þÅË',
+ 'Check printed!' => 'þÅË ÎÁÄÒÕËÏ×ÁÎÏ!',
+ 'Check printing failed!' => 'äÒÕË ÞÅËÕ ÎÅ ×ÄÁ×ÓÑ!',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer' => 'ë̦¤ÎÔ',
+ 'Customer not on file!' => 'ë̦¤ÎÔÁ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Date' => 'äÁÔÁ',
+ 'Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ!',
+ 'Description' => 'ïÐÉÓ',
+ 'Due' => 'äÏ',
+ 'Exchangerate' => 'ëÕÒÓ ×ÁÌÀÔÉ',
+ 'From' => '÷¦Ä / Ú',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Invoices' => 'òÁÈÕÎËÉ-ÆÁËÔÕÒÉ',
+ 'Nothing applied!' => 'î¦ÞÏÇÏ ÎÅ ÚÁÓÔÏÓÏ×ÁÎÏ!',
+ 'Number' => 'îÏÍÅÒ',
+ 'Paid in full' => 'úÁÐÌÁÞÅÎÏ ×ÐÏ×Φ',
+ 'Payment' => 'ðÌÁÔ¦Ö',
+ 'Payment posted!' => 'ðÌÁÔ¦Ö ×ÉÓÔÁ×ÌÅÎÏ!',
+ 'Post' => '÷ÉÓÔÁ×ÉÔÉ',
+ 'Print' => 'îÁÄÒÕËÕ×ÁÔÉ',
+ 'Printer' => 'ðÒÉÎÔÅÒ',
+ 'Project not on file!' => 'ðÒÏÅËÔÕ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Receipt' => 'ë×ÉÔÁÎæÑ',
+ 'Receipt printed!' => 'Receipt printed!',
+ 'Receipt printing failed!' => 'Receipt printing failed!',
+ 'Reference' => 'úÓÉÌËÁ',
+ 'Screen' => 'åËÒÁÎ',
+ 'Select from one of the names below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÅ ¦Ú ÎÁÓÔÕÐÎÉÈ ¦ÍÅÎ/ÎÁÚ×',
+ 'Select from one of the projects below' => '÷ÉÂÅÒ¦ÔØ ÏÄÉÎ ¦Ú ÎÁÓÔÕÐÎÉÈ ÐÒÏÅËÔ¦×',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'Vendor' => 'ðÏÓÔÁÞÁÌØÎÉË',
+ 'Vendor not on file!' => 'ðÏÔÁÞÁÌØÎÉËÁ ÎÅÍÁ Õ ÓÐÉÓËÕ ',
+ 'to' => 'ÄÏ',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÓÔÁ×ÉÔÉ' => 'post',
+ 'îÁÄÒÕËÕ×ÁÔÉ' => 'print',
+ 'ðÏÎÏ×ÉÔÉ' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/ct b/sql-ledger/locale/ua/ct
new file mode 100644
index 0000000..80db8df
--- /dev/null
+++ b/sql-ledger/locale/ua/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'îÏ×ÉÊ',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'All' => '÷Ó¦',
+ 'Bcc' => 'ðÒÉ×ÁÔÎÁ ËÏÐ¦Ñ ÄÏ',
+ 'Cannot delete customer!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ Ë̦¤ÎÔÁ',
+ 'Cannot delete vendor!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÐÏÓÔÁÞÁÌØÎÉËÁ!',
+ 'Cc' => 'ëÏÐ¦Ñ ÄÏ',
+ 'Contact' => 'ëÏÎÔÁËÔÎÁ ÏÓÏÂÁ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Credit Limit' => 'ì¦Í¦Ô ËÒÅÄÉÔÕ',
+ 'Customer deleted!' => 'ë̦¤ÎÔÁ ×ÉÄÁÌÅÎÏ!',
+ 'Customer saved!' => 'ë̦¤ÎÔÁ ÚÂÅÒÅÖÅÎÏ!',
+ 'Customers' => 'ë̦¤ÎÔÉ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Discount' => 'óËÉÄËÁ',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'Edit Customer' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ë̦¤ÎÔÁ',
+ 'Edit Vendor' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ðÏÓÔÁÞÁÌØÎÉËÁ',
+ 'Fax' => 'æÁÈ',
+ 'Include in Report' => 'äÏÄÁÔÉ ÄÏ úצÔÕ',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'Name missing!' => 'îÅ ×ËÁÚÁÎÅ ¦Í\'Ñ (ÎÁÚ×Á)!',
+ 'Notes' => 'ðÒÉͦÔËÉ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Order' => 'úÁÍÏ×ÌÅÎÎÑ',
+ 'Orphaned' => '÷¦ÄÏËÒÅÍÌÅÎÉÊ/ïÓÉÒÏÔ¦ÌÉÊ',
+ 'Phone' => 'ôÅÌ.',
+ 'Save' => 'úÂÅÒÅÇÔÉ',
+ 'Ship to' => 'ðÏÓÌÁÔÉ ÄÏ',
+ 'Tax Included' => 'ðÏÄÁÔÏË ×ËÌÀÞÅÎÏ',
+ 'Taxable' => 'ïÐÏÄÁÔËÏ×Õ¤ÔØÓÑ',
+ 'Terms: Net' => 'õÍÏ×É: úÁÐÌÁÔÉÔÉ',
+ 'Transactions exist, cannot delete customer!' => '¶ÓÎÕÀÔØ ÏÐÅÒÁæ§, ÎÅ ÍÏÖÎÁ ×ÉÄÁÌÉÔÉ Ë̦¤ÎÔÁ',
+ 'Transactions exist, cannot delete vendor!' => '¶ÓÎÕÀÔØ ÏÐÅÒÁæ§, ÎÅ ÍÏÖÎÁ ×ÉÄÁÌÉÔÉ ÐÏÓÔÁÞÁÌØÎÉËÁ',
+ 'Vendor deleted!' => 'ðÏÓÔÁÞÁÌØÎÉË ×ÉÄÁÌÅÎÉÊ',
+ 'Vendor saved!' => 'ðÏÓÔÁÞÁÌØÎÉËÁ ÚÂÅÒÅÖÅÎÏ',
+ 'Vendors' => 'ðÏÓÔÁÞÁÌØÎÉËÉ',
+ 'days' => 'ÄΦ×',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'îÏ×ÉÊ' => 'add',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ 'òÁÈÕÎÏË_ÆÁËÔÕÒÁ' => 'invoice',
+ 'úÁÍÏ×ÌÅÎÎÑ' => 'order',
+ 'úÂÅÒÅÇÔÉ' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/gl b/sql-ledger/locale/ua/gl
new file mode 100644
index 0000000..77e0736
--- /dev/null
+++ b/sql-ledger/locale/ua/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'ïÐÅÒÁæ§ ÷ÉÔÒÁÔ',
+ 'AR Transaction' => 'ïÐÅÒÁÃ¦Ñ äÏÈÏĦ×',
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Add General Ledger Transaction' => 'îÏ×Á ÏÐÅÒÁæÑ',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'All' => '÷Ó¦',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Are you sure you want to delete Transaction' => '÷É ÐÅ×Φ, ÝÏ ÈÏÞÅÔÅ ×ÉÄÁÌÉÔÉ ÄÁÎÕ ÏÐÅÒÁæÀ?',
+ 'Asset' => 'áËÔÉ×',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'Balance' => 'âÁÌÁÎÓ',
+ 'Cannot delete transaction!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÏÒÅ!',
+ 'Cannot have a value in both Debit and Credit!' => 'îÅ ÍÏÖÎÁ ÏÄÎÏÞÁÓÎÏ ÍÁÔÉ ÓÕÍÉ × äÅÂÉÔ¦ ¦ ëÒÅÄÉÔ¦',
+ 'Cannot post a transaction without a value!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÏÐÅÒÁæÀ ÂÅÚ ×ÁÒÔÏÓÔ¦!',
+ 'Cannot post transaction for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÏÐÅÒÁæÀ ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Confirm!' => 'ð¦ÄÔ×ÅÒĦÔØ!',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Customer not on file!' => 'ë̦¤ÎÔÁ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Date' => 'äÁÔÁ',
+ 'Debit' => 'äÅÂÉÔ',
+ 'Debit and credit out of balance!' => 'äÅÂÉÔ ¦ ËÒÅÄÉÔ ÎÅ ÚÂÁÌÁÎÓÏ×ÁΦ!',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Description' => 'ïÐÉÓ',
+ 'Edit General Ledger Transaction' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ïÐÅÒÁæÀ çÏÌÏ×Îϧ ëÎÉÇÉ',
+ 'Equity' => 'ëÁЦÔÁÌ',
+ 'Expense' => '÷ÉÄÁÔËÉ',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'From' => '÷¦Ä / Ú',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'çë ïÐÅÒÁæÑ',
+ 'General Ledger' => 'çÏÌÏ×ÎÁ ëÎÉÇÁ',
+ 'ID' => '¶ÄÅÎÔÉƦËÁæÊÎÉÊ ÎÏÍÅÒ',
+ 'Include in Report' => 'äÏÄÁÔÉ ÄÏ úצÔÕ',
+ 'Income' => 'ðÒÉÂÕÔÏË',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'Liability' => 'ðÁÓÓÉ×',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Notes' => 'ðÒÉͦÔËÉ',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'Post' => '÷ÉÓÔÁ×ÉÔÉ',
+ 'Post as new' => '÷ÉÓÔÁ×ÉÔÉ ÑË ÎÏ×ÉÊ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Project not on file!' => 'ðÒÏÅËÔÕ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Purchase Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Reference' => 'úÓÉÌËÁ',
+ 'Reference missing!' => 'îÅ ×ËÁÚÁÎÁ ÚÓÉÌËÁ!',
+ 'Reports' => 'úצÔÉ',
+ 'Sales Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Select from one of the names below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÅ ¦Ú ÎÁÓÔÕÐÎÉÈ ¦ÍÅÎ/ÎÁÚ×',
+ 'Select from one of the projects below' => '÷ÉÂÅÒ¦ÔØ ÏÄÉÎ ¦Ú ÎÁÓÔÕÐÎÉÈ ÐÒÏÅËÔ¦×',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Source' => 'äÖÅÒÅÌÏ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'Transaction Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ÏÐÅÒÁæ§',
+ 'Transaction deleted!' => 'ïÐÅÒÁÃ¦Ñ ×ÉÄÁÌÅÎÁ',
+ 'Transaction posted!' => 'ïÐÅÒÁÃ¦Ñ ÚĦÊÓÎÅÎÁ',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'Vendor not on file!' => 'ðÏÔÁÞÁÌØÎÉËÁ ÎÅÍÁ Õ ÓÐÉÓËÕ ',
+ 'Yes' => 'Tak',
+ 'to' => 'ÄÏ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'ïÐÅÒÁæ§_÷ÉÔÒÁÔ' => 'ap_transaction',
+ 'ïÐÅÒÁæÑ_äÏÈÏĦ×' => 'ar_transaction',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ 'çë_ïÐÅÒÁæÑ' => 'gl_transaction',
+ '÷ÉÓÔÁ×ÉÔÉ' => 'post',
+ '÷ÉÓÔÁ×ÉÔÉ_ÑË_ÎÏ×ÉÊ' => 'post_as_new',
+ 'òÁÈÕÎÏË_ÆÁËÔÕÒÁ' => 'purchase_invoice',
+ 'òÁÈÕÎÏË_ÆÁËÔÕÒÁ' => 'sales_invoice',
+ 'ðÏÎÏ×ÉÔÉ' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/ic b/sql-ledger/locale/ua/ic
new file mode 100644
index 0000000..9a32568
--- /dev/null
+++ b/sql-ledger/locale/ua/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => 'áËÔÉ×ÎÉÊ',
+ 'Add' => 'îÏ×ÉÊ',
+ 'Add Assembly' => 'îÏ×ÉÊ ËÏÍÐÌÅËÔ',
+ 'Add Part' => 'îÏ×ÉÊ ôÏ×ÁÒ',
+ 'Add Purchase Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ËÕЦ×ÌÀ',
+ 'Add Sales Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ÐÒÏÄÁÖ',
+ 'Add Service' => 'îÏ×Á ÐÏÓÌÕÇÁ',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Assemblies' => 'ëÏÍÐÌÅËÔÉ',
+ 'Assemblies restocked!' => 'ëÏÍÐÌÅËÔÉ ¦Î×ÅÎÔÁÒÉÚÏ×ÁΦ!',
+ 'Assembly Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ËÏÍÐÌÅËÔÕ!',
+ 'Attachment' => 'äÏÄÁÔÏË',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'BOM' => 'BOM',
+ 'Bcc' => 'ðÒÉ×ÁÔÎÁ ËÏÐ¦Ñ ÄÏ',
+ 'Bin' => 'Bin',
+ 'Bought' => 'ëÕÐÌÅÎÏ',
+ 'COGS' => 'COGS',
+ 'Cannot delete item already invoiced!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÔÏ×ÁÒ, ÎÁ ÑËÉÊ ×ÖÅ ×ÉÐÉÓÁÎÁ ÒÁÈÕÎÏË-ÆÁËÔÕÒÁ!',
+ 'Cannot delete item on order!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ Ò¦Þ ¦Ú ÚÁÍÏ×ÌÅÎÎÑ!',
+ 'Cannot delete item which is part of an assembly!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÔÏ×ÁÒ, ÑËÉÊ ¤ ÞÁÓÔÉÎÏÀ ËÏÍÐÌÅËÔÕ!',
+ 'Cannot delete item!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÃÅÊ ÅÌÅÍÅÎÔ',
+ 'Cannot stock assemblies!' => 'îÅ ÍÏÖÌÉ×Ï ¦Î×ÅÎÔÁÒÉÚÕ×ÁÔÉ ËÏÍÐÌÅËÔÉ!',
+ 'Cc' => 'ëÏÐ¦Ñ ÄÏ',
+ 'Contact' => 'ëÏÎÔÁËÔÎÁ ÏÓÏÂÁ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Copies' => 'ëÏЦÊ',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Delivery Date' => 'äÁÔÁ ÄÏÓÔÁ×ËÉ',
+ 'Description' => 'ïÐÉÓ',
+ 'Drawing' => 'íÁÌÀÎÏË',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'E-mail address missing!' => 'îÅ ×ËÁÚÁÎÁ ÁÄÒÅÓÁ ÅÌ. ÐÏÛÔÉ!',
+ 'Edit Assembly' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ËÏÍÐÌÅËÔ',
+ 'Edit Part' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ôÏ×ÁÒ',
+ 'Edit Service' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ÐÏÓÌÕÇÕ',
+ 'Expense' => '÷ÉÄÁÔËÉ',
+ 'Extended' => 'ðÒÏÄÏ×ÖÅÎÏ',
+ 'Fax' => 'æÁÈ',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'From' => '÷¦Ä / Ú',
+ 'Image' => 'úÏÂÒÁÖÅÎÎÑ',
+ 'In-line' => '÷ËÌÀÞÅÎÏ (In-line)',
+ 'Include in Report' => 'äÏÄÁÔÉ ÄÏ úצÔÕ',
+ 'Income' => 'ðÒÉÂÕÔÏË',
+ 'Individual Items' => '¶ÎÄÉצÄÕÁÌØΦ þÁÓÔÉÎÉ',
+ 'Inventory' => '¶Î×ÅÎÔÁÒ',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'ë¦ÌØ˦ÓÔØ × ¦Î×ÅÎÔÁÒ¦ ÐÏ×ÉÎÎÁ ÂÕÔÉ ÎÕÌØ, ÐÅÒÛ Î¦Ö ÍÏÖÎÁ ÐÏÚÎÁÞÉÔÉ ËÏÍÐÌÅËÔ ÚÁÓÔÁÒ¦ÌÉÍ!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'ë¦ÌØ˦ÓÔØ × ¦Î×ÅÎÔÁÒ¦ ÐÏ×ÉÎÎÁ ÂÕÔÉ ÎÕÌØ, ÐÅÒÛ Î¦Ö ÍÏÖÎÁ ÐÏÚÎÁÞÉÔÉ ÃÉÊ ÔÏ×ÁÒ ÚÁÓÔÁÒ¦ÌÉÍ!',
+ 'Inventory quantity must be zero!' => 'ë¦ÌØ˦ÓÔØ × ¦Î×ÅÎÔÁÒ¦ ÐÏ×ÉÎÎÁ ÂÕÔÉ ÎÕÌØ!',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Invoice Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice Number' => 'îÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ',
+ 'Invoice Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Item deleted!' => 'ò¦Þ ×ÉÄÁÌÅÎÏ!',
+ 'Item not on file!' => 'òÅÞ¦ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'Last Cost' => 'ëÕЦ×ÅÌØÎÁ ã¦ÎÁ',
+ 'Line Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Link Accounts' => 'ðÏ×ÑÚÁÔÉ òÁÈÕÎËÉ',
+ 'List Price' => 'ã¦ÎÁ',
+ 'Make' => '÷ÉÒÏÂÎÉÃÔ×Ï',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Message' => 'ðÏצÄÏÍÌÅÎÎÑ',
+ 'Microfiche' => 'í¦ËÒÏƦÛÁ',
+ 'Model' => 'íÏÄÅÌØ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'No.' => 'No.',
+ 'Notes' => 'ðÒÉͦÔËÉ',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Number missing in Row' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ Õ ÒÑÄËÕ',
+ 'Obsolete' => 'úÁÓÔÁÒ¦ÌÅ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'On Hand' => 'îÁ òÕËÁÈ',
+ 'On Order' => 'îÁ úÁÍÏ×ÌÅÎΦ',
+ 'Order' => 'úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ úÁÍÏ×ÌÅÎÎÑ!',
+ 'Order Number' => 'îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Number missing!' => 'îÅ ×ËÁÚÁÎÏ îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Ordered' => 'úÁÍÏ×ÌÅÎÏ',
+ 'Orphaned' => '÷¦ÄÏËÒÅÍÌÅÎÉÊ/ïÓÉÒÏÔ¦ÌÉÊ',
+ 'PDF' => 'PDF ÆÏÒÍÁÔ',
+ 'Packing List' => 'ðÁËÕ×ÁÌØÎÉÊ óÐÉÓÏË',
+ 'Packing List Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Packing List Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ îÏÍÅÒ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Part' => 'ôÏ×ÁÒ',
+ 'Part Number missing!' => 'îÅ ×ËÁÚÁÎÏ îÏÍÅÒ ôÏ×ÁÒÕ!',
+ 'Parts' => 'ÔÏ×ÁÒÉ',
+ 'Phone' => 'ôÅÌ.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'ã¦ÎÁ',
+ 'Printer' => 'ðÒÉÎÔÅÒ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Purchase Order' => 'ëÕЦ×ÅÌØÎÅ úÁÍÏ×ÌÅÎÎÑ',
+ 'Qty' => 'ë¦ÌØ˦ÓÔØ',
+ 'ROP' => 'ROP',
+ 'Recd' => 'ïÔÒÉÍÁÎÏ',
+ 'Required by' => 'ôÅÒͦΠÄÏÓÔÁ×ËÉ',
+ 'Sales' => 'úÂÕÔ',
+ 'Sales Order' => 'îÁËÌÁÄÎÁ ðÒÏÄÁÖÕ ',
+ 'Save' => 'úÂÅÒÅÇÔÉ',
+ 'Screen' => 'åËÒÁÎ',
+ 'Select from one of the items below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÕ ¦Ú ÎÁÓÔÕÐÎÉÈ ÒÅÞÅÊ',
+ 'Select postscript or PDF!' => '÷ÉÂÅÒ¦ÔØ postscript ÁÂÏ PDF ÆÏÒÍÁÔ!',
+ 'Sell Price' => '÷¦ÄÐÕÓËÎÁ ã¦ÎÁ',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Service' => 'ðÏÓÌÕÇÁ',
+ 'Service Number missing!' => 'îÏÍÅÒ ðÏÓÌÕÇÉ ÎÅ ×ËÁÚÁÎÏ',
+ 'Services' => 'ðÏÓÌÕÇÉ',
+ 'Ship' => 'ðÏÓÌÁÔÉ',
+ 'Ship to' => 'ðÏÓÌÁÔÉ ÄÏ',
+ 'Short' => 'óËÏÒÏÞÅÎÏ',
+ 'Sold' => 'ðÒÏÄÁÎÏ',
+ 'Stock Assembly' => '¶Î×ÅÎÔÁÒ ëÏÍÐÌÅËÔÕ',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'Tax' => 'ðÏÄÁÔÏË',
+ 'To' => 'äÏ',
+ 'Top Level' => '÷ÅÒÈÎ¦Ê ò¦×ÅÎØ',
+ 'Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Unit' => 'ïÄÉÎÉÃÑ',
+ 'Unit of measure' => 'ïÄÉÎÉÃÑ ×ÉͦÒÕ',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'Updated' => 'ðÏÎÏ×ÌÅÎÏ',
+ 'Weight' => '÷ÁÇÁ',
+ 'What type of item is this?' => 'ñËÉÊ ÃÅ ×ÉÄ/ÔÉÐ ÔÏ×ÁÒÕ',
+ 'ea' => 'ÛÔ.',
+ 'emailed to' => 'ÐÏÓÌÁÎÏ ÐÏ ÅÌ. ÐÏÛÔ¦ ÄÏ',
+ 'hr' => 'ÇÏÄ.',
+ 'sent to printer' => 'ÐÏÓÌÁÎÏ ÄÏ ÐÒÉÎÔÅÒÁ',
+ 'to' => 'ÄÏ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'îÏ×ÉÊ' => 'add',
+ 'îÏ×ÉÊ_ËÏÍÐÌÅËÔ' => 'add_assembly',
+ 'îÏ×ÉÊ_ôÏ×ÁÒ' => 'add_part',
+ 'îÏ×Á_ÐÏÓÌÕÇÁ' => 'add_service',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ_ËÏÍÐÌÅËÔ' => 'edit_assembly',
+ '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ_ôÏ×ÁÒ' => 'edit_part',
+ '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ_ÐÏÓÌÕÇÕ' => 'edit_service',
+ 'úÂÅÒÅÇÔÉ' => 'save',
+ 'ðÏÎÏ×ÉÔÉ' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/io b/sql-ledger/locale/ua/io
new file mode 100644
index 0000000..dba8567
--- /dev/null
+++ b/sql-ledger/locale/ua/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ËÕЦ×ÌÀ',
+ 'Add Sales Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ÐÒÏÄÁÖ',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Attachment' => 'äÏÄÁÔÏË',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'Bcc' => 'ðÒÉ×ÁÔÎÁ ËÏÐ¦Ñ ÄÏ',
+ 'Bin' => 'Bin',
+ 'Cc' => 'ëÏÐ¦Ñ ÄÏ',
+ 'Contact' => 'ëÏÎÔÁËÔÎÁ ÏÓÏÂÁ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Copies' => 'ëÏЦÊ',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Delivery Date' => 'äÁÔÁ ÄÏÓÔÁ×ËÉ',
+ 'Description' => 'ïÐÉÓ',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'E-mail address missing!' => 'îÅ ×ËÁÚÁÎÁ ÁÄÒÅÓÁ ÅÌ. ÐÏÛÔÉ!',
+ 'Extended' => 'ðÒÏÄÏ×ÖÅÎÏ',
+ 'Fax' => 'æÁÈ',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'In-line' => '÷ËÌÀÞÅÎÏ (In-line)',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Invoice Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Item not on file!' => 'òÅÞ¦ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Message' => 'ðÏצÄÏÍÌÅÎÎÑ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'No.' => 'No.',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Number missing in Row' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ Õ ÒÑÄËÕ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'Order' => 'úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ úÁÍÏ×ÌÅÎÎÑ!',
+ 'Order Number missing!' => 'îÅ ×ËÁÚÁÎÏ îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'PDF' => 'PDF ÆÏÒÍÁÔ',
+ 'Packing List' => 'ðÁËÕ×ÁÌØÎÉÊ óÐÉÓÏË',
+ 'Packing List Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Packing List Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ îÏÍÅÒ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Part' => 'ôÏ×ÁÒ',
+ 'Phone' => 'ôÅÌ.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'ã¦ÎÁ',
+ 'Printer' => 'ðÒÉÎÔÅÒ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Purchase Order' => 'ëÕЦ×ÅÌØÎÅ úÁÍÏ×ÌÅÎÎÑ',
+ 'Qty' => 'ë¦ÌØ˦ÓÔØ',
+ 'Recd' => 'ïÔÒÉÍÁÎÏ',
+ 'Required by' => 'ôÅÒͦΠÄÏÓÔÁ×ËÉ',
+ 'Sales Order' => 'îÁËÌÁÄÎÁ ðÒÏÄÁÖÕ ',
+ 'Screen' => 'åËÒÁÎ',
+ 'Select from one of the items below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÕ ¦Ú ÎÁÓÔÕÐÎÉÈ ÒÅÞÅÊ',
+ 'Select postscript or PDF!' => '÷ÉÂÅÒ¦ÔØ postscript ÁÂÏ PDF ÆÏÒÍÁÔ!',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Service' => 'ðÏÓÌÕÇÁ',
+ 'Ship' => 'ðÏÓÌÁÔÉ',
+ 'Ship to' => 'ðÏÓÌÁÔÉ ÄÏ',
+ 'Subject' => 'ôÅÍÁ',
+ 'To' => 'äÏ',
+ 'Unit' => 'ïÄÉÎÉÃÑ',
+ 'What type of item is this?' => 'ñËÉÊ ÃÅ ×ÉÄ/ÔÉÐ ÔÏ×ÁÒÕ',
+ 'emailed to' => 'ÐÏÓÌÁÎÏ ÐÏ ÅÌ. ÐÏÛÔ¦ ÄÏ',
+ 'sent to printer' => 'ÐÏÓÌÁÎÏ ÄÏ ÐÒÉÎÔÅÒÁ',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/ir b/sql-ledger/locale/ua/ir
new file mode 100644
index 0000000..8caf3fd
--- /dev/null
+++ b/sql-ledger/locale/ua/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Add Purchase Invoice' => 'îÏ×ÉÊ ëÕЦ×ÅÌØÎÉÊ òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Add Purchase Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ËÕЦ×ÌÀ',
+ 'Add Sales Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ÐÒÏÄÁÖ',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Amount' => 'óÕÍÁ',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Are you sure you want to delete Invoice Number' => '÷É ÐÅ×Φ, ÝÏ ÈÏÞÅÔÅ ×ÉÄÁÌÉÔÉ ÄÁÎÉÊ ÒÁÈÕÎÏË?',
+ 'Attachment' => 'äÏÄÁÔÏË',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'Bcc' => 'ðÒÉ×ÁÔÎÁ ËÏÐ¦Ñ ÄÏ',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÁÈÕÎÏË-ÆÁËÔÕÒÕ',
+ 'Cannot post invoice for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÒÁÈÕÎÏË-ÆÁËÔÕÒÕ ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot post invoice!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÒÁÈÕÎÏË-ÆÁËÔÕÒÕ!',
+ 'Cannot post payment for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÐÌÁÔ¦Ö ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cc' => 'ëÏÐ¦Ñ ÄÏ',
+ 'Confirm!' => 'ð¦ÄÔ×ÅÒĦÔØ!',
+ 'Contact' => 'ëÏÎÔÁËÔÎÁ ÏÓÏÂÁ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Copies' => 'ëÏЦÊ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer not on file!' => 'ë̦¤ÎÔÁ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Date' => 'äÁÔÁ',
+ 'Date Due' => 'úÁÐÌÁÔÉÔÉ ÄÏ',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Delivery Date' => 'äÁÔÁ ÄÏÓÔÁ×ËÉ',
+ 'Description' => 'ïÐÉÓ',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'E-mail address missing!' => 'îÅ ×ËÁÚÁÎÁ ÁÄÒÅÓÁ ÅÌ. ÐÏÛÔÉ!',
+ 'Edit Purchase Invoice' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ëÕЦ×ÅÌØÎÉÊ òÁÈÕÎÏË-ÆÁËÔÕÒÕ',
+ 'Exch' => 'ëÕÒÓ',
+ 'Exchangerate' => 'ëÕÒÓ ×ÁÌÀÔÉ',
+ 'Exchangerate for payment missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ ÄÌÑ ÐÌÁÔÅÖÕ!',
+ 'Exchangerate missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ!',
+ 'Extended' => 'ðÒÏÄÏ×ÖÅÎÏ',
+ 'Fax' => 'æÁÈ',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'In-line' => '÷ËÌÀÞÅÎÏ (In-line)',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ',
+ 'Invoice Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice Number' => 'îÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ',
+ 'Invoice Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice deleted!' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ ×ÉÄÁÌÅÎÉÊ!',
+ 'Invoice posted!' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ ×ÉÓÔÁ×ÌÅÎÉÊ!',
+ 'Item not on file!' => 'òÅÞ¦ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Message' => 'ðÏצÄÏÍÌÅÎÎÑ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'No.' => 'No.',
+ 'Notes' => 'ðÒÉͦÔËÉ',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Number missing in Row' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ Õ ÒÑÄËÕ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'Order' => 'úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ úÁÍÏ×ÌÅÎÎÑ!',
+ 'Order Number' => 'îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Number missing!' => 'îÅ ×ËÁÚÁÎÏ îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'PDF' => 'PDF ÆÏÒÍÁÔ',
+ 'Packing List' => 'ðÁËÕ×ÁÌØÎÉÊ óÐÉÓÏË',
+ 'Packing List Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Packing List Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ îÏÍÅÒ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Part' => 'ôÏ×ÁÒ',
+ 'Payment date missing!' => 'îÅ ×ËÁÚÁÎÏ ÄÁÔÕ ðÌÁÔÅÖÕ!',
+ 'Payments' => 'ðÌÁÔÅÖ¦',
+ 'Phone' => 'ôÅÌ.',
+ 'Post' => '÷ÉÓÔÁ×ÉÔÉ',
+ 'Post as new' => '÷ÉÓÔÁ×ÉÔÉ ÑË ÎÏ×ÉÊ',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'ã¦ÎÁ',
+ 'Printer' => 'ðÒÉÎÔÅÒ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Project not on file!' => 'ðÒÏÅËÔÕ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Purchase Order' => 'ëÕЦ×ÅÌØÎÅ úÁÍÏ×ÌÅÎÎÑ',
+ 'Qty' => 'ë¦ÌØ˦ÓÔØ',
+ 'Recd' => 'ïÔÒÉÍÁÎÏ',
+ 'Record in' => '÷ÎÅÓÔÉ ×',
+ 'Required by' => 'ôÅÒͦΠÄÏÓÔÁ×ËÉ',
+ 'Sales Order' => 'îÁËÌÁÄÎÁ ðÒÏÄÁÖÕ ',
+ 'Screen' => 'åËÒÁÎ',
+ 'Select from one of the items below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÕ ¦Ú ÎÁÓÔÕÐÎÉÈ ÒÅÞÅÊ',
+ 'Select from one of the names below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÅ ¦Ú ÎÁÓÔÕÐÎÉÈ ¦ÍÅÎ/ÎÁÚ×',
+ 'Select from one of the projects below' => '÷ÉÂÅÒ¦ÔØ ÏÄÉÎ ¦Ú ÎÁÓÔÕÐÎÉÈ ÐÒÏÅËÔ¦×',
+ 'Select postscript or PDF!' => '÷ÉÂÅÒ¦ÔØ postscript ÁÂÏ PDF ÆÏÒÍÁÔ!',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Service' => 'ðÏÓÌÕÇÁ',
+ 'Ship' => 'ðÏÓÌÁÔÉ',
+ 'Ship to' => 'ðÏÓÌÁÔÉ ÄÏ',
+ 'Source' => 'äÖÅÒÅÌÏ',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'Tax Included' => 'ðÏÄÁÔÏË ×ËÌÀÞÅÎÏ',
+ 'To' => 'äÏ',
+ 'Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Unit' => 'ïÄÉÎÉÃÑ',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'Vendor' => 'ðÏÓÔÁÞÁÌØÎÉË',
+ 'Vendor missing!' => 'ðÏÓÔÁÞÁÌØÎÉË ÎÅ ¦ÓÎÕ¤',
+ 'Vendor not on file!' => 'ðÏÔÁÞÁÌØÎÉËÁ ÎÅÍÁ Õ ÓÐÉÓËÕ ',
+ 'What type of item is this?' => 'ñËÉÊ ÃÅ ×ÉÄ/ÔÉÐ ÔÏ×ÁÒÕ',
+ 'Yes' => 'Tak',
+ 'ea' => 'ÛÔ.',
+ 'emailed to' => 'ÐÏÓÌÁÎÏ ÐÏ ÅÌ. ÐÏÛÔ¦ ÄÏ',
+ 'sent to printer' => 'ÐÏÓÌÁÎÏ ÄÏ ÐÒÉÎÔÅÒÁ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ 'úÁÍÏ×ÌÅÎÎÑ' => 'order',
+ '÷ÉÓÔÁ×ÉÔÉ' => 'post',
+ '÷ÉÓÔÁ×ÉÔÉ_ÑË_ÎÏ×ÉÊ' => 'post_as_new',
+ 'ðÏÎÏ×ÉÔÉ' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/is b/sql-ledger/locale/ua/is
new file mode 100644
index 0000000..f62cc69
--- /dev/null
+++ b/sql-ledger/locale/ua/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Add Purchase Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ËÕЦ×ÌÀ',
+ 'Add Sales Invoice' => 'îÏ×ÉÊ òÁÈÕÎÏ-ÆÁËÔÕÒÁ',
+ 'Add Sales Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ÐÒÏÄÁÖ',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Amount' => 'óÕÍÁ',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Are you sure you want to delete Invoice Number' => '÷É ÐÅ×Φ, ÝÏ ÈÏÞÅÔÅ ×ÉÄÁÌÉÔÉ ÄÁÎÉÊ ÒÁÈÕÎÏË?',
+ 'Attachment' => 'äÏÄÁÔÏË',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'Bcc' => 'ðÒÉ×ÁÔÎÁ ËÏÐ¦Ñ ÄÏ',
+ 'Bin' => 'Bin',
+ 'Cannot delete invoice!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÁÈÕÎÏË-ÆÁËÔÕÒÕ',
+ 'Cannot post invoice for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÒÁÈÕÎÏË-ÆÁËÔÕÒÕ ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cannot post invoice!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÒÁÈÕÎÏË-ÆÁËÔÕÒÕ!',
+ 'Cannot post payment for a closed period!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÓÔÁ×ÉÔÉ ÐÌÁÔ¦Ö ÄÌÑ ÚÁËÒÉÔÏÇÏ ÐÅÒ¦ÏÄÕ!',
+ 'Cc' => 'ëÏÐ¦Ñ ÄÏ',
+ 'Confirm!' => 'ð¦ÄÔ×ÅÒĦÔØ!',
+ 'Contact' => 'ëÏÎÔÁËÔÎÁ ÏÓÏÂÁ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Copies' => 'ëÏЦÊ',
+ 'Credit Limit' => 'ì¦Í¦Ô ËÒÅÄÉÔÕ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer' => 'ë̦¤ÎÔ',
+ 'Customer missing!' => 'îÅ ×ËÁÚÁÎÉÊ Ë̦¤ÎÔ!',
+ 'Customer not on file!' => 'ë̦¤ÎÔÁ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Date' => 'äÁÔÁ',
+ 'Date Due' => 'úÁÐÌÁÔÉÔÉ ÄÏ',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Delivery Date' => 'äÁÔÁ ÄÏÓÔÁ×ËÉ',
+ 'Description' => 'ïÐÉÓ',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'E-mail address missing!' => 'îÅ ×ËÁÚÁÎÁ ÁÄÒÅÓÁ ÅÌ. ÐÏÛÔÉ!',
+ 'Edit Sales Invoice' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ òÁÈÕÎÏË-ÆÁËÔÕÒÕ',
+ 'Exch' => 'ëÕÒÓ',
+ 'Exchangerate' => 'ëÕÒÓ ×ÁÌÀÔÉ',
+ 'Exchangerate for payment missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ ÄÌÑ ÐÌÁÔÅÖÕ!',
+ 'Exchangerate missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ!',
+ 'Extended' => 'ðÒÏÄÏ×ÖÅÎÏ',
+ 'Fax' => 'æÁÈ',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'In-line' => '÷ËÌÀÞÅÎÏ (In-line)',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Invoice Date' => 'äÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ',
+ 'Invoice Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice Number' => 'îÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ',
+ 'Invoice Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice deleted!' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ ×ÉÄÁÌÅÎÉÊ!',
+ 'Invoice posted!' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ ×ÉÓÔÁ×ÌÅÎÉÊ!',
+ 'Item not on file!' => 'òÅÞ¦ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Message' => 'ðÏצÄÏÍÌÅÎÎÑ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'No.' => 'No.',
+ 'Notes' => 'ðÒÉͦÔËÉ',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Number missing in Row' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ Õ ÒÑÄËÕ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'Order' => 'úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ úÁÍÏ×ÌÅÎÎÑ!',
+ 'Order Number' => 'îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Number missing!' => 'îÅ ×ËÁÚÁÎÏ îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'PDF' => 'PDF ÆÏÒÍÁÔ',
+ 'Packing List' => 'ðÁËÕ×ÁÌØÎÉÊ óÐÉÓÏË',
+ 'Packing List Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Packing List Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ îÏÍÅÒ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Part' => 'ôÏ×ÁÒ',
+ 'Payment date missing!' => 'îÅ ×ËÁÚÁÎÏ ÄÁÔÕ ðÌÁÔÅÖÕ!',
+ 'Payments' => 'ðÌÁÔÅÖ¦',
+ 'Phone' => 'ôÅÌ.',
+ 'Post' => '÷ÉÓÔÁ×ÉÔÉ',
+ 'Post as new' => '÷ÉÓÔÁ×ÉÔÉ ÑË ÎÏ×ÉÊ',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'ã¦ÎÁ',
+ 'Print' => 'îÁÄÒÕËÕ×ÁÔÉ',
+ 'Printer' => 'ðÒÉÎÔÅÒ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Project not on file!' => 'ðÒÏÅËÔÕ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Purchase Order' => 'ëÕЦ×ÅÌØÎÅ úÁÍÏ×ÌÅÎÎÑ',
+ 'Qty' => 'ë¦ÌØ˦ÓÔØ',
+ 'Recd' => 'ïÔÒÉÍÁÎÏ',
+ 'Record in' => '÷ÎÅÓÔÉ ×',
+ 'Remaining' => 'úÁÌÉÛÉÌÏÓØ',
+ 'Required by' => 'ôÅÒͦΠÄÏÓÔÁ×ËÉ',
+ 'Sales Order' => 'îÁËÌÁÄÎÁ ðÒÏÄÁÖÕ ',
+ 'Screen' => 'åËÒÁÎ',
+ 'Select from one of the items below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÕ ¦Ú ÎÁÓÔÕÐÎÉÈ ÒÅÞÅÊ',
+ 'Select from one of the names below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÅ ¦Ú ÎÁÓÔÕÐÎÉÈ ¦ÍÅÎ/ÎÁÚ×',
+ 'Select from one of the projects below' => '÷ÉÂÅÒ¦ÔØ ÏÄÉÎ ¦Ú ÎÁÓÔÕÐÎÉÈ ÐÒÏÅËÔ¦×',
+ 'Select postscript or PDF!' => '÷ÉÂÅÒ¦ÔØ postscript ÁÂÏ PDF ÆÏÒÍÁÔ!',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Service' => 'ðÏÓÌÕÇÁ',
+ 'Ship' => 'ðÏÓÌÁÔÉ',
+ 'Ship to' => 'ðÏÓÌÁÔÉ ÄÏ',
+ 'Ship via' => 'ðÏÓÌÁÔÉ ÞÅÒÅÚ',
+ 'Source' => 'äÖÅÒÅÌÏ',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'Tax Included' => 'ðÏÄÁÔÏË ×ËÌÀÞÅÎÏ',
+ 'To' => 'äÏ',
+ 'Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Unit' => 'ïÄÉÎÉÃÑ',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'Vendor not on file!' => 'ðÏÔÁÞÁÌØÎÉËÁ ÎÅÍÁ Õ ÓÐÉÓËÕ ',
+ 'What type of item is this?' => 'ñËÉÊ ÃÅ ×ÉÄ/ÔÉÐ ÔÏ×ÁÒÕ',
+ 'Yes' => 'Tak',
+ 'ea' => 'ÛÔ.',
+ 'emailed to' => 'ÐÏÓÌÁÎÏ ÐÏ ÅÌ. ÐÏÛÔ¦ ÄÏ',
+ 'sent to printer' => 'ÐÏÓÌÁÎÏ ÄÏ ÐÒÉÎÔÅÒÁ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ 'åÌ._ÐÏÛÔÁ' => 'e_mail',
+ 'úÁÍÏ×ÌÅÎÎÑ' => 'order',
+ '÷ÉÓÔÁ×ÉÔÉ' => 'post',
+ '÷ÉÓÔÁ×ÉÔÉ_ÑË_ÎÏ×ÉÊ' => 'post_as_new',
+ 'îÁÄÒÕËÕ×ÁÔÉ' => 'print',
+ 'ðÏÓÌÁÔÉ_ÄÏ' => 'ship_to',
+ 'ðÏÎÏ×ÉÔÉ' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/login b/sql-ledger/locale/ua/login
new file mode 100644
index 0000000..4810b07
--- /dev/null
+++ b/sql-ledger/locale/ua/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'ðÒÏ ÐÒÏÇÒÁÍÕ',
+ 'Database Host' => 'íÁÛÉÎÁ âÁÚÉ äÁÎÉÈ',
+ 'Dataset' => 'âÁÚÁ äÁÎÉÈ',
+ 'Incorrect Dataset version!' => 'îÅצÒÎÁ ×ÅÒÓ¦Ñ âÁÚÉ äÁÎÉÈ!',
+ 'Incorrect Password!' => 'îÅצÒÎÉÊ ðÁÒÏÌØ!',
+ 'Licensed to' => 'ì¦ÃÅÎÚ¦¤À ×ÏÌÏĦ¤:',
+ 'Login' => 'ðÏÞÁÔÏË óÅÁÎÓÕ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'Password' => 'ðÁÒÏÌØ',
+ 'User' => 'ëÏÒÉÓÔÕ×ÁÞ',
+ 'Version' => '÷ÅÒÓ¦Ñ',
+ 'You are logged out!' => '÷ÁÛ ÓÅÁÎÓ ÚÁ˦ÎÞÉ×ÓÑ!',
+ 'You did not enter a name!' => 'îÅ ××ÅÄÅÎÏ ¦Í\'Ñ/ÎÁÚ×Õ',
+ 'is not a member!' => 'ÎÅ ¤ ÞÌÅÎÏÍ!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'ðÏÞÁÔÏË_óÅÁÎÓÕ' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/menu b/sql-ledger/locale/ua/menu
new file mode 100644
index 0000000..0417db0
--- /dev/null
+++ b/sql-ledger/locale/ua/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => '÷ÉÔÒÁÔÉ',
+ 'AP Aging' => 'AP Aging (×ÉÔÒÁÔÉ)',
+ 'AR' => 'äÏÈÏÄÉ',
+ 'AR Aging' => 'AR Aging (ÄÏÈÏÄÉ)',
+ 'Accounting Menu' => 'íÅÎÀ ïÂ̦ËÕ',
+ 'Add Account' => 'îÏ×ÉÊ ÒÁÈÕÎÏË',
+ 'Add Assembly' => 'îÏ×ÉÊ ËÏÍÐÌÅËÔ',
+ 'Add Customer' => 'îÏ×ÉÊ Ë̦¤ÎÔ',
+ 'Add GIFI' => 'îÏ×ÉÊ GIFI',
+ 'Add Part' => 'îÏ×ÉÊ ôÏ×ÁÒ',
+ 'Add Project' => 'îÏ×ÉÊ ðÒÏÅËÔ',
+ 'Add Service' => 'îÏ×Á ÐÏÓÌÕÇÁ',
+ 'Add Transaction' => 'îÏ×Á ÏÐÅÒÁæÑ',
+ 'Add Vendor' => 'îÏ×ÉÊ ÐÏÓÔÁÞÁÌØÎÉË',
+ 'Assemblies' => 'ëÏÍÐÌÅËÔÉ',
+ 'Audit Control' => 'ëÏÎÔÒÏÌØ',
+ 'Backup' => 'òÅÚÅÒ×ÎÁ ËÏЦÑ',
+ 'Balance Sheet' => 'âÁÌÁÎÓ',
+ 'Cash' => 'çÏÔ¦×ËÁ',
+ 'Chart of Accounts' => 'ðÌÁÎ òÁÈÕÎ˦×',
+ 'Check' => 'þÅË',
+ 'Customers' => 'ë̦¤ÎÔÉ',
+ 'General Ledger' => 'çÏÌÏ×ÎÁ ëÎÉÇÁ',
+ 'Goods & Services' => 'ôÏ×ÁÒÉ ¦ ðÏÓÌÕÇÉ',
+ 'HTML Templates' => 'HTML ûÁÂÌÏÎÉ ',
+ 'Income Statement' => 'ú×¦Ô ÐÒÏ ÄÏÈÏÄÉ ¦ ×ÉÄÁÔËÉ',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'LaTeX Templates' => 'LaTeX ûÁÂÌÏÎÉ',
+ 'List Accounts' => 'óÐÉÓÏË òÁÈÕÎ˦×',
+ 'List GIFI' => 'óÐÉÓÏË GIFI',
+ 'Logout' => 'ë¦ÎÅÃØ óÅÁÎÓÕ',
+ 'Order Entry' => '÷ÉÓÔÁ×ÌÅÎÎÑ úÁÍÏ×ÌÅÎÎÑ',
+ 'Packing List' => 'ðÁËÕ×ÁÌØÎÉÊ óÐÉÓÏË',
+ 'Parts' => 'ÔÏ×ÁÒÉ',
+ 'Payment' => 'ðÌÁÔ¦Ö',
+ 'Payments' => 'ðÌÁÔÅÖ¦',
+ 'Preferences' => 'îÁÓÔÒÏÊËÉ',
+ 'Projects' => 'ðÒÏÅËÔÉ',
+ 'Purchase Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Purchase Order' => 'ëÕЦ×ÅÌØÎÅ úÁÍÏ×ÌÅÎÎÑ',
+ 'Purchase Orders' => 'ëÕЦ×ÅÌØΦ úÁÍÏ×ÌÅÎÎÑ',
+ 'Receipt' => 'ë×ÉÔÁÎæÑ',
+ 'Receipts' => 'ë×ÉÔÁÎæ§',
+ 'Reconciliation' => 'õÚÇÏÄÖÅÎÎÑ',
+ 'Reports' => 'úצÔÉ',
+ 'Sales Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Sales Order' => 'îÁËÌÁÄÎÁ ðÒÏÄÁÖÕ ',
+ 'Sales Orders' => 'îÁËÌÁÄΦ ðÒÏÄÁÖÕ',
+ 'Save to File' => 'úÂÅÒÅÇÔÉ Õ æÁÊ̦',
+ 'Send by E-Mail' => '÷ÉÓÌÁÔÉ ÐÏ ÅÌ. ÐÏÛÔ¦',
+ 'Services' => 'ðÏÓÌÕÇÉ',
+ 'Statement' => 'úצÔ',
+ 'Stock Assembly' => '¶Î×ÅÎÔÁÒ ëÏÍÐÌÅËÔÕ',
+ 'Stylesheet' => 'ïÆÏÒÍÌÅÎÎÎÑ',
+ 'System' => 'óÉÓÔÅÍÁ',
+ 'Tax collected' => 'ú¦ÂÒÁÎÏ ÐÏÄÁÔË¦× ',
+ 'Tax paid' => 'ðÏÄÁÔÏË ÚÁÐÌÁÞÅÎÏ',
+ 'Transactions' => 'ïÐÅÒÁæ§',
+ 'Trial Balance' => 'ðÒÏÂÎÉÊ âÁÌÁÎÓ',
+ 'Vendors' => 'ðÏÓÔÁÞÁÌØÎÉËÉ',
+ 'Version' => '÷ÅÒÓ¦Ñ',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/oe b/sql-ledger/locale/ua/oe
new file mode 100644
index 0000000..16c9707
--- /dev/null
+++ b/sql-ledger/locale/ua/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'îÏ×ÉÊ',
+ 'Add Purchase Invoice' => 'îÏ×ÉÊ ëÕЦ×ÅÌØÎÉÊ òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Add Purchase Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ËÕЦ×ÌÀ',
+ 'Add Sales Invoice' => 'îÏ×ÉÊ òÁÈÕÎÏ-ÆÁËÔÕÒÁ',
+ 'Add Sales Order' => 'îÏ×Å ÚÁÍÏ×ÌÅÎÎÑ ÎÁ ÐÒÏÄÁÖ',
+ 'Address' => 'áÄÒÅÓÁ',
+ 'Amount' => 'óÕÍÁ',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Are you sure you want to delete Order Number' => '÷É ÐÅ×Φ, ÝÏ ÈÏÞÅÔÅ ×ÉÄÁÌÉÔÉ ÄÁÎÅ ÚÁÍÏ×ÌÅÎÎÑ?',
+ 'Attachment' => 'äÏÄÁÔÏË',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'Bcc' => 'ðÒÉ×ÁÔÎÁ ËÏÐ¦Ñ ÄÏ',
+ 'Bin' => 'Bin',
+ 'C' => 'ó',
+ 'Cannot delete order!' => 'îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÚÁÍÏ×ÌÅÎÎÑ!',
+ 'Cannot save order!' => 'îÅ ÍÏÖÌÉ×Ï ÚÂÅÒÅÇÔÉ ÚÁÍÏ×ÌÅÎÎÑ!',
+ 'Cc' => 'ëÏÐ¦Ñ ÄÏ',
+ 'Closed' => 'úÁËÒÉÔÏ',
+ 'Confirm!' => 'ð¦ÄÔ×ÅÒĦÔØ!',
+ 'Contact' => 'ëÏÎÔÁËÔÎÁ ÏÓÏÂÁ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Copies' => 'ëÏЦÊ',
+ 'Credit Limit' => 'ì¦Í¦Ô ËÒÅÄÉÔÕ',
+ 'Curr' => '÷ÁÌÀÔÁ',
+ 'Currency' => '÷ÁÌÀÔÁ',
+ 'Customer' => 'ë̦¤ÎÔ',
+ 'Customer missing!' => 'îÅ ×ËÁÚÁÎÉÊ Ë̦¤ÎÔ!',
+ 'Customer not on file!' => 'ë̦¤ÎÔÁ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Date' => 'äÁÔÁ',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Delivery Date' => 'äÁÔÁ ÄÏÓÔÁ×ËÉ',
+ 'Description' => 'ïÐÉÓ',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'E-mail address missing!' => 'îÅ ×ËÁÚÁÎÁ ÁÄÒÅÓÁ ÅÌ. ÐÏÛÔÉ!',
+ 'Edit Purchase Order' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ëÕЦ×ÅÌØÎÅ úÁÍÏ×ÌÅÎÎÑ',
+ 'Edit Sales Order' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ îÁËÌÁÄÎÕ ðÒÏÄÁÖÕ',
+ 'Exchangerate' => 'ëÕÒÓ ×ÁÌÀÔÉ',
+ 'Exchangerate missing!' => 'îÅ ×ËÁÚÁÎÉÊ ËÕÒÓ ×ÁÌÀÔÉ!',
+ 'Extended' => 'ðÒÏÄÏ×ÖÅÎÏ',
+ 'Fax' => 'æÁÈ',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'From' => '÷¦Ä / Ú',
+ 'ID' => '¶ÄÅÎÔÉƦËÁæÊÎÉÊ ÎÏÍÅÒ',
+ 'In-line' => '÷ËÌÀÞÅÎÏ (In-line)',
+ 'Include in Report' => 'äÏÄÁÔÉ ÄÏ úצÔÕ',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Invoice Date missing!' => 'îÅ ×ËÁÚÁÎÁ ÄÁÔÁ ×ÉÓÔÁ×ÌÅÎÎÑ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Invoice Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÒÁÈÕÎËÁ-ÆÁËÔÕÒÉ!',
+ 'Item not on file!' => 'òÅÞ¦ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Message' => 'ðÏצÄÏÍÌÅÎÎÑ',
+ 'Name' => '¶Í\'Ñ / îÁÚ×Á',
+ 'No.' => 'No.',
+ 'Notes' => 'ðÒÉͦÔËÉ',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Number missing in Row' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ Õ ÒÑÄËÕ',
+ 'O' => 'ï',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'Open' => '÷¦ÄËÒÉÔÏ',
+ 'Order' => 'úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Date' => 'äÁÔÁ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ úÁÍÏ×ÌÅÎÎÑ!',
+ 'Order Number' => 'îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order Number missing!' => 'îÅ ×ËÁÚÁÎÏ îÏÍÅÒ úÁÍÏ×ÌÅÎÎÑ',
+ 'Order deleted!' => 'úÁÍÏ×ÌÅÎÎÑ ×ÉÄÁÌÅÎÏ!',
+ 'Order saved!' => 'úÁÍÏ×ÌÅÎÎÑ ÚÂÅÒÅÖÅÎÏ!',
+ 'PDF' => 'PDF ÆÏÒÍÁÔ',
+ 'Packing List' => 'ðÁËÕ×ÁÌØÎÉÊ óÐÉÓÏË',
+ 'Packing List Date missing!' => 'îÅ ×ËÁÚÁÎÁ äÁÔÁ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Packing List Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ îÏÍÅÒ ðÁËÕ×ÁÌØÎÏÇÏ óÐÉÓÏËÕ',
+ 'Part' => 'ôÏ×ÁÒ',
+ 'Phone' => 'ôÅÌ.',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'ã¦ÎÁ',
+ 'Print' => 'îÁÄÒÕËÕ×ÁÔÉ',
+ 'Printer' => 'ðÒÉÎÔÅÒ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Project not on file!' => 'ðÒÏÅËÔÕ ÎÅÍÁ × ÓÐÉÓËÕ!',
+ 'Purchase Order' => 'ëÕЦ×ÅÌØÎÅ úÁÍÏ×ÌÅÎÎÑ',
+ 'Purchase Orders' => 'ëÕЦ×ÅÌØΦ úÁÍÏ×ÌÅÎÎÑ',
+ 'Qty' => 'ë¦ÌØ˦ÓÔØ',
+ 'Recd' => 'ïÔÒÉÍÁÎÏ',
+ 'Remaining' => 'úÁÌÉÛÉÌÏÓØ',
+ 'Required by' => 'ôÅÒͦΠÄÏÓÔÁ×ËÉ',
+ 'Sales Order' => 'îÁËÌÁÄÎÁ ðÒÏÄÁÖÕ ',
+ 'Sales Orders' => 'îÁËÌÁÄΦ ðÒÏÄÁÖÕ',
+ 'Save' => 'úÂÅÒÅÇÔÉ',
+ 'Save as new' => 'úÂÅÒÅÇÔÉ ÑË ÎÏ×Å',
+ 'Screen' => 'åËÒÁÎ',
+ 'Select from one of the items below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÕ ¦Ú ÎÁÓÔÕÐÎÉÈ ÒÅÞÅÊ',
+ 'Select from one of the names below' => '÷ÉÂÅÒ¦ÔØ ÏÄÎÅ ¦Ú ÎÁÓÔÕÐÎÉÈ ¦ÍÅÎ/ÎÁÚ×',
+ 'Select from one of the projects below' => '÷ÉÂÅÒ¦ÔØ ÏÄÉÎ ¦Ú ÎÁÓÔÕÐÎÉÈ ÐÒÏÅËÔ¦×',
+ 'Select postscript or PDF!' => '÷ÉÂÅÒ¦ÔØ postscript ÁÂÏ PDF ÆÏÒÍÁÔ!',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Service' => 'ðÏÓÌÕÇÁ',
+ 'Ship' => 'ðÏÓÌÁÔÉ',
+ 'Ship to' => 'ðÏÓÌÁÔÉ ÄÏ',
+ 'Ship via' => 'ðÏÓÌÁÔÉ ÞÅÒÅÚ',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'Tax' => 'ðÏÄÁÔÏË',
+ 'Tax Included' => 'ðÏÄÁÔÏË ×ËÌÀÞÅÎÏ',
+ 'Terms: Net' => 'õÍÏ×É: úÁÐÌÁÔÉÔÉ',
+ 'To' => 'äÏ',
+ 'Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Unit' => 'ïÄÉÎÉÃÑ',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'Vendor' => 'ðÏÓÔÁÞÁÌØÎÉË',
+ 'Vendor missing!' => 'ðÏÓÔÁÞÁÌØÎÉË ÎÅ ¦ÓÎÕ¤',
+ 'Vendor not on file!' => 'ðÏÔÁÞÁÌØÎÉËÁ ÎÅÍÁ Õ ÓÐÉÓËÕ ',
+ 'What type of item is this?' => 'ñËÉÊ ÃÅ ×ÉÄ/ÔÉÐ ÔÏ×ÁÒÕ',
+ 'Yes' => 'Tak',
+ 'days' => 'ÄΦ×',
+ 'ea' => 'ÛÔ.',
+ 'emailed to' => 'ÐÏÓÌÁÎÏ ÐÏ ÅÌ. ÐÏÛÔ¦ ÄÏ',
+ 'sent to printer' => 'ÐÏÓÌÁÎÏ ÄÏ ÐÒÉÎÔÅÒÁ',
+ 'to' => 'ÄÏ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'îÏ×ÉÊ' => 'add',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ 'åÌ._ÐÏÛÔÁ' => 'e_mail',
+ 'òÁÈÕÎÏË_ÆÁËÔÕÒÁ' => 'invoice',
+ 'îÁÄÒÕËÕ×ÁÔÉ' => 'print',
+ 'úÂÅÒÅÇÔÉ' => 'save',
+ 'úÂÅÒÅÇÔÉ_ÑË_ÎÏ×Å' => 'save_as_new',
+ 'ðÏÓÌÁÔÉ_ÄÏ' => 'ship_to',
+ 'ðÏÎÏ×ÉÔÉ' => 'update',
+ 'tak' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/pe b/sql-ledger/locale/ua/pe
new file mode 100644
index 0000000..3f4e959
--- /dev/null
+++ b/sql-ledger/locale/ua/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'îÏ×ÉÊ',
+ 'Add Project' => 'îÏ×ÉÊ ðÒÏÅËÔ',
+ 'All' => '÷Ó¦',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Delete' => '÷ÉÄÁÌÉÔÉ',
+ 'Description' => 'ïÐÉÓ',
+ 'Edit Project' => '÷¦ÄÒÅÄÁÇÕ×ÁÔÉ ðÒÏÅËÔ',
+ 'Number' => 'îÏÍÅÒ',
+ 'Orphaned' => '÷¦ÄÏËÒÅÍÌÅÎÉÊ/ïÓÉÒÏÔ¦ÌÉÊ',
+ 'Project' => 'ðÒÏÅËÔ',
+ 'Project Number missing!' => 'îÅ ×ËÁÚÁÎÉÊ ÎÏÍÅÒ ÐÒÏÅËÔÕ!',
+ 'Project deleted!' => 'ðÒÏÅËÔ ×ÉÄÁÌÅÎÏ!',
+ 'Project saved!' => 'ðÒÏÅËÔ ÚÂÅÒÅÖÅÎÏ!',
+ 'Projects' => 'ðÒÏÅËÔÉ',
+ 'Save' => 'úÂÅÒÅÇÔÉ',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'îÏ×ÉÊ' => 'add',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ '÷ÉÄÁÌÉÔÉ' => 'delete',
+ 'úÂÅÒÅÇÔÉ' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/rc b/sql-ledger/locale/ua/rc
new file mode 100644
index 0000000..0a91d00
--- /dev/null
+++ b/sql-ledger/locale/ua/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Balance' => 'âÁÌÁÎÓ',
+ 'Cleared Balance' => 'ë¦ÎÃÅ×Å óÁÌØÄÏ',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Date' => 'äÁÔÁ',
+ 'Deposit' => 'äÅÐÏÚÉÔ/÷ËÌÁÄ',
+ 'Description' => 'ïÐÉÓ',
+ 'Difference' => 'ò¦ÚÎÉÃÑ',
+ 'Done' => 'úÒÏÂÌÅÎÏ',
+ 'Exchangerate Difference' => 'ò¦ÚÎÉÃÑ ëÕÒÓÕ ×ÁÌÀÔÉ',
+ 'From' => '÷¦Ä / Ú',
+ 'Out of balance!' => 'îÅ ÚÂÁÌÁÎÓÏ×ÁÎÏ!',
+ 'Payment' => 'ðÌÁÔ¦Ö',
+ 'Reconciliation' => 'õÚÇÏÄÖÅÎÎÑ',
+ 'Select all' => '÷ÉÂÒÁÔÉ ×ÓÅ',
+ 'Source' => 'äÖÅÒÅÌÏ',
+ 'Statement Balance' => 'âÁÌÁÎÓÏ×ÉÊ úצÔ',
+ 'Update' => 'ðÏÎÏ×ÉÔÉ',
+ 'to' => 'ÄÏ',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ 'úÒÏÂÌÅÎÏ' => 'done',
+ '÷ÉÂÒÁÔÉ_×ÓÅ' => 'select_all',
+ 'ðÏÎÏ×ÉÔÉ' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ua/rp b/sql-ledger/locale/ua/rp
new file mode 100644
index 0000000..0553ba6
--- /dev/null
+++ b/sql-ledger/locale/ua/rp
@@ -0,0 +1,120 @@
+$self{texts} = {
+ 'AP Aging' => 'AP Aging (×ÉÔÒÁÔÉ)',
+ 'AR Aging' => 'AR Aging (ÄÏÈÏÄÉ)',
+ 'Account' => 'òÁÈÕÎÏË',
+ 'Accounts' => 'òÁÈÕÎËÉ',
+ 'Amount' => 'óÕÍÁ',
+ 'Apr' => 'ËצÔÎÑ',
+ 'April' => 'ëצÔÅÎØ',
+ 'Attachment' => 'äÏÄÁÔÏË',
+ 'Aug' => 'ÓÅÒÐÎÑ',
+ 'August' => 'óÅÒÐÅÎØ',
+ 'Balance' => 'âÁÌÁÎÓ',
+ 'Balance Sheet' => 'âÁÌÁÎÓ',
+ 'Bcc' => 'ðÒÉ×ÁÔÎÁ ËÏÐ¦Ñ ÄÏ',
+ 'Cash based' => 'çÏÔ¦×ËÏ×ÉÊ',
+ 'Cc' => 'ëÏÐ¦Ñ ÄÏ',
+ 'Compare to' => 'ðÏÒ¦×ÎÑÔÉ Ú',
+ 'Continue' => 'ðÒÏÄÏ×ÖÉÔÉ',
+ 'Copies' => 'ëÏЦÊ',
+ 'Credit' => 'ëÒÅÄÉÔ',
+ 'Current' => 'ðÏÔÏÞÎÉÊ',
+ 'Customer' => 'ë̦¤ÎÔ',
+ 'Date' => 'äÁÔÁ',
+ 'Debit' => 'äÅÂÉÔ',
+ 'Dec' => 'ÇÒÕÄÎÑ',
+ 'December' => 'çÒÕÄÅÎØ',
+ 'Decimalplaces' => 'äÅÓÑÔÉÞΦ ͦÓÃÑ',
+ 'Department' => 'Department',
+ 'Description' => 'ïÐÉÓ',
+ 'Due' => 'äÏ',
+ 'E-mail' => 'åÌ. ÐÏÛÔÁ',
+ 'E-mail Statement to' => 'ðÏÓÌÁÔÉ ÐÏ ÅÌ. ÐÏÛÔ¦ ÄÏ',
+ 'Feb' => 'ÌÀÔÏÇÏ',
+ 'February' => 'ìÀÔÉÊ',
+ 'From' => '÷¦Ä / Ú',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'òÏÚĦÌ',
+ 'ID' => '¶ÄÅÎÔÉƦËÁæÊÎÉÊ ÎÏÍÅÒ',
+ 'In-line' => '÷ËÌÀÞÅÎÏ (In-line)',
+ 'Include in Report' => 'äÏÄÁÔÉ ÄÏ úצÔÕ',
+ 'Income Statement' => 'ú×¦Ô ÐÒÏ ÄÏÈÏÄÉ ¦ ×ÉÄÁÔËÉ',
+ 'Invoice' => 'òÁÈÕÎÏË-ÆÁËÔÕÒÁ',
+ 'Jan' => 'Ó¦ÞÎÑ',
+ 'January' => 'Ó¦ÞÅÎØ',
+ 'Jul' => 'ÌÉÐÎÑ',
+ 'July' => 'ìÉÐÅÎØ',
+ 'Jun' => 'ÞÅÒ×ÎÑ',
+ 'June' => 'þÅÒ×ÅÎØ',
+ 'Mar' => 'ÂÅÒÅÚÎÑ',
+ 'March' => 'âÅÒÅÚÅÎØ',
+ 'May' => 'ÔÒÁ×ÎÑ',
+ 'May ' => 'ôÒÁ×ÅÎØ',
+ 'Message' => 'ðÏצÄÏÍÌÅÎÎÑ',
+ 'N/A' => 'îÅ óÔÏÓÕ¤ÔØÓÑ',
+ 'Nothing selected!' => 'î¦ÞÏÇÏ ÎÅ ×ÉÂÒÁÎÏ!',
+ 'Nov' => 'ÌÉÓÔÏÐÁÄÁ',
+ 'November' => 'ìÉÓÔÏÐÁÄ',
+ 'Oct' => 'ÖÏ×ÔÎÑ',
+ 'October' => 'öÏ×ÔÅÎØ',
+ 'PDF' => 'PDF ÆÏÒÍÁÔ',
+ 'Payments' => 'ðÌÁÔÅÖ¦',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'îÁÄÒÕËÕ×ÁÔÉ',
+ 'Printer' => 'ðÒÉÎÔÅÒ',
+ 'Project Number' => 'Project Number',
+ 'Receipts' => 'ë×ÉÔÁÎæ§',
+ 'Report for' => 'ú×¦Ô ÄÌÑ',
+ 'Retained Earnings' => 'ðÒÉÂÕÔÏË (ÎÅÒÏÚÐÏĦÌÅÎÉÊ)',
+ 'Screen' => 'åËÒÁÎ',
+ 'Select all' => '÷ÉÂÒÁÔÉ ×ÓÅ',
+ 'Select postscript or PDF!' => '÷ÉÂÅÒ¦ÔØ postscript ÁÂÏ PDF ÆÏÒÍÁÔ!',
+ 'Sep' => '×ÅÒÅÓÎÑ',
+ 'September' => '÷ÅÒÅÓÅÎØ',
+ 'Source' => 'äÖÅÒÅÌÏ',
+ 'Standard' => 'óÔÁÎÄÁÒÔΦ',
+ 'Statement' => 'úצÔ',
+ 'Statement sent to' => 'ú×¦Ô ÐÏÓÌÁÎÏ ÄÏ',
+ 'Statements sent to printer!' => 'ú×¦Ô ÐÏÓÌÁÎÏ ÄÏ ÐÒÉÎÔÅÒÁ!',
+ 'Subject' => 'ôÅÍÁ',
+ 'Subtotal' => 'ð¦ÄÓÕÍÏË ÐÏ ÒÏÚĦÌÕ',
+ 'Tax' => 'ðÏÄÁÔÏË',
+ 'Tax collected' => 'ú¦ÂÒÁÎÏ ÐÏÄÁÔË¦× ',
+ 'Tax paid' => 'ðÏÄÁÔÏË ÚÁÐÌÁÞÅÎÏ',
+ 'Total' => 'úÁÇÁÌØÎÁ óÕÍÁ',
+ 'Trial Balance' => 'ðÒÏÂÎÉÊ âÁÌÁÎÓ',
+ 'Vendor' => 'ðÏÓÔÁÞÁÌØÎÉË',
+ 'as at' => 'ÑË ×',
+ 'collected on sales' => 'Ú¦ÂÒÁÎÏ ÐÒÉ ÐÒÏÄÁÖÕ',
+ 'for Period' => 'ÚÁ ðÅÒ¦ÏÄ',
+ 'paid on purchases' => 'ÚÁÐÌÁÞÅÎÏ ÎÁ ÐÏËÕÐËÉ',
+ 'to' => 'ÄÏ',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_accounts' => 'list_accounts',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'ðÒÏÄÏ×ÖÉÔÉ' => 'continue',
+ 'åÌ._ÐÏÛÔÁ' => 'e_mail',
+ 'îÁÄÒÕËÕ×ÁÔÉ' => 'print',
+ '÷ÉÂÒÁÔÉ_×ÓÅ' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/COPYING b/sql-ledger/locale/ve/COPYING
new file mode 100644
index 0000000..11c55f3
--- /dev/null
+++ b/sql-ledger/locale/ve/COPYING
@@ -0,0 +1,23 @@
+######################################################################
+# SQL-Ledger, Accounting Software
+# Copyright (c) 2001
+#
+# Spanish Texts (Venezuela):
+#
+# Author: John Stoddart <jstypo@imagencolor.com.ve>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#######################################################################
+
diff --git a/sql-ledger/locale/ve/LANGUAGE b/sql-ledger/locale/ve/LANGUAGE
new file mode 100644
index 0000000..182ea84
--- /dev/null
+++ b/sql-ledger/locale/ve/LANGUAGE
@@ -0,0 +1 @@
+Venezuelan Spanish
diff --git a/sql-ledger/locale/ve/admin b/sql-ledger/locale/ve/admin
new file mode 100644
index 0000000..19be1bf
--- /dev/null
+++ b/sql-ledger/locale/ve/admin
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'Access Control' => 'Control de Acceso',
+ 'Accounting' => 'Contabilidad',
+ 'Add User' => 'Agregar Usuario',
+ 'Address' => 'Dirección',
+ 'Administration' => 'Administración',
+ 'Administrator' => 'Administrador',
+ 'All Datasets up to date!' => 'Bases de datos actualizadas!',
+ 'Change Admin Password' => 'Cambiar contraseña del Administrador',
+ 'Change Password' => 'Cambiar Contraseña',
+ 'Character Set' => 'Conjunto de Caracteres',
+ 'Click on login name to edit!' => 'Haga click sobre el login para editar',
+ 'Company' => 'Compañía',
+ 'Connect to' => 'Conectar a',
+ 'Continue' => 'Continuar',
+ 'Create Chart of Accounts' => 'Crear Plan de Cuentas',
+ 'Create Dataset' => 'Crear base de datos',
+ 'DBI not installed!' => 'DBI no ha sido instalado!',
+ 'Database' => 'Base de Datos',
+ 'Database Administration' => 'Administración de base de datos',
+ 'Database Driver not checked!' => 'Manejador no seleccionado!',
+ 'Database User missing!' => 'Falta usuario de base de datos!',
+ 'Dataset' => 'Base de datos',
+ 'Dataset missing!' => 'Falta base de datos!',
+ 'Dataset updated!' => 'Base de datos actualizada!',
+ 'Date Format' => 'Formato Fecha',
+ 'Delete' => 'Borrar',
+ 'Delete Dataset' => 'Borrar base de datos',
+ 'Directory' => 'Directorio',
+ 'Driver' => 'Manejador',
+ 'Dropdown Limit' => 'Límite menu dropdown',
+ 'E-mail' => 'E-mail',
+ 'Edit User' => 'Editar Usuario',
+ 'Existing Datasets' => 'Bases de datos existentes',
+ 'Fax' => 'Fax',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Falta nombre del Host!',
+ 'Incorrect Password!' => 'Contraseña equivocada',
+ 'Language' => 'Idioma',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deje en blanco los campos Host y Puerto si no requiere una conección remota',
+ 'Login' => 'Login',
+ 'Multibyte Encoding' => 'Codificación conjunto de caracteres',
+ 'Name' => 'Nombre',
+ 'New Templates' => 'Plantillas Nuevas',
+ 'No Database Drivers available!' => 'No hay manejadores para base de datos!',
+ 'No Dataset selected!' => 'Base de datos no seleccionada!',
+ 'Nothing to delete!' => 'Nada para borrar!',
+ 'Number Format' => 'Formato Numérico',
+ 'Oracle Database Administration' => 'Administración bases de datos Oracle',
+ 'Password' => 'Contraseña',
+ 'Password changed!' => 'Contraseña cambiada!',
+ 'Pg Database Administration' => 'Administración bases de datos Pg',
+ 'Phone' => 'Teléfono',
+ 'Port' => 'Número de Puerto',
+ 'Port missing!' => 'Falta número de puerto',
+ 'Printer' => 'Impresora',
+ 'Save' => 'Guardar',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione base de datos a borrar y pulse "Continue"',
+ 'Setup Templates' => 'Configurar Plantillas',
+ 'Ship via' => 'Envía vía',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Hoja de Estilo',
+ 'Templates' => 'Plantillas',
+ 'The following Datasets are not in use and can be deleted' => 'Las siguientes bases de datos no están en uso y pueden ser borradas',
+ 'The following Datasets need to be updated' => 'Las siguientes bases de datos requieren actualización',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Chequeo preliminar. En esta etapa no se creará ni se borrará nada!',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para agregar un usuario a un grupo, edite un nombre, cambie el login y guárdelo de nuevo. Un nuevo usuario con las mismas variables se creará bajo el nuevo login.',
+ 'Update Dataset' => 'Actualizar base de datos',
+ 'Use Templates' => 'Use Plantilla',
+ 'User' => 'Usuario',
+ 'User deleted!' => 'Usuario borrado!',
+ 'User saved!' => 'Usuario guardado!',
+ 'Version' => 'Versión',
+ 'You must enter a host and port for local and remote connections!' => 'Debe ingresar un host y un puerto para conecciones locales y remotas!',
+ 'does not exist' => 'no existe',
+ 'is already a member!' => 'ya es miembro!',
+ 'localhost' => 'localhost',
+ 'locked!' => 'locked!',
+ 'successfully created!' => 'creado!',
+ 'successfully deleted!' => 'borrado!',
+ 'website' => 'en internet',
+};
+
+$self{subs} = {
+ 'add_user' => 'add_user',
+ 'adminlogin' => 'adminlogin',
+ 'change_admin_password' => 'change_admin_password',
+ 'change_password' => 'change_password',
+ 'check_password' => 'check_password',
+ 'continue' => 'continue',
+ 'create_dataset' => 'create_dataset',
+ 'dbcreate' => 'dbcreate',
+ 'dbdelete' => 'dbdelete',
+ 'dbdriver_defaults' => 'dbdriver_defaults',
+ 'dbselect_source' => 'dbselect_source',
+ 'dbupdate' => 'dbupdate',
+ 'delete' => 'delete',
+ 'delete_dataset' => 'delete_dataset',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'get_value' => 'get_value',
+ 'list_users' => 'list_users',
+ 'login' => 'login',
+ 'login_name' => 'login_name',
+ 'oracle_database_administration' => 'oracle_database_administration',
+ 'pg_database_administration' => 'pg_database_administration',
+ 'save' => 'save',
+ 'update_dataset' => 'update_dataset',
+ 'agregar_usuario' => 'add_user',
+ 'cambiar_contraseña_del_administrador' => 'change_admin_password',
+ 'cambiar_contraseña' => 'change_password',
+ 'continuar' => 'continue',
+ 'crear_base_de_datos' => 'create_dataset',
+ 'borrar' => 'delete',
+ 'borrar_base_de_datos' => 'delete_dataset',
+ 'login' => 'login',
+ 'administración_bases_de_datos_oracle' => 'oracle_database_administration',
+ 'administración_bases_de_datos_pg' => 'pg_database_administration',
+ 'guardar' => 'save',
+ 'actualizar_base_de_datos' => 'update_dataset',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/all b/sql-ledger/locale/ve/all
new file mode 100644
index 0000000..b422b8c
--- /dev/null
+++ b/sql-ledger/locale/ve/all
@@ -0,0 +1,491 @@
+# These are all the texts to build the translations files.
+# The file has the form of 'english text' => 'foreign text',
+# you can add the translation in this file or in the 'missing' file
+# run locales.pl from this directory to rebuild the translation files
+
+$self{texts} = {
+ 'AP' => 'CXP',
+ 'AP Aging' => 'Vencimientos',
+ 'AP Transaction' => 'Cuenta por Pagar',
+ 'AP Transactions' => 'Cuentas por Pagar',
+ 'AR' => 'CXC',
+ 'AR Aging' => 'Vencimientos',
+ 'AR Transaction' => 'Cuenta por Cobrar',
+ 'AR Transactions' => 'Cuentas por Cobrar',
+ 'About' => 'Acerca de',
+ 'Access Control' => 'Control de Acceso',
+ 'Account' => 'Cuenta',
+ 'Account Number' => 'Número de Cuenta',
+ 'Account Number missing!' => 'Falta Número de Cuenta!',
+ 'Account Type' => 'Tipo de Cuenta',
+ 'Account Type missing!' => 'Falta Tipo de Cuenta!',
+ 'Account deleted!' => 'Cuenta borrada!',
+ 'Account saved!' => 'Cuenta guardada!',
+ 'Accounting' => 'Contabilidad',
+ 'Accounting Menu' => 'Menú de Contabilidad',
+ 'Accounts' => 'Cuentas',
+ 'Active' => 'Activa',
+ 'Add' => 'Agregar',
+ 'Add Account' => 'Agregar Cuenta',
+ 'Add Accounts Payables Transaction' => 'Agregar Cuenta por Pagar',
+ 'Add Accounts Receivables Transaction' => 'Agregar Cuenta por Cobrar',
+ 'Add Assembly' => 'Agregar Conjunto',
+ 'Add Customer' => 'Agregar Cliente',
+ 'Add GIFI' => 'Agregar GIFI',
+ 'Add General Ledger Transaction' => 'Agregar Transacción al Mayor General',
+ 'Add Part' => 'Agregar Item',
+ 'Add Project' => 'Agregar Proyecto',
+ 'Add Purchase Invoice' => 'Agregar Factura de Compra',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Invoice' => 'Agregar Factura de Venta',
+ 'Add Sales Order' => 'Agregar Pedido',
+ 'Add Service' => 'Agregar Servicio',
+ 'Add Transaction' => 'Agregar Transacción',
+ 'Add User' => 'Agregar Usuario',
+ 'Add Vendor' => 'Agregar Proveedor',
+ 'Address' => 'Dirección',
+ 'Administration' => 'Administración',
+ 'Administrator' => 'Administrador',
+ 'All' => 'Todos',
+ 'All Datasets up to date!' => 'Bases de datos actualizadas!',
+ 'Amount' => 'Monto',
+ 'Amount Due' => 'Monto Vencido',
+ 'Amount does not equal applied!' => 'Monto no es igual!',
+ 'Amount missing!' => 'Falta monto!',
+ 'Applied' => 'Aplicado',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Seguro que desea borrar Factura?',
+ 'Are you sure you want to delete Order Number' => '¿Seguro que desea borrar Orden de Compra/Pedido?',
+ 'Are you sure you want to delete Transaction' => '¿Seguro que desea borrar Transacción?',
+ 'Assemblies' => 'Conjuntos',
+ 'Assemblies restocked!' => 'Conjuntos re-inventariados',
+ 'Assembly Number missing!' => 'Falta Número Conjunto!',
+ 'Asset' => 'Activo',
+ 'Attachment' => 'Anexo',
+ 'Audit Control' => 'Control de Auditoría',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'BOM' => 'Lista de Materiales',
+ 'Backup' => 'Respaldos',
+ 'Backup sent to' => 'Respaldo enviado a',
+ 'Balance' => 'Balance',
+ 'Balance Sheet' => 'Hoja de Balance',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ubicación',
+ 'Books are open' => 'Libros aperturados',
+ 'Bought' => 'Comprado',
+ 'Business Number' => 'RIF/NIT/CI',
+ 'C' => 'C',
+ 'COGS' => 'Costo Perpetuo',
+ 'Cannot delete account!' => 'No puede borrar cuenta!',
+ 'Cannot delete customer!' => 'No puede borrar cliente!',
+ 'Cannot delete default account!' => 'No puede borrar cuenta "default"!',
+ 'Cannot delete invoice!' => 'No puede borraar factura!',
+ 'Cannot delete item already invoiced!' => 'No puede borrar ítem facturado!',
+ 'Cannot delete item on order!' => 'No puede borrar ítem pedido!',
+ 'Cannot delete item which is part of an assembly!' => 'No puede borrar ítem parte de conjunto!',
+ 'Cannot delete item!' => 'No puede borrar ítem!',
+ 'Cannot delete order!' => 'No puede borrar pedido!',
+ 'Cannot delete transaction!' => 'No puede borrar transacción!',
+ 'Cannot delete vendor!' => 'No puede borrar proveedor!',
+ 'Cannot have a value in both Debit and Credit!' => 'No puede haber Débito y Crédito simultáneamente!',
+ 'Cannot post a transaction without a value!' => 'No puede registrar transacción sin monto!',
+ 'Cannot post invoice for a closed period!' => 'No puede registrar factura para ejercicio cerrado!',
+ 'Cannot post invoice!' => 'No puede registrar factura!',
+ 'Cannot post payment for a closed period!' => 'No puede registrar pago para ejercicio cerrado',
+ 'Cannot post payment!' => 'No puede registrar pago!',
+ 'Cannot post transaction for a closed period!' => 'No puede registrar transacción para ejercicio cerrado!',
+ 'Cannot post transaction!' => 'No puede registrar transacción!',
+ 'Cannot process payment for a closed period!' => 'No puede procesar pago para ejercicio cerrado!',
+ 'Cannot save account!' => 'No puede guardar cuenta!',
+ 'Cannot save order!' => 'No puede guardar órden!',
+ 'Cannot save preferences!' => 'No puede guardar preferencias!',
+ 'Cannot stock assemblies!' => 'No puede inventariar conjuntos!',
+ 'Cash' => 'Caja',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Change Admin Password' => 'Cambiar contraseña del Administrador',
+ 'Change Password' => 'Cambiar Contraseña',
+ 'Character Set' => 'Conjunto de Caracteres',
+ 'Chart of Accounts' => 'Plan de Cuentas',
+ 'Check' => 'Cheque',
+ 'Check printed!' => 'Cheque impreso!',
+ 'Check printing failed!' => 'No se pudo imprimir cheque!',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Click on login name to edit!' => 'Haga click sobre el login para editar',
+ 'Close Books up to' => 'Cerrar ejercicio hasta',
+ 'Closed' => 'Cerrado',
+ 'Company' => 'Compañía',
+ 'Compare to' => 'Comparar a',
+ 'Confirm!' => 'Confirmar!',
+ 'Connect to' => 'Conectar a',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Copy to COA' => 'Copiar a Plan de Cuentas',
+ 'Create Chart of Accounts' => 'Crear Plan de Cuentas',
+ 'Create Dataset' => 'Crear base de datos',
+ 'Credit' => 'Crédito',
+ 'Credit Limit' => 'Límite de Crédito',
+ 'Curr' => 'Div',
+ 'Currency' => 'Divisa',
+ 'Current' => 'Actual',
+ 'Customer' => 'Cliente',
+ 'Customer deleted!' => 'Cliente borrado!',
+ 'Customer missing!' => 'Falta cliente!',
+ 'Customer not on file!' => 'Cliente no existe en archivo!',
+ 'Customer saved!' => 'Cliente guardado!',
+ 'Customers' => 'Clientes',
+ 'DBI not installed!' => 'DBI no ha sido instalado!',
+ 'Database' => 'Base de Datos',
+ 'Database Administration' => 'Administración de base de datos',
+ 'Database Driver not checked!' => 'Manejador no seleccionado!',
+ 'Database Host' => 'Servidor de base de datos',
+ 'Database User missing!' => 'Falta usuario de base de datos!',
+ 'Dataset' => 'Base de datos',
+ 'Dataset missing!' => 'Falta base de datos!',
+ 'Dataset updated!' => 'Base de datos actualizada!',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Vencimiento',
+ 'Date Format' => 'Formato Fecha',
+ 'Date Paid' => 'Fecha Pago',
+ 'Date missing!' => 'Falta fecha!',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito y Crédito fuera de balance!',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Decimalplaces' => 'Posiciones decimales',
+ 'Delete' => 'Borrar',
+ 'Delete Account' => 'Borrar Cuenta',
+ 'Delete Dataset' => 'Borrar base de datos',
+ 'Delivery Date' => 'Fecha de Entrega',
+ 'Deposit' => 'Deposit',
+ 'Description' => 'Descripción',
+ 'Difference' => 'Diferencia',
+ 'Directory' => 'Directorio',
+ 'Discount' => 'Descuento',
+ 'Done' => 'Listo',
+ 'Drawing' => 'Retiro',
+ 'Driver' => 'Manejador',
+ 'Dropdown Limit' => 'Límite menu dropdown',
+ 'Due' => 'Vence',
+ 'Due Date' => 'Vencimiento',
+ 'Due Date missing!' => 'Falta Vencimiento!',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'Enviar estado de cuenta por E-mail a',
+ 'E-mail address missing!' => 'Falta dirección E-mail!',
+ 'Edit' => 'Editar',
+ 'Edit Account' => 'Editar Cuenta',
+ 'Edit Accounts Payables Transaction' => 'Editar Transacción Cuentas por Pagar',
+ 'Edit Accounts Receivables Transaction' => 'Editar Transacción Cuentas por Cobrar',
+ 'Edit Assembly' => 'Editar Conjunto',
+ 'Edit Customer' => 'Editar Cliente',
+ 'Edit GIFI' => 'Editar GIFI',
+ 'Edit General Ledger Transaction' => 'Editar Transacción de Mayor General',
+ 'Edit Part' => 'Editar Item',
+ 'Edit Preferences for' => 'Editar Preferencias para',
+ 'Edit Project' => 'Editar Proyecto',
+ 'Edit Purchase Invoice' => 'Editar Factura de Compra',
+ 'Edit Purchase Order' => 'Editar Orden de Compra',
+ 'Edit Sales Invoice' => 'Editar Factura de Venta',
+ 'Edit Sales Order' => 'Editar Pedido',
+ 'Edit Service' => 'Editar Servicio',
+ 'Edit Template' => 'Editar Plantilla',
+ 'Edit User' => 'Editar Usuario',
+ 'Edit Vendor' => 'Editar Proveedor',
+ 'Employee' => 'Empleado',
+ 'Enforce transaction reversal for all dates' => 'Obligar reverso de transacciones para todas las fechas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Ingrese símbolo de hasta 3 letras para divisas nativa y extranjeras',
+ 'Equity' => 'Capital',
+ 'Exch' => 'Tasa',
+ 'Exchangerate' => 'Tasa de Cambio',
+ 'Exchangerate Difference' => 'Diferencial Dambiario',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Existing Datasets' => 'Bases de datos existentes',
+ 'Expense' => 'Egreso',
+ 'Expense Account' => 'Cuenta de Gasto',
+ 'Expense/Asset' => 'Egreso/Activo',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'Foreign Exchange Gain' => 'Ganancia Cambiaria',
+ 'Foreign Exchange Loss' => 'Pérdida Cambiaria',
+ 'From' => 'Desde',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI borrado!',
+ 'GIFI missing!' => 'Falta GIFI!',
+ 'GIFI saved!' => 'GIFI guardado!',
+ 'GL Transaction' => 'Transacción de mayor',
+ 'General Ledger' => 'Mayor General',
+ 'Goods & Services' => 'Bienes y Servicios',
+ 'HTML Templates' => 'Plantillas HTML',
+ 'Heading' => 'Encabezado',
+ 'Host' => 'Host',
+ 'Hostname missing!' => 'Falta nombre del Host!',
+ 'ID' => 'ID',
+ 'Image' => 'Imagen',
+ 'In-line' => 'Incorporado',
+ 'Include in Report' => 'Incluya en Reporte',
+ 'Include in drop-down menus' => 'Incluya en menús "drop-down"',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluir cuenta en pantallas Cliente/Proveedor para señalar como contribuyente?',
+ 'Income' => 'Ingreso',
+ 'Income Account' => 'Cuenta de Ingreso',
+ 'Income Statement' => 'Estado de Cuentas de Ingreso',
+ 'Incorrect Dataset version!' => 'Versión incorrecta de base de datos!',
+ 'Incorrect Password!' => 'Contraseña equivocada',
+ 'Individual Items' => 'Items Individuales',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Cuenta de Inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Existencia debe ser cero antes de hacer obsoleto a este conjunto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Existencia debe ser cero antes de hacer obsoleto este ítem!',
+ 'Inventory quantity must be zero!' => 'Existencia debe ser cero!',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha Factura',
+ 'Invoice Date missing!' => 'Falta Fecha Factura!',
+ 'Invoice Number' => 'Número Factura',
+ 'Invoice Number missing!' => 'Falta Número Factura!',
+ 'Invoice deleted!' => 'Factura borrada!',
+ 'Invoice posted!' => 'Factura registrada!',
+ 'Invoices' => 'Facturas',
+ 'Is this a summary account to record' => 'Registrar en cuenta de resumen ',
+ 'Item deleted!' => 'Item borrado!',
+ 'Item not on file!' => 'Item no archivado!',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'LaTeX Templates' => 'Plantillas LaTeX',
+ 'Language' => 'Idioma',
+ 'Last Cost' => 'Ultimo Costo',
+ 'Last Invoice Number' => 'Ultima Factura Emitida',
+ 'Last Numbers & Default Accounts' => 'Ultimos Números y Cuentas por Defecto',
+ 'Last Purchase Order Number' => 'Ultimo número Orden de Compra',
+ 'Last Sales Order Number' => 'Ultimo número Pedido',
+ 'Leave host and port field empty unless you want to make a remote connection.' => 'Deje en blanco los campos Host y Puerto si no requiere una conección remota',
+ 'Liability' => 'Pasivo',
+ 'Licensed to' => 'Licenciatario',
+ 'Line Total' => 'Total línea',
+ 'Link' => 'Vinculado a',
+ 'Link Accounts' => 'Vincular Cuentas',
+ 'List Accounts' => 'Listar cuentas',
+ 'List GIFI' => 'Listar GIFI',
+ 'List Price' => 'Precio de Lista',
+ 'List Transactions' => 'Listar Transacciones',
+ 'Login' => 'Login',
+ 'Logout' => 'Salir del sistema',
+ 'Make' => 'Marca',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Message' => 'Mensaje',
+ 'Microfiche' => 'Microficha',
+ 'Model' => 'Modelo',
+ 'Multibyte Encoding' => 'Codificación conjunto de caracteres',
+ 'N/A' => 'N/D',
+ 'Name' => 'Nombre',
+ 'Name missing!' => 'Falta nombre!',
+ 'New Templates' => 'Plantillas Nuevas',
+ 'No' => ' No ',
+ 'No Database Drivers available!' => 'No hay manejadores para base de datos!',
+ 'No Dataset selected!' => 'Base de datos no seleccionada!',
+ 'No email address for' => 'Falta dirección email para',
+ 'No.' => 'No.',
+ 'Notes' => 'Comentario',
+ 'Nothing applied!' => 'Nada aplicado!',
+ 'Nothing selected!' => 'Nada seleccionado!',
+ 'Nothing to delete!' => 'Nada para borrar!',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato Numérico',
+ 'Number missing in Row' => 'Falta número en Hilera',
+ 'O' => 'O',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'On Hand' => 'Existencia',
+ 'On Order' => 'Pedido',
+ 'Open' => 'Abierto',
+ 'Oracle Database Administration' => 'Administración bases de datos Oracle',
+ 'Order' => 'Orden',
+ 'Order Date' => 'Fecha Pedido',
+ 'Order Date missing!' => 'Falta Fecha Pedido!',
+ 'Order Entry' => 'Pedidos<br>Ordenes de Compra',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'Falta Número de Orden',
+ 'Order deleted!' => 'Orden borrada!',
+ 'Order saved!' => 'Orden guardada!',
+ 'Ordered' => 'Pedido',
+ 'Orphaned' => 'Huérfano',
+ 'Out of balance!' => 'Fuera de balance!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'Falta Fecha en Nota de Entrega',
+ 'Packing List Number missing!' => 'Falta Número en Nota de Entrega',
+ 'Paid' => 'Pagado',
+ 'Paid in full' => 'Cancelado',
+ 'Part' => 'Item',
+ 'Part Number missing!' => 'Falta Número de Item!',
+ 'Parts' => 'Items',
+ 'Parts Inventory' => 'Inventario de Items',
+ 'Password' => 'Contraseña',
+ 'Password changed!' => 'Contraseña cambiada!',
+ 'Payables' => 'X Pagar',
+ 'Payment' => 'Pago',
+ 'Payment date missing!' => 'Falta Fecha de Pago',
+ 'Payment posted!' => 'Pago registrado!',
+ 'Payments' => 'Pagos',
+ 'Pg Database Administration' => 'Administración bases de datos Pg',
+ 'Phone' => 'Teléfono',
+ 'Port' => 'Número de Puerto',
+ 'Port missing!' => 'Falta número de puerto',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Postscript' => 'Postscript',
+ 'Preferences' => 'Preferencias',
+ 'Preferences saved!' => 'Preferencias guardadas!',
+ 'Price' => 'Precio',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Project Number missing!' => 'Falta número de proyecto!',
+ 'Project deleted!' => 'Proyecto borrado!',
+ 'Project not on file!' => 'Proyecto no archivado!',
+ 'Project saved!' => 'Proyecto guardado!',
+ 'Projects' => 'Proyectos',
+ 'Purchase Invoice' => 'Factura de Compra',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Purchase Orders' => 'Ordenes de Compra',
+ 'Qty' => 'Cnt',
+ 'ROP' => 'Existencia mínima',
+ 'Rate' => 'Tasa',
+ 'Recd' => 'Rec',
+ 'Receipt' => 'Ingreso',
+ 'Receipts' => 'Ingresos',
+ 'Receivables' => 'X Cobrar',
+ 'Reconciliation' => 'Conciliación',
+ 'Record in' => 'Registrar en',
+ 'Reference' => 'Referencia',
+ 'Reference missing!' => 'Falta referencia!',
+ 'Remaining' => 'Quedan',
+ 'Report for' => 'Reporte de',
+ 'Reports' => 'Reportes',
+ 'Required by' => 'Requerido para el',
+ 'Retained Earnings' => 'Ganancias Retenidas',
+ 'Sales' => 'Ventas',
+ 'Sales Invoice' => 'Factura de Venta',
+ 'Sales Order' => 'Pedido',
+ 'Sales Orders' => 'Pedidos',
+ 'Save' => 'Guardar',
+ 'Save as new' => 'Guardar como nuevo',
+ 'Save to File' => 'Respaldar a Archivo',
+ 'Screen' => 'Pantalla',
+ 'Select a Dataset to delete and press "Continue"' => 'Seleccione base de datos a borrar y pulse "Continue"',
+ 'Select all' => 'Seleccione todos',
+ 'Select from one of the items below' => 'Seleccione uno de los ítems listados',
+ 'Select from one of the names below' => 'Seleccione de uno de los nombres a continuación',
+ 'Select from one of the projects below' => 'Seleccione de uno de los proyectos a continuación',
+ 'Select postscript or PDF!' => 'Seleccione postscript o PDF',
+ 'Sell Price' => 'Precio de Venta',
+ 'Send by E-Mail' => 'Enviar por E-Mail',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Service' => 'Servicio',
+ 'Service Items' => 'Inventario de Servicios',
+ 'Service Number missing!' => 'Falta Número de Servicio!',
+ 'Services' => 'Servicios',
+ 'Setup Templates' => 'Configurar Plantillas',
+ 'Ship' => 'Envíe',
+ 'Ship to' => 'Envíe a',
+ 'Ship via' => 'Envía vía',
+ 'Short' => 'Corto',
+ 'Signature' => 'Firma',
+ 'Sold' => 'Vendido',
+ 'Source' => 'Referencia',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Estado de Cuenta',
+ 'Statement Balance' => 'Balance Estado de Cuenta',
+ 'Statement sent to' => 'Estado de Cuenta enviado a',
+ 'Statements sent to printer!' => 'Estados de Cuenta enviados a impresora!',
+ 'Stock Assembly' => 'Reponer Conjuntos',
+ 'Stylesheet' => 'Hoja de Estilo',
+ 'Subject' => 'Materia',
+ 'Subtotal' => 'Subtotal',
+ 'System' => 'Sistema',
+ 'Tax' => 'ISV',
+ 'Tax Accounts' => 'Cuentas de Impuesto',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Tax collected' => 'Impuesto recaudado',
+ 'Tax paid' => 'Impuesto pagado',
+ 'Taxable' => 'Base imponible',
+ 'Template saved!' => 'Plantilla guardada!',
+ 'Templates' => 'Plantillas',
+ 'Terms: Net' => 'Crédito a',
+ 'The following Datasets are not in use and can be deleted' => 'Las siguientes bases de datos no están en uso y pueden ser borradas',
+ 'The following Datasets need to be updated' => 'Las siguientes bases de datos requieren actualización',
+ 'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'Chequeo preliminar. En esta etapa no se creará ni se borrará nada!',
+ 'To' => 'Hasta',
+ 'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Para agregar un usuario a un grupo, edite un nombre, cambie el login y guárdelo de nuevo. Un nuevo usuario con las mismas variables se creará bajo el nuevo login.',
+ 'Top Level' => 'Nivel superior',
+ 'Total' => 'Total',
+ 'Transaction Date missing!' => 'Falta Fecha Transacción!',
+ 'Transaction deleted!' => 'Transacción borrada!',
+ 'Transaction posted!' => 'Transacción registrada!',
+ 'Transaction reversal enforced for all dates' => 'Reverso de transacciones obligadas para todas la fechas',
+ 'Transaction reversal enforced up to' => 'Reverso de transacciones obligadas hasta',
+ 'Transactions' => 'Transacciones',
+ 'Transactions exist, cannot delete customer!' => 'No podemos borrar cliente, existen transacciones!',
+ 'Transactions exist, cannot delete vendor!' => 'No podemos borrar proveedor, existen transacciones!',
+ 'Transactions exist; cannot delete account!' => 'No podemos borrar cuenta, existen transacciones!',
+ 'Trial Balance' => 'Balance de Comprobación',
+ 'Unit' => 'Unidad',
+ 'Unit of measure' => 'Unidad de medida',
+ 'Update' => 'Actualizar',
+ 'Update Dataset' => 'Actualizar base de datos',
+ 'Updated' => 'Actalizado',
+ 'Use Templates' => 'Use Plantilla',
+ 'User' => 'Usuario',
+ 'User deleted!' => 'Usuario borrado!',
+ 'User saved!' => 'Usuario guardado!',
+ 'Vendor' => 'Proveedor',
+ 'Vendor deleted!' => 'Proveedor borrado!',
+ 'Vendor missing!' => 'Falta proveedor',
+ 'Vendor not on file!' => 'Proveedor no está en archivo!',
+ 'Vendor saved!' => 'Proveedor guardado!',
+ 'Vendors' => 'Proveedores',
+ 'Version' => 'Versión',
+ 'Weight' => 'Peso',
+ 'Weight Unit' => 'Unidad de Peso',
+ 'What type of item is this?' => '¿Qué tipo de ítem es éste?',
+ 'Year End' => 'Cierre',
+ 'Yes' => ' Sí ',
+ 'You are logged out!' => 'Ha salido del sistema!',
+ 'You did not enter a name!' => 'No se ingresó un nombre!',
+ 'You must enter a host and port for local and remote connections!' => 'Debe ingresar un host y un puerto para conecciones locales y remotas!',
+ 'as at' => 'Al',
+ 'collected on sales' => 'recaudado sobre ventas',
+ 'days' => 'días',
+ 'does not exist' => 'no existe',
+ 'ea' => 'cu',
+ 'emailed to' => 'enviado por email a',
+ 'for Period' => 'para el período',
+ 'hr' => 'hr',
+ 'is already a member!' => 'ya es miembro!',
+ 'is not a member!' => 'no es miembro!',
+ 'localhost' => 'localhost',
+ 'locked!' => '',
+ 'paid on purchases' => 'pagado sobre compras',
+ 'sent to printer' => 'enviado a impresora',
+ 'successfully created!' => 'creado!',
+ 'successfully deleted!' => 'borrado!',
+ 'to' => 'a',
+ 'website' => 'en internet',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/am b/sql-ledger/locale/ve/am
new file mode 100644
index 0000000..3002447
--- /dev/null
+++ b/sql-ledger/locale/ve/am
@@ -0,0 +1,139 @@
+$self{texts} = {
+ 'AP' => 'CXP',
+ 'AR' => 'CXC',
+ 'Account' => 'Cuenta',
+ 'Account Number' => 'Número de Cuenta',
+ 'Account Number missing!' => 'Falta Número de Cuenta!',
+ 'Account Type' => 'Tipo de Cuenta',
+ 'Account Type missing!' => 'Falta Tipo de Cuenta!',
+ 'Account deleted!' => 'Cuenta borrada!',
+ 'Account saved!' => 'Cuenta guardada!',
+ 'Add Account' => 'Agregar Cuenta',
+ 'Add GIFI' => 'Agregar GIFI',
+ 'Address' => 'Dirección',
+ 'Asset' => 'Activo',
+ 'Audit Control' => 'Control de Auditoría',
+ 'Backup sent to' => 'Respaldo enviado a',
+ 'Books are open' => 'Libros aperturados',
+ 'Business Number' => 'RIF/NIT/CI',
+ 'COGS' => 'Costo Perpetuo',
+ 'Cannot delete account!' => 'No puede borrar cuenta!',
+ 'Cannot delete default account!' => 'No puede borrar cuenta "default"!',
+ 'Cannot save account!' => 'No puede guardar cuenta!',
+ 'Cannot save preferences!' => 'No puede guardar preferencias!',
+ 'Character Set' => 'Conjunto de Caracteres',
+ 'Chart of Accounts' => 'Plan de Cuentas',
+ 'Close Books up to' => 'Cerrar ejercicio hasta',
+ 'Company' => 'Compañía',
+ 'Continue' => 'Continuar',
+ 'Copy to COA' => 'Copiar a Plan de Cuentas',
+ 'Credit' => 'Crédito',
+ 'Date Format' => 'Formato Fecha',
+ 'Debit' => 'Débito',
+ 'Delete' => 'Borrar',
+ 'Delete Account' => 'Borrar Cuenta',
+ 'Description' => 'Descripción',
+ 'Dropdown Limit' => 'Límite menu dropdown',
+ 'E-mail' => 'E-mail',
+ 'Edit' => 'Editar',
+ 'Edit Account' => 'Editar Cuenta',
+ 'Edit GIFI' => 'Editar GIFI',
+ 'Edit Preferences for' => 'Editar Preferencias para',
+ 'Edit Template' => 'Editar Plantilla',
+ 'Enforce transaction reversal for all dates' => 'Obligar reverso de transacciones para todas las fechas',
+ 'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Ingrese símbolo de hasta 3 letras para divisas nativa y extranjeras',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Egreso',
+ 'Expense Account' => 'Cuenta de Gasto',
+ 'Expense/Asset' => 'Egreso/Activo',
+ 'Fax' => 'Fax',
+ 'Foreign Exchange Gain' => 'Ganancia Cambiaria',
+ 'Foreign Exchange Loss' => 'Pérdida Cambiaria',
+ 'GIFI' => 'GIFI',
+ 'GIFI deleted!' => 'GIFI borrado!',
+ 'GIFI missing!' => 'Falta GIFI!',
+ 'GIFI saved!' => 'GIFI guardado!',
+ 'Heading' => 'Encabezado',
+ 'Include in drop-down menus' => 'Incluya en menús "drop-down"',
+ 'Include this account on the customer/vendor forms to flag customer/vendor as taxable?' => 'Incluir cuenta en pantallas Cliente/Proveedor para señalar como contribuyente?',
+ 'Income' => 'Ingreso',
+ 'Income Account' => 'Cuenta de Ingreso',
+ 'Inventory' => 'Inventario',
+ 'Inventory Account' => 'Cuenta de Inventario',
+ 'Is this a summary account to record' => 'Registrar en cuenta de resumen ',
+ 'Language' => 'Idioma',
+ 'Last Invoice Number' => 'Ultima Factura Emitida',
+ 'Last Numbers & Default Accounts' => 'Ultimos Números y Cuentas por Defecto',
+ 'Last Purchase Order Number' => 'Ultimo número Orden de Compra',
+ 'Last Sales Order Number' => 'Ultimo número Pedido',
+ 'Liability' => 'Pasivo',
+ 'Link' => 'Vinculado a',
+ 'Name' => 'Nombre',
+ 'No' => ' No ',
+ 'No email address for' => 'Falta dirección email para',
+ 'Number' => 'Número',
+ 'Number Format' => 'Formato Numérico',
+ 'Parts Inventory' => 'Inventario de Items',
+ 'Password' => 'Contraseña',
+ 'Payables' => 'X Pagar',
+ 'Payment' => 'Pago',
+ 'Phone' => 'Teléfono',
+ 'Preferences saved!' => 'Preferencias guardadas!',
+ 'Rate' => 'Tasa',
+ 'Receivables' => 'X Cobrar',
+ 'Sales' => 'Ventas',
+ 'Save' => 'Guardar',
+ 'Service Items' => 'Inventario de Servicios',
+ 'Ship via' => 'Envía vía',
+ 'Signature' => 'Firma',
+ 'Stylesheet' => 'Hoja de Estilo',
+ 'Tax' => 'ISV',
+ 'Tax Accounts' => 'Cuentas de Impuesto',
+ 'Template saved!' => 'Plantilla guardada!',
+ 'Transaction reversal enforced for all dates' => 'Reverso de transacciones obligadas para todas la fechas',
+ 'Transaction reversal enforced up to' => 'Reverso de transacciones obligadas hasta',
+ 'Transactions exist; cannot delete account!' => 'No podemos borrar cuenta, existen transacciones!',
+ 'Weight Unit' => 'Unidad de Peso',
+ 'Year End' => 'Cierre',
+ 'Yes' => ' Sí ',
+ 'does not exist' => 'no existe',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_gifi' => 'add_gifi',
+ 'audit_control' => 'audit_control',
+ 'backup' => 'backup',
+ 'config' => 'config',
+ 'continue' => 'continue',
+ 'copy_to_coa' => 'copy_to_coa',
+ 'delete' => 'delete',
+ 'delete_account' => 'delete_account',
+ 'delete_gifi' => 'delete_gifi',
+ 'display_form' => 'display_form',
+ 'display_stylesheet' => 'display_stylesheet',
+ 'doclose' => 'doclose',
+ 'edit' => 'edit',
+ 'edit_gifi' => 'edit_gifi',
+ 'edit_template' => 'edit_template',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gifi_footer' => 'gifi_footer',
+ 'gifi_header' => 'gifi_header',
+ 'list' => 'list',
+ 'list_gifi' => 'list_gifi',
+ 'save' => 'save',
+ 'save_account' => 'save_account',
+ 'save_gifi' => 'save_gifi',
+ 'save_preferences' => 'save_preferences',
+ 'save_template' => 'save_template',
+ 'agregar_cuenta' => 'add_account',
+ 'continuar' => 'continue',
+ 'copiar_a_plan_de_cuentas' => 'copy_to_coa',
+ 'borrar' => 'delete',
+ 'editar' => 'edit',
+ 'editar_cuenta' => 'edit_account',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/ap b/sql-ledger/locale/ve/ap
new file mode 100644
index 0000000..754f856
--- /dev/null
+++ b/sql-ledger/locale/ve/ap
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AP Transaction' => 'Cuenta por Pagar',
+ 'AP Transactions' => 'Cuentas por Pagar',
+ 'Account' => 'Cuenta',
+ 'Add Accounts Payables Transaction' => 'Agregar Cuenta por Pagar',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Monto',
+ 'Amount Due' => 'Monto Vencido',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Are you sure you want to delete Transaction' => '¿Seguro que desea borrar Transacción?',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'Cannot delete transaction!' => 'No puede borrar transacción!',
+ 'Cannot post payment for a closed period!' => 'No puede registrar pago para ejercicio cerrado',
+ 'Cannot post transaction for a closed period!' => 'No puede registrar transacción para ejercicio cerrado!',
+ 'Cannot post transaction!' => 'No puede registrar transacción!',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Divisa',
+ 'Customer not on file!' => 'Cliente no existe en archivo!',
+ 'Date' => 'Fecha',
+ 'Date Paid' => 'Fecha Pago',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Due Date' => 'Vencimiento',
+ 'Due Date missing!' => 'Falta Vencimiento!',
+ 'Edit Accounts Payables Transaction' => 'Editar Transacción Cuentas por Pagar',
+ 'Employee' => 'Empleado',
+ 'Exch' => 'Tasa',
+ 'Exchangerate' => 'Tasa de Cambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluya en Reporte',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha Factura',
+ 'Invoice Date missing!' => 'Falta Fecha Factura!',
+ 'Invoice Number' => 'Número Factura',
+ 'Invoice Number missing!' => 'Falta Número Factura!',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Notes' => 'Comentario',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Number' => 'Orden Número',
+ 'Paid' => 'Pagado',
+ 'Payment date missing!' => 'Falta Fecha de Pago',
+ 'Payments' => 'Pagos',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => 'Proyecto no archivado!',
+ 'Purchase Invoice' => 'Factura de Compra',
+ 'Select from one of the names below' => 'Seleccione de uno de los nombres a continuación',
+ 'Select from one of the projects below' => 'Seleccione de uno de los proyectos a continuación',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Source' => 'Referencia',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'ISV',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transacción borrada!',
+ 'Transaction posted!' => 'Transacción registrada!',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => 'Falta proveedor',
+ 'Vendor not on file!' => 'Proveedor no está en archivo!',
+ 'Yes' => ' Sí ',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_subtotal' => 'ap_subtotal',
+ 'ap_transaction' => 'ap_transaction',
+ 'ap_transactions' => 'ap_transactions',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'cuenta_por_pagar' => 'ap_transaction',
+ 'agregar_cuenta_por_pagar' => 'add_accounts_payables_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'editar_transacción_cuentas_por_pagar' => 'edit_accounts_payables_transaction',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'factura_de_compra' => 'purchase_invoice',
+ 'actualizar' => 'update',
+ '_sí_' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/ar b/sql-ledger/locale/ve/ar
new file mode 100644
index 0000000..55da07b
--- /dev/null
+++ b/sql-ledger/locale/ve/ar
@@ -0,0 +1,133 @@
+$self{texts} = {
+ 'AR Transaction' => 'Cuenta por Cobrar',
+ 'AR Transactions' => 'Cuentas por Cobrar',
+ 'Account' => 'Cuenta',
+ 'Add Accounts Receivables Transaction' => 'Agregar Cuenta por Cobrar',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Monto',
+ 'Amount Due' => 'Monto Vencido',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Are you sure you want to delete Transaction' => '¿Seguro que desea borrar Transacción?',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'Cannot delete transaction!' => 'No puede borrar transacción!',
+ 'Cannot post payment for a closed period!' => 'No puede registrar pago para ejercicio cerrado',
+ 'Cannot post transaction for a closed period!' => 'No puede registrar transacción para ejercicio cerrado!',
+ 'Cannot post transaction!' => 'No puede registrar transacción!',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Límite de Crédito',
+ 'Currency' => 'Divisa',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Falta cliente!',
+ 'Customer not on file!' => 'Cliente no existe en archivo!',
+ 'Date' => 'Fecha',
+ 'Date Paid' => 'Fecha Pago',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Due Date' => 'Vencimiento',
+ 'Due Date missing!' => 'Falta Vencimiento!',
+ 'Edit Accounts Receivables Transaction' => 'Editar Transacción Cuentas por Cobrar',
+ 'Employee' => 'Empleado',
+ 'Exch' => 'Tasa',
+ 'Exchangerate' => 'Tasa de Cambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluya en Reporte',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha Factura',
+ 'Invoice Date missing!' => 'Falta Fecha Factura!',
+ 'Invoice Number' => 'Número Factura',
+ 'Invoice Number missing!' => 'Falta Número Factura!',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Notes' => 'Comentario',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Number' => 'Orden Número',
+ 'Paid' => 'Pagado',
+ 'Payment date missing!' => 'Falta Fecha de Pago',
+ 'Payments' => 'Pagos',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => 'Proyecto no archivado!',
+ 'Remaining' => 'Quedan',
+ 'Sales Invoice' => 'Factura de Venta',
+ 'Select from one of the names below' => 'Seleccione de uno de los nombres a continuación',
+ 'Select from one of the projects below' => 'Seleccione de uno de los proyectos a continuación',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Source' => 'Referencia',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'ISV',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Total' => 'Total',
+ 'Transaction deleted!' => 'Transacción borrada!',
+ 'Transaction posted!' => 'Transacción registrada!',
+ 'Update' => 'Actualizar',
+ 'Vendor not on file!' => 'Proveedor no está en archivo!',
+ 'Yes' => ' Sí ',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_subtotal' => 'ar_subtotal',
+ 'ar_transaction' => 'ar_transaction',
+ 'ar_transactions' => 'ar_transactions',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_links' => 'create_links',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'cuenta_por_cobrar' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'factura_de_venta' => 'sales_invoice',
+ 'actualizar' => 'update',
+ '_sí_' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/arap b/sql-ledger/locale/ve/arap
new file mode 100644
index 0000000..deba2e5
--- /dev/null
+++ b/sql-ledger/locale/ve/arap
@@ -0,0 +1,30 @@
+$self{texts} = {
+ 'Address' => 'Dirección',
+ 'Continue' => 'Continuar',
+ 'Customer not on file!' => 'Cliente no existe en archivo!',
+ 'Description' => 'Descripción',
+ 'Number' => 'Número',
+ 'Project not on file!' => 'Proyecto no archivado!',
+ 'Select from one of the names below' => 'Seleccione de uno de los nombres a continuación',
+ 'Select from one of the projects below' => 'Seleccione de uno de los proyectos a continuación',
+ 'Vendor not on file!' => 'Proveedor no está en archivo!',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/ca b/sql-ledger/locale/ve/ca
new file mode 100644
index 0000000..8de34b6
--- /dev/null
+++ b/sql-ledger/locale/ve/ca
@@ -0,0 +1,50 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'Balance' => 'Balance',
+ 'Chart of Accounts' => 'Plan de Cuentas',
+ 'Credit' => 'Crédito',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Description' => 'Descripción',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'GIFI',
+ 'Include in Report' => 'Incluya en Reporte',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'List Transactions' => 'Listar Transacciones',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'Reference' => 'Referencia',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Subtotal' => 'Subtotal',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'ca_subtotal' => 'ca_subtotal',
+ 'chart_of_accounts' => 'chart_of_accounts',
+ 'list' => 'list',
+ 'list_transactions' => 'list_transactions',
+ 'listar_transacciones' => 'list_transactions',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/cp b/sql-ledger/locale/ve/cp
new file mode 100644
index 0000000..91c9350
--- /dev/null
+++ b/sql-ledger/locale/ve/cp
@@ -0,0 +1,75 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Monto',
+ 'Amount does not equal applied!' => 'Monto no es igual!',
+ 'Amount missing!' => 'Falta monto!',
+ 'Applied' => 'Aplicado',
+ 'Cannot post payment!' => 'No puede registrar pago!',
+ 'Cannot process payment for a closed period!' => 'No puede procesar pago para ejercicio cerrado!',
+ 'Check' => 'Cheque',
+ 'Check printed!' => 'Cheque impreso!',
+ 'Check printing failed!' => 'No se pudo imprimir cheque!',
+ 'Continue' => 'Continuar',
+ 'Currency' => 'Divisa',
+ 'Customer' => 'Cliente',
+ 'Customer not on file!' => 'Cliente no existe en archivo!',
+ 'Date' => 'Fecha',
+ 'Date missing!' => 'Falta fecha!',
+ 'Description' => 'Descripción',
+ 'Due' => 'Vence',
+ 'Exchangerate' => 'Tasa de Cambio',
+ 'From' => 'Desde',
+ 'Invoice' => 'Factura',
+ 'Invoices' => 'Facturas',
+ 'Nothing applied!' => 'Nada aplicado!',
+ 'Number' => 'Número',
+ 'Paid in full' => 'Cancelado',
+ 'Payment' => 'Pago',
+ 'Payment posted!' => 'Pago registrado!',
+ 'Post' => 'Registrar',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Project not on file!' => 'Proyecto no archivado!',
+ 'Receipt' => 'Ingreso',
+ 'Reference' => 'Referencia',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the names below' => 'Seleccione de uno de los nombres a continuación',
+ 'Select from one of the projects below' => 'Seleccione de uno de los proyectos a continuación',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Proveedor',
+ 'Vendor not on file!' => 'Proveedor no está en archivo!',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'list_invoices' => 'list_invoices',
+ 'name_selected' => 'name_selected',
+ 'payment' => 'payment',
+ 'post' => 'post',
+ 'print' => 'print',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+ 'registrar' => 'post',
+ 'imprimir' => 'print',
+ 'actualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/ct b/sql-ledger/locale/ve/ct
new file mode 100644
index 0000000..60f585b
--- /dev/null
+++ b/sql-ledger/locale/ve/ct
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'Add' => 'Agregar',
+ 'Address' => 'Dirección',
+ 'All' => 'Todos',
+ 'Bcc' => 'Bcc',
+ 'Cannot delete customer!' => 'No puede borrar cliente!',
+ 'Cannot delete vendor!' => 'No puede borrar proveedor!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Credit Limit' => 'Límite de Crédito',
+ 'Customer deleted!' => 'Cliente borrado!',
+ 'Customer saved!' => 'Cliente guardado!',
+ 'Customers' => 'Clientes',
+ 'Delete' => 'Borrar',
+ 'Discount' => 'Descuento',
+ 'E-mail' => 'E-mail',
+ 'Edit Customer' => 'Editar Cliente',
+ 'Edit Vendor' => 'Editar Proveedor',
+ 'Fax' => 'Fax',
+ 'Include in Report' => 'Incluya en Reporte',
+ 'Invoice' => 'Factura',
+ 'Name' => 'Nombre',
+ 'Name missing!' => 'Falta nombre!',
+ 'Notes' => 'Comentario',
+ 'Number' => 'Número',
+ 'Order' => 'Orden',
+ 'Orphaned' => 'Huérfano',
+ 'Phone' => 'Teléfono',
+ 'Save' => 'Guardar',
+ 'Ship to' => 'Envíe a',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Taxable' => 'Base imponible',
+ 'Terms: Net' => 'Crédito a',
+ 'Transactions exist, cannot delete customer!' => 'No podemos borrar cliente, existen transacciones!',
+ 'Transactions exist, cannot delete vendor!' => 'No podemos borrar proveedor, existen transacciones!',
+ 'Vendor deleted!' => 'Proveedor borrado!',
+ 'Vendor saved!' => 'Proveedor guardado!',
+ 'Vendors' => 'Proveedores',
+ 'days' => 'días',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'customer_invoice' => 'customer_invoice',
+ 'customer_order' => 'customer_order',
+ 'delete' => 'delete',
+ 'delete_customer' => 'delete_customer',
+ 'delete_vendor' => 'delete_vendor',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'invoice' => 'invoice',
+ 'list_names' => 'list_names',
+ 'order' => 'order',
+ 'save' => 'save',
+ 'save_customer' => 'save_customer',
+ 'save_vendor' => 'save_vendor',
+ 'search' => 'search',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_order' => 'vendor_order',
+ 'agregar' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'factura' => 'invoice',
+ 'orden' => 'order',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/gl b/sql-ledger/locale/ve/gl
new file mode 100644
index 0000000..06c4137
--- /dev/null
+++ b/sql-ledger/locale/ve/gl
@@ -0,0 +1,124 @@
+$self{texts} = {
+ 'AP Transaction' => 'Cuenta por Pagar',
+ 'AR Transaction' => 'Cuenta por Cobrar',
+ 'Account' => 'Cuenta',
+ 'Add General Ledger Transaction' => 'Agregar Transacción al Mayor General',
+ 'Address' => 'Dirección',
+ 'All' => 'Todos',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Are you sure you want to delete Transaction' => '¿Seguro que desea borrar Transacción?',
+ 'Asset' => 'Activo',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'Balance' => 'Balance',
+ 'Cannot delete transaction!' => 'No puede borrar transacción!',
+ 'Cannot have a value in both Debit and Credit!' => 'No puede haber Débito y Crédito simultáneamente!',
+ 'Cannot post a transaction without a value!' => 'No puede registrar transacción sin monto!',
+ 'Cannot post transaction for a closed period!' => 'No puede registrar transacción para ejercicio cerrado!',
+ 'Confirm!' => 'Confirmar!',
+ 'Continue' => 'Continuar',
+ 'Credit' => 'Crédito',
+ 'Customer not on file!' => 'Cliente no existe en archivo!',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Debit and credit out of balance!' => 'Débito y Crédito fuera de balance!',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Edit General Ledger Transaction' => 'Editar Transacción de Mayor General',
+ 'Equity' => 'Capital',
+ 'Expense' => 'Egreso',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'GIFI',
+ 'GL Transaction' => 'Transacción de mayor',
+ 'General Ledger' => 'Mayor General',
+ 'ID' => 'ID',
+ 'Include in Report' => 'Incluya en Reporte',
+ 'Income' => 'Ingreso',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'Liability' => 'Pasivo',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Notes' => 'Comentario',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Number' => 'Número',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => 'Proyecto no archivado!',
+ 'Purchase Invoice' => 'Factura de Compra',
+ 'Reference' => 'Referencia',
+ 'Reference missing!' => 'Falta referencia!',
+ 'Reports' => 'Reportes',
+ 'Sales Invoice' => 'Factura de Venta',
+ 'Select from one of the names below' => 'Seleccione de uno de los nombres a continuación',
+ 'Select from one of the projects below' => 'Seleccione de uno de los proyectos a continuación',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Source' => 'Referencia',
+ 'Subtotal' => 'Subtotal',
+ 'Transaction Date missing!' => 'Falta Fecha Transacción!',
+ 'Transaction deleted!' => 'Transacción borrada!',
+ 'Transaction posted!' => 'Transacción registrada!',
+ 'Update' => 'Actualizar',
+ 'Vendor not on file!' => 'Proveedor no está en archivo!',
+ 'Yes' => ' Sí ',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'form_row' => 'form_row',
+ 'generate_report' => 'generate_report',
+ 'gl_subtotal' => 'gl_subtotal',
+ 'gl_transaction' => 'gl_transaction',
+ 'name_selected' => 'name_selected',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'search' => 'search',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'update' => 'update',
+ 'yes' => 'yes',
+ 'cuenta_por_pagar' => 'ap_transaction',
+ 'cuenta_por_cobrar' => 'ar_transaction',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'transacción_de_mayor' => 'gl_transaction',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'factura_de_compra' => 'purchase_invoice',
+ 'factura_de_venta' => 'sales_invoice',
+ 'actualizar' => 'update',
+ '_sí_' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/ic b/sql-ledger/locale/ve/ic
new file mode 100644
index 0000000..9c4e9c8
--- /dev/null
+++ b/sql-ledger/locale/ve/ic
@@ -0,0 +1,206 @@
+$self{texts} = {
+ 'Active' => 'Activa',
+ 'Add' => 'Agregar',
+ 'Add Assembly' => 'Agregar Conjunto',
+ 'Add Part' => 'Agregar Item',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Order' => 'Agregar Pedido',
+ 'Add Service' => 'Agregar Servicio',
+ 'Address' => 'Dirección',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Assemblies' => 'Conjuntos',
+ 'Assemblies restocked!' => 'Conjuntos re-inventariados',
+ 'Assembly Number missing!' => 'Falta Número Conjunto!',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'BOM' => 'Lista de Materiales',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ubicación',
+ 'Bought' => 'Comprado',
+ 'COGS' => 'Costo Perpetuo',
+ 'Cannot delete item already invoiced!' => 'No puede borrar ítem facturado!',
+ 'Cannot delete item on order!' => 'No puede borrar ítem pedido!',
+ 'Cannot delete item which is part of an assembly!' => 'No puede borrar ítem parte de conjunto!',
+ 'Cannot delete item!' => 'No puede borrar ítem!',
+ 'Cannot stock assemblies!' => 'No puede inventariar conjuntos!',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Fecha de Entrega',
+ 'Description' => 'Descripción',
+ 'Drawing' => 'Retiro',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Falta dirección E-mail!',
+ 'Edit Assembly' => 'Editar Conjunto',
+ 'Edit Part' => 'Editar Item',
+ 'Edit Service' => 'Editar Servicio',
+ 'Expense' => 'Egreso',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'From' => 'Desde',
+ 'Image' => 'Imagen',
+ 'In-line' => 'Incorporado',
+ 'Include in Report' => 'Incluya en Reporte',
+ 'Income' => 'Ingreso',
+ 'Individual Items' => 'Items Individuales',
+ 'Inventory' => 'Inventario',
+ 'Inventory quantity must be zero before you can set this assembly obsolete!' => 'Existencia debe ser cero antes de hacer obsoleto a este conjunto!',
+ 'Inventory quantity must be zero before you can set this part obsolete!' => 'Existencia debe ser cero antes de hacer obsoleto este ítem!',
+ 'Inventory quantity must be zero!' => 'Existencia debe ser cero!',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta Fecha Factura!',
+ 'Invoice Number' => 'Número Factura',
+ 'Invoice Number missing!' => 'Falta Número Factura!',
+ 'Item deleted!' => 'Item borrado!',
+ 'Item not on file!' => 'Item no archivado!',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'Last Cost' => 'Ultimo Costo',
+ 'Line Total' => 'Total línea',
+ 'Link Accounts' => 'Vincular Cuentas',
+ 'List Price' => 'Precio de Lista',
+ 'Make' => 'Marca',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Message' => 'Mensaje',
+ 'Microfiche' => 'Microficha',
+ 'Model' => 'Modelo',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Comentario',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta número en Hilera',
+ 'Obsolete' => 'Obsoleto',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'On Hand' => 'Existencia',
+ 'On Order' => 'Pedido',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'Falta Fecha Pedido!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'Falta Número de Orden',
+ 'Ordered' => 'Pedido',
+ 'Orphaned' => 'Huérfano',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'Falta Fecha en Nota de Entrega',
+ 'Packing List Number missing!' => 'Falta Número en Nota de Entrega',
+ 'Part' => 'Item',
+ 'Part Number missing!' => 'Falta Número de Item!',
+ 'Parts' => 'Items',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cnt',
+ 'ROP' => 'Existencia mínima',
+ 'Recd' => 'Rec',
+ 'Required by' => 'Requerido para el',
+ 'Sales' => 'Ventas',
+ 'Sales Order' => 'Pedido',
+ 'Save' => 'Guardar',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los ítems listados',
+ 'Select postscript or PDF!' => 'Seleccione postscript o PDF',
+ 'Sell Price' => 'Precio de Venta',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Service' => 'Servicio',
+ 'Service Number missing!' => 'Falta Número de Servicio!',
+ 'Services' => 'Servicios',
+ 'Ship' => 'Envíe',
+ 'Ship to' => 'Envíe a',
+ 'Short' => 'Corto',
+ 'Sold' => 'Vendido',
+ 'Stock Assembly' => 'Reponer Conjuntos',
+ 'Subject' => 'Materia',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'ISV',
+ 'To' => 'Hasta',
+ 'Top Level' => 'Nivel superior',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Unit of measure' => 'Unidad de medida',
+ 'Update' => 'Actualizar',
+ 'Updated' => 'Actalizado',
+ 'Weight' => 'Peso',
+ 'What type of item is this?' => '¿Qué tipo de ítem es éste?',
+ 'ea' => 'cu',
+ 'emailed to' => 'enviado por email a',
+ 'hr' => 'hr',
+ 'sent to printer' => 'enviado a impresora',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'assembly_row' => 'assembly_row',
+ 'check_form' => 'check_form',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'delete_assembly' => 'delete_assembly',
+ 'delete_item' => 'delete_item',
+ 'delete_part' => 'delete_part',
+ 'delete_service' => 'delete_service',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'link_part' => 'link_part',
+ 'list_assemblies' => 'list_assemblies',
+ 'makemodel_row' => 'makemodel_row',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'parts_subtotal' => 'parts_subtotal',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'restock_assemblies' => 'restock_assemblies',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'stock_assembly' => 'stock_assembly',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'agregar' => 'add',
+ 'agregar_conjunto' => 'add_assembly',
+ 'agregar_item' => 'add_part',
+ 'agregar_servicio' => 'add_service',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'editar_conjunto' => 'edit_assembly',
+ 'editar_item' => 'edit_part',
+ 'editar_servicio' => 'edit_service',
+ 'guardar' => 'save',
+ 'actualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/io b/sql-ledger/locale/ve/io
new file mode 100644
index 0000000..9370f8f
--- /dev/null
+++ b/sql-ledger/locale/ve/io
@@ -0,0 +1,106 @@
+$self{texts} = {
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Order' => 'Agregar Pedido',
+ 'Address' => 'Dirección',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ubicación',
+ 'Cc' => 'Cc',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Delivery Date' => 'Fecha de Entrega',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Falta dirección E-mail!',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'In-line' => 'Incorporado',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta Fecha Factura!',
+ 'Invoice Number missing!' => 'Falta Número Factura!',
+ 'Item not on file!' => 'Item no archivado!',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta número en Hilera',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'Falta Fecha Pedido!',
+ 'Order Number missing!' => 'Falta Número de Orden',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'Falta Fecha en Nota de Entrega',
+ 'Packing List Number missing!' => 'Falta Número en Nota de Entrega',
+ 'Part' => 'Item',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cnt',
+ 'Recd' => 'Rec',
+ 'Required by' => 'Requerido para el',
+ 'Sales Order' => 'Pedido',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los ítems listados',
+ 'Select postscript or PDF!' => 'Seleccione postscript o PDF',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Envíe',
+ 'Ship to' => 'Envíe a',
+ 'Subject' => 'Materia',
+ 'To' => 'Hasta',
+ 'Unit' => 'Unidad',
+ 'What type of item is this?' => '¿Qué tipo de ítem es éste?',
+ 'emailed to' => 'enviado por email a',
+ 'sent to printer' => 'enviado a impresora',
+};
+
+$self{subs} = {
+ 'check_form' => 'check_form',
+ 'customer_details' => 'customer_details',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post_as_new' => 'post_as_new',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'select_item' => 'select_item',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'continuar' => 'continue',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/ir b/sql-ledger/locale/ve/ir
new file mode 100644
index 0000000..29eec22
--- /dev/null
+++ b/sql-ledger/locale/ve/ir
@@ -0,0 +1,178 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Add Purchase Invoice' => 'Agregar Factura de Compra',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Order' => 'Agregar Pedido',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Monto',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Seguro que desea borrar Factura?',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ubicación',
+ 'Cannot delete invoice!' => 'No puede borraar factura!',
+ 'Cannot post invoice for a closed period!' => 'No puede registrar factura para ejercicio cerrado!',
+ 'Cannot post invoice!' => 'No puede registrar factura!',
+ 'Cannot post payment for a closed period!' => 'No puede registrar pago para ejercicio cerrado',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Currency' => 'Divisa',
+ 'Customer not on file!' => 'Cliente no existe en archivo!',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Vencimiento',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Fecha de Entrega',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Falta dirección E-mail!',
+ 'Edit Purchase Invoice' => 'Editar Factura de Compra',
+ 'Exch' => 'Tasa',
+ 'Exchangerate' => 'Tasa de Cambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'In-line' => 'Incorporado',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha Factura',
+ 'Invoice Date missing!' => 'Falta Fecha Factura!',
+ 'Invoice Number' => 'Número Factura',
+ 'Invoice Number missing!' => 'Falta Número Factura!',
+ 'Invoice deleted!' => 'Factura borrada!',
+ 'Invoice posted!' => 'Factura registrada!',
+ 'Item not on file!' => 'Item no archivado!',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Comentario',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta número en Hilera',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'Falta Fecha Pedido!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'Falta Número de Orden',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'Falta Fecha en Nota de Entrega',
+ 'Packing List Number missing!' => 'Falta Número en Nota de Entrega',
+ 'Part' => 'Item',
+ 'Payment date missing!' => 'Falta Fecha de Pago',
+ 'Payments' => 'Pagos',
+ 'Phone' => 'Teléfono',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => 'Proyecto no archivado!',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cnt',
+ 'Recd' => 'Rec',
+ 'Record in' => 'Registrar en',
+ 'Required by' => 'Requerido para el',
+ 'Sales Order' => 'Pedido',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los ítems listados',
+ 'Select from one of the names below' => 'Seleccione de uno de los nombres a continuación',
+ 'Select from one of the projects below' => 'Seleccione de uno de los proyectos a continuación',
+ 'Select postscript or PDF!' => 'Seleccione postscript o PDF',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Envíe',
+ 'Ship to' => 'Envíe a',
+ 'Source' => 'Referencia',
+ 'Subject' => 'Materia',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => 'Falta proveedor',
+ 'Vendor not on file!' => 'Proveedor no está en archivo!',
+ 'What type of item is this?' => '¿Qué tipo de ítem es éste?',
+ 'Yes' => ' Sí ',
+ 'ea' => 'cu',
+ 'emailed to' => 'enviado por email a',
+ 'sent to printer' => 'enviado a impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'orden' => 'order',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'actualizar' => 'update',
+ '_sí_' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/is b/sql-ledger/locale/ve/is
new file mode 100644
index 0000000..28d7abd
--- /dev/null
+++ b/sql-ledger/locale/ve/is
@@ -0,0 +1,185 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Invoice' => 'Agregar Factura de Venta',
+ 'Add Sales Order' => 'Agregar Pedido',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Monto',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Are you sure you want to delete Invoice Number' => '¿Seguro que desea borrar Factura?',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ubicación',
+ 'Cannot delete invoice!' => 'No puede borraar factura!',
+ 'Cannot post invoice for a closed period!' => 'No puede registrar factura para ejercicio cerrado!',
+ 'Cannot post invoice!' => 'No puede registrar factura!',
+ 'Cannot post payment for a closed period!' => 'No puede registrar pago para ejercicio cerrado',
+ 'Cc' => 'Cc',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit Limit' => 'Límite de Crédito',
+ 'Currency' => 'Divisa',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Falta cliente!',
+ 'Customer not on file!' => 'Cliente no existe en archivo!',
+ 'Date' => 'Fecha',
+ 'Date Due' => 'Vencimiento',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Fecha de Entrega',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Falta dirección E-mail!',
+ 'Edit Sales Invoice' => 'Editar Factura de Venta',
+ 'Exch' => 'Tasa',
+ 'Exchangerate' => 'Tasa de Cambio',
+ 'Exchangerate for payment missing!' => 'No se encuentra pago por cambio de moneda',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'In-line' => 'Incorporado',
+ 'Invoice' => 'Factura',
+ 'Invoice Date' => 'Fecha Factura',
+ 'Invoice Date missing!' => 'Falta Fecha Factura!',
+ 'Invoice Number' => 'Número Factura',
+ 'Invoice Number missing!' => 'Falta Número Factura!',
+ 'Invoice deleted!' => 'Factura borrada!',
+ 'Invoice posted!' => 'Factura registrada!',
+ 'Item not on file!' => 'Item no archivado!',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Comentario',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta número en Hilera',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'Order' => 'Orden',
+ 'Order Date missing!' => 'Falta Fecha Pedido!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'Falta Número de Orden',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'Falta Fecha en Nota de Entrega',
+ 'Packing List Number missing!' => 'Falta Número en Nota de Entrega',
+ 'Part' => 'Item',
+ 'Payment date missing!' => 'Falta Fecha de Pago',
+ 'Payments' => 'Pagos',
+ 'Phone' => 'Teléfono',
+ 'Post' => 'Registrar',
+ 'Post as new' => 'Registrar como nuevo',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => 'Proyecto no archivado!',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Qty' => 'Cnt',
+ 'Recd' => 'Rec',
+ 'Record in' => 'Registrar en',
+ 'Remaining' => 'Quedan',
+ 'Required by' => 'Requerido para el',
+ 'Sales Order' => 'Pedido',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los ítems listados',
+ 'Select from one of the names below' => 'Seleccione de uno de los nombres a continuación',
+ 'Select from one of the projects below' => 'Seleccione de uno de los proyectos a continuación',
+ 'Select postscript or PDF!' => 'Seleccione postscript o PDF',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Envíe',
+ 'Ship to' => 'Envíe a',
+ 'Ship via' => 'Envía vía',
+ 'Source' => 'Referencia',
+ 'Subject' => 'Materia',
+ 'Subtotal' => 'Subtotal',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'To' => 'Hasta',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Actualizar',
+ 'Vendor not on file!' => 'Proveedor no está en archivo!',
+ 'What type of item is this?' => '¿Qué tipo de ítem es éste?',
+ 'Yes' => ' Sí ',
+ 'ea' => 'cu',
+ 'emailed to' => 'enviado por email a',
+ 'sent to printer' => 'enviado a impresora',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice_links' => 'invoice_links',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'post' => 'post',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_invoice' => 'prepare_invoice',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'orden' => 'order',
+ 'registrar' => 'post',
+ 'registrar_como_nuevo' => 'post_as_new',
+ 'imprimir' => 'print',
+ 'envíe_a' => 'ship_to',
+ 'actualizar' => 'update',
+ '_sí_' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/login b/sql-ledger/locale/ve/login
new file mode 100644
index 0000000..0546b90
--- /dev/null
+++ b/sql-ledger/locale/ve/login
@@ -0,0 +1,27 @@
+$self{texts} = {
+ 'About' => 'Acerca de',
+ 'Database Host' => 'Servidor de base de datos',
+ 'Dataset' => 'Base de datos',
+ 'Incorrect Dataset version!' => 'Versión incorrecta de base de datos!',
+ 'Incorrect Password!' => 'Contraseña equivocada',
+ 'Licensed to' => 'Licenciatario',
+ 'Login' => 'Login',
+ 'Name' => 'Nombre',
+ 'Password' => 'Contraseña',
+ 'User' => 'Usuario',
+ 'Version' => 'Versión',
+ 'You are logged out!' => 'Ha salido del sistema!',
+ 'You did not enter a name!' => 'No se ingresó un nombre!',
+ 'is not a member!' => 'no es miembro!',
+ 'localhost' => 'localhost',
+};
+
+$self{subs} = {
+ 'company_logo' => 'company_logo',
+ 'login' => 'login',
+ 'login_screen' => 'login_screen',
+ 'logout' => 'logout',
+ 'login' => 'login',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/menu b/sql-ledger/locale/ve/menu
new file mode 100644
index 0000000..063e0af
--- /dev/null
+++ b/sql-ledger/locale/ve/menu
@@ -0,0 +1,71 @@
+$self{texts} = {
+ 'AP' => 'CXP',
+ 'AP Aging' => 'Vencimientos',
+ 'AR' => 'CXC',
+ 'AR Aging' => 'Vencimientos',
+ 'Accounting Menu' => 'Menú de Contabilidad',
+ 'Add Account' => 'Agregar Cuenta',
+ 'Add Assembly' => 'Agregar Conjunto',
+ 'Add Customer' => 'Agregar Cliente',
+ 'Add GIFI' => 'Agregar GIFI',
+ 'Add Part' => 'Agregar Item',
+ 'Add Project' => 'Agregar Proyecto',
+ 'Add Service' => 'Agregar Servicio',
+ 'Add Transaction' => 'Agregar Transacción',
+ 'Add Vendor' => 'Agregar Proveedor',
+ 'Assemblies' => 'Conjuntos',
+ 'Audit Control' => 'Control de Auditoría',
+ 'Backup' => 'Respaldos',
+ 'Balance Sheet' => 'Hoja de Balance',
+ 'Cash' => 'Caja',
+ 'Chart of Accounts' => 'Plan de Cuentas',
+ 'Check' => 'Cheque',
+ 'Customers' => 'Clientes',
+ 'General Ledger' => 'Mayor General',
+ 'Goods & Services' => 'Bienes y Servicios',
+ 'HTML Templates' => 'Plantillas HTML',
+ 'Income Statement' => 'Estado de Cuentas de Ingreso',
+ 'Invoice' => 'Factura',
+ 'LaTeX Templates' => 'Plantillas LaTeX',
+ 'List Accounts' => 'Listar cuentas',
+ 'List GIFI' => 'Listar GIFI',
+ 'Logout' => 'Salir del sistema',
+ 'Order Entry' => 'Pedidos<br>Ordenes de Compra',
+ 'Packing List' => 'Lista de Empaque',
+ 'Parts' => 'Items',
+ 'Payment' => 'Pago',
+ 'Payments' => 'Pagos',
+ 'Preferences' => 'Preferencias',
+ 'Projects' => 'Proyectos',
+ 'Purchase Invoice' => 'Factura de Compra',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Purchase Orders' => 'Ordenes de Compra',
+ 'Receipt' => 'Ingreso',
+ 'Receipts' => 'Ingresos',
+ 'Reconciliation' => 'Conciliación',
+ 'Reports' => 'Reportes',
+ 'Sales Invoice' => 'Factura de Venta',
+ 'Sales Order' => 'Pedido',
+ 'Sales Orders' => 'Pedidos',
+ 'Save to File' => 'Respaldar a Archivo',
+ 'Send by E-Mail' => 'Enviar por E-Mail',
+ 'Services' => 'Servicios',
+ 'Statement' => 'Estado de Cuenta',
+ 'Stock Assembly' => 'Reponer Conjuntos',
+ 'Stylesheet' => 'Hoja de Estilo',
+ 'System' => 'Sistema',
+ 'Tax collected' => 'Impuesto recaudado',
+ 'Tax paid' => 'Impuesto pagado',
+ 'Transactions' => 'Transacciones',
+ 'Trial Balance' => 'Balance de Comprobación',
+ 'Vendors' => 'Proveedores',
+ 'Version' => 'Versión',
+};
+
+$self{subs} = {
+ 'acc_menu' => 'acc_menu',
+ 'display' => 'display',
+ 'section_menu' => 'section_menu',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/oe b/sql-ledger/locale/ve/oe
new file mode 100644
index 0000000..899747c
--- /dev/null
+++ b/sql-ledger/locale/ve/oe
@@ -0,0 +1,200 @@
+$self{texts} = {
+ 'Add' => 'Agregar',
+ 'Add Purchase Invoice' => 'Agregar Factura de Compra',
+ 'Add Purchase Order' => 'Agregar Orden de Compra',
+ 'Add Sales Invoice' => 'Agregar Factura de Venta',
+ 'Add Sales Order' => 'Agregar Pedido',
+ 'Address' => 'Dirección',
+ 'Amount' => 'Monto',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Are you sure you want to delete Order Number' => '¿Seguro que desea borrar Orden de Compra/Pedido?',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'Bcc' => 'Bcc',
+ 'Bin' => 'Ubicación',
+ 'C' => 'C',
+ 'Cannot delete order!' => 'No puede borrar pedido!',
+ 'Cannot save order!' => 'No puede guardar órden!',
+ 'Cc' => 'Cc',
+ 'Closed' => 'Cerrado',
+ 'Confirm!' => 'Confirmar!',
+ 'Contact' => 'Contacto',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit Limit' => 'Límite de Crédito',
+ 'Curr' => 'Div',
+ 'Currency' => 'Divisa',
+ 'Customer' => 'Cliente',
+ 'Customer missing!' => 'Falta cliente!',
+ 'Customer not on file!' => 'Cliente no existe en archivo!',
+ 'Date' => 'Fecha',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Delete' => 'Borrar',
+ 'Delivery Date' => 'Fecha de Entrega',
+ 'Description' => 'Descripción',
+ 'E-mail' => 'E-mail',
+ 'E-mail address missing!' => 'Falta dirección E-mail!',
+ 'Edit Purchase Order' => 'Editar Orden de Compra',
+ 'Edit Sales Order' => 'Editar Pedido',
+ 'Exchangerate' => 'Tasa de Cambio',
+ 'Exchangerate missing!' => 'No se encuentra cambio de moneda',
+ 'Extended' => 'Extendido',
+ 'Fax' => 'Fax',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'From' => 'Desde',
+ 'ID' => 'ID',
+ 'In-line' => 'Incorporado',
+ 'Include in Report' => 'Incluya en Reporte',
+ 'Invoice' => 'Factura',
+ 'Invoice Date missing!' => 'Falta Fecha Factura!',
+ 'Invoice Number missing!' => 'Falta Número Factura!',
+ 'Item not on file!' => 'Item no archivado!',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Message' => 'Mensaje',
+ 'Name' => 'Nombre',
+ 'No.' => 'No.',
+ 'Notes' => 'Comentario',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Number' => 'Número',
+ 'Number missing in Row' => 'Falta número en Hilera',
+ 'O' => 'O',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'Open' => 'Abierto',
+ 'Order' => 'Orden',
+ 'Order Date' => 'Fecha Pedido',
+ 'Order Date missing!' => 'Falta Fecha Pedido!',
+ 'Order Number' => 'Orden Número',
+ 'Order Number missing!' => 'Falta Número de Orden',
+ 'Order deleted!' => 'Orden borrada!',
+ 'Order saved!' => 'Orden guardada!',
+ 'PDF' => 'PDF',
+ 'Packing List' => 'Lista de Empaque',
+ 'Packing List Date missing!' => 'Falta Fecha en Nota de Entrega',
+ 'Packing List Number missing!' => 'Falta Número en Nota de Entrega',
+ 'Part' => 'Item',
+ 'Phone' => 'Teléfono',
+ 'Postscript' => 'Postscript',
+ 'Price' => 'Precio',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Project' => 'Proyecto',
+ 'Project not on file!' => 'Proyecto no archivado!',
+ 'Purchase Order' => 'Orden de Compra',
+ 'Purchase Orders' => 'Ordenes de Compra',
+ 'Qty' => 'Cnt',
+ 'Recd' => 'Rec',
+ 'Remaining' => 'Quedan',
+ 'Required by' => 'Requerido para el',
+ 'Sales Order' => 'Pedido',
+ 'Sales Orders' => 'Pedidos',
+ 'Save' => 'Guardar',
+ 'Save as new' => 'Guardar como nuevo',
+ 'Screen' => 'Pantalla',
+ 'Select from one of the items below' => 'Seleccione uno de los ítems listados',
+ 'Select from one of the names below' => 'Seleccione de uno de los nombres a continuación',
+ 'Select from one of the projects below' => 'Seleccione de uno de los proyectos a continuación',
+ 'Select postscript or PDF!' => 'Seleccione postscript o PDF',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Service' => 'Servicio',
+ 'Ship' => 'Envíe',
+ 'Ship to' => 'Envíe a',
+ 'Ship via' => 'Envía vía',
+ 'Subject' => 'Materia',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'ISV',
+ 'Tax Included' => 'Impuesto Incluido',
+ 'Terms: Net' => 'Crédito a',
+ 'To' => 'Hasta',
+ 'Total' => 'Total',
+ 'Unit' => 'Unidad',
+ 'Update' => 'Actualizar',
+ 'Vendor' => 'Proveedor',
+ 'Vendor missing!' => 'Falta proveedor',
+ 'Vendor not on file!' => 'Proveedor no está en archivo!',
+ 'What type of item is this?' => '¿Qué tipo de ítem es éste?',
+ 'Yes' => ' Sí ',
+ 'days' => 'días',
+ 'ea' => 'cu',
+ 'emailed to' => 'enviado por email a',
+ 'sent to printer' => 'enviado a impresora',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'add_transaction' => 'add_transaction',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'check_form' => 'check_form',
+ 'check_name' => 'check_name',
+ 'check_project' => 'check_project',
+ 'continue' => 'continue',
+ 'create_backorder' => 'create_backorder',
+ 'customer_details' => 'customer_details',
+ 'delete' => 'delete',
+ 'display_form' => 'display_form',
+ 'display_row' => 'display_row',
+ 'e_mail' => 'e_mail',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'gl_transaction' => 'gl_transaction',
+ 'invoice' => 'invoice',
+ 'invoicetotal' => 'invoicetotal',
+ 'item_selected' => 'item_selected',
+ 'name_selected' => 'name_selected',
+ 'new_item' => 'new_item',
+ 'order' => 'order',
+ 'order_links' => 'order_links',
+ 'orders' => 'orders',
+ 'post_as_new' => 'post_as_new',
+ 'prepare_order' => 'prepare_order',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'project_selected' => 'project_selected',
+ 'purchase_invoice' => 'purchase_invoice',
+ 'sales_invoice' => 'sales_invoice',
+ 'save' => 'save',
+ 'save_as_new' => 'save_as_new',
+ 'search' => 'search',
+ 'select_item' => 'select_item',
+ 'select_name' => 'select_name',
+ 'select_project' => 'select_project',
+ 'send_email' => 'send_email',
+ 'ship_to' => 'ship_to',
+ 'subtotal' => 'subtotal',
+ 'update' => 'update',
+ 'validate_items' => 'validate_items',
+ 'vendor_details' => 'vendor_details',
+ 'yes' => 'yes',
+ 'agregar' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'e_mail' => 'e_mail',
+ 'factura' => 'invoice',
+ 'imprimir' => 'print',
+ 'guardar' => 'save',
+ 'guardar_como_nuevo' => 'save_as_new',
+ 'envíe_a' => 'ship_to',
+ 'actualizar' => 'update',
+ '_sí_' => 'yes',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/pe b/sql-ledger/locale/ve/pe
new file mode 100644
index 0000000..cafe0af
--- /dev/null
+++ b/sql-ledger/locale/ve/pe
@@ -0,0 +1,35 @@
+$self{texts} = {
+ 'Add' => 'Agregar',
+ 'Add Project' => 'Agregar Proyecto',
+ 'All' => 'Todos',
+ 'Continue' => 'Continuar',
+ 'Delete' => 'Borrar',
+ 'Description' => 'Descripción',
+ 'Edit Project' => 'Editar Proyecto',
+ 'Number' => 'Número',
+ 'Orphaned' => 'Huérfano',
+ 'Project' => 'Proyecto',
+ 'Project Number missing!' => 'Falta número de proyecto!',
+ 'Project deleted!' => 'Proyecto borrado!',
+ 'Project saved!' => 'Proyecto guardado!',
+ 'Projects' => 'Proyectos',
+ 'Save' => 'Guardar',
+};
+
+$self{subs} = {
+ 'add' => 'add',
+ 'continue' => 'continue',
+ 'delete' => 'delete',
+ 'edit' => 'edit',
+ 'form_footer' => 'form_footer',
+ 'form_header' => 'form_header',
+ 'generate_report' => 'generate_report',
+ 'save' => 'save',
+ 'search' => 'search',
+ 'agregar' => 'add',
+ 'continuar' => 'continue',
+ 'borrar' => 'delete',
+ 'guardar' => 'save',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/rc b/sql-ledger/locale/ve/rc
new file mode 100644
index 0000000..caeb32a
--- /dev/null
+++ b/sql-ledger/locale/ve/rc
@@ -0,0 +1,37 @@
+$self{texts} = {
+ 'Account' => 'Cuenta',
+ 'Balance' => 'Balance',
+ 'Cleared Balance' => 'Cleared Balance',
+ 'Continue' => 'Continuar',
+ 'Date' => 'Fecha',
+ 'Deposit' => 'Deposit',
+ 'Description' => 'Descripción',
+ 'Difference' => 'Diferencia',
+ 'Done' => 'Listo',
+ 'Exchangerate Difference' => 'Diferencial Dambiario',
+ 'From' => 'Desde',
+ 'Out of balance!' => 'Fuera de balance!',
+ 'Payment' => 'Pago',
+ 'Reconciliation' => 'Conciliación',
+ 'Select all' => 'Seleccione todos',
+ 'Source' => 'Referencia',
+ 'Statement Balance' => 'Balance Estado de Cuenta',
+ 'Update' => 'Actualizar',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'continue' => 'continue',
+ 'display_form' => 'display_form',
+ 'done' => 'done',
+ 'get_payments' => 'get_payments',
+ 'reconciliation' => 'reconciliation',
+ 'select_all' => 'select_all',
+ 'update' => 'update',
+ 'continuar' => 'continue',
+ 'listo' => 'done',
+ 'seleccione_todos' => 'select_all',
+ 'actualizar' => 'update',
+};
+
+1;
diff --git a/sql-ledger/locale/ve/rp b/sql-ledger/locale/ve/rp
new file mode 100644
index 0000000..bdc2bb6
--- /dev/null
+++ b/sql-ledger/locale/ve/rp
@@ -0,0 +1,116 @@
+$self{texts} = {
+ 'AP Aging' => 'Vencimientos',
+ 'AR Aging' => 'Vencimientos',
+ 'Account' => 'Cuenta',
+ 'Accounts' => 'Cuentas',
+ 'Amount' => 'Monto',
+ 'Apr' => 'abr',
+ 'April' => 'de abril',
+ 'Attachment' => 'Anexo',
+ 'Aug' => 'ago',
+ 'August' => 'de agosto',
+ 'Balance Sheet' => 'Hoja de Balance',
+ 'Bcc' => 'Bcc',
+ 'Cash based' => 'Cash based',
+ 'Cc' => 'Cc',
+ 'Compare to' => 'Comparar a',
+ 'Continue' => 'Continuar',
+ 'Copies' => 'Copias',
+ 'Credit' => 'Crédito',
+ 'Current' => 'Actual',
+ 'Customer' => 'Cliente',
+ 'Date' => 'Fecha',
+ 'Debit' => 'Débito',
+ 'Dec' => 'dic',
+ 'December' => 'de diciembre',
+ 'Decimalplaces' => 'Posiciones decimales',
+ 'Description' => 'Descripción',
+ 'Due' => 'Vence',
+ 'E-mail' => 'E-mail',
+ 'E-mail Statement to' => 'Enviar estado de cuenta por E-mail a',
+ 'Feb' => 'feb',
+ 'February' => 'de febrero',
+ 'From' => 'Desde',
+ 'GIFI' => 'GIFI',
+ 'Heading' => 'Encabezado',
+ 'ID' => 'ID',
+ 'In-line' => 'Incorporado',
+ 'Include in Report' => 'Incluya en Reporte',
+ 'Income Statement' => 'Estado de Cuentas de Ingreso',
+ 'Invoice' => 'Factura',
+ 'Jan' => 'ene',
+ 'January' => 'de enero',
+ 'Jul' => 'jul',
+ 'July' => 'de julio',
+ 'Jun' => 'jun',
+ 'June' => 'de junio',
+ 'Mar' => 'mar',
+ 'March' => 'de marzo',
+ 'May' => 'may',
+ 'May ' => 'de mayo',
+ 'Message' => 'Mensaje',
+ 'N/A' => 'N/D',
+ 'Nothing selected!' => 'Nada seleccionado!',
+ 'Nov' => 'nov',
+ 'November' => 'de noviembre',
+ 'Oct' => 'oct',
+ 'October' => 'de octubre',
+ 'PDF' => 'PDF',
+ 'Payments' => 'Pagos',
+ 'Postscript' => 'Postscript',
+ 'Print' => 'Imprimir',
+ 'Printer' => 'Impresora',
+ 'Receipts' => 'Ingresos',
+ 'Report for' => 'Reporte de',
+ 'Retained Earnings' => 'Ganancias Retenidas',
+ 'Screen' => 'Pantalla',
+ 'Select all' => 'Seleccione todos',
+ 'Select postscript or PDF!' => 'Seleccione postscript o PDF',
+ 'Sep' => 'sep',
+ 'September' => 'de septiembre',
+ 'Source' => 'Referencia',
+ 'Standard' => 'Standard',
+ 'Statement' => 'Estado de Cuenta',
+ 'Statement sent to' => 'Estado de Cuenta enviado a',
+ 'Statements sent to printer!' => 'Estados de Cuenta enviados a impresora!',
+ 'Subject' => 'Materia',
+ 'Subtotal' => 'Subtotal',
+ 'Tax' => 'ISV',
+ 'Tax collected' => 'Impuesto recaudado',
+ 'Tax paid' => 'Impuesto pagado',
+ 'Total' => 'Total',
+ 'Trial Balance' => 'Balance de Comprobación',
+ 'Vendor' => 'Proveedor',
+ 'as at' => 'Al',
+ 'collected on sales' => 'recaudado sobre ventas',
+ 'for Period' => 'para el período',
+ 'paid on purchases' => 'pagado sobre compras',
+ 'to' => 'a',
+};
+
+$self{subs} = {
+ 'aging' => 'aging',
+ 'continue' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'generate_ap_aging' => 'generate_ap_aging',
+ 'generate_ar_aging' => 'generate_ar_aging',
+ 'generate_balance_sheet' => 'generate_balance_sheet',
+ 'generate_income_statement' => 'generate_income_statement',
+ 'generate_tax_report' => 'generate_tax_report',
+ 'generate_trial_balance' => 'generate_trial_balance',
+ 'list_payments' => 'list_payments',
+ 'print' => 'print',
+ 'print_form' => 'print_form',
+ 'print_options' => 'print_options',
+ 'report' => 'report',
+ 'select_all' => 'select_all',
+ 'send_email' => 'send_email',
+ 'statement_details' => 'statement_details',
+ 'tax_subtotal' => 'tax_subtotal',
+ 'continuar' => 'continue',
+ 'e_mail' => 'e_mail',
+ 'imprimir' => 'print',
+ 'seleccione_todos' => 'select_all',
+};
+
+1;
diff --git a/sql-ledger/login.pl b/sql-ledger/login.pl
new file mode 100755
index 0000000..726c780
--- /dev/null
+++ b/sql-ledger/login.pl
@@ -0,0 +1,132 @@
+#!/usr/bin/perl
+#
+######################################################################
+# SQL-Ledger Accounting
+# Copyright (C) 2001
+#
+# Author: Dieter Simader
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+# Contributors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#######################################################################
+#
+# this script sets up the terminal and runs the scripts
+# in bin/$terminal directory
+# admin.pl is linked to this script
+#
+#######################################################################
+
+
+# setup defaults, these are overidden by sql-ledger.conf
+# DO NOT CHANGE
+$userspath = "users";
+$templates = "templates";
+$memberfile = "users/members";
+$sendmail = "| /usr/sbin/sendmail -t";
+########## end ###########################################
+
+
+$| = 1;
+
+eval { require "sql-ledger.conf"; };
+
+if (-e "$userspath/nologin") {
+ print "
+Login disabled!\n";
+
+ exit;
+}
+
+
+if ($ENV{CONTENT_LENGTH}) {
+ read(STDIN, $_, $ENV{CONTENT_LENGTH});
+}
+
+if ($ENV{QUERY_STRING}) {
+ $_ = $ENV{QUERY_STRING};
+}
+
+if ($ARGV[0]) {
+ $_ = $ARGV[0];
+}
+
+
+%form = split /[&=]/;
+
+# fix for apache 2.0
+map { $form{$_} =~ s/\\$// } keys %form;
+
+# name of this script
+$0 =~ tr/\\/\//;
+$pos = rindex $0, '/';
+$script = substr($0, $pos + 1);
+
+
+if ($form{path}) {
+ $form{path} =~ s/%2[fF]/\//g;
+ $form{path} =~ s/\.\.\///g;
+
+ if ($form{path} !~ /^bin\//) {
+ print "
+Invalid path!\n";
+ die;
+ }
+
+
+ $ARGV[0] = "$_&script=$script";
+ require "$form{path}/$script";
+} else {
+
+ if (!$form{terminal}) {
+ if ($ENV{HTTP_USER_AGENT}) {
+ # web browser
+ if ($ENV{HTTP_USER_AGENT} =~ /(mozilla|links|opera|w3m)/i) {
+ $form{terminal} = "mozilla";
+ }
+
+ if ($ENV{HTTP_USER_AGENT} =~ /lynx/i) {
+ $form{terminal} = "lynx";
+ }
+ } else {
+ if ($ENV{TERM} =~ /xterm/) {
+ $form{terminal} = "xterm";
+ }
+ if ($ENV{TERM} =~ /(console|linux|vt.*)/i) {
+ $form{terminal} = "console";
+ }
+ }
+ }
+
+
+ if ($form{terminal}) {
+
+ $ARGV[0] = "path=bin/$form{terminal}&script=$script";
+ map { $ARGV[0] .= "&${_}=$form{$_}" } keys %form;
+
+ require "bin/$form{terminal}/$script";
+
+ } else {
+
+ print qq|
+ Unknown terminal
+ |;
+ }
+
+}
+
+# end of main
+
diff --git a/sql-ledger/menu.ini b/sql-ledger/menu.ini
new file mode 100644
index 0000000..8720798
--- /dev/null
+++ b/sql-ledger/menu.ini
@@ -0,0 +1,394 @@
+[AR]
+
+[AR--Add Transaction]
+module=ar.pl
+action=add
+
+[AR--Sales Invoice]
+module=is.pl
+action=add
+type=invoice
+
+[AR--Reports]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[AR--Reports--Transactions]
+module=ar.pl
+action=search
+nextsub=ar_transactions
+
+[AR--Reports--AR Aging]
+module=rp.pl
+action=report
+report=ar_aging
+
+[AR--Reports--Tax collected]
+module=rp.pl
+action=report
+report=tax_collected
+
+[AR--Customers]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[AR--Customers--Add Customer]
+module=ct.pl
+action=add
+db=customer
+
+[AR--Customers--Reports]
+module=ct.pl
+action=search
+db=customer
+
+[AP]
+
+[AP--Add Transaction]
+module=ap.pl
+action=add
+
+[AP--Vendor Invoice]
+module=ir.pl
+action=add
+type=invoice
+
+[AP--Reports]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[AP--Reports--Transactions]
+module=ap.pl
+action=search
+nextsub=ap_transactions
+
+[AP--Reports--AP Aging]
+module=rp.pl
+action=report
+report=ap_aging
+
+[AP--Reports--Tax paid]
+module=rp.pl
+action=report
+report=tax_paid
+
+[AP--Vendors]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[AP--Vendors--Add Vendor]
+module=ct.pl
+action=add
+db=vendor
+
+[AP--Vendors--Reports]
+module=ct.pl
+action=search
+db=vendor
+
+[Cash]
+
+[Cash--Receipt]
+module=cp.pl
+action=payment
+vc=customer
+
+[Cash--Payment]
+module=cp.pl
+action=payment
+vc=vendor
+
+[Cash--Reports]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[Cash--Reports--Receipts]
+module=rp.pl
+action=report
+report=receipts
+
+[Cash--Reports--Payments]
+module=rp.pl
+action=report
+report=payments
+
+[Cash--Reconciliation]
+module=rc.pl
+action=reconciliation
+
+[Order Entry]
+
+[Order Entry--Sales Order]
+module=oe.pl
+action=add
+type=sales_order
+
+[Order Entry--Purchase Order]
+module=oe.pl
+action=add
+type=purchase_order
+
+[Order Entry--Reports]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[Order Entry--Reports--Sales Orders]
+module=oe.pl
+action=search
+type=sales_order
+
+[Order Entry--Reports--Purchase Orders]
+module=oe.pl
+action=search
+type=purchase_order
+
+[General Ledger]
+
+[General Ledger--Add Transaction]
+module=gl.pl
+action=add
+
+[General Ledger--Reports]
+module=gl.pl
+action=search
+
+[Goods & Services]
+
+[Goods & Services--Add Part]
+module=ic.pl
+action=add
+item=part
+
+[Goods & Services--Add Service]
+module=ic.pl
+action=add
+item=service
+
+[Goods & Services--Add Assembly]
+module=ic.pl
+action=add
+item=assembly
+
+[Goods & Services--Add Group]
+module=pe.pl
+action=add
+type=partsgroup
+
+[Goods & Services--Stock Assembly]
+module=ic.pl
+action=stock_assembly
+
+[Goods & Services--Reports]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[Goods & Services--Reports--Parts]
+module=ic.pl
+action=search
+searchitems=part
+
+[Goods & Services--Reports--Services]
+module=ic.pl
+action=search
+searchitems=service
+
+[Goods & Services--Reports--Assemblies]
+module=ic.pl
+action=search
+searchitems=assembly
+
+[Goods & Services--Reports--Groups]
+module=pe.pl
+action=search
+type=partsgroup
+
+[Projects]
+
+[Projects--Add Project]
+module=pe.pl
+action=add
+type=project
+
+[Projects--Reports]
+module=pe.pl
+action=search
+type=project
+
+[Reports]
+
+[Reports--Chart of Accounts]
+module=ca.pl
+action=chart_of_accounts
+
+[Reports--Trial Balance]
+module=rp.pl
+action=report
+report=trial_balance
+
+[Reports--Income Statement]
+module=rp.pl
+action=report
+report=income_statement
+
+[Reports--Balance Sheet]
+module=rp.pl
+action=report
+report=balance_sheet
+
+[System]
+
+[System--Chart of Accounts]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[System--Chart of Accounts--Add Account]
+module=am.pl
+action=add
+
+[System--Chart of Accounts--List Accounts]
+module=am.pl
+action=list
+
+[System--Chart of Accounts--Add GIFI]
+module=am.pl
+action=add_gifi
+
+[System--Chart of Accounts--List GIFI]
+module=am.pl
+action=list_gifi
+
+[System--HTML Templates]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[System--HTML Templates--Income Statement]
+module=am.pl
+action=display_form
+file=templates=income_statement.html
+
+[System--HTML Templates--Balance Sheet]
+module=am.pl
+action=display_form
+file=templates=balance_sheet.html
+
+[System--HTML Templates--Invoice]
+module=am.pl
+action=display_form
+file=templates=invoice.html
+
+[System--HTML Templates--Packing List]
+module=am.pl
+action=display_form
+file=templates=packing_list.html
+
+[System--HTML Templates--Sales Order]
+module=am.pl
+action=display_form
+file=templates=sales_order.html
+
+[System--HTML Templates--Purchase Order]
+module=am.pl
+action=display_form
+file=templates=purchase_order.html
+
+[System--HTML Templates--Statement]
+module=am.pl
+action=display_form
+file=templates=statement.html
+
+[System--LaTeX Templates]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[System--LaTeX Templates--Invoice]
+module=am.pl
+action=display_form
+file=templates=invoice.tex
+
+[System--LaTeX Templates--Packing List]
+module=am.pl
+action=display_form
+file=templates=packing_list.tex
+
+[System--LaTeX Templates--Sales Order]
+module=am.pl
+action=display_form
+file=templates=sales_order.tex
+
+[System--LaTeX Templates--Purchase Order]
+module=am.pl
+action=display_form
+file=templates=purchase_order.tex
+
+[System--LaTeX Templates--Statement]
+module=am.pl
+action=display_form
+file=templates=statement.tex
+
+[System--LaTeX Templates--Check]
+module=am.pl
+action=display_form
+file=templates=check.tex
+
+[System--LaTeX Templates--Receipt]
+module=am.pl
+action=display_form
+file=templates=receipt.tex
+
+[System--Stylesheet]
+module=am.pl
+action=display_stylesheet
+
+[System--Backup]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[System--Backup--Send by E-Mail]
+module=am.pl
+action=backup
+media=email
+
+[System--Backup--Save to File]
+module=am.pl
+action=backup
+media=file
+
+[System--Audit Control]
+module=am.pl
+action=audit_control
+
+[System--Preferences]
+module=am.pl
+action=config
+
+[Version]
+module=login.pl
+action=company_logo
+
+[Logout]
+module=login.pl
+action=logout
+target=_top
+
diff --git a/sql-ledger/setup.pl b/sql-ledger/setup.pl
new file mode 100755
index 0000000..740a869
--- /dev/null
+++ b/sql-ledger/setup.pl
@@ -0,0 +1,594 @@
+#!/usr/bin/perl
+#
+######################################################################
+# SQL-Ledger, Accounting Software Installer
+# Copyright (c) 2002, Dieter Simader
+#
+# Email: dsimader@sql-ledger.org
+# Web: http://www.sql-ledger.org
+#
+#######################################################################
+
+$| = 1;
+
+if ($ENV{HTTP_USER_AGENT}) {
+ print "
+This does not work yet!
+use $0 from the command line";
+ exit;
+}
+
+$lynx = `lynx -version`; # if LWP is not installed use lynx
+$gzip = `gzip -V 2>&1`; # gz decompression utility
+$tar = `tar --version 2>&1`; # tar archiver
+$latex = `latex -version`;
+
+@source = ( "http://unc.dl.sourceforge.net/sourceforge/sql-ledger",
+ "http://www.sql-ledger.org/source",
+ "http://abacus.sql-ledger.org/source" );
+
+$userspath = "users"; # default for new installation
+
+eval { require "sql-ledger.conf"; };
+
+$filename = shift;
+
+# is LWP installed
+eval { require LWP::Simple; };
+$lwp = !($@);
+
+unless ($lwp || $lynx || $filename) {
+ die "You must have either lynx or LWP installed
+or specify a filename.
+perl $0 filename\n";
+}
+
+if ($filename) {
+ # extract version
+ die "Not a SQL-Ledger archive\n" if ($filename !~ /^sql-ledger/);
+
+ $version = $filename;
+ $version =~ s/sql-ledger-(\d+\.\d+\.\d+).*$/$1/;
+
+ $newinstall = 1;
+}
+
+if (!$filename && -f "VERSION") {
+ # get installed version from VERSION file
+ open(FH, "VERSION");
+ @a = <FH>;
+ close(FH);
+ $version = $a[0];
+ chomp $version;
+
+ $newinstall = !$version;
+} else {
+ $newinstall = 1;
+}
+
+
+$webowner = $<;
+$webgroup = $(;
+
+if ($httpd = `find /etc /usr/local/etc -type f -name 'httpd.conf'`) {
+ chomp $httpd;
+ $webowner = `grep "^User " $httpd`;
+ $webgroup = `grep "^Group " $httpd`;
+ $serverroot = `grep "^ServerRoot " $httpd`;
+
+ chomp $webowner;
+ chomp $webgroup;
+ chomp $serverroot;
+
+ ($null, $webowner) = split / /, $webowner;
+ ($null, $webgroup) = split / /, $webgroup;
+ ($null, $serverroot) = split / /, $serverroot;
+
+ $serverroot =~ s/"//g;
+
+}
+
+system("tput clear");
+
+if ($filename) {
+ $install = "\ninstall $version from (f)ile\n";
+}
+
+# check for latest version
+&get_latest_version;
+
+if (!$newinstall) {
+
+ $install .= "\n(r)einstall $version\n";
+
+}
+
+if ($version && $latest_version) {
+ if (!$filename && $version ne $latest_version) {
+ if (substr($version, 0, rindex($version, ".")) eq substr($latest_version, 0, rindex($latest_version, "."))) {
+ $install .= "\n(u)pgrade to $latest_version\n";
+ }
+ }
+}
+
+
+$install .= "\n(i)nstall $latest_version (from Internet)\n" if $latest_version;
+
+$install .= "\n(d)ownload $latest_version (no installation)" unless $filename;
+
+ print qq|
+
+
+ SQL-Ledger Accounting Software Installation
+
+
+
+$install
+
+
+Enter: |;
+
+$a = <STDIN>;
+chomp $a;
+
+exit unless $a;
+$a = lc $a;
+
+ if ($newinstall && ($a =~ /(i|r|f)/)) {
+
+ print qq|\nEnter httpd owner [$webowner] : |;
+ $web = <STDIN>;
+ chomp $web;
+ $webowner = $web if $web;
+
+ print qq|\nEnter httpd group [$webgroup] : |;
+ $web = <STDIN>;
+ chomp $web;
+ $webgroup = $web if $web;
+
+ }
+
+if ($a eq 'd') {
+ &download;
+}
+if ($a eq 'i') {
+ &install;
+}
+if ($a eq 'r') {
+ $latest_version = $version;
+ &install;
+}
+if ($a eq 'u') {
+ &upgrade;
+}
+
+if ($a eq 'f') {
+ &install;
+}
+
+exit;
+# end main
+
+
+sub download {
+
+ &get_source_code;
+
+}
+
+
+sub get_latest_version {
+
+ print "Checking for latest version number .... ";
+
+ if ($filename) {
+ print "skipping, filename supplied\n";
+ return;
+ }
+
+ if ($lwp) {
+ foreach $source (@source) {
+ $host = $source;
+ $host =~ s/(\w\/).*/$1/g;
+ chop $host;
+ print "\nTrying $host ... ";
+
+ $latest_version = LWP::Simple::get("$source/latest_version");
+
+ if ($latest_version) {
+ last;
+ } else {
+ print "not found";
+ }
+ }
+ } else {
+ if (!$lynx) {
+ print "\nYou must have either lynx or LWP installed";
+ exit 1;
+ }
+
+ foreach $source (@source) {
+ $host = $source;
+ $host =~ s/(\w\/).*/$1/g;
+ chop $host;
+ print "\nTrying $host ... ";
+ $ok = `lynx -dump -head $source/latest_version`;
+ if ($ok = ($ok =~ s/HTTP.*?200 OK//g)) {
+ $latest_version = `lynx -dump $source/latest_version`;
+ chomp $latest_version;
+ last;
+ } else {
+ print "not found";
+ }
+ }
+ die unless $ok;
+ }
+
+ chomp $latest_version;
+ if ($latest_version) {
+ print "ok\n";
+ 1;
+ }
+
+}
+
+
+sub get_source_code {
+
+ $err = 0;
+
+ if ($latest_version) {
+ # download it
+ $latest_version = "sql-ledger-${latest_version}.tar.gz";
+
+ print "\nStatus\n";
+ print "Downloading $latest_version .... ";
+
+ foreach $source (@source) {
+ $host = $source;
+ $host =~ s/(\w\/).*/$1/g;
+ chop $host;
+ print "\nTrying $host .... ";
+
+ if ($lwp) {
+ $err = LWP::Simple::getstore("$source/$latest_version", "$latest_version");
+ $err -= 200;
+ } else {
+ $ok = `lynx -dump -head $source/$latest_version`;
+ $err = !($ok =~ s/HTTP.*?200 OK//);
+
+ if (!$err) {
+ $err = system("lynx -dump $source/$latest_version > $latest_version");
+ }
+ }
+
+ last unless $err;
+
+ }
+
+ } else {
+ $err = -1;
+ }
+
+ if ($err) {
+ die "Cannot get $latest_version";
+ } else {
+ print "ok\n";
+ }
+
+ $latest_version;
+
+}
+
+
+sub install {
+
+ if ($filename) {
+ $latest_version = $filename;
+ } else {
+ $latest_version = &get_source_code;
+ }
+
+ &decompress;
+
+ if ($upgrade) {
+ print qq|
+
+Don't forget to upgrade the datasets!
+
+Load the admin panel in your web browser
+|;
+ }
+
+ if ($newinstall) {
+ # if this is not root, check if user is part of $webgroup
+ if ($>) {
+ if ($permset = ($) =~ getgrnam $webgroup)) {
+ `chown -R :$webgroup *`;
+ }
+ } else {
+ `chown -R $webowner:$webgroup *`;
+ }
+
+ chmod 0771, 'users', 'templates';
+
+ open(FH, "sql-ledger.conf.default");
+ @f = <FH>;
+ close(FH);
+ unless ($latex) {
+ grep { s/^\$latex.*/\$latex = 0;/ } @f;
+ }
+ open(FH, ">sql-ledger.conf");
+ print FH @f;
+ close(FH);
+
+ $alias = $absolutealias = $ENV{'PWD'};
+ $alias =~ s/.*\///g;
+
+ $httpddir = `dirname $httpd`;
+ chomp $httpddir;
+ $filename = "sql-ledger-httpd.conf";
+
+ # do we have write permission?
+ if (!open(FH, ">>$httpddir/$filename")) {
+ open(FH, ">$filename");
+ $norw = 1;
+ }
+
+ $directives = qq|
+Alias /$alias/ $absolutealias/
+<Directory $absolutealias>
+ AllowOverride All
+ AddHandler cgi-script .pl
+ Options ExecCGI Includes FollowSymlinks
+ Order Allow,Deny
+ Allow from All
+</Directory>
+
+<Directory $absolutealias/users>
+ Order Deny,Allow
+ Deny from All
+</Directory>
+
+|;
+
+ print FH $directives;
+ close(FH);
+
+ print qq|
+This is a new installation.
+
+|;
+
+ if ($norw) {
+ print qq|
+Webserver directives were written to $filename
+
+Copy $filename to $httpddir and add
+|;
+
+ # strip serverroot off httpddir
+ $httpddir =~ s/$serverroot\///;
+
+ print qq|
+Include $httpddir/$filename
+
+to $httpd
+
+Don't forget to restart your webserver!
+|;
+
+ if (!$permset) {
+ print qq|
+WARNING: permissions for templates and users directory
+could not be set. Login as root and set permissions
+
+# chown $webowner:$webgroup users templates
+# chmod 771 users templates
+
+|;
+ }
+
+ } else {
+
+ if (!(`grep "^# SQL-Ledger" $httpd`)) {
+ # append Include directive
+ $httpddir =~ s/$serverroot\///;
+
+ open(FH, ">>$httpd");
+
+ print FH qq|
+
+# SQL-Ledger
+Include $httpddir/$filename
+|;
+ close(FH);
+
+ print qq|
+Webserver directives were written to
+
+ $httpddir/$filename
+|;
+ }
+ }
+
+ if (!$>) {
+ # send SIGHUP to httpd
+ $pid = `cat /var/run/httpd.pid`;
+ chomp $pid;
+ system("kill -s HUP $pid") if $pid;
+ }
+ }
+
+ unlink "sql-ledger.conf.default";
+
+ &cleanup;
+
+ while ($a !~ /(Y|N)/) {
+ print qq|\nDisplay README (Y/n) : |;
+ $a = <STDIN>;
+ chomp $a;
+ $a = ($a) ? uc $a : 'Y';
+
+ if ($a eq 'Y') {
+ @args = ("more", "doc/README");
+ system(@args);
+ }
+ }
+
+}
+
+
+sub decompress {
+
+ die "Error: gzip not installed\n" unless ($gzip);
+ die "Error: tar not installed\n" unless ($tar);
+
+ &create_lockfile;
+
+ # ungzip and extract source code
+ print "Decompressing $latest_version ... ";
+
+ if (system("gzip -df $latest_version")) {
+ print "Error: Could not decompress $latest_version\n";
+ &remove_lockfile;
+ exit;
+ } else {
+ print "done\n";
+ }
+
+ # strip gz from latest_version
+ $latest_version =~ s/\.gz//;
+
+ # now untar it
+ print "Unpacking $latest_version ... ";
+ if (system("tar -xf $latest_version")) {
+ print "Error: Could not unpack $latest_version\n";
+ &remove_lockfile;
+ exit;
+ } else {
+ # now we have a copy in sql-ledger
+ if (system("tar -cf $latest_version -C sql-ledger .")) {
+ print "Error: Could not create archive for $latest_version\n";
+ &remove_lockfile;
+ exit;
+ } else {
+ if (system("tar -xf $latest_version")) {
+ print "Error: Could not unpack $latest_version\n";
+ &remove_lockfile;
+ exit;
+ } else {
+ print "done\n";
+ print "cleaning up ... ";
+ `rm -rf sql-ledger`;
+ print "done\n";
+ }
+ }
+ }
+}
+
+
+sub create_lockfile {
+
+ if (-d "$userspath") {
+ open(FH, ">$userspath/nologin");
+ close(FH);
+ $upgrade = 1;
+ }
+
+}
+
+
+sub cleanup {
+
+ unlink "$latest_version";
+ unlink "$userspath/members.default" if (-f "$userspath/members.default");
+
+ &remove_lockfile;
+
+}
+
+
+sub remove_lockfile { unlink "$userspath/nologin" if (-f "$userspath/nologin") };
+
+
+sub upgrade {
+
+ $latest_version = &get_patch;
+
+ &decompress;
+
+ &cleanup;
+
+ # if this is not root, check if user is part of $webgroup
+ if ($>) {
+ if ($permset = ($) =~ getgrnam $webgroup)) {
+ `chown -R :$webgroup *`;
+ }
+ } else {
+ `chown -R $webowner:$webgroup *`;
+ }
+
+ chmod 0771, 'users', 'templates';
+
+
+ print qq|
+
+Don't forget to upgrade your datasets and read
+the upgrade file in the doc directory.
+
+|;
+
+}
+
+
+
+sub get_patch {
+
+ $err = 0;
+
+ if ($version) {
+ # download the patch
+ $patchfile = "patch-${latest_version}.tar.gz";
+
+ print "Status\n";
+ print "Downloading $patchfile .... ";
+
+ foreach $source (@source) {
+ $host = $source;
+ $host =~ s/(\w\/).*/$1/g;
+ chop $host;
+ print "\nTrying $host .... ";
+
+ if ($lwp) {
+ $err = LWP::Simple::getstore("$source/$patchfile", "$patchfile");
+ $err -= 200;
+ } else {
+ $ok = `lynx -dump -head $source/$patchfile`;
+ $err = !($ok =~ /HTTP.*?200 OK/);
+
+ if (!$err) {
+ $err = system("lynx -dump $source/$patchfile > $patchfile");
+ }
+ }
+
+ last unless $err;
+
+ }
+
+ } else {
+ $err = -1;
+ }
+
+ if ($err) {
+ print "Cannot get $patchfile\n";
+ exit;
+ } else {
+ print "ok\n";
+ }
+
+ $patchfile;
+
+}
+
+
diff --git a/sql-ledger/sql-ledger.conf.default b/sql-ledger/sql-ledger.conf.default
new file mode 100644
index 0000000..96fb9b8
--- /dev/null
+++ b/sql-ledger/sql-ledger.conf.default
@@ -0,0 +1,33 @@
+use vars qw($userspath $memberfile $templates $sendmail $language $sid);
+
+# path to user configuration files
+# you may use an absolute path i.e. /var/tmp
+$userspath = "users";
+
+# templates base directory; this one needs to be here for now
+$templates = "templates";
+
+# member file, could also be in "/usr/local/etc/slusers"
+$memberfile = "users/members";
+
+# location of sendmail
+$sendmail = "| /usr/sbin/sendmail -t";
+
+# set language for login and admin; two letter code
+$language = "";
+
+# Oracle
+$sid = "T80509";
+$ENV{"ORACLE_HOME"} = "/usr/local/oracle";
+
+# if you have latex installed set to 1
+$latex = 1;
+
+# if the server can't find latex, dvips or pdflatex, add the path
+$ENV{PATH} .= ":/usr/local/bin";
+
+# on mac os X using Fink's Perl libs, add the path
+$ENV{PERL5LIB} .= ":/sw/lib/perl5";
+
+
+1;
diff --git a/sql-ledger/sql-ledger.png b/sql-ledger/sql-ledger.png
new file mode 100644
index 0000000..0297a1b
--- /dev/null
+++ b/sql-ledger/sql-ledger.png
Binary files differ
diff --git a/sql-ledger/sql/Austria-chart.sql b/sql-ledger/sql/Austria-chart.sql
new file mode 100644
index 0000000..85810c5
--- /dev/null
+++ b/sql-ledger/sql/Austria-chart.sql
@@ -0,0 +1,143 @@
+-- Kontoplan für Österreich
+-- Ferdinand Gassauer, Tue, 5 Feb 2002
+-- checked and completed, Thu, 7 Feb 2002, Dieter Simader
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0000','AUFWENDUNGEN FÜR INGANGSETZEN UND ERWEITERN DES BETRIEBES','H','00','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0010','Firmenwert','A','015','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0100','IMMATERIELLE VERMÖGENSGEGENSTÄNDE','H','01','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0110','Rechte','A','011','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0200','GRUNDSTÜCKE','H','02-03','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0210','unbebaute Grundstücke','A','020','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0220','bebaute Grundstücke','A','021','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0229','kum. Abschreibung bebaute Grundstücke','A','039','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0400','MASCHINEN','H','04-05','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0410','Maschinen','A','041','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0419','kum. Abschreibung Maschinen','A','069','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0500','FAHRZEUGE','H','06','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0510','Fahrzeuge','A','063','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0519','kum. Abschreibung Fahrzeuge','A','069','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0600','BETRIEBS- UND GESCHÄFTSAUSSTATTUNG','H','06','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0620','Büroeinrichtungen','A','066','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0625','kum. Abschreibung Betriebs- und Geschäftsausstattung','A','069','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0700','GELEISTETE ANZAHLUNGEN','H','07','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0800','FINANZANLAGEN','H','08-09','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0810','Beteiligungen','A','081','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0820','Wertpapiere','A','080','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1100','ROHSTOFFE','H','1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1120','Vorräte - Rohstoffe','A','110-119','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200','BEZOGENE TEILE','H','1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1220','Vorräte - bezogene Teile','A','120-129','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1300','HILFS- UND BETRIEBSSTOFFE','H','1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1320','Hilfsstoffe','A','130-134','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1350','Betriebssstoffe','A','135-139','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1400','UNFERTIGE ERZEUGNISSE','H','1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1420','Vorräte - unfertige Erzeugnisse','A','140-149','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1500','FERTIGE ERZEUGNISSE','H','1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1520','Vorräte - Hardware','A','150-159','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1530','Vorräte - Software','A','150-159','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1540','Vorräte - Ersatzteile','A','150-159','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1600','WAREN','H','1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1700','NOCH NICHT ABGERECHNETE LEISTUNGEN','H','1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800','GELEISTETE ANZAHLUNGEN','H','1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1900','WERTBERICHTIGUNGEN','H','1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000','FORDEUNGEN AUS LIEFERUNGEN UND LEISTUNGEN','H','2','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2010','Forderungen Lieferung & Leistung','A','200-207','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2019','Wertberichtigung uneinbringliche Forderungen','A','20-21','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2300','SONSTIGE FORDERUNGEN','H','2','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2320','sonstige Forderungen','A','23-24','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2500','FORDERUNGEN AUS ABGABENVERRECHNUNG','H','2','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2520','sonstige Forderungen aus Abgebenverrechnung','A','25','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2600','WERTPAPIERE UND ANTEILE','H','2','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2620','Wertpapiere Umlaufvermögen','A','26','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2700','KASSABESTAND','H','2','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2701','Kassa','A','27-28','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2800','SCHECKS, GUTHABEN BEI KREDITINSTITUTEN','H','2','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2810','Schecks','A','27-28','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2820','Bankguthaben','A','280-288','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3100','LANGFRISTIGE VERBINDLICHKEITEN','H','3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3110','Bank Verbindlichkeiten','A','31','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3120','Kredite von Eigentümern','A','310','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3300','VERBINDLICHKEITEN AUS LIEFERUNGEN UND LEISTUNGEN','H','33','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3310','Verbindlichkeiten aus Lieferungen und Leistungen','A','330-335','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3500','VERBINDLICHKEITEN FINANZAMT','H','35','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3510','Finanzamt Verrechnung Körperschaftssteuer','A','350-359','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3520','Finanzamt Verrechnung Umsatzsteuer','A','350-359','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3530','Mehrwertsteuer 0%','A','350-359','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3531','Mehrwertsteuer 10%','A','350-359','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3532','Mehrwertsteuer 20%','A','350-359','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3540','Vorsteuer 0%','A','350-359','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3541','Vorsteuer 10%','A','350-359','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3542','Vorsteuer 20%','A','350-359','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4000','UMSATZ','H','4','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4020','Verkauf - Hardware','A','40-44','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4030','Verkauf - Software ','A','40-44','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4040','Verkauf - Ersatzteile','A','40-44','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4300','UMSATZ BERATUNG','H','4','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4320','Erlöse Beratung','A','40-44','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4330','Erlöse Programmierung','A','40-44','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4600','SONSTIGE ERLÖSE','H','4','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4630','Frachterlöse','A','46-49','I','IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5000','WARENEINSATZ','H','5','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5020','Wareneinsatz / Hardware','A','500-509','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5030','Wareneinsatz / Software','A','500-509','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5040','Wareneinsatz / Ersatzteile','A','520-529','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5600','VERBRAUCH BRENN- UND TREIBSTOFFEN, ENERGIE UND WASSER','H','5','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5610','Energie, Wasser','A','560-569','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6000','LOHNAUFWAND','H','6','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6010','Lohn ','A','600-619','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6200','GEAHLTSAUFWAND','H','6','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6210','Gehalt ','A','620-639','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6500','GESETZLICHER SOZIALAUFWAND','H','6','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6510','Dienstgeberanteile','A','645-649','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6700','FREIWILLIGER SOZIALAUFWAND','H','6','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6710','freiwilliger Sozialaufwand','A','660-665','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7000','ABSCHREIBUNGEN','H','7','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7010','Abschreibungen','A','700','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7020','geringwertige Wirtschaftsgüter','A','701-708','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7100','SONSTIGE STEUERN','H','71','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7110','Ertragssteuern','A','710-719','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7120','Grundsteuern','A','710-719','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7200','INSTANDHALTUNGSAUFWAND','H','7','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7210','Reparatur und Instandhaltung','A','720-729','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7300','TRANSPORTKOSTEN','H','73','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7310','Frachtaufwand','A','730-731','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7400','MIET-,PACHT-,LEASING-, LIZENZAUFWAND','H','74','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7410','Miete','A','740-743','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7411','Lizenzen','A','748-749','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7600','VERWALTUNGSKOSTEN','H','76','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7610','Beratungsaufwand','A','775-776','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7611','Büromaterialien','A','760','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7615','Werbung und Marketing','A','765-768','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7620','uneinbringliche Forderungen','A','799','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7630','Telephonkosten','A','738-739','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7631','Internetkosten','A','738-739','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7632','Reise- und Repräsentationsaufwand','A','734-735','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7634','Registrierungsgebühren','A','748-749','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7700','VERSICHERUNGEN','H','77-78','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7710','Versicherung','A','770-774','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8000','FINANZERTRÄGE UND FINANZAUFWENDUNGEN','H','8','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8020','Bankzinsen und Gebühren','A','80-83','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8100','BETEILIGUNGSERTRÄGE','H','8','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8110','Erträge aus Beteiligungen','A','800-804','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9000','KAPITAL','H','9','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9010','Aktien, Geschäftsanteile','A','900-918','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9020','nicht einbezahltes Kapital','A','919','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9200','KAPITALRÜCKLAGEN','H','9','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9210','freie Rücklage','A','920-929','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9300','GEWINN','H','939','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9310','Gewinnvortrag Vorjahr','A','980','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9320','Jahresgewinn','A','985','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9400','RÜCKSTELLUNGEN','H','3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9420','Abfertigungsrückstellung','A','300','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9430','Urlaubsrückstellung','A','304-309','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9700','EINLAGEN STILLER GESELLSCHAFTER','H','9','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9800','EB,SB,G+V KONTEN','H','9','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4640','Devisengewinne','A','80-83','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8050','Devisenverluste','A','80-83','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '3530'),0.00);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '3531'),0.10);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '3532'),0.20);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '7610'), fxgain_accno_id = (select id from chart where accno = '4640'), fxloss_accno_id = (select id from chart where accno = '8050'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'EUR:USD', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Austria-gifi.sql b/sql-ledger/sql/Austria-gifi.sql
new file mode 100644
index 0000000..43f213f
--- /dev/null
+++ b/sql-ledger/sql/Austria-gifi.sql
@@ -0,0 +1,334 @@
+-- Österreichischer Einheitskontenrahmen / Kontenplan (ÖSV Österreichischer Steuerverein)
+--
+INSERT INTO gifi (accno, description) VALUES ('0', 'Anlagevermögen und Aufwendungen für das Ingangsetzen und Erweitern eines Betriebes');
+--
+INSERT INTO gifi (accno, description) VALUES ('00', 'Aufwendungen für das Ingangsetzen und Erweitern eines Betriebes');
+INSERT INTO gifi (accno, description) VALUES ('001', 'Aufwendungen für das Ingangsetzen und Erweitern eines Betriebes');
+INSERT INTO gifi (accno, description) VALUES ('009', 'Kumulierte Abschreibungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('01', 'Immaterielle Vermögensgegenstände');
+INSERT INTO gifi (accno, description) VALUES ('010', 'Konzessionen');
+INSERT INTO gifi (accno, description) VALUES ('011', 'Patentrechte und Lizenzen');
+INSERT INTO gifi (accno, description) VALUES ('012', 'Datenverarbeitungsprogramme');
+INSERT INTO gifi (accno, description) VALUES ('013', 'Marken, Warenzeichen und Musterschutzrechte, sonstige Urheberrechte');
+INSERT INTO gifi (accno, description) VALUES ('014', 'Pacht- und Mietrechte');
+INSERT INTO gifi (accno, description) VALUES ('015', 'Geschäfts(Firmen)wert');
+INSERT INTO gifi (accno, description) VALUES ('018', 'Geleistete Anzahlungen');
+INSERT INTO gifi (accno, description) VALUES ('019', 'Kumulierte Abschreibungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('02-03', 'Grundstücke, grundstücksgleiche Rechte und Bauten, einschließlich der Bauten auf fremden Grund');
+INSERT INTO gifi (accno, description) VALUES ('020', 'Unbebaute Grundstücke');
+INSERT INTO gifi (accno, description) VALUES ('021', 'Bebaute Grundstücke (Grundwert)');
+INSERT INTO gifi (accno, description) VALUES ('022', 'Grundstücksgleiche Rechte');
+INSERT INTO gifi (accno, description) VALUES ('030', 'Betriebs- und Geschäftsgebäude auf eigenem Grund');
+INSERT INTO gifi (accno, description) VALUES ('031', 'Wohn- und Sozialgebäude auf eigenem Grund');
+INSERT INTO gifi (accno, description) VALUES ('032', 'Betriebs- und Geschäftsgebäude auf fremdem Grund');
+INSERT INTO gifi (accno, description) VALUES ('033', 'Wohn- und Sozialgebäude auf fremdem Grund');
+INSERT INTO gifi (accno, description) VALUES ('034', 'Grundstückseinrichtungen auf eigenem Grund');
+INSERT INTO gifi (accno, description) VALUES ('035', 'Grundstückseinrichtungen auf fremdem Grund');
+INSERT INTO gifi (accno, description) VALUES ('036', 'Bauliche Investitionen in fremden (gepachteten) Betriebs- und Geschäftsgebäuden');
+INSERT INTO gifi (accno, description) VALUES ('037', 'Bauliche Investitionen in fremden (gepachteten) Wohn- und Sozialgebäuden');
+INSERT INTO gifi (accno, description) VALUES ('039', 'Kumulierte Abschreibungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('04-05', 'Technische Anlagen und Maschinen');
+INSERT INTO gifi (accno, description) VALUES ('040', 'Fertigungsmaschinen');
+INSERT INTO gifi (accno, description) VALUES ('041', 'Antriebsmaschinen');
+INSERT INTO gifi (accno, description) VALUES ('042', 'Energieversorgungsanlagen');
+INSERT INTO gifi (accno, description) VALUES ('043', 'Transportanlagen');
+INSERT INTO gifi (accno, description) VALUES ('044-049', 'Sonstige Maschinen und maschinelle Anlagen');
+INSERT INTO gifi (accno, description) VALUES ('050', 'Maschinenwerkzeuge');
+INSERT INTO gifi (accno, description) VALUES ('051', 'Allgemeine Werkzeuge und Handwerkzeuge');
+INSERT INTO gifi (accno, description) VALUES ('052', 'Vorrichtungen, Formen und Modelle');
+INSERT INTO gifi (accno, description) VALUES ('053', 'Andere Erzeugungshilfsmittel');
+INSERT INTO gifi (accno, description) VALUES ('054', 'Hebezeuge und Montageanlagen');
+INSERT INTO gifi (accno, description) VALUES ('055', 'Geringwertige Vermögensgegenstände, soweit im Erzeugungsprozeß verwendet');
+--
+INSERT INTO gifi (accno, description) VALUES ('06', 'Andere Anlagen, Betriebs- und Geschäftsausstattung');
+INSERT INTO gifi (accno, description) VALUES ('060', 'Beheizungs- und Beleuchtungsanlagen');
+INSERT INTO gifi (accno, description) VALUES ('061', 'Nachrichten- und Kontrollanlagen');
+INSERT INTO gifi (accno, description) VALUES ('062', 'Büromaschinen, EDV-Anlagen');
+INSERT INTO gifi (accno, description) VALUES ('063', 'PKW');
+INSERT INTO gifi (accno, description) VALUES ('064', 'LKW');
+INSERT INTO gifi (accno, description) VALUES ('065', 'Andere Beförderungsmittel');
+INSERT INTO gifi (accno, description) VALUES ('066', 'Andere Betriebs- und Geschäftsausstattung');
+INSERT INTO gifi (accno, description) VALUES ('067', 'Gebinde');
+INSERT INTO gifi (accno, description) VALUES ('068', 'Geringwertige Vermögensgegenstände, soweit nicht im Erzeugungsprozeß verwendet');
+INSERT INTO gifi (accno, description) VALUES ('069', 'Kumulierte Abschreibungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('07', 'Geleistete Anzahlungen und Anlagen in Bau');
+INSERT INTO gifi (accno, description) VALUES ('070', 'Geleistete Anzahlungen');
+INSERT INTO gifi (accno, description) VALUES ('071', 'Anlagen in Bau');
+INSERT INTO gifi (accno, description) VALUES ('079', 'Kumulierte Abschreibungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('08-09', 'Finanzanlagen');
+INSERT INTO gifi (accno, description) VALUES ('080', 'Anteile an verbundenen Unternehmen');
+INSERT INTO gifi (accno, description) VALUES ('081', 'Beteiligungen an Gemeinschaftsunternehmen');
+INSERT INTO gifi (accno, description) VALUES ('082', 'Beteiligungen an angeschlossenen (assoziierten) Unternehmen');
+INSERT INTO gifi (accno, description) VALUES ('083', 'Sonstige Beteiligungen');
+INSERT INTO gifi (accno, description) VALUES ('084', 'Ausleihungen an verbundene Unternehmen');
+INSERT INTO gifi (accno, description) VALUES ('085', 'Ausleihungen an Unternehmen, mit denen ein Beteiligungsverhältnis besteht');
+INSERT INTO gifi (accno, description) VALUES ('086', 'Sonstige Ausleihungen');
+INSERT INTO gifi (accno, description) VALUES ('087', 'Anteile an Kapitalgesellschaften ohne Beteiligungscharakter');
+INSERT INTO gifi (accno, description) VALUES ('088', 'Anteile an Personengesellschaften ohne Beteiligungscharakter');
+INSERT INTO gifi (accno, description) VALUES ('090', 'Genossenschaftsanteile ohne Beteiligungscharakter');
+INSERT INTO gifi (accno, description) VALUES ('091', 'Anteile an Investmentfonds');
+INSERT INTO gifi (accno, description) VALUES ('092-093', 'Festverzinsliche Wertpapiere des Anlagevermögens');
+INSERT INTO gifi (accno, description) VALUES ('094-097', 'Sonstige Finanzanlagen, Wertrechte');
+INSERT INTO gifi (accno, description) VALUES ('098', 'Geleistete Anzahlungen');
+INSERT INTO gifi (accno, description) VALUES ('099', 'Kumulierte Abschreibungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('1', 'Vorräte');
+INSERT INTO gifi (accno, description) VALUES ('100-109', 'Bezugsverrechnung');
+INSERT INTO gifi (accno, description) VALUES ('110-119', 'Rohstoffe');
+INSERT INTO gifi (accno, description) VALUES ('120-129', 'Bezogene Teile');
+INSERT INTO gifi (accno, description) VALUES ('130-134', 'Hilfsstoffe');
+INSERT INTO gifi (accno, description) VALUES ('135-139', 'Betriebsstoffe');
+INSERT INTO gifi (accno, description) VALUES ('140-149', 'Unfertige Erzeugnisse');
+INSERT INTO gifi (accno, description) VALUES ('150-159', 'Fertige Erzeugnisse');
+INSERT INTO gifi (accno, description) VALUES ('160-169', 'Waren');
+INSERT INTO gifi (accno, description) VALUES ('170-179', 'Noch nicht abrechenbare Leistungen');
+INSERT INTO gifi (accno, description) VALUES ('180', 'Geleistete Anzahlungen');
+INSERT INTO gifi (accno, description) VALUES ('190-199', 'Wertberichtigungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('2', 'Sonstiges Umlaufvermögen, Rechnungsabgrenzungsposten');
+INSERT INTO gifi (accno, description) VALUES ('20-21', 'Forderungen aus Lieferungen und Leistungen');
+INSERT INTO gifi (accno, description) VALUES ('200-207', 'Forderungen aus Lieferungen und Leistungen Inland');
+INSERT INTO gifi (accno, description) VALUES ('208', 'Einzelwertberichtigungen zu Forderungen aus Lieferungen und Leistungen Inland');
+INSERT INTO gifi (accno, description) VALUES ('209', 'Pauschalwertberichtigungen zu Forderungen aus Lieferungen und Leistungen Inland');
+INSERT INTO gifi (accno, description) VALUES ('210-212', 'Forderungen aus Lieferungen und Leistungen Währungsunion');
+INSERT INTO gifi (accno, description) VALUES ('213', 'Einzelwertberichtigungen zu Forderungen aus Lieferungen und Leistungen Währungsunion');
+INSERT INTO gifi (accno, description) VALUES ('214', 'Pauschalwertberichtigungen zu Forderungen aus Lieferungen und Leistungen Währungsunion');
+INSERT INTO gifi (accno, description) VALUES ('215-217', 'Forderungen aus Lieferungen und Leistungen sonstiges Ausland');
+INSERT INTO gifi (accno, description) VALUES ('218', 'Einzelwertberichtigungen zu Forderungen aus Lieferungen und Leistungen sonstiges Ausland');
+INSERT INTO gifi (accno, description) VALUES ('219', 'Pauschalwertberichtigungen zu Forderungen aus Lieferungen und Leistungen sonstiges Ausland');
+--
+INSERT INTO gifi (accno, description) VALUES ('22', 'Forderungen gegenüber verbundenen Unternehmen und Unternehmen, mit denen ein Beteiligungsverhältnis besteht');
+INSERT INTO gifi (accno, description) VALUES ('220-222', 'Forderungen gegenüber verbundenen Unternehmen');
+INSERT INTO gifi (accno, description) VALUES ('223', 'Einzelwertberichtigungen zu Forderungen gegenüber verbundenen Unternehmen');
+INSERT INTO gifi (accno, description) VALUES ('224', 'Pauschalwertberichtigungen zu Forderungen gegenüber verbundenen Unternehmen');
+INSERT INTO gifi (accno, description) VALUES ('225-227', 'Forderungen gegenüber Unternehmen, mit denen ein Beteiligungsverhältnis besteht');
+INSERT INTO gifi (accno, description) VALUES ('228', 'Einzelwertberichtigungen zu Forderungen gegenüber Unternehmen, mit denen ein Beteiligungsverhältnis besteht');
+INSERT INTO gifi (accno, description) VALUES ('229', 'Pauschalwertberichtigungen zu Forderungen gegenüber Unternehmen, mit denen ein Beteiligungsverhältnis besteht');
+--
+INSERT INTO gifi (accno, description) VALUES ('23-24', 'Sonstige Forderungen und Vermögensgegenstände');
+INSERT INTO gifi (accno, description) VALUES ('230-246', 'Sonstige Forderungen und Vermögensgegenstände');
+INSERT INTO gifi (accno, description) VALUES ('247', 'Eingeforderte, aber noch nicht eingezahlte Einlagen');
+INSERT INTO gifi (accno, description) VALUES ('248', 'Einzelwertberichtigungen zu sonstigen Forderungen und Vermögensgegenständen');
+INSERT INTO gifi (accno, description) VALUES ('249', 'Pauschalwertberichtigungen zu sonstigen Forderungen und Vermögensgegenständen');
+--
+INSERT INTO gifi (accno, description) VALUES ('25', 'Forderungen aus der Abgabenverrechnung');
+INSERT INTO gifi (accno, description) VALUES ('250-259', 'Forderungen aus der Abgabenverrechnung');
+--
+INSERT INTO gifi (accno, description) VALUES ('26', 'Wertpapiere und Anteile');
+INSERT INTO gifi (accno, description) VALUES ('260', 'Eigene Anteile');
+INSERT INTO gifi (accno, description) VALUES ('261', 'Anteile an verbundenen Unternehmen');
+INSERT INTO gifi (accno, description) VALUES ('262', 'Sonstige Anteile');
+INSERT INTO gifi (accno, description) VALUES ('263-267', 'Sonstige Wertpapiere');
+INSERT INTO gifi (accno, description) VALUES ('268', 'Besitzwechsel, soweit dem Unternehmen nicht die der Ausstellung zugrundeliegenden Forderungen zustehen');
+INSERT INTO gifi (accno, description) VALUES ('269', 'Wertberichtigungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('27-28', 'Kassenbestand, Schecks, Guthaben bei Kreditinstituten');
+INSERT INTO gifi (accno, description) VALUES ('270-272', 'Kassenbestände in Inlandswährung');
+INSERT INTO gifi (accno, description) VALUES ('273', 'Postwertzeichen');
+INSERT INTO gifi (accno, description) VALUES ('274', 'Stempelmarken');
+INSERT INTO gifi (accno, description) VALUES ('275-277', 'Kassenbestände in Fremdwährung');
+INSERT INTO gifi (accno, description) VALUES ('278', 'Schecks in Inlandswährung');
+INSERT INTO gifi (accno, description) VALUES ('280-288', 'Guthaben bei Kreditinstituten');
+INSERT INTO gifi (accno, description) VALUES ('289', 'Wertberichtigungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('29', 'Rechnungsabgrenzungsposten');
+INSERT INTO gifi (accno, description) VALUES ('290', 'Aktive Rechnungsabgrenzungsposten');
+INSERT INTO gifi (accno, description) VALUES ('295', 'Disagio');
+INSERT INTO gifi (accno, description) VALUES ('296', 'Unterschiedsbetrag zur gebotenen Pensionsrückstellung');
+INSERT INTO gifi (accno, description) VALUES ('297', 'Unterschiedsbetrag gem. Abschnitt XII Pensionskassengesetz');
+INSERT INTO gifi (accno, description) VALUES ('298', 'Steuerabgrenzung');
+--
+INSERT INTO gifi (accno, description) VALUES ('3', 'Rückstellungen, Verbindlichkeiten und Rechnungsabgrenzungsposten');
+--
+INSERT INTO gifi (accno, description) VALUES ('30', 'Rückstellungen');
+INSERT INTO gifi (accno, description) VALUES ('300', 'Rückstellungen für Abfertigungen');
+INSERT INTO gifi (accno, description) VALUES ('301', 'Rückstellungen für Pensionen');
+INSERT INTO gifi (accno, description) VALUES ('302-303', 'Steuerrückstellungen');
+INSERT INTO gifi (accno, description) VALUES ('304-309', 'Sonstige Rückstellungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('31', 'Anleihen, Verbindlichkeiten gegenüber Kreditinstituten und Finanzinstituten');
+INSERT INTO gifi (accno, description) VALUES ('310', 'Anleihen (einschließlich konvertibler)');
+INSERT INTO gifi (accno, description) VALUES ('311-317', 'Verbindlichkeiten gegenüber Kreditinstituten');
+INSERT INTO gifi (accno, description) VALUES ('318-319', 'Verbindlichkeiten gegenüber Finanzinstituten');
+--
+INSERT INTO gifi (accno, description) VALUES ('32', 'Erhaltene Anzahlungen auf Bestellungen');
+INSERT INTO gifi (accno, description) VALUES ('320', 'Erhaltene Anzahlungen auf Bestellungen');
+INSERT INTO gifi (accno, description) VALUES ('321', 'Umsatzsteuer-Evidenzkonto für erhaltene Anzahlungen auf Bestellungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('33', 'Verbindlichkeiten aus Lieferungen und Leistungen, Verbindlichkeiten aus der Annahme gezogener und der Ausstellung eigener Wechsel');
+INSERT INTO gifi (accno, description) VALUES ('330-335', 'Verbindlichkeiten aus Lieferungen und Leistungen Inland');
+INSERT INTO gifi (accno, description) VALUES ('336', 'Verbindlichkeiten aus Lieferungen und Leistungen Währungsunion');
+INSERT INTO gifi (accno, description) VALUES ('337', 'Verbindlichkeiten aus Lieferungen und Leistungen sonstiges Ausland');
+INSERT INTO gifi (accno, description) VALUES ('338-339', 'Verbindlichkeiten aus der Annahme gezogener Wechsel und der Ausstellung eigener Wechsel');
+--
+INSERT INTO gifi (accno, description) VALUES ('34', 'Verbindlichkeiten gegenüber verbundenen Unternehmen, gegenüber Unternehmen, mit denen ein Beteiligungsverhältnis besteht und gegenüber Gesellschaftern');
+INSERT INTO gifi (accno, description) VALUES ('340-347', 'Verbindlichkeiten gegenüber verbundenen Unternehmen, Verbindlichkeiten gegenüber Unternehmen, mit denen ein Beteiligungsverhältnis besteht');
+INSERT INTO gifi (accno, description) VALUES ('348', 'Verbindlichkeiten gegenüber Gesellschaftern');
+--
+INSERT INTO gifi (accno, description) VALUES ('35', 'Verbindlichkeiten aus Steuern');
+INSERT INTO gifi (accno, description) VALUES ('350-359', 'Verbindlichkeiten aus Steuern');
+--
+INSERT INTO gifi (accno, description) VALUES ('36', 'Verbindlichkeiten im Rahmen der sozialen Sicherheit');
+INSERT INTO gifi (accno, description) VALUES ('360-369', 'Verbindlichkeiten im Rahmen der sozialen Sicherheit');
+--
+INSERT INTO gifi (accno, description) VALUES ('37-38', 'Übrige sonstige Verbindlichkeiten');
+INSERT INTO gifi (accno, description) VALUES ('370-389', 'Übrige sonstige Verbindlichkeiten');
+--
+INSERT INTO gifi (accno, description) VALUES ('39', 'Rechnungsabgrenzungsposten');
+INSERT INTO gifi (accno, description) VALUES ('390-399', 'Passive Rechnungsabgrenzungsposten');
+--
+INSERT INTO gifi (accno, description) VALUES ('4', 'Betriebliche Erträge');
+--
+INSERT INTO gifi (accno, description) VALUES ('40-44', 'Brutto-Umsatzerlöse und Erlösschmälerungen');
+INSERT INTO gifi (accno, description) VALUES ('400-439', 'Brutto-Umsatzerlöse');
+INSERT INTO gifi (accno, description) VALUES ('440-449', 'Erlösschmälerungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('45', 'Bestandsveränderungen und aktivierte Eigenleistungen');
+INSERT INTO gifi (accno, description) VALUES ('450-457', 'Veränderungen des Bestandes an fertigen und unfertigen Erzeugnissen sowie an noch nicht abrechenbaren Leistungen');
+INSERT INTO gifi (accno, description) VALUES ('458-459', 'andere aktivierte Eigenleistungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('46-49', 'Sonstige betriebliche Erträge');
+INSERT INTO gifi (accno, description) VALUES ('460-462', 'Erlöse aus dem Abgang vom Anlagevermögen, ausgenommen Finanzanlagen');
+INSERT INTO gifi (accno, description) VALUES ('463-465', 'Erträge aus dem Abgang vom Anlagevermögen, ausgenommen Finanzanlagen');
+INSERT INTO gifi (accno, description) VALUES ('466-467', 'Erträge aus der Zuschreibung zum Anlagevermögen, ausgenommen Finanzanlagen');
+INSERT INTO gifi (accno, description) VALUES ('470-479', 'Erträge aus der Auflösung von Rückstellungen');
+INSERT INTO gifi (accno, description) VALUES ('480-499', 'Übrige betriebliche Erträge');
+--
+INSERT INTO gifi (accno, description) VALUES ('5', 'Materialaufwand und sonstige bezogene Herstellungsleistungen');
+INSERT INTO gifi (accno, description) VALUES ('500-509', 'Wareneinsatz');
+INSERT INTO gifi (accno, description) VALUES ('510-519', 'Verbrauch von Rohstoffen');
+INSERT INTO gifi (accno, description) VALUES ('520-529', 'Verbrauch von bezogenen Fertig- und Einzelteilen');
+INSERT INTO gifi (accno, description) VALUES ('530-539', 'Verbrauch von Hilfsstoffen');
+INSERT INTO gifi (accno, description) VALUES ('540-549', 'Verbrauch von Betriebsstoffen');
+INSERT INTO gifi (accno, description) VALUES ('550-559', 'Verbrauch von Werkzeugen und anderen Erzeugungshilfsmitteln');
+INSERT INTO gifi (accno, description) VALUES ('560-569', 'Verbrauch von Brenn- und Treibstoffen, Energie und Wasser');
+INSERT INTO gifi (accno, description) VALUES ('570-579', 'Sonstige bezogene Herstellungsleistungen');
+INSERT INTO gifi (accno, description) VALUES ('580', 'Skontoerträge auf Materialaufwand');
+INSERT INTO gifi (accno, description) VALUES ('581', 'Skontoerträge auf sonstige bezogene Herstellungsleistungen');
+INSERT INTO gifi (accno, description) VALUES ('590', 'Aufwandsstellenrechnung');
+--
+INSERT INTO gifi (accno, description) VALUES ('6', 'Personalaufwand');
+INSERT INTO gifi (accno, description) VALUES ('600-619', 'Löhne');
+INSERT INTO gifi (accno, description) VALUES ('620-639', 'Gehälter');
+INSERT INTO gifi (accno, description) VALUES ('640-644', 'Aufwendungen für Abfertigungen');
+INSERT INTO gifi (accno, description) VALUES ('645-649', 'Aufwendungen für Altersversorgung');
+INSERT INTO gifi (accno, description) VALUES ('650-655', 'Gesetzlicher Sozialaufwand Arbeiter');
+INSERT INTO gifi (accno, description) VALUES ('656-659', 'Gesetzlicher Sozialaufwand Angestellte');
+INSERT INTO gifi (accno, description) VALUES ('660-665', 'Lohnabhängige Abgaben und Pflichtbeiträge');
+INSERT INTO gifi (accno, description) VALUES ('666-669', 'Gehaltsabhängige Abgaben und Pflichtbeiträge');
+INSERT INTO gifi (accno, description) VALUES ('670-689', 'Sonstige Sozialaufwendungen');
+INSERT INTO gifi (accno, description) VALUES ('690', 'Aufwandsstellenrechnung');
+--
+INSERT INTO gifi (accno, description) VALUES ('7', 'Abschreibungen und sonstige betriebliche Aufwendunge');
+--
+INSERT INTO gifi (accno, description) VALUES ('70', 'Abschreibungen');
+INSERT INTO gifi (accno, description) VALUES ('700', 'Abschreibungen auf aktivierte Aufwendungen für das Ingangsetzen und Erweitern eines Betriebes');
+INSERT INTO gifi (accno, description) VALUES ('701-708', 'Abschreibungen auf das Anlagevermögen (ausgenommen Finanzanlagen)');
+INSERT INTO gifi (accno, description) VALUES ('709', 'Abschreibungen vom Umlaufvermögen, soweit diese die im Unternehmen üblichen Abschreibungen übersteigen');
+--
+INSERT INTO gifi (accno, description) VALUES ('71', 'Sonstige Steuern');
+INSERT INTO gifi (accno, description) VALUES ('710-719', 'Sonstige Steuern');
+--
+INSERT INTO gifi (accno, description) VALUES ('72-78', 'Übrige betriebliche Aufwendungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('72', 'Instandhaltung und Reinigung durch Dritte, Entsorgung, Beleuchtung');
+INSERT INTO gifi (accno, description) VALUES ('720-729', 'Instandhaltung und Reinigung durch Dritte, Entsorgung, Beleuchtung');
+--
+INSERT INTO gifi (accno, description) VALUES ('73', 'Transport-, Reise- und Fahrtaufwand, Nachrichtenaufwand');
+INSERT INTO gifi (accno, description) VALUES ('730-731', 'Transporte durch Dritte');
+INSERT INTO gifi (accno, description) VALUES ('732-733', 'Kfz-Aufwand');
+INSERT INTO gifi (accno, description) VALUES ('734-735', 'Reise- und Fahrtaufwand');
+INSERT INTO gifi (accno, description) VALUES ('736-737', 'Tag- und Nächtigungsgelder');
+INSERT INTO gifi (accno, description) VALUES ('738-739', 'Nachrichtenaufwand');
+--
+INSERT INTO gifi (accno, description) VALUES ('74', 'Miet-, Pacht-, Leasing- und Lizenzaufwand');
+INSERT INTO gifi (accno, description) VALUES ('740-743', 'Miet- und Pachtaufwand');
+INSERT INTO gifi (accno, description) VALUES ('744-747', 'Leasingaufwand');
+INSERT INTO gifi (accno, description) VALUES ('748-749', 'Lizenzaufwand');
+--
+INSERT INTO gifi (accno, description) VALUES ('75', 'Aufwand für beigestelltes Personal, Provisionen an Dritte, Aufsichtsratsvergütungen');
+INSERT INTO gifi (accno, description) VALUES ('750-753', 'Aufwand für beigestelltes Personal');
+INSERT INTO gifi (accno, description) VALUES ('754-757', 'Provisionen an Dritte');
+INSERT INTO gifi (accno, description) VALUES ('758-759', 'Aufsichtsratsvergütungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('76', 'Büro-, Werbe- und Repräsentationsaufwand');
+INSERT INTO gifi (accno, description) VALUES ('760', 'Büromaterial und Drucksorten');
+INSERT INTO gifi (accno, description) VALUES ('761-762', 'Druckerzeugnisse und Vervielfältigungen');
+INSERT INTO gifi (accno, description) VALUES ('763', 'Fachliteratur und Zeitungen');
+INSERT INTO gifi (accno, description) VALUES ('765-768', 'Werbung und Repräsentation');
+INSERT INTO gifi (accno, description) VALUES ('769', 'Spenden und Trinkgelder');
+--
+INSERT INTO gifi (accno, description) VALUES ('77-78', 'Versicherungen, Übrige Aufwendungen');
+INSERT INTO gifi (accno, description) VALUES ('770-774', 'Versicherungen');
+INSERT INTO gifi (accno, description) VALUES ('775-776', 'Beratungs- und Prüfungsaufwand');
+INSERT INTO gifi (accno, description) VALUES ('777', 'Aus- und Fortbildung');
+INSERT INTO gifi (accno, description) VALUES ('778', 'Mitgliedsbeiträge');
+INSERT INTO gifi (accno, description) VALUES ('779', 'Spesen des Geldverkehrs');
+INSERT INTO gifi (accno, description) VALUES ('780-781', 'Schadensfälle');
+INSERT INTO gifi (accno, description) VALUES ('782', 'Buchwert abgegangener Anlagen, ausgenommen Finanzanlagen');
+INSERT INTO gifi (accno, description) VALUES ('783', 'Verluste aus dem Abgang vom Anlagevermögen, ausgenommen Finanzanlagen');
+INSERT INTO gifi (accno, description) VALUES ('784-788', 'Verschiedene betriebliche Aufwendungen');
+INSERT INTO gifi (accno, description) VALUES ('789', 'Skontoerträge auf sonstige betriebliche Aufwendungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('79', 'Konten für das Umsatzkostenverfahren');
+INSERT INTO gifi (accno, description) VALUES ('790', 'Aufwandsstellenrechnung');
+INSERT INTO gifi (accno, description) VALUES ('791-799', 'Aufwandsstellen im Rahmen des Umsatzkostenverfahrens');
+INSERT INTO gifi (accno, description) VALUES ('791-795', 'Aufwandsstellen der Herstellung');
+INSERT INTO gifi (accno, description) VALUES ('796', 'Herstellungskosten der zur Erzielung der Umsatzerlöse erbrachten Leistungen');
+INSERT INTO gifi (accno, description) VALUES ('797', 'Vertriebskosten');
+INSERT INTO gifi (accno, description) VALUES ('798', 'Verwaltungskosten');
+INSERT INTO gifi (accno, description) VALUES ('799', 'Sonstige betriebliche Aufwendungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('8', 'Finanzerträge und Finanzaufwendungen, a.o. Erträge und a.o. Aufwendungen, Steuern vom Einkommen und vom Ertrag, Rücklagenbewegung');
+--
+INSERT INTO gifi (accno, description) VALUES ('80-83', 'Finanzerträge und Finanzaufwendungen');
+INSERT INTO gifi (accno, description) VALUES ('800-804', 'Erträge aus Beteiligungen');
+INSERT INTO gifi (accno, description) VALUES ('805-809', 'Erträge aus anderen Wertpapieren und Ausleihungen des Finanzanlagevermögens');
+INSERT INTO gifi (accno, description) VALUES ('810-813', 'Sonstige Zinsen und ähnliche Erträge');
+INSERT INTO gifi (accno, description) VALUES ('814', 'Erlöse aus dem Abgang von Beteiligungen');
+INSERT INTO gifi (accno, description) VALUES ('815', 'Erlöse aus dem Abgang von sonstigen Finanzanlagen');
+INSERT INTO gifi (accno, description) VALUES ('816', 'Erlöse aus dem Abgang von Wertpapieren des Umlaufvermögens');
+INSERT INTO gifi (accno, description) VALUES ('817', 'Buchwert abgegangener Beteiligungen');
+INSERT INTO gifi (accno, description) VALUES ('818', 'Buchwert abgegangener sonstiger Finanzanlagen');
+INSERT INTO gifi (accno, description) VALUES ('819', 'Buchwert abgegangener Wertpapiere des Umlaufvermögens');
+INSERT INTO gifi (accno, description) VALUES ('820', 'Erträge aus dem Abgang von und der Zuschreibung zu Finanzanlagen');
+INSERT INTO gifi (accno, description) VALUES ('821', 'Erträge aus dem Abgang von und der Zuschreibung zu Wertpapieren des Umlaufvermögens');
+INSERT INTO gifi (accno, description) VALUES ('822-825', 'Aufwendungen aus Beteiligungen');
+INSERT INTO gifi (accno, description) VALUES ('826-827', 'Aufwendungen aus sonstigen Finanzanlagen und aus Wertpapieren des Umlaufvermögens');
+INSERT INTO gifi (accno, description) VALUES ('828-834', 'Zinsen und ähnliche Aufwendungen');
+INSERT INTO gifi (accno, description) VALUES ('835', 'Nicht ausgenützte Lieferantenskonti');
+--
+INSERT INTO gifi (accno, description) VALUES ('84', 'Außerordentliche Erträge und außerordentliche Aufwendungen');
+INSERT INTO gifi (accno, description) VALUES ('840-844', 'Außerordentliche Erträge');
+INSERT INTO gifi (accno, description) VALUES ('845-849', 'Außerordentliche Aufwendungen');
+--
+INSERT INTO gifi (accno, description) VALUES ('85', 'Steuern vom Einkommen und vom Ertrag');
+INSERT INTO gifi (accno, description) VALUES ('850-859', 'Steuern vom Einkommen und vom Ertrag');
+--
+INSERT INTO gifi (accno, description) VALUES ('86-89', 'Rücklagenbewegung, Ergebnisüberrechnung');
+INSERT INTO gifi (accno, description) VALUES ('860-869', 'Auflösung unversteuerter Rücklagen');
+INSERT INTO gifi (accno, description) VALUES ('870-874', 'Auflösung von Kapitalrücklagen');
+INSERT INTO gifi (accno, description) VALUES ('875-879', 'Auflösung von Gewinnrücklagen');
+INSERT INTO gifi (accno, description) VALUES ('880-889', 'Zuweisung zu unversteuerten Rücklagen');
+INSERT INTO gifi (accno, description) VALUES ('890-895', 'Zuweisung zu Gewinnrücklagen');
+INSERT INTO gifi (accno, description) VALUES ('899', 'Gewinnabfuhr bzw. Verlustüberrechnung aus Ergebnisabführungsverträgen');
+--
+INSERT INTO gifi (accno, description) VALUES ('9', 'Eigenkapital, unversteuerte Rücklagen, Einlagen Stiller Gesellschafter, Abschluß- und Evidenzkonten');
+--
+INSERT INTO gifi (accno, description) VALUES ('900-918', 'Gezeichnetes bzw. gewidmetes Kapital');
+INSERT INTO gifi (accno, description) VALUES ('919', 'Nicht eingeforderte ausstehende Einlagen');
+INSERT INTO gifi (accno, description) VALUES ('920-929', 'Kapitalrücklagen');
+INSERT INTO gifi (accno, description) VALUES ('930-938', 'Gewinnrücklagen');
+INSERT INTO gifi (accno, description) VALUES ('939', 'Bilanzgewinn (-verlust)');
+INSERT INTO gifi (accno, description) VALUES ('940-959', 'Bewertungsreserven und sonstige unversteuerte Rücklagen');
+INSERT INTO gifi (accno, description) VALUES ('960-969', 'Privat- und Verrechnungskonten bei Einzelunternehmen und Personengesellschaften');
+INSERT INTO gifi (accno, description) VALUES ('970-979', 'Einlagen Stiller Gesellschafter');
+INSERT INTO gifi (accno, description) VALUES ('980', 'Eröffnungsbilanz');
+INSERT INTO gifi (accno, description) VALUES ('985', 'Schlußbilanz');
+INSERT INTO gifi (accno, description) VALUES ('989', 'Gewinn- und Verlustrechnung');
+INSERT INTO gifi (accno, description) VALUES ('990-999', 'Evidenzkonten');
diff --git a/sql-ledger/sql/Brazil_General-chart.sql b/sql-ledger/sql/Brazil_General-chart.sql
new file mode 100644
index 0000000..1c983e6
--- /dev/null
+++ b/sql-ledger/sql/Brazil_General-chart.sql
@@ -0,0 +1,70 @@
+-- General Brazilien Portuguese COA
+-- sample only
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1000','RECURSOS ATUAIS','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1060','Checando Cliente','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1065','Caixa Baixo','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200','Contas a Receber','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1205','Provisão para devedors duvidosos','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1500','INVENTÁRIO DE CLIENTES','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1520','Inventário / Geral','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1530','Inventário / Mercado Secundário','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1540','Inventário / Computer Parts','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800','CAPITAL ASSETS','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1820','Escritório Móvel & Equipamentos','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1825','Accum. Amort. -Móvel. & Equip.','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1840','Veículo','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1845','Accum. Amort. -Veículo','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000','BALANÇO ATUAL','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2100','Contas a Pagar','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2170','Taxas federais','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2310','VAT (7%)','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2320','VAT (8%)','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2380','Contas a pagar de férias','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2400','DEDUÇÕES DE FOLHA DE PAGAMENTO','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2450','Imposto de Renda Devido','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2600','Passivi exigível a longo prazo','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2620','Empréstimo bancário','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2680','Empréstimo de Acionistas','A','','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3300','DIVISÃO DE CAPITAL','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3350','Divisão comum','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4000','VENDAS RECEITAS','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4020','Vendas Gerais','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4030','Partes para mercado secundário','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4040','Parte Computacional','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4300','CONSULTANDO FONTES DE RENDA','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4320','Consultando','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4330','Programando','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4340','Loja','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4400','OUTRAS RENDAS','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4430','Transporte & Taxa','A','','I','IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4440','Juros Acumulados','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4450','Ganho de câmbio estrangeiro','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5000','CUSTO DE VENDAS DE PRODUTOS','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5010','Compras','A','','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5050','Mercado Secundário','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5060','Parte Computacional','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5100','Frete','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5400','DESPESAS E FOLHA DE PAGAMENTO','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5410','Salários','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5600','GERAL E DESPESAS ADMINISTRATIVAS','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5610','Contabilidade & Leis','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5615','Publicidade & Promoções','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5620','Balanço','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5660','Amortização','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5680','Imposto de Renda','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5685','Seguro','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5690','Interesses & Encargos Bancários','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5700','Materiais de Escritório','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5760','Aluguel','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5765','Manutenção & Reparos','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5780','Telefone','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5785','Cursos & Entretenimentos','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5790','Serviços Públicos','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5800','Licenciamento para exportações','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5810','Troca com Estrangeiro','A','','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2310'),0.07);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2320'),0.08);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '5010'), fxgain_accno_id = (select id from chart where accno = '4450'), fxloss_accno_id = (select id from chart where accno = '5810'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'R$:EUR:USD', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Canada-gifi.sql b/sql-ledger/sql/Canada-gifi.sql
new file mode 100644
index 0000000..fe9641c
--- /dev/null
+++ b/sql-ledger/sql/Canada-gifi.sql
@@ -0,0 +1,754 @@
+-- GIFI codes as set by the Canadian Government
+-- It's a dirty job, but it seems somebody allready did it
+-- PDF Tammes, Tue , 02 Apr 2002
+-- remarks or questions to finance@bermuda-holding.com
+--
+-- From the GIFI documentation:
+--
+-- The GIFI information has to balance. We use the following rules to verify the information you provide.
+-- total assets = total liabilities + total shareholder equity
+-- total revenue - total expenses = net non-farming income
+-- total farm revenue - total farm expenses = net farm income
+--
+-- You have to provide certain line items so that we can verify the above equations. Each GIFI must include:
+-- balance sheet
+-- Item 2599 Total assets
+-- Item 3499 Total liabilities
+-- Item 3620 Total shareholder equity
+-- non-farming income and expenses
+-- Item 8299 Total revenue
+-- Item 9368 Total expenses
+-- and/or
+-- farming income and expenses
+-- Item 9659 Total farm revenue
+-- Item 9898 Total farm expenses
+-- when reporting a breakdown of retained earnings
+-- Item 3849 Retained earnings/deficit end
+-- extraordinary items and income taxes
+-- Item 9999 Net income/loss after taxes and extraordinary items
+-- If the amount of a required item is NIL, you have to enter 0.
+--
+INSERT INTO gifi (accno,description) VALUES ('1000', 'Cash & Deposits');
+INSERT INTO gifi (accno,description) VALUES ('1001', 'Cash');
+INSERT INTO gifi (accno,description) VALUES ('1002', 'Deposits In Canadian Banks And Institutions - Canadian Currency');
+INSERT INTO gifi (accno,description) VALUES ('1003', 'Deposits In Canadian Banks And Institutions - Foreign Currency');
+INSERT INTO gifi (accno,description) VALUES ('1004', 'Deposits In Foreign Banks - Canadian Currency');
+INSERT INTO gifi (accno,description) VALUES ('1005', 'Deposits In Foreign Banks - Foreign Currency');
+INSERT INTO gifi (accno,description) VALUES ('1006', 'Credit Union Central Deposits');
+INSERT INTO gifi (accno,description) VALUES ('1007', 'Other Cash Like Instruments - Gold Bullion, Silver Bullion');
+INSERT INTO gifi (accno,description) VALUES ('1060', 'Accounts Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1061', 'Allowance For Doubtfull Accounts Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1062', 'Trade Accounts Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1063', 'Allowance For Doubtfull Trade Accounts Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1064', 'Trade Accounts Receivable Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('1065', 'Allowance For Doubtfull Trade Accounts Receivable Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('1066', 'Taxes Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1067', 'Intrest Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1068', 'Holdbacks Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1069', 'Leases Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1070', 'Allowance For Doubtfull Leases Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1071', 'Accounts Receivable Employees');
+INSERT INTO gifi (accno,description) VALUES ('1072', 'Allowance For Doubtfull Accounts Receivable Employees');
+INSERT INTO gifi (accno,description) VALUES ('1073', 'Accounts Receivable From Members Of NPO');
+INSERT INTO gifi (accno,description) VALUES ('1120', 'Inventories');
+INSERT INTO gifi (accno,description) VALUES ('1121', 'Inventory Of Goods For Sale/Finished Goods');
+INSERT INTO gifi (accno,description) VALUES ('1122', 'Inventory Of Parts And Supplies');
+INSERT INTO gifi (accno,description) VALUES ('1125', 'Work In Progress');
+INSERT INTO gifi (accno,description) VALUES ('1126', 'Raw Materials');
+INSERT INTO gifi (accno,description) VALUES ('1180', 'Short Term Investments');
+INSERT INTO gifi (accno,description) VALUES ('1181', 'Canadian Term Deposits');
+INSERT INTO gifi (accno,description) VALUES ('1182', 'Canadian Shares');
+INSERT INTO gifi (accno,description) VALUES ('1183', 'Canadian Bonds');
+INSERT INTO gifi (accno,description) VALUES ('1184', 'Canadian Treasury Bills');
+INSERT INTO gifi (accno,description) VALUES ('1185', 'Securities Purchased Under Resale Agreement');
+INSERT INTO gifi (accno,description) VALUES ('1186', 'Other Short Term Canadian Investments');
+INSERT INTO gifi (accno,description) VALUES ('1187', 'Short Term Foreign Investments');
+INSERT INTO gifi (accno,description) VALUES ('1240', 'Loans & Notes Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1241', 'Demand Loans Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1242', 'Other Loans Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1243', 'Notes Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1244', 'Mortgages Receivable');
+INSERT INTO gifi (accno,description) VALUES ('1300', 'Due From Shareholder(s)/Director(s)');
+INSERT INTO gifi (accno,description) VALUES ('1301', 'Due From Individual Shareholder(s)');
+INSERT INTO gifi (accno,description) VALUES ('1302', 'Due From Corporate Shareholder(s)');
+INSERT INTO gifi (accno,description) VALUES ('1303', 'Due From Director(s)');
+INSERT INTO gifi (accno,description) VALUES ('1360', 'Investment In Joint Venture(s)/Partnership(s)');
+INSERT INTO gifi (accno,description) VALUES ('1380', 'Due From Joint Venture(s)/Partnership(s)');
+INSERT INTO gifi (accno,description) VALUES ('1400', 'Due From/Investment In Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('1401', 'Demand Notes From Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('1402', 'Interest Receivable From Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('1403', 'Loans/Advances Due From Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('1480', 'Other Current Assets');
+INSERT INTO gifi (accno,description) VALUES ('1481', 'Deferred Income Taxes');
+INSERT INTO gifi (accno,description) VALUES ('1482', 'Accrued Investment Income');
+INSERT INTO gifi (accno,description) VALUES ('1483', 'Taxes Recoverable/Refundable');
+INSERT INTO gifi (accno,description) VALUES ('1484', 'Prepaid Expenses');
+INSERT INTO gifi (accno,description) VALUES ('1485', 'Drilling Advances');
+INSERT INTO gifi (accno,description) VALUES ('1486', 'Security Deposits');
+INSERT INTO gifi (accno,description) VALUES ('1599', 'Total Current Assets');
+INSERT INTO gifi (accno,description) VALUES ('1600', 'Land');
+INSERT INTO gifi (accno,description) VALUES ('1601', 'Land Improvement');
+INSERT INTO gifi (accno,description) VALUES ('1602', 'Accumulated Amortization Of Land & Land Improvement');
+INSERT INTO gifi (accno,description) VALUES ('1620', 'Depletable Assets');
+INSERT INTO gifi (accno,description) VALUES ('1621', 'Accumulated Amortization Of Depletable Assets');
+INSERT INTO gifi (accno,description) VALUES ('1622', 'Petroleum & Natural Gas Properties');
+INSERT INTO gifi (accno,description) VALUES ('1623', 'Accumulated Amortization Of Petroleum & Natural Gas Properties');
+INSERT INTO gifi (accno,description) VALUES ('1624', 'Mining Properties');
+INSERT INTO gifi (accno,description) VALUES ('1625', 'Accumulated Amortization Of Mining Properties');
+INSERT INTO gifi (accno,description) VALUES ('1626', 'Deferred Exporation & Development charges');
+INSERT INTO gifi (accno,description) VALUES ('1627', 'Accumulated Amortization Of Petroleum & Deferred Exporation & Development charges');
+INSERT INTO gifi (accno,description) VALUES ('1628', 'Quarries');
+INSERT INTO gifi (accno,description) VALUES ('1629', 'Accumulated Amortization Of Quarries');
+INSERT INTO gifi (accno,description) VALUES ('1630', 'Gravel Pits');
+INSERT INTO gifi (accno,description) VALUES ('1631', 'Accumulated Amortization Of Gravel Pits');
+INSERT INTO gifi (accno,description) VALUES ('1632', 'Timber Limits');
+INSERT INTO gifi (accno,description) VALUES ('1633', 'Accumulated Amortization Of Timber Limits');
+INSERT INTO gifi (accno,description) VALUES ('1680', 'Buildings');
+INSERT INTO gifi (accno,description) VALUES ('1681', 'Accumulated Amortization Of Buildings');
+INSERT INTO gifi (accno,description) VALUES ('1682', 'Manufacturing And Processing Plant');
+INSERT INTO gifi (accno,description) VALUES ('1683', 'Accumulated Amortization Of Manufacturing and Processing Plant');
+INSERT INTO gifi (accno,description) VALUES ('1684', 'Buildings Under Construction');
+INSERT INTO gifi (accno,description) VALUES ('1740', 'Machinery, Equipment, furniture & fixtures');
+INSERT INTO gifi (accno,description) VALUES ('1741', 'Accumulated Amortization Of Machinery, Equipment, furniture & fixtures');
+INSERT INTO gifi (accno,description) VALUES ('1742', 'Motor Vehicles');
+INSERT INTO gifi (accno,description) VALUES ('1743', 'Accumulated Amortization Of Motor Vehicles');
+INSERT INTO gifi (accno,description) VALUES ('1744', 'Tools and Dies');
+INSERT INTO gifi (accno,description) VALUES ('1745', 'Accumulated Amortization Of Tools and Dies');
+INSERT INTO gifi (accno,description) VALUES ('1746', 'Construction & Excavating Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1747', 'Accumulated Amortization Of Construction & Excavating Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1748', 'Forestry & Logging Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1749', 'Accumulated Amortization Of Forestry & Logging Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1750', 'Fishing Gear & Nets');
+INSERT INTO gifi (accno,description) VALUES ('1751', 'Accumulated Amortization Of Fishing Gear & Nets');
+INSERT INTO gifi (accno,description) VALUES ('1752', 'Mining Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1753', 'Accumulated Amortization Of Mining Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1754', 'Oil & Gas Systems');
+INSERT INTO gifi (accno,description) VALUES ('1755', 'Accumulated Amortization Of Oil & Gas Systems');
+INSERT INTO gifi (accno,description) VALUES ('1756', 'Production Equipment for resource industries');
+INSERT INTO gifi (accno,description) VALUES ('1757', 'Accumulated Amortization Of Production Equipment for resource industries');
+INSERT INTO gifi (accno,description) VALUES ('1758', 'Production Equipment for other industries');
+INSERT INTO gifi (accno,description) VALUES ('1759', 'Accumulated Amortization Of Production Equipment for other industries');
+INSERT INTO gifi (accno,description) VALUES ('1760', 'Exploration Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1761', 'Accumulated Amortization Of Exploration Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1762', 'Shipping Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1763', 'Accumulated Amortization Of Shipping Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1764', 'Ships & Boats');
+INSERT INTO gifi (accno,description) VALUES ('1765', 'Accumulated Amortization Of Ships & Boats');
+INSERT INTO gifi (accno,description) VALUES ('1766', 'Aircraft');
+INSERT INTO gifi (accno,description) VALUES ('1767', 'Accumulated Amortization Of Aircraft');
+INSERT INTO gifi (accno,description) VALUES ('1768', 'Signs');
+INSERT INTO gifi (accno,description) VALUES ('1769', 'Accumulated Amortization Of Signs');
+INSERT INTO gifi (accno,description) VALUES ('1770', 'Small Tools');
+INSERT INTO gifi (accno,description) VALUES ('1771', 'Accumulated Amortization Of Small Tools');
+INSERT INTO gifi (accno,description) VALUES ('1772', 'Radio & Communication Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1773', 'Accumulated Amortization Of Radio & Communication Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1774', 'Computer Equipment/Software');
+INSERT INTO gifi (accno,description) VALUES ('1775', 'Accumulated Amortization Of Computer Equipment/software');
+INSERT INTO gifi (accno,description) VALUES ('1776', 'Musical Instruments');
+INSERT INTO gifi (accno,description) VALUES ('1777', 'Accumulated Amortization Of Musical Instruments');
+INSERT INTO gifi (accno,description) VALUES ('1778', 'Satellites');
+INSERT INTO gifi (accno,description) VALUES ('1779', 'Accumulated Amortization Of Satellites');
+INSERT INTO gifi (accno,description) VALUES ('1780', 'Earth Stations');
+INSERT INTO gifi (accno,description) VALUES ('1781', 'Accumulated Amortization Of Earth Stations');
+INSERT INTO gifi (accno,description) VALUES ('1782', 'Machinery & Equipment Under Construction');
+INSERT INTO gifi (accno,description) VALUES ('1783', 'Transportation Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1784', 'Accumulated Amortization Of Transportation Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1785', 'Other Machinery & Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1786', 'Accumulated Amortization Of Other Machinery & Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1787', 'Furniture & Fixtures');
+INSERT INTO gifi (accno,description) VALUES ('1788', 'Accumulated Amortization Of Furniture & Fixtures');
+INSERT INTO gifi (accno,description) VALUES ('1900', 'Other Tangible Capital Assets');
+INSERT INTO gifi (accno,description) VALUES ('1901', 'Accumulated Amortization Of Other Tangible Capital Assets');
+INSERT INTO gifi (accno,description) VALUES ('1902', 'Logging Roads');
+INSERT INTO gifi (accno,description) VALUES ('1903', 'Accumulated Amortization Of Logging Roads');
+INSERT INTO gifi (accno,description) VALUES ('1904', 'Asphalt & Parking Areas');
+INSERT INTO gifi (accno,description) VALUES ('1905', 'Accumulated Amortization Of Asphalt & Parking Areas');
+INSERT INTO gifi (accno,description) VALUES ('1906', 'Wharves, Docks & Marinas');
+INSERT INTO gifi (accno,description) VALUES ('1907', 'Accumulated Amortization Of Wharves, Docks & Marinas');
+INSERT INTO gifi (accno,description) VALUES ('1908', 'Fences');
+INSERT INTO gifi (accno,description) VALUES ('1909', 'Accumulated Amortization Of Fences');
+INSERT INTO gifi (accno,description) VALUES ('1910', 'Capital Leases - Buildings');
+INSERT INTO gifi (accno,description) VALUES ('1911', 'Accumulated Amortization Of Capital Leases - Buildings');
+INSERT INTO gifi (accno,description) VALUES ('1912', 'Capital Leases - Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1913', 'Accumulated Amortization Of Capital Leases - Equipment');
+INSERT INTO gifi (accno,description) VALUES ('1914', 'Capital Leases - Vehicles');
+INSERT INTO gifi (accno,description) VALUES ('1915', 'Accumulated Amortization Of Capital Leases - Vehicles');
+INSERT INTO gifi (accno,description) VALUES ('1916', 'Capital Leases - Other');
+INSERT INTO gifi (accno,description) VALUES ('1917', 'Accumulated Amortization Of Capital Leases - Other');
+INSERT INTO gifi (accno,description) VALUES ('1918', 'Leasehold Improvements');
+INSERT INTO gifi (accno,description) VALUES ('1919', 'Accumulated Amortization Of Leasehold Improvements');
+INSERT INTO gifi (accno,description) VALUES ('1920', 'Other Capital Assets Under Construction');
+INSERT INTO gifi (accno,description) VALUES ('1921', 'Campsites');
+INSERT INTO gifi (accno,description) VALUES ('1922', 'Accumulated Amortization Of Campsites');
+INSERT INTO gifi (accno,description) VALUES ('2008', 'Total Tangible Capital Assets');
+INSERT INTO gifi (accno,description) VALUES ('2009', 'Total Accumulated Amortization Of Tangible Capital Assets');
+INSERT INTO gifi (accno,description) VALUES ('2010', 'Intangible Assets');
+INSERT INTO gifi (accno,description) VALUES ('2011', 'Accumulated Amortization Of Intangible Assets');
+INSERT INTO gifi (accno,description) VALUES ('2012', 'Goodwill');
+INSERT INTO gifi (accno,description) VALUES ('2013', 'Accumulated Amortization Of Goodwill');
+INSERT INTO gifi (accno,description) VALUES ('2014', 'Quota');
+INSERT INTO gifi (accno,description) VALUES ('2015', 'Accumulated Amortization Of Quota');
+INSERT INTO gifi (accno,description) VALUES ('2016', 'Licences');
+INSERT INTO gifi (accno,description) VALUES ('2017', 'Accumulated Amortization Of Licences');
+INSERT INTO gifi (accno,description) VALUES ('2018', 'Incorporation Costs');
+INSERT INTO gifi (accno,description) VALUES ('2019', 'Accumulated Amortization Of Incorporation Costs');
+INSERT INTO gifi (accno,description) VALUES ('2020', 'Trademarks & Patents');
+INSERT INTO gifi (accno,description) VALUES ('2021', 'Accumulated Amortization Of Trademarks & Patents');
+INSERT INTO gifi (accno,description) VALUES ('2022', 'Customer Lists');
+INSERT INTO gifi (accno,description) VALUES ('2023', 'Accumulated Amortization Of Customer Lists');
+INSERT INTO gifi (accno,description) VALUES ('2024', 'Rights');
+INSERT INTO gifi (accno,description) VALUES ('2025', 'Accumulated Amortization Of Rights');
+INSERT INTO gifi (accno,description) VALUES ('2026', 'Research & Development');
+INSERT INTO gifi (accno,description) VALUES ('2027', 'Accumulated Amortization Of Research & Development');
+INSERT INTO gifi (accno,description) VALUES ('2070', 'Resource Rights');
+INSERT INTO gifi (accno,description) VALUES ('2071', 'Accumulated Amortization Of Resource Rights');
+INSERT INTO gifi (accno,description) VALUES ('2072', 'Timber Rights');
+INSERT INTO gifi (accno,description) VALUES ('2073', 'Accumulated Amortization Of Timber Rights');
+INSERT INTO gifi (accno,description) VALUES ('2074', 'Mining Rights');
+INSERT INTO gifi (accno,description) VALUES ('2075', 'Accumulated Amortization Of Mining Rights');
+INSERT INTO gifi (accno,description) VALUES ('2076', 'Oil & Gas Rights');
+INSERT INTO gifi (accno,description) VALUES ('2077', 'Accumulated Amortization Of Oil & Gas Rights');
+INSERT INTO gifi (accno,description) VALUES ('2078', 'Total Intangible Capital Assets');
+INSERT INTO gifi (accno,description) VALUES ('2079', 'Total Accumulated Amortization Of Intangible Capital Assets');
+INSERT INTO gifi (accno,description) VALUES ('2180', 'Long Term Due From Shareholder(s)/Director(s)');
+INSERT INTO gifi (accno,description) VALUES ('2181', 'Long Term Due From Individual Shareholder(s)');
+INSERT INTO gifi (accno,description) VALUES ('2182', 'Long Term Due From Corporate Shareholder(s)');
+INSERT INTO gifi (accno,description) VALUES ('2183', 'Long Term Due From Director(s)');
+INSERT INTO gifi (accno,description) VALUES ('2200', 'Long Term Investment In Joint Venture(s)/Partnership(s)');
+INSERT INTO gifi (accno,description) VALUES ('2220', 'Long Term Due From Joint Venture(s)/Partnership(s)');
+INSERT INTO gifi (accno,description) VALUES ('2240', 'Long Term Due From/Investment In Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('2241', 'Due From/Investment In Canadian Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('2242', 'Shares In Canadian Related Corporations');
+INSERT INTO gifi (accno,description) VALUES ('2243', 'Loans/Advances To Canadian Related Corporations');
+INSERT INTO gifi (accno,description) VALUES ('2244', 'Investment In Canadian Related Corporations At Cost');
+INSERT INTO gifi (accno,description) VALUES ('2245', 'Investment In Canadian Related Corporations At Equity');
+INSERT INTO gifi (accno,description) VALUES ('2246', 'Due From/Investment In Foreign Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('2247', 'Shares In Foreign Related Corporations');
+INSERT INTO gifi (accno,description) VALUES ('2248', 'Loans/Advances To Foreign Related Corporations');
+INSERT INTO gifi (accno,description) VALUES ('2249', 'Investment In Foreign Related Corporations At Cost');
+INSERT INTO gifi (accno,description) VALUES ('2250', 'Investment In Foreign Related Corporations At Equity');
+INSERT INTO gifi (accno,description) VALUES ('2280', 'Investment In Co-Tenancy');
+INSERT INTO gifi (accno,description) VALUES ('2300', 'Long Term Investments');
+INSERT INTO gifi (accno,description) VALUES ('2301', 'Foreign Shares');
+INSERT INTO gifi (accno,description) VALUES ('2302', 'Other Type Of Foreign Investments');
+INSERT INTO gifi (accno,description) VALUES ('2303', 'Canadian Shares');
+INSERT INTO gifi (accno,description) VALUES ('2304', 'Government Of Canada Debt');
+INSERT INTO gifi (accno,description) VALUES ('2305', 'Canadian Provinvial & Municipal Government Debt');
+INSERT INTO gifi (accno,description) VALUES ('2306', 'Canadian Corporate Bonds & Debentures');
+INSERT INTO gifi (accno,description) VALUES ('2307', 'Debt Securities');
+INSERT INTO gifi (accno,description) VALUES ('2308', 'Equity Securities');
+INSERT INTO gifi (accno,description) VALUES ('2309', 'Securities Purchased Under Resale Agreements');
+INSERT INTO gifi (accno,description) VALUES ('2310', 'Central Credit Union Shares');
+INSERT INTO gifi (accno,description) VALUES ('2311', 'Other Long Term Canadian Investments');
+INSERT INTO gifi (accno,description) VALUES ('2360', 'Long Term Loans');
+INSERT INTO gifi (accno,description) VALUES ('2361', 'Mortgages');
+INSERT INTO gifi (accno,description) VALUES ('2362', 'Personal & Credit Card Loans');
+INSERT INTO gifi (accno,description) VALUES ('2363', 'Business & Government Loans');
+INSERT INTO gifi (accno,description) VALUES ('2364', 'Line Of Credit');
+INSERT INTO gifi (accno,description) VALUES ('2420', 'Other Long Term Assets');
+INSERT INTO gifi (accno,description) VALUES ('2421', 'Deferred Income Taxes / Tax Reserves');
+INSERT INTO gifi (accno,description) VALUES ('2422', 'Deferred Pension Charges');
+INSERT INTO gifi (accno,description) VALUES ('2423', 'Deferred Unrealized Exchange Losses');
+INSERT INTO gifi (accno,description) VALUES ('2424', 'Other Deferred Items/Charges');
+INSERT INTO gifi (accno,description) VALUES ('2425', 'Accumulated Amortization Of Deferred Charges');
+INSERT INTO gifi (accno,description) VALUES ('2426', 'Reserve Fund');
+INSERT INTO gifi (accno,description) VALUES ('2427', 'Cash Surrender Value Of Life Insurance');
+INSERT INTO gifi (accno,description) VALUES ('2589', 'Total Long Term Assets');
+INSERT INTO gifi (accno,description) VALUES ('2590', 'Assets Held In Trust');
+INSERT INTO gifi (accno,description) VALUES ('2599', 'Total Assets');
+INSERT INTO gifi (accno,description) VALUES ('2600', 'Bank Overdraft');
+INSERT INTO gifi (accno,description) VALUES ('2620', 'Amounts Payable & Accrued Liabilities');
+INSERT INTO gifi (accno,description) VALUES ('2621', 'Accounts Payable Trade');
+INSERT INTO gifi (accno,description) VALUES ('2622', 'Accounts Payable To Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('2623', 'Holdbacks Payable');
+INSERT INTO gifi (accno,description) VALUES ('2624', 'Wages Payable');
+INSERT INTO gifi (accno,description) VALUES ('2625', 'Management Fees Payable');
+INSERT INTO gifi (accno,description) VALUES ('2626', 'Bonuses Payable');
+INSERT INTO gifi (accno,description) VALUES ('2627', 'Employee Deductions Payable');
+INSERT INTO gifi (accno,description) VALUES ('2628', 'Withholding Taxes Payable');
+INSERT INTO gifi (accno,description) VALUES ('2629', 'Intrest Payable');
+INSERT INTO gifi (accno,description) VALUES ('2680', 'Taxes Payable');
+INSERT INTO gifi (accno,description) VALUES ('2681', 'Capital Taxes Payable');
+INSERT INTO gifi (accno,description) VALUES ('2682', 'Foreign Taxes Payable');
+INSERT INTO gifi (accno,description) VALUES ('2683', 'Federal Taxes Payable');
+INSERT INTO gifi (accno,description) VALUES ('2684', 'Provincial Taxes Payable');
+INSERT INTO gifi (accno,description) VALUES ('2685', 'GST Payable');
+INSERT INTO gifi (accno,description) VALUES ('2686', 'PST Payable');
+INSERT INTO gifi (accno,description) VALUES ('2700', 'Short Term Debt');
+INSERT INTO gifi (accno,description) VALUES ('2701', 'Loans From Canadian Banks');
+INSERT INTO gifi (accno,description) VALUES ('2702', 'Liability For Securities Sold Short');
+INSERT INTO gifi (accno,description) VALUES ('2703', 'Liability For Securities Sold Under Repurchase Agreements');
+INSERT INTO gifi (accno,description) VALUES ('2704', 'Gold & Silver Certificates');
+INSERT INTO gifi (accno,description) VALUES ('2705', 'Cheques & Other Items In Transit');
+INSERT INTO gifi (accno,description) VALUES ('2706', 'Lien Notes');
+INSERT INTO gifi (accno,description) VALUES ('2770', 'Deferred Income');
+INSERT INTO gifi (accno,description) VALUES ('2780', 'Due To Shareholder(s)/Director(s)');
+INSERT INTO gifi (accno,description) VALUES ('2781', 'Due To Individual Shareholder(s)');
+INSERT INTO gifi (accno,description) VALUES ('2782', 'Due To Corporate Shareholder(s)');
+INSERT INTO gifi (accno,description) VALUES ('2783', 'Due To Director(s)');
+INSERT INTO gifi (accno,description) VALUES ('2840', 'Due To Joint Venture(s)/Partnership(s)');
+INSERT INTO gifi (accno,description) VALUES ('2860', 'Due To Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('2861', 'Demand Notes Due To Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('2862', 'Interest Payable To Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('2863', 'Advances Due To Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('2920', 'Current Portion Of Long Term Liability');
+INSERT INTO gifi (accno,description) VALUES ('2960', 'Other Current Liabilities');
+INSERT INTO gifi (accno,description) VALUES ('2961', 'Deposits Received');
+INSERT INTO gifi (accno,description) VALUES ('2962', 'Dividends Payable');
+INSERT INTO gifi (accno,description) VALUES ('2963', 'Deferred Income Taxes');
+INSERT INTO gifi (accno,description) VALUES ('2964', 'Reserves For Guarantees, Warranties Or Indemnities');
+INSERT INTO gifi (accno,description) VALUES ('2965', 'General Reserves / Provisions');
+INSERT INTO gifi (accno,description) VALUES ('2966', 'Crew Shares');
+INSERT INTO gifi (accno,description) VALUES ('3139', 'Total Current Liabilities');
+INSERT INTO gifi (accno,description) VALUES ('3140', 'Long Term Debt');
+INSERT INTO gifi (accno,description) VALUES ('3141', 'Mortgages');
+INSERT INTO gifi (accno,description) VALUES ('3142', 'Farm Credit Corporation Loan');
+INSERT INTO gifi (accno,description) VALUES ('3143', 'Chartered Bank Loan');
+INSERT INTO gifi (accno,description) VALUES ('3144', 'Credit Union/Caisse Populaire Loan');
+INSERT INTO gifi (accno,description) VALUES ('3145', 'Provincial Government Loan');
+INSERT INTO gifi (accno,description) VALUES ('3146', 'Supply Company Loan');
+INSERT INTO gifi (accno,description) VALUES ('3147', 'Private Loan');
+INSERT INTO gifi (accno,description) VALUES ('3148', 'Central, Leagues And Federation Loans');
+INSERT INTO gifi (accno,description) VALUES ('3149', 'Line Of Credit');
+INSERT INTO gifi (accno,description) VALUES ('3150', 'Liability For Securities Sold Short');
+INSERT INTO gifi (accno,description) VALUES ('3151', 'Liability For Securities Sold Under Repurchase Agreements');
+INSERT INTO gifi (accno,description) VALUES ('3152', 'Lien Notes');
+INSERT INTO gifi (accno,description) VALUES ('3210', 'Bonds And Debentures');
+INSERT INTO gifi (accno,description) VALUES ('3220', 'Deferred Income');
+INSERT INTO gifi (accno,description) VALUES ('3240', 'Deferred Income Taxes');
+INSERT INTO gifi (accno,description) VALUES ('3260', 'Long Term Due To Shareholder(s)/Director(s)');
+INSERT INTO gifi (accno,description) VALUES ('3261', 'Long Term Due To Individual Shareholder(s)');
+INSERT INTO gifi (accno,description) VALUES ('3262', 'Long Term Due To Corporate Shareholder(s)');
+INSERT INTO gifi (accno,description) VALUES ('3263', 'Long Term Due To Director(s)');
+INSERT INTO gifi (accno,description) VALUES ('3280', 'Long Term Due To Joint Venture(s)/Partnership(s)');
+INSERT INTO gifi (accno,description) VALUES ('3300', 'Long Term Due To Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('3301', 'Amounts Owing To Related Canadian Parties');
+INSERT INTO gifi (accno,description) VALUES ('3302', 'Amounts Owing To Related Foreign Parties');
+INSERT INTO gifi (accno,description) VALUES ('3320', 'Other Long Term Liabilities');
+INSERT INTO gifi (accno,description) VALUES ('3321', 'Long Term Obligations/Commitments/Leases');
+INSERT INTO gifi (accno,description) VALUES ('3322', 'Reserves For Guarantees, Warranties Or Indemnities');
+INSERT INTO gifi (accno,description) VALUES ('3323', 'Provision For Site Restoration');
+INSERT INTO gifi (accno,description) VALUES ('3324', 'Contributions To Qualifying Environmental Trust');
+INSERT INTO gifi (accno,description) VALUES ('3325', 'General Provisions / Reserves');
+INSERT INTO gifi (accno,description) VALUES ('3326', 'Preference Shares Restated');
+INSERT INTO gifi (accno,description) VALUES ('3327', 'Member Allocations');
+INSERT INTO gifi (accno,description) VALUES ('3328', 'Deferred Income From Incomplete Contracts');
+INSERT INTO gifi (accno,description) VALUES ('3450', 'Total Long Term Liabilities');
+INSERT INTO gifi (accno,description) VALUES ('3460', 'Subordinated Debt');
+INSERT INTO gifi (accno,description) VALUES ('3470', 'Amounts Held In Trust');
+INSERT INTO gifi (accno,description) VALUES ('3499', 'Total Liabilities');
+INSERT INTO gifi (accno,description) VALUES ('3500', 'Common Shares');
+INSERT INTO gifi (accno,description) VALUES ('3520', 'Preferred Shares');
+INSERT INTO gifi (accno,description) VALUES ('3540', 'Contributed & Other Surplus');
+INSERT INTO gifi (accno,description) VALUES ('3541', 'Contributed Surplus');
+INSERT INTO gifi (accno,description) VALUES ('3542', 'Appraisal Surplus');
+INSERT INTO gifi (accno,description) VALUES ('3543', 'General Reserve');
+INSERT INTO gifi (accno,description) VALUES ('3570', 'Head Office Account');
+INSERT INTO gifi (accno,description) VALUES ('3600', 'Retained Earnings/Deficit');
+INSERT INTO gifi (accno,description) VALUES ('3620', 'Total Shareholder Equity');
+INSERT INTO gifi (accno,description) VALUES ('3640', 'Total Liabilities & Shareholder Equity');
+INSERT INTO gifi (accno,description) VALUES ('3660', 'Retained Earnings/Deficit Start');
+INSERT INTO gifi (accno,description) VALUES ('3680', 'Net Income/Loss');
+INSERT INTO gifi (accno,description) VALUES ('3700', 'Dividend Declared');
+INSERT INTO gifi (accno,description) VALUES ('3701', 'Cash Dividend');
+INSERT INTO gifi (accno,description) VALUES ('3702', 'Patronage Dividend');
+INSERT INTO gifi (accno,description) VALUES ('3720', 'Prior Year Adjustments');
+INSERT INTO gifi (accno,description) VALUES ('3740', 'Other Items Affecting Retained Earnings');
+INSERT INTO gifi (accno,description) VALUES ('3741', 'Share Redemptions');
+INSERT INTO gifi (accno,description) VALUES ('3742', 'Special Reserves');
+INSERT INTO gifi (accno,description) VALUES ('3743', 'Currency Adjustments');
+INSERT INTO gifi (accno,description) VALUES ('3744', 'Unusual Revenue Items');
+INSERT INTO gifi (accno,description) VALUES ('3745', 'Interfund Transfers (NPO)');
+INSERT INTO gifi (accno,description) VALUES ('3849', 'Retained Earnings/Deficit End');
+INSERT INTO gifi (accno,description) VALUES ('8000', 'Trade Sales of Goods and Services');
+INSERT INTO gifi (accno,description) VALUES ('8020', 'Sales To Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('8030', 'Interdivisional Sales');
+INSERT INTO gifi (accno,description) VALUES ('8040', 'Sales From Resource Properties');
+INSERT INTO gifi (accno,description) VALUES ('8041', 'Petroleum & Natural Gas Sales');
+INSERT INTO gifi (accno,description) VALUES ('8042', 'Petroleum & Natural Gas Sales To Related Parties');
+INSERT INTO gifi (accno,description) VALUES ('8043', 'Gas Marketing');
+INSERT INTO gifi (accno,description) VALUES ('8044', 'Processing Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8045', 'Pipeline Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8046', 'Seismic Sales');
+INSERT INTO gifi (accno,description) VALUES ('8047', 'Mining Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8048', 'Coal Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8049', 'Oil Sands Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8050', 'Royalty Income');
+INSERT INTO gifi (accno,description) VALUES ('8051', 'Oil & Gas Partnership/Joint Venture Income/Loss');
+INSERT INTO gifi (accno,description) VALUES ('8052', 'Mining Partnership/Joint Venture Income/Loss');
+INSERT INTO gifi (accno,description) VALUES ('8053', 'Other Production Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8089', 'Total Sales Of Goods And Services');
+INSERT INTO gifi (accno,description) VALUES ('8090', 'Investment Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8091', 'Interest From Foreign Sources');
+INSERT INTO gifi (accno,description) VALUES ('8092', 'Interest From Canadian Bonds And Debentures');
+INSERT INTO gifi (accno,description) VALUES ('8093', 'Interest From Canadian Mortgage Loans');
+INSERT INTO gifi (accno,description) VALUES ('8094', 'Interest From Other Canadian Sources');
+INSERT INTO gifi (accno,description) VALUES ('8095', 'Dividend Income');
+INSERT INTO gifi (accno,description) VALUES ('8096', 'Dividend From Canadian Sources');
+INSERT INTO gifi (accno,description) VALUES ('8097', 'Interest From Foreign Sources');
+INSERT INTO gifi (accno,description) VALUES ('8120', 'Commission Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8121', 'Commission Income On Real Estate Transactions');
+INSERT INTO gifi (accno,description) VALUES ('8140', 'Rental Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8141', 'Real Estate Rental Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8150', 'Vehicle Leasing');
+INSERT INTO gifi (accno,description) VALUES ('8160', 'Fishing Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8161', 'Fish Products');
+INSERT INTO gifi (accno,description) VALUES ('8162', 'Other Marine Products');
+INSERT INTO gifi (accno,description) VALUES ('8163', 'Fishing Grants, Credits & Rebates');
+INSERT INTO gifi (accno,description) VALUES ('8164', 'Fishing Subsidies');
+INSERT INTO gifi (accno,description) VALUES ('8165', 'Compensation For Loss Of Fishing Income/Property');
+INSERT INTO gifi (accno,description) VALUES ('8166', 'Sharesman Income');
+INSERT INTO gifi (accno,description) VALUES ('8210', 'Realized Gains/Losses On Disposal Of Assets');
+INSERT INTO gifi (accno,description) VALUES ('8211', 'Realized Gains/Losses On Sale Of Investments');
+INSERT INTO gifi (accno,description) VALUES ('8212', 'Realized Gains/Losses On Sale Of Resource Properties');
+INSERT INTO gifi (accno,description) VALUES ('8220', 'NPO Amounts Received');
+INSERT INTO gifi (accno,description) VALUES ('8221', 'Membership Fees');
+INSERT INTO gifi (accno,description) VALUES ('8222', 'Assessments');
+INSERT INTO gifi (accno,description) VALUES ('8223', 'Gifts');
+INSERT INTO gifi (accno,description) VALUES ('8224', 'Gross Sales And Revenues From Organizational Activities');
+INSERT INTO gifi (accno,description) VALUES ('8230', 'Other Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8231', 'Foreign Exchange Gains/Losses');
+INSERT INTO gifi (accno,description) VALUES ('8232', 'Income/Loss Of Subsidiaries/Affiliates');
+INSERT INTO gifi (accno,description) VALUES ('8233', 'Income/Loss Of Other Divisions');
+INSERT INTO gifi (accno,description) VALUES ('8234', 'Income/Loss Of Joint Ventures');
+INSERT INTO gifi (accno,description) VALUES ('8235', 'Income/Loss Of Partnerships');
+INSERT INTO gifi (accno,description) VALUES ('8236', 'RealizaTion Of Deferred Revenues');
+INSERT INTO gifi (accno,description) VALUES ('8237', 'Royalty Income Other Than Resource');
+INSERT INTO gifi (accno,description) VALUES ('8238', 'Alberta Royalty Tax Credits');
+INSERT INTO gifi (accno,description) VALUES ('8239', 'Management & Administration Fees');
+INSERT INTO gifi (accno,description) VALUES ('8240', 'Telecommunications Revenues');
+INSERT INTO gifi (accno,description) VALUES ('8241', 'Consulting Fees');
+INSERT INTO gifi (accno,description) VALUES ('8242', 'Subsidies & Grants');
+INSERT INTO gifi (accno,description) VALUES ('8243', 'Sale Of By-Products');
+INSERT INTO gifi (accno,description) VALUES ('8244', 'Deposit Services');
+INSERT INTO gifi (accno,description) VALUES ('8245', 'Credit Services');
+INSERT INTO gifi (accno,description) VALUES ('8246', 'Card Services');
+INSERT INTO gifi (accno,description) VALUES ('8247', 'Patronage Dividends');
+INSERT INTO gifi (accno,description) VALUES ('8248', 'Insurance Recoveries');
+INSERT INTO gifi (accno,description) VALUES ('8249', 'Expense Recoveries');
+INSERT INTO gifi (accno,description) VALUES ('8250', 'Bad Debt Recoveries');
+INSERT INTO gifi (accno,description) VALUES ('8299', 'Total Revenue');
+INSERT INTO gifi (accno,description) VALUES ('8300', 'Opening Inventory');
+INSERT INTO gifi (accno,description) VALUES ('8301', 'Opening Inventory - finished goods');
+INSERT INTO gifi (accno,description) VALUES ('8302', 'Opening Inventory - raw materials');
+INSERT INTO gifi (accno,description) VALUES ('8303', 'Opening Inventory - goods in process');
+INSERT INTO gifi (accno,description) VALUES ('8304', 'Opening Inventory - work in process');
+INSERT INTO gifi (accno,description) VALUES ('8320', 'Purchases / Cost of Materials');
+INSERT INTO gifi (accno,description) VALUES ('8321', 'Purchases Product A');
+INSERT INTO gifi (accno,description) VALUES ('8322', 'Purchases Product B');
+INSERT INTO gifi (accno,description) VALUES ('8331', 'Price Differences & Discounts On Purchases');
+INSERT INTO gifi (accno,description) VALUES ('8340', 'Direct Wages');
+INSERT INTO gifi (accno,description) VALUES ('8350', 'Benefits On Direct Wages');
+INSERT INTO gifi (accno,description) VALUES ('8360', 'Trades & Sub-contracts');
+INSERT INTO gifi (accno,description) VALUES ('8370', 'Production Costs Other Than Resource');
+INSERT INTO gifi (accno,description) VALUES ('8400', 'Resource Production Costs');
+INSERT INTO gifi (accno,description) VALUES ('8401', 'Pipeline Operations');
+INSERT INTO gifi (accno,description) VALUES ('8402', 'Drilling');
+INSERT INTO gifi (accno,description) VALUES ('8403', 'Site Restoration Costs');
+INSERT INTO gifi (accno,description) VALUES ('8404', 'Gross Overriding Royalty');
+INSERT INTO gifi (accno,description) VALUES ('8405', 'Freehold Royalties');
+INSERT INTO gifi (accno,description) VALUES ('8406', 'Other Producing Properties Rental');
+INSERT INTO gifi (accno,description) VALUES ('8407', 'Prospect & Geological');
+INSERT INTO gifi (accno,description) VALUES ('8408', 'Well Operating, Fuel & Equipment');
+INSERT INTO gifi (accno,description) VALUES ('8409', 'Well Abandonment & Dry Holes');
+INSERT INTO gifi (accno,description) VALUES ('8410', 'Other Lease Rentals');
+INSERT INTO gifi (accno,description) VALUES ('8411', 'Exploration Expenses, Aerial Surveys');
+INSERT INTO gifi (accno,description) VALUES ('8412', 'Development Expenses, stripping costs');
+INSERT INTO gifi (accno,description) VALUES ('8435', 'Crown Charges');
+INSERT INTO gifi (accno,description) VALUES ('8436', 'Crown royalties');
+INSERT INTO gifi (accno,description) VALUES ('8437', 'Crown lease rentals');
+INSERT INTO gifi (accno,description) VALUES ('8438', 'Freehold mineral tax');
+INSERT INTO gifi (accno,description) VALUES ('8439', 'Mining taxes');
+INSERT INTO gifi (accno,description) VALUES ('8440', 'Oil and Sand leases');
+INSERT INTO gifi (accno,description) VALUES ('8441', 'Saskatchewan resource surcharge');
+INSERT INTO gifi (accno,description) VALUES ('8450', 'Other Direct Costs');
+INSERT INTO gifi (accno,description) VALUES ('8451', 'Equipment Hire & Operation');
+INSERT INTO gifi (accno,description) VALUES ('8452', 'Log Yard');
+INSERT INTO gifi (accno,description) VALUES ('8453', 'Forestry costs');
+INSERT INTO gifi (accno,description) VALUES ('8454', 'Logging Road costs');
+INSERT INTO gifi (accno,description) VALUES ('8455', 'Stumpage costs');
+INSERT INTO gifi (accno,description) VALUES ('8456', 'Royalty costs');
+INSERT INTO gifi (accno,description) VALUES ('8457', 'Freight In & Customs Duty');
+INSERT INTO gifi (accno,description) VALUES ('8458', 'Inventory Write Down');
+INSERT INTO gifi (accno,description) VALUES ('8459', 'Direct cost amortization of tangible assets');
+INSERT INTO gifi (accno,description) VALUES ('8460', 'Direct cost amortization of natural resource assets');
+INSERT INTO gifi (accno,description) VALUES ('8461', 'Overhead expenses allocated to cost of sales');
+INSERT INTO gifi (accno,description) VALUES ('8500', 'Closing Inventory');
+INSERT INTO gifi (accno,description) VALUES ('8501', 'Closing Inventory - Finished Goods');
+INSERT INTO gifi (accno,description) VALUES ('8502', 'Closing Inventory - Raw Materials');
+INSERT INTO gifi (accno,description) VALUES ('8503', 'Closing Inventory - Goods In Process');
+INSERT INTO gifi (accno,description) VALUES ('8504', 'Closing Inventory - Work In Process');
+INSERT INTO gifi (accno,description) VALUES ('8518', 'Cost Of Sales');
+INSERT INTO gifi (accno,description) VALUES ('8519', 'Gross Profit/Loss');
+INSERT INTO gifi (accno,description) VALUES ('8520', 'Advertising & Promotion');
+INSERT INTO gifi (accno,description) VALUES ('8521', 'Advertising');
+INSERT INTO gifi (accno,description) VALUES ('8522', 'Donations');
+INSERT INTO gifi (accno,description) VALUES ('8523', 'Meals & Entertainment');
+INSERT INTO gifi (accno,description) VALUES ('8524', 'Promotion');
+INSERT INTO gifi (accno,description) VALUES ('8570', 'Amortization Of Intangible Assets');
+INSERT INTO gifi (accno,description) VALUES ('8590', 'Bad Debt Expense');
+INSERT INTO gifi (accno,description) VALUES ('8610', 'Loan Losses');
+INSERT INTO gifi (accno,description) VALUES ('8611', 'Provision for Loan Losses');
+INSERT INTO gifi (accno,description) VALUES ('8620', 'Employee Benefits');
+INSERT INTO gifi (accno,description) VALUES ('8621', 'Group Insurance Benefits');
+INSERT INTO gifi (accno,description) VALUES ('8622', 'Employers Portion Of Employee Benefits');
+INSERT INTO gifi (accno,description) VALUES ('8623', 'Contributions To Deferred Income Plans');
+INSERT INTO gifi (accno,description) VALUES ('8650', 'Amortization Of Natural Resource Assets');
+INSERT INTO gifi (accno,description) VALUES ('8670', 'Amortization Of Tangible Assets');
+INSERT INTO gifi (accno,description) VALUES ('8690', 'Insurance');
+INSERT INTO gifi (accno,description) VALUES ('8691', 'Life Insurance On Executives');
+INSERT INTO gifi (accno,description) VALUES ('8710', 'Interest & Bank Charges');
+INSERT INTO gifi (accno,description) VALUES ('8711', 'Interest On Short Term Debt');
+INSERT INTO gifi (accno,description) VALUES ('8712', 'Interest On Bonds And Debentures');
+INSERT INTO gifi (accno,description) VALUES ('8713', 'Interest On Mortgages');
+INSERT INTO gifi (accno,description) VALUES ('8714', 'Interest On Long Term Debt');
+INSERT INTO gifi (accno,description) VALUES ('8715', 'Bank Charges');
+INSERT INTO gifi (accno,description) VALUES ('8716', 'Credit Card Charges');
+INSERT INTO gifi (accno,description) VALUES ('8717', 'Collection & Credit costs');
+INSERT INTO gifi (accno,description) VALUES ('8760', 'Business Taxes, Licences & Memberships');
+INSERT INTO gifi (accno,description) VALUES ('8761', 'Memberships');
+INSERT INTO gifi (accno,description) VALUES ('8762', 'Business Taxes');
+INSERT INTO gifi (accno,description) VALUES ('8763', 'Franchise Fees');
+INSERT INTO gifi (accno,description) VALUES ('8764', 'Government Fees');
+INSERT INTO gifi (accno,description) VALUES ('8780', 'New Brunswick Tax On Large Corporations');
+INSERT INTO gifi (accno,description) VALUES ('8790', 'Nova Scotia Tax On Large Corporations');
+INSERT INTO gifi (accno,description) VALUES ('8810', 'Office Expenses');
+INSERT INTO gifi (accno,description) VALUES ('8811', 'Office Stationary And Supplies');
+INSERT INTO gifi (accno,description) VALUES ('8812', 'Office Utilities');
+INSERT INTO gifi (accno,description) VALUES ('8813', 'Data Processing');
+INSERT INTO gifi (accno,description) VALUES ('8860', 'Professional Fees');
+INSERT INTO gifi (accno,description) VALUES ('8861', 'Legal Fees');
+INSERT INTO gifi (accno,description) VALUES ('8862', 'Accounting Fees');
+INSERT INTO gifi (accno,description) VALUES ('8863', 'Consulting Fees');
+INSERT INTO gifi (accno,description) VALUES ('8864', 'Architect Fees');
+INSERT INTO gifi (accno,description) VALUES ('8865', 'Appraisal Fees');
+INSERT INTO gifi (accno,description) VALUES ('8866', 'Laboratory Fees');
+INSERT INTO gifi (accno,description) VALUES ('8867', 'Medical Fees');
+INSERT INTO gifi (accno,description) VALUES ('8868', 'Veterinary Fees');
+INSERT INTO gifi (accno,description) VALUES ('8869', 'Brokerage Fees');
+INSERT INTO gifi (accno,description) VALUES ('8870', 'Transfer Fees');
+INSERT INTO gifi (accno,description) VALUES ('8871', 'Management & Administration Fees');
+INSERT INTO gifi (accno,description) VALUES ('8872', 'Refining & Assay');
+INSERT INTO gifi (accno,description) VALUES ('8873', 'Registrar & Transfer Agent Fees');
+INSERT INTO gifi (accno,description) VALUES ('8874', 'Restructuring Costs');
+INSERT INTO gifi (accno,description) VALUES ('8875', 'Security & Exchange Commission Fees');
+INSERT INTO gifi (accno,description) VALUES ('8876', 'Training Expense');
+INSERT INTO gifi (accno,description) VALUES ('8877', 'Studio & Recording');
+INSERT INTO gifi (accno,description) VALUES ('8910', 'Rental');
+INSERT INTO gifi (accno,description) VALUES ('8911', 'Real Estate Rental');
+INSERT INTO gifi (accno,description) VALUES ('8912', 'Occupancy Costs');
+INSERT INTO gifi (accno,description) VALUES ('8913', 'Condominium Fees');
+INSERT INTO gifi (accno,description) VALUES ('8914', 'Equipment Rental');
+INSERT INTO gifi (accno,description) VALUES ('8915', 'Motor Vehicle Rental');
+INSERT INTO gifi (accno,description) VALUES ('8916', 'Moorage (Boat)');
+INSERT INTO gifi (accno,description) VALUES ('8917', 'Storage');
+INSERT INTO gifi (accno,description) VALUES ('8918', 'Quota Rental');
+INSERT INTO gifi (accno,description) VALUES ('8960', 'Repairs & Maintenance - Aircraft');
+INSERT INTO gifi (accno,description) VALUES ('8961', 'Repairs & Maintenance - Buildings');
+INSERT INTO gifi (accno,description) VALUES ('8962', 'Repairs & Maintenance - Vehicles');
+INSERT INTO gifi (accno,description) VALUES ('8963', 'Repairs & Maintenance - Boats');
+INSERT INTO gifi (accno,description) VALUES ('8964', 'Repairs & Maintenance - Machinery & Equipment');
+INSERT INTO gifi (accno,description) VALUES ('9010', 'Other Repairs & Maintenance - Janitor & Yard');
+INSERT INTO gifi (accno,description) VALUES ('9011', 'Machine Shop Expense');
+INSERT INTO gifi (accno,description) VALUES ('9012', 'Road Costs');
+INSERT INTO gifi (accno,description) VALUES ('9013', 'Security');
+INSERT INTO gifi (accno,description) VALUES ('9014', 'Garbage Removal');
+INSERT INTO gifi (accno,description) VALUES ('9060', 'Salaries & Wages');
+INSERT INTO gifi (accno,description) VALUES ('9061', 'Commissions');
+INSERT INTO gifi (accno,description) VALUES ('9062', 'Crew Share');
+INSERT INTO gifi (accno,description) VALUES ('9063', 'Bonuses');
+INSERT INTO gifi (accno,description) VALUES ('9064', 'Director''s Fees');
+INSERT INTO gifi (accno,description) VALUES ('9065', 'Management Salaries');
+INSERT INTO gifi (accno,description) VALUES ('9066', 'Employee Salaries');
+INSERT INTO gifi (accno,description) VALUES ('9110', 'Sub-Contracts');
+INSERT INTO gifi (accno,description) VALUES ('9130', 'Supplies');
+INSERT INTO gifi (accno,description) VALUES ('9131', 'Small Tools');
+INSERT INTO gifi (accno,description) VALUES ('9132', 'Shop Expense');
+INSERT INTO gifi (accno,description) VALUES ('9133', 'Uniforms');
+INSERT INTO gifi (accno,description) VALUES ('9134', 'Laundry');
+INSERT INTO gifi (accno,description) VALUES ('9135', 'Food & Catering');
+INSERT INTO gifi (accno,description) VALUES ('9136', 'Fishing Gear');
+INSERT INTO gifi (accno,description) VALUES ('9137', 'Nets & Traps');
+INSERT INTO gifi (accno,description) VALUES ('9138', 'Salt, Bait & Ice');
+INSERT INTO gifi (accno,description) VALUES ('9139', 'Camp Supplies');
+INSERT INTO gifi (accno,description) VALUES ('9150', 'Computer Related Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9151', 'Upgrade');
+INSERT INTO gifi (accno,description) VALUES ('9152', 'Internet');
+INSERT INTO gifi (accno,description) VALUES ('9180', 'Property Taxes');
+INSERT INTO gifi (accno,description) VALUES ('9200', 'Travel Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9201', 'Meetings & Conventions');
+INSERT INTO gifi (accno,description) VALUES ('9220', 'Utilities');
+INSERT INTO gifi (accno,description) VALUES ('9221', 'Electricity');
+INSERT INTO gifi (accno,description) VALUES ('9222', 'Water');
+INSERT INTO gifi (accno,description) VALUES ('9223', 'Heat');
+INSERT INTO gifi (accno,description) VALUES ('9224', 'Fuel Costs');
+INSERT INTO gifi (accno,description) VALUES ('9225', 'Telephone & Communications');
+INSERT INTO gifi (accno,description) VALUES ('9270', 'Other Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9271', 'Cash Over/Short');
+INSERT INTO gifi (accno,description) VALUES ('9272', 'Reimbursement Of Parent Company Expense');
+INSERT INTO gifi (accno,description) VALUES ('9273', 'Selling Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9274', 'Shipping & Warehouse Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9275', 'Delivery, Freight & Express');
+INSERT INTO gifi (accno,description) VALUES ('9276', 'Warranty Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9277', 'Royalty Expenses - Resident');
+INSERT INTO gifi (accno,description) VALUES ('9278', 'Royalty Expenses - Non-Resident');
+INSERT INTO gifi (accno,description) VALUES ('9279', 'Dumping Charges');
+INSERT INTO gifi (accno,description) VALUES ('9280', 'Land Fill Fees');
+INSERT INTO gifi (accno,description) VALUES ('9281', 'Vehicle Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9282', 'Research & Development');
+INSERT INTO gifi (accno,description) VALUES ('9283', 'Withholding Taxes');
+INSERT INTO gifi (accno,description) VALUES ('9284', 'General & Administrative Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9285', 'Interdivisional Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9286', 'Interfund Transfer (NPO)');
+INSERT INTO gifi (accno,description) VALUES ('9367', 'Total Operating Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9368', 'Total Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9369', 'Net Non-Farming Income');
+INSERT INTO gifi (accno,description) VALUES ('9370', 'Grains And Oilseeds');
+INSERT INTO gifi (accno,description) VALUES ('9371', 'Wheat');
+INSERT INTO gifi (accno,description) VALUES ('9372', 'Oats');
+INSERT INTO gifi (accno,description) VALUES ('9373', 'Barley');
+INSERT INTO gifi (accno,description) VALUES ('9374', 'Mixed Grains');
+INSERT INTO gifi (accno,description) VALUES ('9375', 'Corn');
+INSERT INTO gifi (accno,description) VALUES ('9376', 'Canola');
+INSERT INTO gifi (accno,description) VALUES ('9377', 'Flaxseed');
+INSERT INTO gifi (accno,description) VALUES ('9378', 'Soya Beans');
+INSERT INTO gifi (accno,description) VALUES ('9379', 'Wheat Board Payments');
+INSERT INTO gifi (accno,description) VALUES ('9420', 'Other Crop Revenues');
+INSERT INTO gifi (accno,description) VALUES ('9321', 'Fruit');
+INSERT INTO gifi (accno,description) VALUES ('9322', 'Potatoes');
+INSERT INTO gifi (accno,description) VALUES ('9323', 'Vegetables');
+INSERT INTO gifi (accno,description) VALUES ('9324', 'Tobacco');
+INSERT INTO gifi (accno,description) VALUES ('9325', 'Greenhouse & Nursery Products');
+INSERT INTO gifi (accno,description) VALUES ('9326', 'Forage Crops');
+INSERT INTO gifi (accno,description) VALUES ('9470', 'Livestock & Animal Products Revenue');
+INSERT INTO gifi (accno,description) VALUES ('9471', 'Cattle');
+INSERT INTO gifi (accno,description) VALUES ('9472', 'Swine');
+INSERT INTO gifi (accno,description) VALUES ('9473', 'Poultry');
+INSERT INTO gifi (accno,description) VALUES ('9474', 'Sheep & Lambs');
+INSERT INTO gifi (accno,description) VALUES ('9475', 'Pregnant Mare Urine (PMU)');
+INSERT INTO gifi (accno,description) VALUES ('9476', 'Milk & Cream - Excluding Dairy Subsidies');
+INSERT INTO gifi (accno,description) VALUES ('9477', 'Eggs For Consumption');
+INSERT INTO gifi (accno,description) VALUES ('9478', 'Hatching Eggs');
+INSERT INTO gifi (accno,description) VALUES ('9479', 'Aquaculture');
+INSERT INTO gifi (accno,description) VALUES ('9480', 'Horses - Breeding & Meat');
+INSERT INTO gifi (accno,description) VALUES ('9520', 'Other Commodities');
+INSERT INTO gifi (accno,description) VALUES ('9521', 'Maple Products');
+INSERT INTO gifi (accno,description) VALUES ('9522', 'Artificial Insemination (AI)');
+INSERT INTO gifi (accno,description) VALUES ('9523', 'Semen Production');
+INSERT INTO gifi (accno,description) VALUES ('9524', 'Embryo Production');
+INSERT INTO gifi (accno,description) VALUES ('9540', 'Program Payment Revenues');
+INSERT INTO gifi (accno,description) VALUES ('9541', 'Dairy Subsidies');
+INSERT INTO gifi (accno,description) VALUES ('9542', 'Crop Insurance');
+INSERT INTO gifi (accno,description) VALUES ('9543', 'NISA Payments');
+INSERT INTO gifi (accno,description) VALUES ('9544', 'Disaster Assistance Program Payments');
+INSERT INTO gifi (accno,description) VALUES ('9570', 'Rebates');
+INSERT INTO gifi (accno,description) VALUES ('9571', 'Rebates - Fuel');
+INSERT INTO gifi (accno,description) VALUES ('9572', 'Rebates - Interest');
+INSERT INTO gifi (accno,description) VALUES ('9573', 'Rebates - Property Taxes');
+INSERT INTO gifi (accno,description) VALUES ('9574', 'Resales, Rebates, GST For NISA Eligible Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9575', 'Rebates, GST For NISA Non-Eligible Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9600', 'Other Farm Revenues/Losses');
+INSERT INTO gifi (accno,description) VALUES ('9601', 'Custom Or Contract Work');
+INSERT INTO gifi (accno,description) VALUES ('9602', 'Wood Sales');
+INSERT INTO gifi (accno,description) VALUES ('9603', 'Horse Racing');
+INSERT INTO gifi (accno,description) VALUES ('9604', 'Insurance Proceeds');
+INSERT INTO gifi (accno,description) VALUES ('9605', 'Patronage Dividends');
+INSERT INTO gifi (accno,description) VALUES ('9606', 'Rental Income');
+INSERT INTO gifi (accno,description) VALUES ('9607', 'Interest Income');
+INSERT INTO gifi (accno,description) VALUES ('9608', 'Dividend Income');
+INSERT INTO gifi (accno,description) VALUES ('9609', 'Gains/Losses On Disposal Of Assets');
+INSERT INTO gifi (accno,description) VALUES ('9610', 'Gravel');
+INSERT INTO gifi (accno,description) VALUES ('9611', 'Trucking');
+INSERT INTO gifi (accno,description) VALUES ('9612', 'Resale Of Commodities Purchased');
+INSERT INTO gifi (accno,description) VALUES ('9613', 'Leases');
+INSERT INTO gifi (accno,description) VALUES ('9614', 'Machine Rentals');
+INSERT INTO gifi (accno,description) VALUES ('9615', 'Farming Partnership Income/Loss');
+INSERT INTO gifi (accno,description) VALUES ('9616', 'Farming Joint Venture Income/Loss');
+INSERT INTO gifi (accno,description) VALUES ('9650', 'Non-Farming Income');
+INSERT INTO gifi (accno,description) VALUES ('9659', 'Total Farm Revenue');
+INSERT INTO gifi (accno,description) VALUES ('9660', 'Crop Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9661', 'Containers, Twine And Baling Wire');
+INSERT INTO gifi (accno,description) VALUES ('9662', 'Fertilizers And Lime');
+INSERT INTO gifi (accno,description) VALUES ('9663', 'Pesticides');
+INSERT INTO gifi (accno,description) VALUES ('9664', 'Seeds & Plants');
+INSERT INTO gifi (accno,description) VALUES ('9665', 'Insurance Premiums (Crop) NISA ACS');
+INSERT INTO gifi (accno,description) VALUES ('9710', 'Livestock Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9711', 'Feed, Supplements, Straw & Bedding');
+INSERT INTO gifi (accno,description) VALUES ('9712', 'Livestock Purchases');
+INSERT INTO gifi (accno,description) VALUES ('9713', 'Veterinary Fees, Medicine & Breeding Fees');
+INSERT INTO gifi (accno,description) VALUES ('9760', 'Machinery Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9761', 'Machinery Insurance');
+INSERT INTO gifi (accno,description) VALUES ('9762', 'Machinery Licences');
+INSERT INTO gifi (accno,description) VALUES ('9763', 'Machinery Repairs');
+INSERT INTO gifi (accno,description) VALUES ('9764', 'Machinery Fuel');
+INSERT INTO gifi (accno,description) VALUES ('9765', 'Machinery Lease');
+INSERT INTO gifi (accno,description) VALUES ('9790', 'General Farm Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9791', 'Amortization Of Tangible Assets');
+INSERT INTO gifi (accno,description) VALUES ('9792', 'Advertising, Marketing Costs & Promotion');
+INSERT INTO gifi (accno,description) VALUES ('9793', 'Bad Debt');
+INSERT INTO gifi (accno,description) VALUES ('9794', 'Benefits Related To Employee Salaries');
+INSERT INTO gifi (accno,description) VALUES ('9795', 'Building Repairs & Maintenance');
+INSERT INTO gifi (accno,description) VALUES ('9796', 'Clearing, Levelling & Draining Land');
+INSERT INTO gifi (accno,description) VALUES ('9797', 'Crop Insurance, GRIP and Stabilization Premiums');
+INSERT INTO gifi (accno,description) VALUES ('9798', 'Custom Or Contract Work');
+INSERT INTO gifi (accno,description) VALUES ('9799', 'Electricity');
+INSERT INTO gifi (accno,description) VALUES ('9800', 'Fence Repairs & Maintenance');
+INSERT INTO gifi (accno,description) VALUES ('9801', 'Freight & Trucking');
+INSERT INTO gifi (accno,description) VALUES ('9802', 'Heating Fuel & Curing Fuel');
+INSERT INTO gifi (accno,description) VALUES ('9803', 'Insurance Program Overpayment Recapture');
+INSERT INTO gifi (accno,description) VALUES ('9804', 'Other Insurance Premiums');
+INSERT INTO gifi (accno,description) VALUES ('9805', 'Interest & Bank Charges');
+INSERT INTO gifi (accno,description) VALUES ('9806', 'Marketing Board Fees');
+INSERT INTO gifi (accno,description) VALUES ('9807', 'Membership/Subscription Fees');
+INSERT INTO gifi (accno,description) VALUES ('9808', 'Office Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9809', 'Professional Fees');
+INSERT INTO gifi (accno,description) VALUES ('9810', 'Property Taxes');
+INSERT INTO gifi (accno,description) VALUES ('9811', 'Rent - Land & Buildings');
+INSERT INTO gifi (accno,description) VALUES ('9812', 'Rent - Machinery');
+INSERT INTO gifi (accno,description) VALUES ('9813', 'Other Rental Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9814', 'Salaries & Wages');
+INSERT INTO gifi (accno,description) VALUES ('9815', 'Salaries & Wages Other Than Spouse Or Dependants');
+INSERT INTO gifi (accno,description) VALUES ('9816', 'Salaries & Wages Paid To Dependants');
+INSERT INTO gifi (accno,description) VALUES ('9817', 'Selling Costs');
+INSERT INTO gifi (accno,description) VALUES ('9818', 'Supplies');
+INSERT INTO gifi (accno,description) VALUES ('9819', 'Motor Vehicle Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9820', 'Small Tools');
+INSERT INTO gifi (accno,description) VALUES ('9821', 'Soil Testing');
+INSERT INTO gifi (accno,description) VALUES ('9822', 'Storage/Drying');
+INSERT INTO gifi (accno,description) VALUES ('9823', 'Licences/Permits');
+INSERT INTO gifi (accno,description) VALUES ('9824', 'Telephone');
+INSERT INTO gifi (accno,description) VALUES ('9825', 'Quota Rental');
+INSERT INTO gifi (accno,description) VALUES ('9826', 'Gravel');
+INSERT INTO gifi (accno,description) VALUES ('9827', 'Purchases Of Commodities Resold');
+INSERT INTO gifi (accno,description) VALUES ('9828', 'Salaries & Wages Paid To Spouse');
+INSERT INTO gifi (accno,description) VALUES ('9829', 'Motor Vehicle Interest And Leasing Costs');
+INSERT INTO gifi (accno,description) VALUES ('9830', 'Prepared Feed');
+INSERT INTO gifi (accno,description) VALUES ('9831', 'Custom Feed');
+INSERT INTO gifi (accno,description) VALUES ('9832', 'Amortization Of Intangible Assets');
+INSERT INTO gifi (accno,description) VALUES ('9833', 'Amortization Of Milk Quota');
+INSERT INTO gifi (accno,description) VALUES ('9834', 'Travel Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9835', 'Capital/Business Taxes');
+INSERT INTO gifi (accno,description) VALUES ('9850', 'Non-Farming Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9870', 'Net Inventory Adjustment');
+INSERT INTO gifi (accno,description) VALUES ('9898', 'Total Farm Expenses');
+INSERT INTO gifi (accno,description) VALUES ('9899', 'Net Farm Income');
+INSERT INTO gifi (accno,description) VALUES ('9970', 'Net Income/Loss Before Taxes And Extraordinary Items');
+INSERT INTO gifi (accno,description) VALUES ('9975', 'Extraordinary Items');
+INSERT INTO gifi (accno,description) VALUES ('9976', 'Legal Settlements');
+INSERT INTO gifi (accno,description) VALUES ('9980', 'Unrealized Gains/Losses');
+INSERT INTO gifi (accno,description) VALUES ('9985', 'Unusual Items');
+INSERT INTO gifi (accno,description) VALUES ('9990', 'Current Income Taxes');
+INSERT INTO gifi (accno,description) VALUES ('9995', 'Deferred Income Tax Provision');
+INSERT INTO gifi (accno,description) VALUES ('9999', 'Net Income/Loss After Taxes And Extraordinary Items');
+-- This item represents the net amount of:
+-- Item 9970 - Net income/loss before taxes and extraordinary items minus
+-- Item 9975 - Extraordinary item(s) minus
+-- Item 9976 - Legal settlements plus
+-- Item 9980 - Unrealized gains/losses minus
+-- Item 9985 - Unusual items minus
+-- Item 9990 - Current income taxes minus
+-- Item 9995 - Deferred income tax provision
+-- and must be reported.
+-- Any amount reported in this item should be equal to the amount reported at Item 3680 - Net income/loss,
+-- in the retained earnings section.
+--
diff --git a/sql-ledger/sql/Canada_General-chart.sql b/sql-ledger/sql/Canada_General-chart.sql
new file mode 100644
index 0000000..a0b9e7f
--- /dev/null
+++ b/sql-ledger/sql/Canada_General-chart.sql
@@ -0,0 +1,77 @@
+-- General Canadian COA
+-- sample only
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1000','CURRENT ASSETS','H','1000','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1060','Chequing Account','A','1002','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1065','Petty Cash','A','1001','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200','Accounts Receivables','A','1060','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1205','Allowance for doubtful accounts','A','1063','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1500','INVENTORY ASSETS','H','1120','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1520','Inventory / General','A','1122','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1530','Inventory / Aftermarket Parts','A','1122','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1540','Inventory / Computer Parts','A','1122','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800','CAPITAL ASSETS','H','1900','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1820','Office Furniture & Equipment','A','1787','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1825','Accum. Amort. -Furn. & Equip.','A','1788','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1840','Vehicle','A','1742','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1845','Accum. Amort. -Vehicle','A','1743','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000','CURRENT LIABILITIES','H','2620','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2100','Accounts Payable','A','2621','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2160','Federal Taxes Payable','A','2683','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2170','Provincial Taxes Payable','A','2684','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2310','GST','A','2685','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2320','PST','A','2686','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2380','Vacation Pay Payable','A','2624','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2390','WCB Payable','A','2627','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2400','PAYROLL DEDUCTIONS','H','2620','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2410','EI Payable','A','2627','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2420','CPP Payable','A','2627','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2450','Income Tax Payable','A','2628','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2600','LONG TERM LIABILITIES','H','3140','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2620','Bank Loans','A','2701','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2680','Loans from Shareholders','A','2780','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3300','SHARE CAPITAL','H','3500','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3350','Common Shares','A','3500','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4000','SALES REVENUE','H','8000','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4020','General Sales','A','8000','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4030','Aftermarket Parts','A','8000','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4040','Computer Parts','A','8000','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4300','CONSULTING REVENUE','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4320','Consulting','A','8241','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4330','Programming','A','8000','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4340','Shop Labour','A','8000','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4400','OTHER REVENUE','H','8090','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4430','Shipping & Handling','A','8457','I','IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4440','Interest','A','8090','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4450','Foreign Exchange Gain','A','8231','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5000','COST OF GOODS SOLD','H','8515','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5010','Purchases','A','8320','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5050','Aftermarket Parts','A','8320','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5060','Computer Parts','A','8320','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5100','Freight','A','8457','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5400','PAYROLL EXPENSES','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5410','Wages & Salaries','A','9060','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5420','EI Expense','A','8622','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5430','CPP Expense','A','8622','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5440','WCB Expense','A','8622','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5600','GENERAL & ADMINISTRATIVE EXPENSES','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5610','Accounting & Legal','A','8862','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5615','Advertising & Promotions','A','8520','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5620','Bad Debts','A','8590','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5660','Amortization Expense','A','8670','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5680','Income Taxes','A','9990','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5685','Insurance','A','9804','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5690','Interest & Bank Charges','A','9805','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5700','Office Supplies','A','8811','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5760','Rent','A','9811','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5765','Repair & Maintenance','A','8964','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5780','Telephone','A','9225','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5785','Travel & Entertainment','A','8523','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5790','Utilities','A','8812','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5800','Licenses','A','8760','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5810','Foreign Exchange Loss','A','8231','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2310'),0.07);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2320'),0.08);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '5010'), fxgain_accno_id = (select id from chart where accno = '4450'), fxloss_accno_id = (select id from chart where accno = '5810'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'CAD:USD:EUR', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Czech_Republic-chart.sql b/sql-ledger/sql/Czech_Republic-chart.sql
new file mode 100644
index 0000000..c43fed4
--- /dev/null
+++ b/sql-ledger/sql/Czech_Republic-chart.sql
@@ -0,0 +1,317 @@
+-- Czech chart of accounts
+-- Tomas.Fencl@centrum.cz
+-- Kompletní úètová osnova platná v roce 2001
+-- Osnova má 2 místa pro tvorbu analytik
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1000', 'Dlouhodobý nehmotný majetek','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1100', 'Zøizovací výdaje','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200', 'Nehmotné výsledky výzkumu a vývoje','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1300', 'Software','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1400', 'Ocenitelná práva','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800', 'Drobný dlouhodobý nehmotný majetek','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1900', 'Ostatní dlouhodobý nehmotný majetek','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000', 'Dlouhodobý Hmotný majetek odpisovaný','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2100', 'Stavby','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2200', 'Samostatné movité vìci a soubory movitých vìcí','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2500', 'Pìstitelské celky trvalých porostù','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2600', 'Základní stádo a ta¾ná zvíøata','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2800', 'Drobný dlouhodobý hmotný majetek','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2900', 'Ostatní dlouhodobý hmotný majetek','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3000', 'Dlouhodobý hmotný majetek neodpisovaný','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3100', 'Pozemky','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3200', 'Umìlecká díla a sbírky','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4000', 'Poøízení dlouhodobého nehmotného a hmotného majetku','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4100', 'Poøízení dlouhodobého nehmotného majetku','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4200', 'Poøízení dlouhodobého hmotného majetku','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5000', 'Poskytnuté zálohy na dlouhodobý nehmotný a hmotný majetek','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5100', 'Poskytnuté zálohy na dlouhodobý nehmotný majetek','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5200', 'Poskytnuté zálohy na dlouhodobý hmotný majetek','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6000', 'Dlouhodobý finanèní majetek','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6100', 'Podílové cenné papíry a vklady v podnicích s rozhodujícím','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6200', 'Podílové cenné papíry a vklady v podnicích s podstatným','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6300', 'Ostatní dlouhodobé cenné papíry a vklady','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6600', 'Pùjèky podnikùm ve skupinì','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6700', 'Ostatní pùjèky','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6900', 'Ostatní dlouhodobý finanèní majetek','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7000', 'Oprávky k dlouhodobému nehmotnému majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7100', 'Oprávky ke zøizovacím výdajùm','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7200', 'Oprávky k nehmotným výsledkùm výzkumu a vývoje','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7300', 'Oprávky k softwaru','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7400', 'Oprávky k ocenitelným právùm','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7800', 'Oprávky k drobnému dlouhodobému nehmotnému majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7900', 'Oprávky k ostatnímu dlouhodobému nehmotnému majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8000', 'Oprávky k dlouhodobému hmotnému majetku','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8100', 'Oprávky ke stavbám','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8200', 'Oprávky k samostatným movitým vìcem a souborùm movitých vìcí','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8500', 'Oprávky k pìstitelským celkùm trvalých porostù','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8600', 'Oprávky k základnímu stádu a ta¾ným zvíøatùm','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8800', 'Oprávky k drobnému dlouhodobému hmotnému majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8900', 'Oprávky k ostatnímu dlouhodobému hmotnému majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9000', 'Opravné polo¾ky k dlouhodobému majetku','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9100', 'Opravná polo¾ka k dlouhodobému nehmotnému majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9200', 'Opravná polo¾ka k dlouhodobému hmotnému majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9300', 'Opravná polo¾ka k dlouhodobému nedokonèenému nehmotnému','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9400', 'Opravná polo¾ka k dlouhodobému nedokonèenému hmotnému','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9500', 'Opravná polo¾ka k poskytnutým zálohám','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9600', 'Opravná polo¾ka k dlouhodobému finanènímu majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9700', 'Opravná polo¾ka k nabytému majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9800', 'Oprávky k opravné polo¾ce k nabytému majetku','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('10000', 'Zásoby','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('11000', 'Materiál','H','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('11100', 'Poøízení materiálu','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('11200', 'Materiál na skladì','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('11900', 'Materiál na cestì','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('12000', 'Zásoby vlastní výroby','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('12100', 'Nedokonèená výroba','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('12200', 'Polotovary vlastní výroby','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('12300', 'Výrobky','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('12400', 'Zvíøata','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('13000', 'Zbo¾í','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('13100', 'Poøízení zbo¾í','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('13200', 'Zbo¾í na skladì a v prodejnách','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('13900', 'Zbo¾í na cestì','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('19000', 'Opravné polo¾ky k zásobám','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('19100', 'Opravná polo¾ka k materiálu','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('19200', 'Opravná polo¾ka k nedokonèené výrobì','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('19300', 'Opravná polo¾ka k polotovarùm vlastní výroby','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('19400', 'Opravná polo¾ka k výrobkùm','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('19500', 'Opravná polo¾ka ke zvíøatùm','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('19600', 'Opravná polo¾ka ke zbo¾í','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('20000', 'Finanèní úèty','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('21000', 'Peníze','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('21100', 'Pokladna','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('21300', 'Ceniny','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('22000', 'Úèty v bankách','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('22100', 'Bankovní úèty','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('22200', 'Bankovní úèty klientù','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('23000', 'Bì¾né bankovní úvìry','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('23100', 'Krátkodobé bankovní úvìry','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('23200', 'Eskontní úvìry','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('24000', 'Jiné krátkodobé finanèní výpomoci','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('24100', 'Emitované krátkodobé dluhopisy','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('24900', 'Ostatní krátkodobé finanèní výpomoci','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('25000', 'Krátkodobý finanèní majetek','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('25100', 'Majetkové cenné papíry','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('25200', 'Vlastní akcie a vlastní obchodní podíly','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('25300', 'Dlu¾né cenné papíry','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('25500', 'Vlastní dluhopisy','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('25600', 'Ostatní cenné papíry','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('26000', 'Pøevody mezi finanèními úèty','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('26100', 'Peníze na cestì','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('29000', 'Opravné polo¾ky ke krátkodobému finanènímu majetku','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('29100', 'Opravná polo¾ka k majetkovým cenným papírùm','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('29300', 'Opravná polo¾ka k dlu¾ným cenným papírùm','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('30000', 'Zúètovací vztahy','H','','H','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('31000', 'Pohledávky','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('31100', 'Odbìratelé','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('31200', 'Smìnky k inkasu','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('31300', 'Pohledávky za eskontované cenné papíry','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('31400', 'Poskytnuté provozní zálohy','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('31500', 'Ostatní pohledávky','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('32000', 'Závazky','H','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('32100', 'Dodavatelé','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('32200', 'Smìnky k úhradì','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('32400', 'Pøijaté zálohy','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('32500', 'Ostatní závazky','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('32600', ' Závazky vùèi klientùm','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('32700', ' Závazky vùèi trhùm','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('33000', 'Zúètování se zamìstnanci a institucemi','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('33100', 'Zamìstnanci','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('33300', 'Ostatní závazky vùèi zamìstnancùm','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('33500', 'Pohledávky za zamìstnanci','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('33600', 'Zúètování s institucemi sociálního zabezpeèení a zdravotního','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34000', 'Zúètování daní a dotací','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34100', 'Daò z pøíjmù','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34200', 'Ostatní pøímé danì','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34300', 'Daò z pøidané hodnoty - zúètování','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34311', 'DPH 5% vstup','A','','L','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34312', 'DPH 22% vstup','A','','L','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34321', 'DPH 5% výstup','A','','L','AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34322', 'DPH 22% výstup','A','','L','AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34500', 'Ostatní danì a poplatky','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34600', 'Dotace ze státního rozpoètu','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('34700', 'Ostatní dotace','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('35000', 'Pohledávky ke spoleèníkùm a sdru¾ení','H','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('35100', 'Pohledávky k podnikùm ve skupinì','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('35300', 'Pohledávky za upsaný vlastní kapitál','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('35400', 'Pohledávky za spoleèníky pøi úhradì ztráty','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('35500', 'Ostatní pohledávky za spoleèníky','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('35800', 'Pohledávky k úèastníkùm sdru¾ení','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('36000', 'Závazky ke spoleèníkùm a sdru¾ení','H','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('36100', 'Závazky k podnikùm ve skupinì','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('36400', 'Závazky ke spoleèníkùm pøi rozdìlování zisku','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('36500', 'Ostatní závazky ke spoleèníkùm','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('36600', 'Závazky ke spoleèníkùm a èlenùm dru¾stva ze závislé','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('36700', 'Závazky z upsaných nesplacených cenných papírù a vkladù','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('36800', 'Závazky k úèastníkùm sdru¾ení','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('37000', 'Jiné pohledávky a závazky','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('37100', 'Odlo¾ená daòová pohledávka a závazek','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('37300', 'Nakoupené opce','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('37400', 'Prodané opce','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('37500', 'Pohledávky z emitovaných dluhopisù','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('37700', ' Zúètování obchodù','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('37800', 'Jiné pohledávky','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('37900', 'Jiné závazky','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38000', 'Pøechodné úèty aktiv a pasív','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38100', 'Náklady pøí¹tích období','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38200', 'Komplexní náklady pøí¹tích období','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38300', 'Výdaje pøí¹tích období','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38400', 'Výnosy pøí¹tích období','A','','L','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38500', 'Pøíjmy pøí¹tích období','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38600', 'Kursové rozdíly aktivní','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38700', 'Kursové rozdíly pasívní','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38800', 'Dohadné úèty aktivní','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('38900', 'Dohadné úèty pasívní','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('39000', 'Opravná polo¾ka k zúètovacím vztahùm a vnitøní zúètování','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('39100', 'Opravná polo¾ka k pohledávkám','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('39500', 'Vnitøní zúètování','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('39800', 'Spojovací úèet pøi sdru¾ení','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('40000', 'Kapitálové úèty a dlouhodobé závazky','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('41000', 'Základní kapitál a kapitálové fondy','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('41100', 'Základní kapitál','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('41200', 'Emisní á¾io','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('41300', 'Ostatní kapitálové fondy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('41400', 'Oceòovací rozdíly z pøecenìní majetku a závazkù','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('42000', 'Fondy ze zisku a pøevedené hospodáøské výsledky','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('42100', 'Zákonný rezervní fond','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('42200', 'Nedìlitelný fond','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('42300', 'Statutární fondy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('42700', 'Ostatní fondy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('42800', 'Nerozdìlený zisk minulých let','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('42900', 'Neuhrazená ztráta minulých let','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('43000', 'Hospodáøský výsledek','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('43100', 'Hospodáøský výsledek ve schvalovacím øízení','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('45000', 'Rezervy','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('45100', 'Rezervy zákonné','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('45400', 'Rezerva na kursové ztráty','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('45900', 'Ostatní rezervy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('46000', 'Bankovní úvìry','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('46100', 'Bankovní úvìry','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('47000', 'Dlouhodobé závazky','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('47100', 'Dlouhodobé závazky k podnikùm ve skupinì','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('47300', 'Emitované dluhopisy','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('47400', 'Závazky z pronájmu','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('47500', 'Dlouhodobé pøijaté zálohy','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('47800', 'Dlouhodobé smìnky k úhradì','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('47900', 'Ostatní dlouhodobé závazky','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('49000', 'Individuální podnikatel','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('49100', 'Úèet individuálního podnikatele','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('50000', 'Spotøebované nákupy','A','','E','AP_amount:IC_COGS');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('50100', 'Spotøeba materiálu','A','','E','AP_amount:IC_COGS');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('50200', 'Spotøeba energie','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('50300', 'Spotøeba ostatních neskladovatelných dodávek','A','','E','AP_amount:IC_COGS');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('50400', 'Prodané zbo¾í','A','','E','AP_amount:IC_COGS');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('51000', 'Slu¾by','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('51100', 'Opravy a udr¾ování','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('51200', 'Cestovné','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('51300', 'Náklady na reprezentaci','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('51800', 'Ostatní slu¾by','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('52000', 'Osobní náklady','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('52100', 'Mzdové náklady','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('52200', 'Pøíjmy spoleèníkù a èlenù dru¾stva ze závislé èinnosti','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('52300', 'Odmìny èlenùm orgánù spoleènosti a dru¾stva','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('52400', 'Zákonné sociální poji¹tìní','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('52500', 'Ostatní sociální poji¹tìní','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('52600', 'Sociální náklady individuálního podnikatele','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('52700', 'Zákonné sociální náklady','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('52800', 'Ostatní sociální náklady','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('53000', 'Danì a poplatky','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('53100', 'Daò silnièní','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('53200', 'Daò z nemovitostí','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('53800', 'Ostatní danì a poplatky','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('54000', 'Jiné provozní náklady','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('54100', 'Zùstatková cena prodaného dlouhodobého nehmotného a hmotného','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('54200', 'Prodaný materiál','A','','E','IC_COGS');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('54300', 'Dary','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('54400', 'Smluvní pokuty a úroky z prodlení','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('54500', 'Ostatní pokuty a penále','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('54600', 'Odpis pohledávky','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('54800', 'Ostatní provozní náklady','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('55000', 'Odpisy, rezervy a opravné polo¾ky provozních nákladù','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('55100', 'Odpisy dlouhodobého nehmotného a hmotného majetku','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('55200', 'Tvorba zákonných rezerv','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('55400', 'Tvorba ostatních rezerv','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('55500', 'Zúètování komplexních nákladù pøí¹tích období','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('55700', 'Zúètování oprávky k opravné polo¾ce k nabytému majetku','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('55800', 'Tvorba zákonných opravných polo¾ek','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('55900', 'Tvorba opravných polo¾ek','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('56000', 'Finanèní náklady','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('56100', 'Prodané cenné papíry a vklady','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('56200', 'Úroky','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('56300', 'Kursové ztráty','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('56800', 'Ostatní finanèní náklady','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('57000', 'Rezervy a opravné polo¾ky finanèních nákladù','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('57400', 'Tvorba rezerv','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('57900', 'Tvorba opravných polo¾ek','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('58000', 'Mimoøádné náklady','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('58100', 'Náklady na zmìnu metody','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('58200', 'Manka a ¹kody','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('58400', 'Tvorba rezerv','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('58800', 'Ostatní mimoøádné náklady','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('58900', 'Tvorba opravných polo¾ek','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('59000', 'Danì z pøíjmù a pøevodové úèty','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('59100', 'Daò z pøíjmù z bì¾né èinnosti - splatná','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('59200', 'Daò z pøíjmù z bì¾né èinnosti - odlo¾ená','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('59300', 'Daò z pøíjmù z mimoøádné èinnosti - splatná','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('59400', 'Daò z pøíjmù z mimoøádné èinnosti - odlo¾ené','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('59500', 'Dodateèné odvody danì z pøíjmù','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('59600', 'Pøevod podílu na hospodáøském výsledku spoleèníkùm','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('59700', 'Pøevod provozních nákladù','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('59800', 'Pøevod finanèních nákladù','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('60000', 'Tr¾by za vlastní výkony a zbo¾í','A','','I','AR_amount:IC_sale:IC_Income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('60100', 'Tr¾by za vlastní výrobky','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('60200', 'Tr¾by z prodeje slu¾eb','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('60400', 'Tr¾by za zbo¾í','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('61000', 'Zmìny stavu vnitropodnikových zásob','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('61100', 'Zmìna stavu nedokonèené výroby','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('61200', 'Zmìna stavu polotovarù','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('61300', 'Zmìna stavu výrobkù','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('61400', 'Zmìna stavu zvíøat','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('62000', 'Aktivace','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('62100', 'Aktivace materiálu a zbo¾í','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('62200', 'Aktivace vnitropodnikových slu¾eb','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('62300', 'Aktivace dlouhodobého nehmotného majetku','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('62400', 'Aktivace dlouhodobého hmotného majetku','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('64000', 'Jiné provozní výnosy.','A','','I','AR_amount:IC_sale:IC_Income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('64100', 'Tr¾by z prodeje dlouhodobého nehmotného a hmotného majetku','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('64200', 'Tr¾by z prodeje materiálu','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('64400', 'Smluvní pokuty a úroky z prodlení','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('64600', 'Výnosy z odepsaných pohledávek','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('64800', 'Jiné provozní výnosy','A','','I','AR_amount:IC_sale:IC_Income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('65000', 'Zúètování rezerv a opravných polo¾ek provozních výnosù','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('65200', 'Zúètování zákonných rezerv','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('65400', 'Zúètování ostatních rezerv','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('65500', 'Zúètování komplexních nákladù pøí¹tích období','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('65700', 'Zúètování oprávky k opravné polo¾ce k nabytému majetku','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('65800', 'Zúètování zákonných opravných polo¾ek','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('65900', 'Zúètování opravných polo¾ek','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('66000', 'Finanèní výnosy','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('66100', 'Tr¾by z prodeje cenných papírù a vkladù','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('66200', 'Úroky','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('66300', 'Kursové zisky','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('66500', 'Výnosy z dlouhodobého finanèního majetku','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('66600', 'Výnosy z krátkodobého finanèního majetku','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('66800', 'Ostatní finanèní výnosy','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('67000', 'Zúètování rezerv a opravných polo¾ek finanèních výnosù','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('67400', 'Zúètování rezerv','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('67900', 'Zúètování opravných polo¾ek','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('68000', 'Mimoøádné výnosy','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('68100', 'Výnosy ze zmìny metody','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('68400', 'Zúètování rezerv','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('68800', 'Ostatní mimoøádné výnosy','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('68900', 'Zúètování opravných polo¾ek','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('69000', 'Pøevodové úèty','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('69700', 'Pøevod provozních výnosù','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('69800', 'Pøevod finanèních výnosù','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('70000', 'Úèty rozva¾né','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('70100', 'Poèáteèní úèet rozva¾ný','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('70200', 'Koneèný úèet rozva¾ný','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('71000', 'Úèet ziskù a ztrát','A','','A','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '34311'),0.05);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '34312'),0.22);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '34321'),0.05);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '34322'),0.22);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '13200'), income_accno_id = (select id from chart where accno = '60000'), expense_accno_id = (select id from chart where accno = '50000'), fxgain_accno_id = (select id from chart where accno = '99998'), fxloss_accno_id = (select id from chart where accno = '99999'), invnumber = '1000', sonumber = '5000', ponumber = '1000', curr = 'Kè', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Danish_Default-chart.sql b/sql-ledger/sql/Danish_Default-chart.sql
new file mode 100644
index 0000000..aafcfb0
--- /dev/null
+++ b/sql-ledger/sql/Danish_Default-chart.sql
@@ -0,0 +1,75 @@
+-- Default chart of accounts
+-- sample only
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1000','KORTFRISTEDE AKTIVER','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1061','Bank','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1065','Kasse','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200','Indbetalinger','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1205','Hensættelser til formodet gæld','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1210','Moms indgående','A','','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1500','LAGER-AKTIVER','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1520','Lager / udstyr','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1530','Lager / programmel','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1540','Lager / tillægssalg','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1550','Lager / arrangementer','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800','AKTIVER','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1820','Kontorinventar og -udstyr','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1825','Samlede afskrivninger, inventar, udstyr','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1840','Køretøjer','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1845','Samlede afskrivninger, køretøjer','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000','KORTFRISTET GÆLD','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2100','Udbetalinger','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2160','Selskabsskat','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2190','Afgifter','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2311','Moms udgående','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2600','LANGFRISTET GÆLD','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2620','Banklån','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3300','AKTIEKAPITAL','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3350','Almindelige aktier','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3500','EGENKAPITAL','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3510','Egenkapital primo','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3600','Årets resultat','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4000','SALGSINDTÆGT','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4020','Salg / udstyr','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4030','Salg / programmel','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4040','Salg / tillægssalg','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4050','Salg / arrangementer','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4300','KONSULENTINDTÆGT','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4320','Konsulentbistand','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4330','Programmering','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4400','ANDEN INDTÆGT','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4440','Renter','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4450','Foreign Exchange Gain','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5000','SALGSOMKOSTNINGER','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5020','Omkostninger / udstyr','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5010','Anskaffelser under 8.000','A','','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5011','Anskaffelser over 8.000','A','','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5030','Omkostninger / programmel','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5040','Omkostninger / tillægssalg','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5050','Omkostninger / arrangementer','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5100','Fragt, post','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5400','LØNUDGIFTER','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5410','Lønninger og honorarer','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5420','ATP','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5470','Personalegoder','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5600','GENERELLE & ADMINISTRATIVE UDGIFTER','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5610','Bogføring, revision, advokat','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5615','Marketing','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5620','Dårlige skyldnere','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5660','Afdrag på lån','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5680','A-skat','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5685','Forsikringer','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5690','Renter og bankgebyrer','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5700','Kontorudgifter','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5760','Husleje','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5765','Vedligeholdelse og reparation','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5780','Telefon','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5785','Rejser & repræsentation','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5790','El, vand, varme','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5800','Licenser','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5810','Foreign Exchange Loss','A','','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1210'),0.25);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2311'),0.25);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '5010'), fxgain_accno_id = (select id from chart where accno = '4450'), fxloss_accno_id = (select id from chart where accno = '5810'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'DKK', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Default-chart.sql b/sql-ledger/sql/Default-chart.sql
new file mode 100644
index 0000000..c85d41b
--- /dev/null
+++ b/sql-ledger/sql/Default-chart.sql
@@ -0,0 +1,81 @@
+-- Default chart of accounts
+-- sample only
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1000','CURRENT ASSETS','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1060','Chequing Account','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1065','Petty Cash','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200','Accounts Receivables','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1205','Allowance for doubtful accounts','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1500','INVENTORY ASSETS','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1520','Inventory / Computer Parts','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1530','Inventory / Software','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1540','Inventory / Aftermarket Parts','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800','CAPITAL ASSETS','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1820','Office Furniture & Equipment','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1825','Accum. Amort. -Furn. & Equip.','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1840','Vehicle','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1845','Accum. Amort. -Vehicle','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000','CURRENT LIABILITIES','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2100','Accounts Payable','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2160','Corporate Taxes Payable','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2190','Federal Income Tax Payable','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2210','Workers Comp Payable','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2220','Vacation Pay Payable','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2250','Pension Plan Payable','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2260','Employment Insurance Payable','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2280','Payroll Taxes Payable','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2310','VAT (10%)','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2320','VAT (14%)','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2330','VAT (30%)','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2600','LONG TERM LIABILITIES','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2620','Bank Loans','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2680','Loans from Shareholders','A','','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3300','SHARE CAPITAL','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3350','Common Shares','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4000','SALES REVENUE','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4020','Sales / Hardware','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4030','Sales / Software','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4040','Sales / Aftermarket Parts','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4300','CONSULTING REVENUE','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4320','Consulting','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4330','Programming','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4400','OTHER REVENUE','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4430','Shipping & Handling','A','','I','IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4440','Interest','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4450','Foreign Exchange Gain','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5000','COST OF GOODS SOLD','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5010','Purchases','A','','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5020','COGS / Hardware','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5030','COGS / Software','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5040','COGS / Aftermarket Parts','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5100','Freight','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5400','PAYROLL EXPENSES','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5410','Wages & Salaries','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5420','Employment Insurance Expense','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5430','Pension Plan Expense','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5440','Workers Comp Expense','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5470','Employee Benefits','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5600','GENERAL & ADMINISTRATIVE EXPENSES','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5610','Accounting & Legal','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5615','Advertising & Promotions','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5620','Bad Debts','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5650','Capital Cost Allowance Expense','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5660','Amortization Expense','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5680','Income Taxes','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5685','Insurance','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5690','Interest & Bank Charges','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5700','Office Supplies','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5760','Rent','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5765','Repair & Maintenance','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5780','Telephone','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5785','Travel & Entertainment','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5790','Utilities','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5795','Registrations','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5800','Licenses','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5810','Foreign Exchange Loss','A','','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2310'),0.1);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2320'),0.14);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2330'),0.3);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '5010'), fxgain_accno_id = (select id from chart where accno = '4450'), fxloss_accno_id = (select id from chart where accno = '5810'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'USD:CAD:EUR', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Dutch_Default-chart.sql b/sql-ledger/sql/Dutch_Default-chart.sql
new file mode 100644
index 0000000..758d6d4
--- /dev/null
+++ b/sql-ledger/sql/Dutch_Default-chart.sql
@@ -0,0 +1,80 @@
+--
+-- Dutch Chart of Accounts
+-- AJ Hettema, Mon, 20 Aug 2001
+--
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1000','HUIDIGE ACTIVA','H','','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1061','Bank','A','','A','AR_paid:AP_paid');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1065','Kas','A','','A','AR_paid:AP_paid');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1200','Debiteuren','A','','A','AR');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1205','Toelage voor precaire rekeningen','A','','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1500','VOORRAAD ACTIVA','H','','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1520','Voorraad / Hardware','A','','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1530','Voorraad / Software','A','','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1540','Voorraad / Aftermarket Parts','A','','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1800','LANGE TERMIJN ACTIVA','H','','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1820','Inventaris','A','','A','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1825','Afschrijving inventaris','A','','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1840','Auto','A','','A','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1845','Afschrijving auto','A','','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2000','HUIDIGE PASSIVA','H','','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2100','Crediteuren','A','','L','AP');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2160','Niet-rijks Belastingen','A','','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2170','Omzetbelasting','A','','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2190','Vennootschapsbelasting','A','','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2310','BTW hoog','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2311','BTW laag','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2600','LANGE TERMIJN PASSIVA','H','','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2620','Bank Leningen','A','','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2680','Aandelenvermogen','A','','L','AP_paid');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('3300','AANDELEN KAPITAAL','H','','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('3350','Aandelen in portefeuille','A','','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('3500','WINSTRESERVE','H','','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('3590','Winstreserve voorgaande jaren','A','','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('3600','Huidige winstreserve','A','','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4000','VERKOOP INKOMSTEN','H','','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4020','Verkoop / Hardware','A','','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4030','Verkoop / Software','A','','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4040','Verkoop / Aftermarket Parts','A','','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4300','CONSULTANCY INKOMSTEN','H','','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4320','Consultancy','A','','I','AR_amount:IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4330','Programmeren','A','','I','AR_amount:IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4400','ANDERE INKOMSTEN','H','','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4430','Verzend & Administratie','A','','I','IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4440','Rente','A','','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4450','Foreign Exchange Gain','A','','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5000','INKOOPPRIJS VERKOPEN','H','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5010','Inkoopkosten algemeen','A','','E','AP_amount:IC_cogs:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5020','Inkoopkosten / Hardware','A','','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5030','Inkoopkosten / Software','A','','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5040','Inkoopkosten / Aftermarket Parts','A','','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5100','Vrachtkosten','A','','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5400','PERSONEELS KOSTEN','H','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5410','Salarissen','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5420','EI Expense','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5430','CPP Expense','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5440','WCB Expense','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5470','Employee Benefits','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5600','GENERAL & ADMINISTRATIVE EXPENSES','H','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5610','Boekhouding- & Rechtkosten','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5615','Reclame- & Promotiekosten','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5620','Slechte Schulden','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5660','Afschrijvingskosten','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5680','Inkomsten Belastingen','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5685','Verzekeringen','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5690','Rente & Bankkosten','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5700','Kantoorvoorzieningen','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5760','Huurkosten','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5765','Reparatie- & Onderhoudskosten','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5780','Telefoonkosten','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5781','Internetkosten','A','','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5785','Reis- & Vermaakkosten','A','','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5790','NUTS Kosten','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5795','Registratie''s','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5800','Licenties','A','','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5810','Foreign Exchange Loss','A','','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2310'),0.19);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2311'),0.06);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '5010'), fxgain_accno_id = (select id from chart where accno = '4450'), fxloss_accno_id = (select id from chart where accno = '5810'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'EUR:USD', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Dutch_Standard-chart.sql b/sql-ledger/sql/Dutch_Standard-chart.sql
new file mode 100644
index 0000000..cd7c8eb
--- /dev/null
+++ b/sql-ledger/sql/Dutch_Standard-chart.sql
@@ -0,0 +1,233 @@
+-- Nederlandstalig Rekeningschema conform het Decimaal Stelsel.
+-- Dutch Chart of Accounts following the Decimal Standards as set by the famous Philips Accounting Department
+-- PDF Tammes, Fri, 29 Mar 2002 ( remarks or questions to finance@bermuda-holding.com )
+-- Just delete any accounts not needed after importing the scheme, beats entering all manually (or add -- at the beginning)
+-- Account groups (first number in accountnumber defines to which group it belongs)
+-- 0 : Vaste Activa, Eigen Vermogen, Voorzieningen en lang vreemd vermogen => Fixed Assets, Capital, Accruals and long term loans
+-- 1 : Financiele Rekeningen => Financial Accounts
+-- 2 : Tussenrekeningen => Intermediate Accounts
+-- 3 : Voorraad grond- en hulpstoffen => Stocks (minerals, parts not yet assembled etc)
+-- 4 : Kostenrekeningen => Costs Accounts
+-- 5 : Verdeling Directe kosten => Accounts to recharge several Direct Costs to separate departments
+-- 6 : Fabricagekosten => Assembly Costs
+-- 7 : Voorraad gereed produkt en product in bewerking => Stocks (Trade Articles, half-finished assemblies, projects under construction)
+-- 8 : Rekeningen voor vaststelling van het verkoopresultaat => Accounts for dediding Sales Result
+-- 9 : Rekeningen voor vaststelling van de resultatenrekening => Accounts for dediding Profit & Loss (P/L)
+-- The general idea is to allocate all costs to the 4/5/6 accounts, all stock transactions to 7 and sales related to 8. At the end of the
+-- year you clean out the seperate accounts via x999 and kick the result to the relevant 9xxx series. That way you have a specialized
+-- P/L in the seperate accounts and an overview/shirt version of the P/L in the 9 series, where also various results not related to normal
+-- operations is recorded (tax, donations, that kind of thing. Finally the 9999 account is used to kick the result to retained earnings and
+-- related accounts in the balance sheet, and we are ready for the next year
+--
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0000','Vaste Activa & Eigen Vermogen','H','0000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0010','Terreinen','A','0010','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0015','Afschrijving Terreinen','A','0015','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0200','Gebouwen','A','0200','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0205','Afschrijving Gebouwen','A','0205','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0230','Inventaris','A','0230','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0235','Afschrijving Inventaris','A','0235','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0240','Computers','A','0240','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0245','Afschrijving Computers','A','0245','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0250','Auto','A','0250','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0255','Afschrijving Auto','A','0255','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0260','Machines','A','0260','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0265','Afschrijving Machines','A','0265','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0290','Goodwill','A','0290','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0295','Afschrijving Goodwill','A','0295','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0370','Overige Leningen u/g','A','0370','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0380','Aandelen & Effecten','A','0380','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0381','Beleggingen Spaarbeleg','A','0381','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0390','Beleggingen Legiolease','A','0390','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0400','Aandelenkapitaal','A','0400','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0410','Aandelen in portefeuille','A','0410','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0420','Aandelen uit te reiken','A','0420','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0430','Agioreserve','A','0430','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0440','Winstreserve','A','0440','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0450','Herwaarderingsreserve','A','0450','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0470','Oprichtingskosten','A','0470','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0480','Winst na belasting lopend jaar','A','0480','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0500','Eigen Vermogen','A','0500','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0510','Prive','A','0510','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0550','Onverdeeld Resultaat','A','0550','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0600','Voorziening Onderhoud','A','0600','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0610','Voorziening Garantie','A','0610','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0620','Voorziening Assurantie','A','0620','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0630','Voorziening Debiteuren','A','0630','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0700','Obligatielening','A','0700','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0710','Obligaties in portefeuille','A','0710','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0720','Converteerbare Obligatielening','A','0720','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0730','Agio op Obligaties','A','0730','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0740','Disagio op Obligaties','A','0740','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('0800','Hypothecaire lening o/g','A','0800','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1000','Financiele Rekeningen','H','1000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1001','Kas','A','1001','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1050','Contante Verkopen','A','1050','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1100','Interbank','A','1100','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1110','ABN-AMRO','A','1110','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1119','Postbank Plus','A','1119','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1120','Postbank Giro','A','1120','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1121','Postbank Kapitaal','A','1121','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1122','Postbank Leeuw','A','1122','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1139','Postbank Effectenrekening','A','1139','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1140','Rabobank','A','1140','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1141','Rabobank Rendementrekening','A','1141','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1160','van Lanschotbank','A','1160','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1170','Finansbank','A','1170','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1180','VISA Creditcard','A','1180','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1190','Kruisposten','A','1190','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1200','Debiteuren','A','1200','A','AR');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1205','Dubieuze Debiteuren','A','1205','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1321','Rekening Courant < A','A','1321','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1322','Rekening Courant < B','A','1322','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1340','Goederen ontvangen / GO','A','1340','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1500','Te betalen loonheffing','A','1500','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1520','Te betalen Sociale Lasten','A','1520','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1530','Te betalen Pensioenpremies','A','1530','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1600','Crediteuren','A','1600','L','AP');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1605','Nog te Ontvangen Facturen / NOF','A','1605','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1610','Te betalen tantiemes','A','1610','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1615','Te betalen Vennootschapsbelasting','A','1615','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1620','Interimdividend','A','1620','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1630','Te betalen dividend','A','1630','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1640','Te betalen dividendbelasting','A','1640','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1650','Aandeelhouders nog te storten','A','1650','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1700','Te betalen interest','A','1700','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1710','Te betalen coupons','A','1710','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1770','Uitgelote obligaties','A','1770','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1800','Te vorderen BTW hoog','A','1800','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1801','Te vorderen BTW laag','A','1801','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1810','Te betalen BTW hoog','A','1810','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1811','Te betalen BTW laag','A','1811','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1850','Saldo BTW','A','1850','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1941','Rekening Courant > A','A','1941','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1942','Rekening Courant > B','A','1942','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1960','Vooruitbetaalde bedragen','A','1960','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1970','Vooruitontvangen bedragen','A','1970','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1980','Nog te ontvangen bedragen','A','1980','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('1990','Nog te betalen bedragen','A','1990','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2000','Tussenrekeningen','H','2000','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2100','Vraagposten','A','2100','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2400','Onbekende betalingen','A','2400','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2800','Tussenrekening Lonen','A','2800','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('2900','Tussenrekening Beginbalans','A','2900','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('3000','Voorraad Grond- en Hulpstoffen','H','3000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('3010','Voorraad Grondstof A','A','3010','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4000','Kostenrekeningen','H','4000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4001','Verbruik Grondstoffen','A','4001','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4100','Directe Loonkosten','A','4100','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4110','Indirecte Loonkosten','A','4110','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4120','Sociale Lasten','A','4120','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4130','Kosten Pensioenen','A','4130','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4190','Overige Personeelskosten','A','4190','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4200','Kosten externe medewerkers','A','4200','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4210','Kosten Personeelsuitjes','A','4210','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4220','Kantinekosten','A','4220','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4240','Lief en Leedpot externe medewerkers','A','4240','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4300','Afschrijvingskosten Gebouwen','A','4300','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4330','Afschrijvingskosten Inventaris','A','4330','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4340','Afschrijvingskosten Computers','A','4340','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4350','Afschrijvingskosten Autos','A','4350','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4360','Afschrijvingskosten Machines','A','4360','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4390','Afschrijvingskosten Goodwill','A','4390','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4400','Huurkosten','A','4400','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4410','Asurantiekosten','A','4410','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4520','Gas, Licht & Water','A','4520','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4530','Vaste Lasten','A','4530','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4540','Reparatie- & Onderhoudskosten','A','4540','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4560','Verzekering en Beveiliging Pand','A','4560','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4600','Directe Verkoopkosten','A','4600','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4650','Indirecte Verkoopkosten','A','4650','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4730','Relatiegeschenken','A','4730','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4740','Reis en Verblijfkosten','A','4740','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4800','Kasverschillen','A','4800','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4810','Voorraadverschillen','A','4810','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4900','Telefoon & Faxkosten','A','4900','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4910','Contributies & Abonnementen','A','4910','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4920','Verzekeringen Algemeen','A','4920','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4930','Kantoorartikelen','A','4930','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4931','Kantoorbenodigdheden','A','4931','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4932','Vakliteratuur','A','4932','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4940','Licenties & Software','A','4940','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4941','Administratie & Acountantskosten','A','4941','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4943','Notaris & Advocaatkosten','A','4943','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4950','Drukwerk & Papier','A','4950','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4970','Porti','A','4970','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4980','Bankkosten','A','4980','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4981','Bankprovisie Effectenhandel','A','4981','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4990','Overige Algemene Kosten','A','4990','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4991','Bijzondere baten en lasten','A','4991','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('4999','Overboekingsrekening Rubriek 4','A','4999','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5000','Verdeling Indirecte Kosten','H','5000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5400','Indirecte fabricagekosten','A','5400','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5450','Opslag Indirecte fabricagekosten','A','5450','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5500','Indirecte verkoopkosten','A','5500','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5550','Opslag Indirecte verkoopkosten','A','5550','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('5999','Overboekingsrekening Rubriek 5','A','5999','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('6000','Fabricagerekeningen','H','6000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('6001','Verbruik Grondstoffen','A','6001','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('6010','Directe Lonen','A','6010','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('6020','Toeslag Indirecte fabricagekosten','A','6020','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('6101','Standaard Verbruik Grondstoffen','A','6101','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('6110','Standaard Directe Lonen','A','6110','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('6120','Standaard Toeslag Indirecte fabricagekosten','A','6120','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('6999','Overboekingsrekening Rubriek 6','A','6999','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7000','Voorraden gereed product','H','7000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7001','Voorraad A','A','7001','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7002','Voorraad B','A','7002','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7003','Voorraad C','A','7003','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7010','Voorraad Incourante goederen','A','7010','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7015','Afschrijving Incourante goederen','A','7015','L','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7200','Voorraad Goederen in bewerking','A','7200','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7300','Nog te Ontvangen Goederen / NOG','A','7300','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7350','Nog af te leveren goederen','A','7350','L','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7400','Prijsverschillen bij inkoop','A','7400','I','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('7999','Overboekingsrekening Rubriek 7','A','7999','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8000','Rekeningen tbv Verkoopresultaat','H','8000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8010','Inkoopkosten algemeen','A','8010','E','AP_amount:IC_cogs:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8020','Kostprijs Verkopen A','A','8020','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8030','Kostprijs Verkopen B','A','8030','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8040','Kostprijs Verkopen C','A','8040','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8100','Directe Verkoopkosten','A','8100','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8150','Toeslag Indirecte Verkoopkosten','E','8150','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8300','Kortingen bij Verkoop','A','8300','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8520','Opbrengst Verkopen A','A','8520','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8530','Opbrengst Verkopen B','A','8530','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8540','Opbrengst Verkopen C','A','8540','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('8999','Overboekingsrekening Rubriek 8','A','8999','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9000','Rekeningen tbv Resultatenrekening','H','9000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9010','Resultaat Indirecte Kosten','A','9010','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9011','Resultaat Fabricage','A','9011','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9012','Resultaat Verkoop','A','9012','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9015','Resultaat Prijsverschillen','A','9015','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9030','Rente bate deposito','A','9030','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9040','Rente bate lening u/g','A','9040','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9050','Rente bate bank','A','9050','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9080','Rente bate Fiscus','A','9080','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9100','Rente last hypothecaire lening','A','9100','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9110','Rente last lening bank','A','9110','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9130','Rente last lening o/g','A','9130','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9150','Rente last bank','A','9150','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9180','Rente last Fiscus','A','9180','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9190','Rente last overig','A','9190','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9200','Ontvangen Dividend (bruto)','A','9200','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9205','Ingehouden Dividendbelasting','A','9205','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9210','Koersresultaat Effecten)','A','9210','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9220','Valutaresultaat','A','9220','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9300','Huuropbrengsten','A','9300','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9400','Resultaat tgv inhaalafschrijvingen','A','9400','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9500','Incidentele Resultaten','A','9500','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9600','Giften en Donaties','A','9600','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9700','Tantiemes','A','9700','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9800','Belasting Lopend Jaar','A','9800','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9810','Belasting Voorgaande Jaren','A','9810','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9900','Vennootschapsbelasting','A','9900','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('9999','Overboekingsrekening','A','9999','I','');
+--
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1800'),0.19);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1801'),0.06);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1810'),0.19);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1811'),0.06);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '7001'), income_accno_id = (select id from chart where accno = '8520'), expense_accno_id = (select id from chart where accno = '8010'), fxgain_accno_id = (select id from chart where accno = '9220'), fxloss_accno_id = (select id from chart where accno = '9220'), invnumber = '0000', sonumber = '0000', ponumber = '0000', curr = 'EUR:USD', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/France-chart.sql b/sql-ledger/sql/France-chart.sql
new file mode 100644
index 0000000..a34e013
--- /dev/null
+++ b/sql-ledger/sql/France-chart.sql
@@ -0,0 +1,951 @@
+-- Chart of Accounts for France
+-- From: Oscar Buijten <oscar@elbie.com>
+-- Mon, 6 Aug 2001
+--
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('101000', 'CAPITAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('101100', 'CAPITAL SOUSCRIT NON APPELE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('101200', 'CAPITAL SOUSCRIT APPELE NON VERSE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('101300', 'CAPITAL SOUSCRIT APPELE VERSE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('101310', 'CAPITAL NON AMORTI', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('101320', 'CAPITAL AMORTI', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('101800', 'CAPITAL SOUSCR. A REGLEM. PART.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('104000', 'PRIMES LIEES AU CAPITAL SOCIAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('104100', 'PRIMES D\'EMISSION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('104200', 'PRIMES DE FUSION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('104300', 'PRIMES D\'APPORT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('104400', 'PRIMES CONVERS. OBLIGAT. ACTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('104500', 'BONS DE SOUSCRIPTION D\'ACTION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('105000', 'ECARTS DE REEVALUATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('105100', 'RESERVE SPECIALE DE REEVALUATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('105200', 'ECART DE REEVALUATION LIBRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('105300', 'RESERVE DE REEVALUATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('105500', 'ECARTS REEVAL. (AUT. OPER. LEG.)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('105700', 'AUT. ECARTS REEVAL. EN FRANCE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('105800', 'AUT. ECARTS REEVAL. A L\'ETRANGER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106000', 'RESERVES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106100', 'RESERVE LEGALE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106110', 'RESERVE LEGALE PROPREMENT DITE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106120', 'PLUS-VALUES NETTES A LONG TERME', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106200', 'RESERVES INDISPONIBLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106300', 'RESERVES STATUT. OU CONTRACTUELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106400', 'RESERVES REGLEMENTEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106410', 'PLUS-VALUES NETTES A LONG TERME', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106430', 'RESER. CONSEC. OCTROI SUBV. INVEST', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106480', 'AUTRES RESERVES REGLEMENTEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106800', 'AUTRES RESERVES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106810', 'RESERVE DE PROPRE ASSUREUR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('106880', 'RESERVES DIVERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('107000', 'ECART D\'EQUIVALENCE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('109000', 'ACTIONN. CAPITAL SOUSC. NON APPELE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('110000', 'REPORT A NOUVEAU (SOLDE CREDITEUR)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('119000', 'REPORT A NOUVEAU (SOLDE DEBITEUR)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('120000', 'RESULTAT DE L\'EXERCICE (BENEFICE)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('129000', 'RESULTAT DE L\'EXERCICE (PERTE)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('131000', 'SUBVENTIONS D\'EQUIPEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('131100', 'ETAT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('131200', 'REGIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('131300', 'DEPARTEMENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('131400', 'COMMUNES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('131500', 'COLLECTIVITES PUBLIQUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('131600', 'ENTREPRISES PUBLIQUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('131700', 'ENTREPRISES ET ORGANISMES PRIVES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('131800', 'AUTRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('138000', 'AUTRES SUBVENTIONS D\'INVESTIS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139000', 'SUBV. INVES. INSC. AU CPTE RESULT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139100', 'SUBVENTIONS D\'EQUIPEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139110', 'ETAT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139120', 'REGIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139130', 'DEPARTEMENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139140', 'COMMUNES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139150', 'COLLECTIVITES PUBLIQUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139160', 'ENTREPRISES PUBLIQUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139170', 'ENTREPRISES ET ORGANISMES PRIVES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139180', 'AUTRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('139800', 'AUTRES SUBVENTIONS D\'INVESTIS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('142000', 'PROVIS. REGLEM. RELATIV. AUX IMMO.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('142300', 'PROVIS. POUR RECONSTITUTION GIS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('142400', 'PROVIS. INVESTIS. (PARTIC. SALAR.)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('143000', 'PROVIS. REGLEMENT. RELATIV. STOCKS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('143100', 'HAUSSE DES PRIX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('143200', 'FLUCTUATION DES COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('144000', 'PROVIS. REGLEM. RELAT. ELEM. ACTIF', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('145000', 'AMORTISSEMENTS DEROGATOIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('146000', 'PROVISION SPECIALE DE REEVALUATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('147000', 'PLUS-VALUES REINVESTIES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('148000', 'AUTRES PROVISIONS REGLEMENTEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('151000', 'PROVISIONS POUR RISQUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('151100', 'PROVISIONS POUR LITIGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('151200', 'PROV. GARANT. DONNEES AUX CLIENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('151300', 'PROV. PERTES SUR MARCHES A TERME.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('151400', 'PROVIS. POUR AMENDES ET PENALITES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('151500', 'PROVIS. POUR PERTES DE CHANGE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('151800', 'AUTRES PROVISIONS POUR RISQUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('153000', 'PROVIS. PENSIONS ET OBLIG. SIMIL.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('155000', 'PROVISIONS POUR IMPOTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('156000', 'PROVIS. RENOUV. IMMO (ETS CONCESS)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('157000', 'PROV. CHARG. A REPART. SUR EXERC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('157200', 'PROVIS. POUR GROSSES REPARATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('158000', 'AUTRES PROVISIONS POUR CHARGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('158200', 'PROVIS. CHARG. SOCIA. FISC. SUR CP', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('161000', 'EMPRUNTS OBLIGATOIRES CONVERTIBLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('163000', 'AUTRES EMPRUNTS OBLIGATAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('164000', 'EMPRUNTS AUPRES ETABLIS. DE CREDIT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('165000', 'DEPOTS ET CAUTIONNEMENTS RECUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('165100', 'DEPOTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('165500', 'CAUTIONNEMENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('166000', 'PARTICIP. SALARIES AUX RESULTAS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('166100', 'COMPTES BLOQUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('166200', 'FONDS DE PARTICIPATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('167000', 'EMPR. DETTES ASSORT. CONDIT. PART.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('167100', 'EMISSION DE TITRES PARTICIPATIFS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('167400', 'AVANCES CONDITIONNEES DE L\'ETAT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('167500', 'EMPRUNTS PARTICIPATIFS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168000', 'AUTRES EMPR. ET DETTES ASSIMILEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168100', 'AUTRES EMPRUNTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168500', 'RENTES VIAGERES CAPITALISEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168700', 'AUTRES DETTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168800', 'INTERETS COURUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168810', 'SUR EMPR. OBLIGATAIR. CONVERTIBLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168830', 'SUR AUTRES EMPRUNTS OBLIGATAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168840', 'SUR EMPRUNTS AUPRES ETABLI. CREDIT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168850', 'SUR DEPOTS ET CAUTIONNEMENTS RECUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168860', 'SUR PARTICIP. SALAR. RESULTATS ETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168870', 'SUR EMPR. DETTES ASSOR. COND. PART', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('168880', 'SUR AUTRES EMPR. DETTES ASSIMILEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('169000', 'PRIMES REMBOURSEMENT OBLIGATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('171000', 'DETTES RATTACH. A PARTIC. (GROUPE)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('174000', 'DETTES RATT. A PART. (HORS GROUPE)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('178000', 'DETTES RATTACH. A STES EN PARTIC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('178100', 'PRINCIPAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('178800', 'INTERETS COURUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('181000', 'COMPTE DE LIAISON ETABLISSEMENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('186000', 'BIENS PREST. SERV. ECH. (CHARGES)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('187000', 'BIENS PREST. SERV. ECH. (PRODUITS)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('188000', 'COMPTES DE LIAISON STES EN PARTIC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('201100', 'FRAIS DE CONSTITUTION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('201200', 'FRAIS DE PREMIER ETABLISSEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('201210', 'FRAIS DE PROSPECTION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('201220', 'FRAIS DE PUBLICITE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('201300', 'FRAIS AUGMEN. CAPIT. OPER. DIVERS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('203000', 'FRAIS RECHERCHE ET DEVELOPPEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('205000', 'CONCESSIONS ET DROITS SIMILAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('206000', 'DROIT AU BAIL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('207000', 'FONDS COMMERCIAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('208000', 'AUTRES IMMOBILISATIONS INCORPOR.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211000', 'TERRAINS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211100', 'TERRAINS NUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211200', 'TERRAINS AMENAGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211300', 'SOUS-SOLS ET SUR-SOLS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211400', 'TERRAINS DE GISEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211410', 'CARRIERES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211500', 'TERRAINS BATIS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211510', 'ENSEMBLES IMMOBILIERS INDUSTRIELS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211550', 'ENSEMBLES IMMOB. ADM. ET COMMERC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211580', 'AUTRES ENSEMBLES IMMOBILIERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211581', 'AFFECTES AUX OPERAT. PROFESSION.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211588', 'AFFECTES AUX OPERAT. NON PROF.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('211600', 'COMPTE D\'ORDRE SUR IMMOBILISATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('212000', 'AGENCEMENTS AMENAGEMENTS TERRAINS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213000', 'CONSTRUCTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213100', 'BATIMENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213110', 'ENSEMBLES IMMOB. INDUSTRIELS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213150', 'ENSEMBLES IMMOB. ADM. ET COMMERC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213180', 'AUTRES ENSEMBLES IMMOBILIERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213181', 'AFFECTES AUX OPERAT. PROFESSION.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213188', 'AFFECTES AUX OPERAT. NON PROF.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213500', 'INSTALLATIONS GENERALES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213800', 'OUVRAGES D\'INFRASTRUCTURE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213810', 'VOIES DE TERRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213820', 'VOIES DE FER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213830', 'VOIES D\'EAU', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213840', 'BARRAGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('213850', 'PISTES D\'AERODROMES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('214000', 'CONSTRUCTIONS SUR SOL D\'AUTRUI', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215000', 'INSTALL. TECH. MAT. OUTIL. INDUS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215100', 'INSTALL. COMPLEXES SPECIALISEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215110', 'SUR SOL PROPRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215140', 'SUR SOL D\'AUTRUI', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215300', 'INSTALL. A CARACTERE SPECIFIQUE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215310', 'SUR SOL PROPRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215340', 'SUR SOL D\'AUTRUI', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215400', 'MATERIEL INDUSTRIEL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215500', 'OUTILLAGE INDUSTRIEL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('215700', 'AGENCEM. AMENAG. MAT. OUTIL. INDUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('218000', 'AUTRES IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('218100', 'INSTALL. GENE. AGENC. AMENAG. DIV.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('218200', 'MATERIEL DE TRANSPORT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('218300', 'MATERIEL DE BUREAU ET INFORMATIQUE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('218400', 'MOBILIER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('218500', 'CHEPTEL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('218600', 'EMBALLAGES RECUPERABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('231000', 'IMMOBILISAT. CORPORELLES EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('231200', 'TERRAINS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('231300', 'CONSTRUCTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('231500', 'INSTALL. TECH. MAT. OUTIL. INDUST.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('231800', 'AUTRES IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('232000', 'IMMO. INCORPORELLES EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('237000', 'AVANC. ACOMPT. VERSES SUR IMM. INC', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('238000', 'AVANC. ACOMP. VERSES CDES IMM. COR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('238200', 'TERRAINS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('238300', 'CONSTRUCTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('238500', 'INSTALL. TECH. MAT. OUTIL. INDUST.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('238800', 'AUTRES IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('261000', 'TITRES DE PARTICIPATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('261100', 'ACTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('261800', 'AUTRES TITRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('266000', 'AUTRES FORMES DE PARTICIPATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('267000', 'CREANCES RATTACHEES A PARTICIPAT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('267100', 'CREANCES RATT. A PART. (GROUPE)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('267400', 'CREANC. RATT. PART. (HORS GROUPE)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('267500', 'VERSEM. D\'APPORTS NON CAPITALISES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('267600', 'AVANCES CONSOLIDABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('267700', 'AUTRES CREANCES RATT. A PART.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('267800', 'INTERETS COURUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('268000', 'CREANCES RATT. A STE EN PART.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('268100', 'PRINCIPAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('268800', 'INTERETS COURUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('269000', 'VERS. REST. A EFFECT. SUR T.P.N.L.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('271000', 'TITRES IMMOBILISES (DROIT PROP.)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('271100', 'ACTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('271800', 'AUTRES TITRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('272000', 'TITRES IMMOBILISES (DROIT CREANCE)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('272100', 'OBLIGATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('272200', 'BONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('273000', 'TITRES IMMOBILISES DE L\'ACT. DE PORTEF.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('274000', 'PRETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('274100', 'PRETS PARTICIPATIFS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('274200', 'PRETS AUX ASSOCIES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('274300', 'PRETS AU PERSONNEL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('274800', 'AUTRES PRETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('275000', 'DEPOTS ET CAUTIONNEMENTS VERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('275100', 'DEPOTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('275500', 'CAUTIONNEMENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('276000', 'AUTRES CREANCES IMMOBILISEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('276100', 'CREANCES DIVERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('276800', 'INTERETS COURUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('276820', 'SUR TITRES IMMOB. (DROIT CREANCE)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('276840', 'SUR PRETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('276850', 'SUR DEPOTS ET CAUTIONNEMENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('276880', 'SUR CREANCES DIVERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('277100', 'ACTIONS PROPRES OU PARTS PROPRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('277200', 'ACT. PRO. OU PARTS PRO. VOIE D\'ANNUL.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('279000', 'VERSEM. A EFFECT. SUR T.I.N.L.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('280000', 'AMORTISS. IMMOBILISATIONS INCORP.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('280100', 'FRAIS D\'ETABLISSEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('280300', 'FRAIS DE RECHERCHE ET DEVELOPP.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('280500', 'CONCESSIONS ET DROITS SIMILAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('280700', 'FONDS COMMERCIAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('280800', 'AUTRES IMMOBILISATIONS INCORPOR.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('281000', 'AMORTISS. IMMOBILISATIONS CORPOR.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('281100', 'TERRAINS DE GISEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('281200', 'AGENCEMENTS AMENAGEMENTS TERRAINS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('281300', 'CONSTRUCTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('281400', 'CONSTRUCTIONS SUR SOL D\'AUTRUI', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('281500', 'INSTALL TECH. MAT. OUTIL. INDUST.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('281800', 'AUTRES IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('282000', 'AMORTISS. IMMOBIL. EN CONCESSION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('290000', 'PROVIS. DEPRECIATION IMMOB. INCORP', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('290500', 'MARQUES PROCEDES DROITS ET VALEURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('290600', 'DROIT AU BAIL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('290700', 'FONDS COMMERCIAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('290800', 'AUTRES IMMOB. INCORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('291000', 'PROVIS. DEPRECIATION IMMOB. CORPOR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('291100', 'TERRAINS (AUTRES QUE GISEMENT)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('292000', 'PROVIS. DEPRECIAT. IMMOB. CONCESS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('293000', 'PROVIS. DEPRECIAT. IMMOB. EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('293100', 'IMMOBILISATIONS CORPOR. EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('293200', 'IMMO. INCORPORELLES EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('296000', 'PROV. DEPREC. PART ET CREANC. PART', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('296100', 'TITRES DE PARTICIPATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('296600', 'AUTRES FORMES DE PARTICIPATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('296700', 'CREANCES RATT. A PARTICIPATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('296800', 'CREANCES RATT. A STE EN PARTICIP.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('297000', 'PROVIS. DEPRECIATION AUTRES IMMOB.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('297100', 'TITRES IMMOBILISES DROIT PROPRIETE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('297200', 'TITRES IMMOBILISES DROIT CREANCE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('297300', 'TITRES IMMO. DE L\'ACT. DE PORTEF.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('297400', 'PRETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('297500', 'DEPOTS ET CAUTIONNEMENTS VERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('297600', 'AUTRES CREANCES IMMOBILISEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('311000', 'MATIERE (OU GROUPE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('312000', 'MATIERE (OU GROUPE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('317000', 'FOURNITURES A, B, C...', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('321000', 'MATIERES CONSOMMABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('321100', 'MATIERE (OU GROUPE) C', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('321200', 'MATIERE (OU GROUPE) D', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('322000', 'FOURNITURES CONSOMMABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('322100', 'COMBUSTIBLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('322200', 'PRODUITS D\'ENTRETIEN', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('322300', 'FOURNITURES D\'ATELIER ET D\'USINE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('322400', 'FOURNITURES DE MAGASIN', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('322500', 'FOURNITURES DE BUREAU', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('326000', 'EMBALLAGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('326100', 'EMBALLAGES PERDUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('326500', 'EMBAL. RECUPER. NON IDENTIFIABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('326700', 'EMBALLAGES A USAGE MIXTE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('331000', 'PRODUITS EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('331100', 'PRODUITS EN COURS P1', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('331200', 'PRODUITS EN COURS P2', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('335000', 'TRAVAUX EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('335100', 'TRAVAUX EN COURS T1', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('335200', 'TRAVAUX EN COURS T2', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('341000', 'ETUDES EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('341100', 'ETUDE EN COURS E1', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('341200', 'ETUDE EN COURS E2', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('345000', 'PRESTATIONS DE SERVICES EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('345100', 'PRESTATION DE SERVICES S1', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('345200', 'PRESTATION DE SERVICES S2', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('351000', 'PRODUITS INTERMEDIAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('351100', 'PRODUIT INTERMEDIAIRE (OU GRPE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('351200', 'PRODUIT INTERMEDIAIRE (OU GRPE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('355000', 'PRODUITS FINIS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('355100', 'PRODUIT FINI (OU GROUPE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('355200', 'PRODUIT FINI (OU GROUPE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('358000', 'PROD. RESIDUELS (OU MAT. RECUP.)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('358100', 'DECHETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('358500', 'REBUTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('358600', 'MATIERES DE RECUPERATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('371000', 'MARCHANDISE (OU GROUPE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('372000', 'MARCHANDISE (OU GROUPE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('391000', 'PROVIS. POUR DEPRECIAT. MAT. PREM.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('391100', 'MATIERE (OU GROUPE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('391200', 'MATIERE (OU GROUPE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('391700', 'FOURNITURE A, B, C...', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('392000', 'PROVIS. POUR DEPRECIAT. AUT. APPRO', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('392100', 'MATIERES CONSOMMABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('392200', 'FOURNITURES CONSOMMABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('392600', 'EMBALLAGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('393000', 'PROV. DEPREC. EN-COURS PROD. BIENS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('393100', 'PRODUITS EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('393500', 'TRAVAUX EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('394000', 'PROV. DEPREC. EN-COURS PROD. SERV.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('394100', 'ETUDES EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('394500', 'PRESTATIONS DE SERVICES EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('395000', 'PROV. POUR DEPREC. STOCKS DE PROD.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('395100', 'PRODUITS INTERMEDIAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('395500', 'PRODUITS FINIS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('397000', 'PROV. POUR DEPREC. STOCKS MARCHAN.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('397100', 'MARCHANDISE OU GROUPE A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('397200', 'MARCHANDISE OU GROUPE B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('401000', 'FOURNISSEURS DIVERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('403000', 'FOURNISSEURS - EFFETS A PAYER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('404000', 'FOURNISSEURS D\'IMMOBILISATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('404100', 'FOURNISSEURS ACHATS D\'IMMOBILISAT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('404700', 'FOURNIS. D\'IMMOB. RETENUES DE GAR.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('405000', 'FOURNIS. D\'IMMOB. EFFETS A PAYER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('408000', 'FOURNIS. FACTURES NON PARVENUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('408100', 'FOURNISSEURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('408400', 'FOURNISSEURS D\'IMMOBILISATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('408800', 'FOURNISSEURS INTERETS COURUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('409000', 'FOURNISSEURS DEBITEURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('409100', 'FOURNIS. AVANC. & ACOMPT. SUR CDES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('409600', 'FOURN. CREAN. EMB. & MAT. A RENDRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('409700', 'FOURNISSEURS AUTRES AVOIRS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('409710', 'FOURNISSEURS D\'EXPLOITATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('409740', 'FOURNISSEURS D\'IMMOBILISATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('409800', 'RABAIS REMISES RISTOUR. A OBTENIR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('410000', 'CLIENTS ET COMPTES RATTACHES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('411000', 'CLIENTS DIVERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('413000', 'CLIENTS EFFETS A RECEVOIR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('416000', 'CLIENTS DOUTEUX OU LITIGIEUX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('417000', 'CREANC. SUR TRAV. NON ENCORE FACT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('418000', 'CLIENTS PRODUITS NON ENCORE FACT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('418100', 'CLIENTS FACTURES A ETABLIR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('418800', 'CLIENTS INTERETS COURUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('419000', 'CLIENTS CREDITEURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('419100', 'CLTS AVANC. & ACOMP. RECUS SUR CDE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('419600', 'CLTS DETT. POUR EMB. & MAT. CONSIG', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('419700', 'CLIENTS - AUTRES AVOIRS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('419800', 'RABAIS REMISES RIST. A ACCORDER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('421000', 'PERSONNEL REMUNERATIONS DUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('422000', 'COMITES D\'ENTREPRISE, D\'ETABLIS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('424000', 'PARTICIP. DES SALAR. AUX RESULTATS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('424600', 'RESERVE SPECIALE (ART L442.2)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('424800', 'COMPTES COURANTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('425000', 'PERSONNEL AVANCES ET ACOMPTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('426000', 'PERSONNEL DEPOTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('427000', 'PERSONNEL OPPOSITIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('428000', 'PERS. CHARG. A PAY. & PROD. A REC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('428200', 'DETTES PROVISIO. POUR CONGES PAYES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('428400', 'DETT. PROV. PART. SAL. AUX RESULT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('428600', 'AUTRES CHARGES A PAYER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('428700', 'PRODUITS A RECEVOIR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('438000', 'ORG. SOC. CHARG. A PAY. & PROD.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('438200', 'CHARGES SOCIALES SUR CONGES PAYES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('438700', 'PRODUITS A RECEVOIR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('441000', 'ETATS SUBVENTIONS A RECEVOIR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('441100', 'SUBVENTIONS D\'INVESTISSEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('441700', 'SUBVENTIONS D\'EXPLOITATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('441800', 'SUBVENTIONS D\'EQUILIBRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('441900', 'AVANCES SUR SUBVENTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('442000', 'ETAT IMP. & TAX. RECOUV. SUR TIERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('442400', 'OBLIGATAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('442500', 'ASSOCIES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('443000', 'OPERATIONS PART. AVEC L\'ETAT,...', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('443100', 'CREANCES ETAT SUPPR. DECAL. TVA', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('443800', 'INTERES COURUS CREANCES CPTE 443100', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('444000', 'ETAT IMPOTS SUR LES BENEFICES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('444500', 'ETAT TAXES SUR LE CHIFFRE D\'AFF.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445200', 'TVA DUE INTRACOMMUNAUTAIRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445510', 'TVA A DECAISSER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445580', 'TAXES ASSIMILEES A TVA', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445600', 'TAXES SUR LE CA DEDUCTIBLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445621', 'TVA SUR IMMO. 5.5%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445622', 'TVA SUR IMMO. 20.6%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445623', 'TVA SUR IMMO. 19.6%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445630', 'TVA TRANSFEREE PAR D\'AUTRES ETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445662', 'TVA DEDUCTIBLE 20.6%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445670', 'CREDIT DE TVA A REPORTER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445680', 'TAXES ASSIMILEES A LA TVA', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445700', 'TAXE SUR LE C.A. COLLECT. ENTREPR.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445712', 'TVA COLLECTEE 20.6%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445800', 'TAXES SUR CA A REGULAR. OU EN ATT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445810', 'ACOMPTES REGIME SIMPLIFIE D\'IMPOS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445820', 'ACOMPTES REGIME DU FORFAIT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445830', 'REMBOURS. TAXES SUR CA DEMANDE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445840', 'TVA RECUPEREE D\'AVANCE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445861', 'TVA EN ATTENTE DEDUCTIBLE 5.5%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445862', 'TVA EN ATTENTE DEDUCTIBLE 20.6%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445863', 'TVA EN ATTENTE DEDUCTIBLE 19.6%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445871', 'TVA EN ATTENTE COLLECTEE 5.5%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445872', 'TVA EN ATTENTE COLLECTEE 20.6%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445873', 'TVA EN ATTENTE COLLECTEE 19.6%', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('446000', 'TITRES SUR TVA', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('446100', 'OBLIGATIONS CAUTIONNEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('446900', 'CREANCE TVA DECALAGE D\'UN MOIS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('447000', 'AUTRES IMPOTS, TAX. ET VERS. ASSIM', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('448000', 'ETAT CHARG. A PAY. & PROD. A RECEV', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('448200', 'CHARGES FISCALES SUR CONG. A PAYER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('448600', 'AUTRES CHARGES A PAYER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('448700', 'PRODUITS A RECEVOIR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('451000', 'GROUPE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('455000', 'ASSOCIES COMPTES COURANTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('455100', 'PRINCIPAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('455780', 'TAXES ASSIMILEES A LA TVA', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('455800', 'INTERETS COURUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456000', 'ASSOCIES OPERATIONS SUR LE CAPITAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456100', 'ASSOCIES COMPTES D\'APPORT EN STE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456110', 'APPORTS EN NATURE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456150', 'APPORTS EN NUMERAIRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456200', 'APPORTEURS CAPIT. APPELE NON VERSE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456210', 'ACTION. CAP. SOUSC. APP. NON VERSE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456250', 'ASSOCIES CAPITAL APPELE NON VERSE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456300', 'ASSOC. VERS. RECUS SUR AUGM. CAPIT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456400', 'ASSOCIES VERSEMENTS ANTICIPES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456600', 'ACTIONNAIRES DEFAILLANTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('456700', 'ASSOCIES CAPITAL A REMBOURSER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('457000', 'ASSOCIES DIVIDENDES A PAYER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('458000', 'ASSOC. OPERAT. EN COMMUN ET EN GIE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('458100', 'OPERATIONS COURANTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('458800', 'INTERETS COURUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('462000', 'CREANCES SUR CESSIONS D\'IMMOBILIS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('464000', 'DETTES SUR ACQUIS. VALEURS MOBI.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('465000', 'CREANC. SUR CESSIONS VALEURS MOB.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('467000', 'AUTRES COMPTES DEBIT. OU CREDIT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('467200', 'DEBOURS PAYES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('468000', 'DIVERS CHARG. A PAY. & PROD. A REC', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('468600', 'CHARGES A PAYER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('468700', 'PRODUITS A RECEVOIR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('471000', 'COMPTES D\'ATTENTE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('471100', 'REIMPUTATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('476000', 'DIFFERENCES DE CONVERSION ACTIF', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('476100', 'DIMINUTION DES CREANCES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('476200', 'AUGMENTATION DES DETTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('476800', 'DIFFER. COMPENS. PAR COUV. CHANGE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('477000', 'DIFFERENCES DE CONVERSION PASSIF', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('477100', 'AUGMENTATION DES CREANCES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('477200', 'DIMINUTION DES DETTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('477800', 'DIFFER. COMPENS. PAR COUV. CHANGE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('478000', 'AUTRES COMPTES TRANSITOIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('481000', 'CHARG. A REPART. SUR PLUS. EXERC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('481100', 'CHARGES DIFFEREES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('481200', 'FRAIS D\'ACQUISITION DES IMMOBILIS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('481600', 'FRAIS D\'EMISSION DES EMPRUNTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('481800', 'CHARGES A ETALER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('486000', 'CHARGES CONSTATEES D\'AVANCE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('487000', 'PRODUITS CONSTATES D\'AVANCE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('488000', 'CPTES REPART. PERIO. CHARG. & PROD', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('488600', 'CHARGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('488700', 'PRODUITS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('491000', 'PROVIS. POUR DEPREC. CPTES CLIENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('495000', 'PROV. POUR DEPREC. CPTES GRPE ASS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('495100', 'COMPTES DU GROUPE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('495500', 'COMPTES COURANTS DES ASSOCIES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('495800', 'OPERAT. FAITES EN COMMUN & EN GIE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('496000', 'PROVIS. POUR DEPREC. CPTES DEBIT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('496200', 'CREANCES SUR CESSIONS D\'IMMOBILIS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('496500', 'CREANC. SUR CESSIONS VALEURS MOB.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('496700', 'AUTRES COMPTES DEBITEURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('501000', 'PARTS DANS DES ENTREPRISES LIEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('502000', 'ACTIONS PROPRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('503000', 'ACTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('503100', 'TITRES COTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('503500', 'TITRES NON COTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('504000', 'AUTRES TITRES CONFERANT DROIT PROP', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('505000', 'OBLIG. & BONS EMIS PAR LA SOCIETE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('506000', 'OBLIGATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('506100', 'TITRES COTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('506500', 'TITRES NON COTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('507000', 'BONS TRESOR & BONS CAISSE A CT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('508000', 'AUTRES VALEURS MOB. ET CREANC. ASS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('508100', 'AUTRES VALEURS MOBILIERES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('508200', 'BONS DE SOUSCRIPTION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('508800', 'INTER. COURUS SUR OBLIGATIONS BONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('509000', 'VERS. A EFFECT. SUR VALEURS MOBIL.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('511000', 'VALEURS A L\'ENCAISSEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('511100', 'COUPONS ECHUS A L\'ENCAISSEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('511200', 'CHEQUES A ENCAISSER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('511300', 'EFFETS A L\'ENCAISSEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('511400', 'EFFETS A L\'ESCOMPTE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('512100', 'COMPTES EN MONNAIE NATIONALE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('512400', 'COMPTES EN DEVISES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('514000', 'CHEQUES POSTAUX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('515000', 'CAISSES DU TRESOR ET ETS PUBLICS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('516000', 'SOCIETE DE BOURSE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('517000', 'AUTRES ORGANISMES FINANCIERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('518000', 'INTERETS EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('518600', 'INTERETS COURUS A PAYER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('518700', 'INTERETS COURUS A RECEVOIR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('519000', 'CONCOURS BANCAIRES COURANTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('519100', 'CREDIT MOBIL. CREANC. CCIALES CMCC', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('519300', 'MOBIL. CREANCES NEES A L\'ETRANGER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('519800', 'INT. COURUS SUR CONCOURS BANCAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('520000', 'INSTRUMENTS DE TRESORERIE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('531000', 'CAISSE SIEGE SOCIAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('531100', 'CAISSE EN MONNAIE NATIONALE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('531400', 'CAISSE EN DEVISES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('532000', 'CAISSE SUCCURSALE (OU USINE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('533000', 'CAISSE SUCCURSALE (OU USINE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('580100', 'VIREMENT DE TRESORERIE A TRESORERIE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('590000', 'PROVIS. POUR DEPREC. VALEURS MOB.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('590300', 'ACTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('590400', 'AUTRES TIT. CONFERANT DROIT PROP.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('590600', 'OBLIGATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('590800', 'AUTRES VALEURS MOB. & CREANC. ASS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('601100', 'MATIERE (OU GROUPE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('601200', 'MATIERE (OU GROUPE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('601700', 'FOURNITURES A, B, C...', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602000', 'ACHATS STOCKES AUTRES APPROV.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602100', 'MATIERES CONSOMMABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602110', 'MATIERE (OU GROUPE) C', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602120', 'MATIERE (OU GROUPE) D', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602200', 'FOURNITURES CONSOMMABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602210', 'COMBUSTIBLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602220', 'PRODUITS D\'ENTRETIEN', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602230', 'FOURNITURES D\'ATELIER / USINES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602240', 'FOURNITURES DE MAGASINS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602250', 'FOURNITURES DE BUREAU', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602600', 'EMBALLAGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602610', 'EMBALLAGES PERDUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602650', 'EMBALL. RECUPERA. NON IDENTIF.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('602670', 'EMBALLAGES A USAGE MIXTE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('603000', 'VARIATION DES STOCKS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('603100', 'VARIAT. STOCKS MAT. PREM. ET FOURN', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('603200', 'VARIAT. STOCKS AUTRES APPROVISION.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('603700', 'VARIATION STOCKS DE MARCHANDISES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('604000', 'ACHATS ETUDES ET PRESTAT. SERVICES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('605000', 'ACHATS MATERIEL EQUIPEM. TRAVAUX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('606000', 'ACHATS NON STOCKES DE MAT. PREM.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('606400', 'FOURNITURES ADMINISTRATIVES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('606500', 'ACHATS SPECIAUX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('606800', 'AUTRES MATIERES ET FOURNITURES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('607100', 'MARCHANDISE (OU GROUPE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('607200', 'MARCHANDISE (OU GROUPE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('608000', 'FRAIS ACCESSOIRES D\'ACHAT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('609000', 'RABAIS REMISES RIST. SUR ACHATS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('609100', 'DE MATIERES PREMIERES (ET FOURN.)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('609200', 'D\'AUTRES APPROVISIONN. STOCKES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('609500', 'DE MATERIEL EQUIPEMENTS DE TRAVAUX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('609600', 'D\'APPROVISIONNEMENTS NON STOCKES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('609700', 'DE MARCHANDISES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('609800', 'RABAIS REMISES RIST. NON AFFECTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('612000', 'REDEVANCES DE CREDIT-BAIL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('612200', 'CREDIT-BAIL MOBILIER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('612500', 'CREDIT-BAIL IMMOBILIER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('613000', 'LOCATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('613600', 'MALIS SUR EMBALLAGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('614000', 'CHARGES LOCATIVES & DE COPROPRIETE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('615200', 'SUR BIENS IMMOBILIERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('615500', 'SUR BIENS MOBILIERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('615600', 'MAINTENANCE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('616100', 'MULTIRISQUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('616200', 'ASSUR. OBLIGAT. DOMMAGE-CONSTRUCT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('616300', 'ASSURANCE-TRANSPORT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('616360', 'SUR ACHATS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('616370', 'SUR VENTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('616380', 'SUR AUTRES BIENS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('616400', 'RISQUES D\'EXPLOITATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('616500', 'INSOLVABILITE CLIENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('618000', 'DIVERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('618100', 'DOCUMENTATION GENERALE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('618500', 'FRAIS DE COLLOQUES, SEMIN., CONFER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('619000', 'RABAIS REMISES RIST. SUR SERV. EXT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('621000', 'PERSONNEL EXTERIEUR A L\'ENTREPRISE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('621400', 'PERSONNEL DETACHE OU PRETE A L\'ETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('622000', 'REMUNERAT. D\'INTERM. ET HONORAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('622100', 'COMMISSIONS & COURTAGES SUR ACHATS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('622200', 'COMMISSIONS & COURTAGES SUR VENTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('622400', 'REMUNERATIONS DES TRANSITAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('622500', 'REMUNERATIONS D\'AFFACTURAGE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('622800', 'DIVERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('623000', 'PUBLICITE PUBLICAT. RELAT. PUBLIQ.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('623100', 'ANNONCES ET INSERTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('623200', 'ECHANTILLONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('623300', 'FOIRES ET EXPOSITIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('623500', 'PRIMES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('623600', 'CATALOGUES ET IMPRIMES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('623700', 'PUBLICATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('623800', 'DIVERS (POURBOIRES, DONS COURANTS)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('624000', 'TRANSP. BIENS & TRANSP. COLL. PERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('624100', 'TRANSPORTS SUR ACHATS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('624200', 'TRANSPORTS SUR VENTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('624300', 'TRANSPORTS ENTRE ETS OU CHANTIERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('624400', 'TRANSPORTS ADMINISTRATIFS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('624700', 'TRANSPORTS COLLECTIFS DU PERSONNEL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('624800', 'DIVERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('625000', 'DEPLACEM. MISSIONS ET RECEPTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('625500', 'FRAIS DE DEMENAGEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('625700', 'RECEPTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('627000', 'SERVICES BANCAIRES ET ASSIMILES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('627100', 'FRAIS SUR TITRES (ACHAT, VENTE,.).', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('627200', 'COMMISSIONS & FRAIS SUR EMPRUNTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('627500', 'FRAIS SUR EFFETS (COMM. D\'ENDOS,.)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('627600', 'LOCATION DE COFFRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('627800', 'AUTRES FRAIS & COMM. PREST. SERV.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('628000', 'DIVERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('628400', 'FRAIS DE RECRUTEMENT DU PERSONNEL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('629000', 'RABAIS REMISES RIST. SUR SERV. EXT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('631000', 'IMPOTS TAXES & VERS. SUR REMUNER.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('631100', 'TAXE SUR LES SALAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('631200', 'TAXE D\'APPRENTISSAGE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('631300', 'PART. EMPLOY. A FORM. PROF. CONT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('631400', 'COTIS. DEFAUT INVEST. DANS CONST.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('631800', 'AUTRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('633000', 'IMPOTS TAXES & VERS. SUR REMUNER.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('633100', 'VERSEMENT SUR LE TRANSPORT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('633200', 'ALLOCATION LOGEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('633300', 'PART. EMPLOY. A FORM. PROF. CONT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('633400', 'PART. EMPLOY. A EFFORT CONSTRUCT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('633500', 'VERS. LIBERAT. A EXONER. TAXE APP.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635000', 'AUTRES IMPOTS TAXES & VERS. ASS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635100', 'IMPOTS DIRECTS (SAUF IMPOT BENEF.)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635120', 'TAXES FONCIERES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635130', 'AUTRES IMPOTS LOCAUX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635140', 'TAXE SUR LES VEHICULES SOCIETES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635200', 'TAXES SUR CA NON RECUPERABLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635300', 'IMPOTS INDIRECTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635400', 'DROITS D\'ENREGISTREMENT ET TIMBRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635410', 'DROIT DE MUTATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635800', 'AUTRES DROITS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('637000', 'AUTRES IMPOTS TAXES ET VERS. ASS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('637100', 'CONTRIB. SOC. SOLID. A CHARGE STES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('637200', 'TAXES PERCUES PAR ORG. PUBLICS INT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('637400', 'IMPOTS & TAXES EXIGIB. A L\'ETRANG.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('637800', 'TAXES DIVERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('641100', 'SALAIRES APPOINT. COMMIS. DE BASE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('641200', 'CONGES PAYES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('641300', 'PRIMES ET GRATIFICATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('641400', 'SALAIRES, APPOINTEMENTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('641500', 'SUPPLEMENT FAMILIAL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('644000', 'REMUNERATION TRAVAIL DE L\'EXPLOIT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('647000', 'AUTRES CHARGES SOCIALES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('647100', 'PRESTATIONS DIRECTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('647200', 'VERS. AUX COMITES D\'ETS & D\'ETAB.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('647300', 'VERS. AUX COMITES HYGIENE ET SECUR', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('647400', 'VERSEMENTS AUX OEUVRES SOCIALES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('647500', 'MEDECINE DU TRAVAIL, PHARMACIE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('648000', 'AUTRES CHARGES DE PERSONNEL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('651000', 'REDEVANC. CONCESS. BREV. LICENC,..', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('651100', 'REDEV. CONCESS. BREV, LIC, MARQ,..', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('651600', 'DROITS D\'AUTEUR ET DE REPRODUCT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('651800', 'AUTRES DROITS & VALEURS SIMILAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('653000', 'JETONS DE PRESENCE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('654000', 'PERTES SUR CREANCES IRRECOUVRAB.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('654100', 'CREANCES DE L\'EXERCICE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('654400', 'CREANCES DES EXERCICES ANTERIEURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('655000', 'QUOTE-PARTS RESULT. OPER. EN COMM.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('655100', 'Q-P BENEF. TRANSF. (CPTA GERANT)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('655500', 'QUOTE-PART PERTE SUPP. (CPTA ASS)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('658000', 'CHARGES DIVERSES GESTION COURANTE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661000', 'CHARGES D\'INTERETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661100', 'INTERETS DES EMPRUNTS ET DETTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661160', 'DES EMPRUNTS ET DETTES ASSIMILEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661170', 'DES DETTES RATT. A PARTICIPATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661500', 'INTERETS CPTES COUR. & DEP. CREDIT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661600', 'INTERETS BANC. & SUR OPER. FINANC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661700', 'INTERETS OBLIGATIONS CAUTIONNEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661800', 'INTERETS DES AUTRES DETTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661810', 'DES DETTES COMMERCIALES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('661880', 'DES DETTES DIVERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('664000', 'PERTES CREANCES LIEES A PARTICIP.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('665000', 'ESCOMPTES ACCORDES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('667000', 'CHARG. NETTES SUR CESS. VAL. MOBIL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('668000', 'AUTRES CHARGES FINANCIERES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('668800', 'ECART DE CONVERSION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('671000', 'CHARG. EXCEPT. SUR OPERAT. GESTION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('671100', 'PENALITES SUR MARCHES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('671200', 'PENALITES AMENDES FISC. & PENALES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('671300', 'DONS, LIBERALITES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('671400', 'CREANC. DEVEN. IRRECOUV. SUR BENEF', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('671500', 'SUBVENTIONS ACCORDEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('671700', 'RAPPEL D\'IMPOTS (AUTRE QUE BENEF)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('671800', 'AUT. CHARG. EXCEP. SUR OPER. GEST.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('672000', 'CHARGES SUR EXERCICES ANTERIEURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('675000', 'VAL. COMPT. DES ELEM. ACTIF CEDES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('675100', 'IMMOBILISATIONS INCORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('675200', 'IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('675600', 'IMMOBILISATIONS FINANCIERES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('675800', 'AUTRES ELEMENTS D\'ACTIF', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('678000', 'AUTRES CHARGES EXCEPTIONNELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('678100', 'MALIS PROVENANT DE CLAUSES INDEXAT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('678200', 'LOTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('678300', 'MALIS DU RACHAT PAR ETS D\'ACTIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('678800', 'CHARGES EXCEPTIONNELLES DIVERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681100', 'DOTAT. AUX AMORT. DES IMMOB. CORPO', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681110', 'IMMOBILISATIONS INCORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681120', 'IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681200', 'DOTAT. AUX AMORT. CHARG. EXPLOIT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681500', 'DOTAT. AUX PROV. RISQ. & CHARG. EX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681600', 'DOTAT. AUX PROV. DEPREC. IMMOB.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681610', 'IMMOBILISATIONS INCORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681620', 'IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681700', 'DOTAT. AUX PROV. DEPREC. ACTIFS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681740', 'CREANCES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('686000', 'DOTAT. AUX AMORT. ET AUX PROVIS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('686100', 'DOT. AUX AMORT. PRIME REMB. OBLIG.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('686500', 'DOT. AUX PROV. RISQ. & CHARG. FIN.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('686600', 'DOT. AUX PROV. DEPREC. ELEM. FINAN', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('686620', 'IMMOBILISATIONS FINANCIERES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('686650', 'VALEURS MOBILIERES DE PLACEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('686800', 'AUTRES DOTATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('687000', 'DOTAT. AUX AMORT. ET PROVISIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('687100', 'DOTAT. AUX AMORT. EXCEPT. IMMOB.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('687200', 'DOTAT. AUX PROV. REGLEM. (IMMOB)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('687250', 'AMORTISSEMENTS DEROGATOIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('687300', 'DOTAT. AUX PROV. REGLEM. (STOCKS)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('687400', 'DOTAT. AUX AUTRES PROV. REGLEMENT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('687500', 'DOTAT. PROV. RISQ. & CHARG. EXCEP.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('691000', 'PARTICIPATIONS DES SALARIES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('695200', 'CONTRIB. ADDITIO. IMPOT BENEFICES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('695400', 'IMPOTS DUS A L\'ETRANGER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('696000', 'SUPPLEMENT D\'IMPOTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('697000', 'IMPOSITION FORF. ANUELLE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('698000', 'INTEGRATION FISCALE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('698100', 'INTEGRATION FISCALE - CHARGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('698900', 'INTEGRATION FISCALE - PRODUITS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('699000', 'PRODUITS REP. EN ARR. DES DEFICITS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('701000', 'VENTES DE PRODUITS FINIS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('701100', 'PRODUIT FINI (OU GROUPE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('701200', 'PRODUIT FINI (OU GROUPE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('702000', 'VENTES DE PRODUITS INTERMEDIAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('703000', 'VENTES DE PRODUITS RESIDUELS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('704000', 'TRAVAUX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('704100', 'TRAVAUX DE CATEG. (OU ACTIV.) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('704200', 'TRAVAUX DE CATEG. (OU ACTIV.) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('705000', 'ETUDES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('707100', 'MARCHANDISE (OU GROUPE) A', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('707200', 'MARCHANDISE (OU GROUPE) B', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('708000', 'PRODUITS DES ACTIVITES ANNEXES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('708100', 'PROD. SERV. EXPLOIT. INTER. PERSON', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('708200', 'COMMISSIONS ET COURTAGES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('708300', 'LOCATIONS DIVERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('708400', 'MISE A DISPOS. PERSONNEL FACTUREE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('708500', 'PORTS ET FRAIS ACCESSOIRES FACT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('708600', 'BONIS SUR REPRISES EMBALL. CONSIG.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('708700', 'BONIFICAT. CLTS & PRIMES VENTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('708800', 'AUTRES PRODUITS ACTIVITES ANNEXES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('709000', 'RABAIS REMISES RIST. ACCORD. A ETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('709100', 'SUR VENTES DE PRODUITS FINIS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('709200', 'SUR VENTES PRODUITS INTERMEDIAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('709400', 'SUR TRAVAUX', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('709500', 'SUR ETUDES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('709600', 'SUR PRESTATIONS DE SERVICES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('709700', 'SUR VENTES MARCHANDISES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('709800', 'SUR PRODUITS ACTIVITES ANNEXES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713000', 'VARIAT. STOCKS (EN-COURS PRODUCT.)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713300', 'VARIATION EN-COURS PRODUC. BIENS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713310', 'PRODUITS EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713350', 'TRAVAUX EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713400', 'VARIATION EN-COURS PROD. SERVICES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713410', 'ETUDES EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713450', 'PRESTATIONS SERVICES EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713500', 'VARIATION STOCKS DE PRODUITS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713510', 'PRODUITS INTERMEDIAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713550', 'PRODUITS FINIS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('713580', 'PRODUITS RESIDUELS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('721000', 'IMMOBILISATIONS INCORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('722000', 'IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('731000', 'PROD. NETS PART. SUR OP. EN COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('739000', 'PROD. NETS PART. SUR OP. TERMINEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('751000', 'REDEV. POUR CONCES. BREV. LIC....', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('751100', 'REDEV. POUR CONCES. BREV. LIC...', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('751600', 'DROITS D\'AUTEUR ET DE REPRODUCTION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('751800', 'AUTRES DROITS & VALEURS SIMILAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('752000', 'REV. IMMEUB. NON AFFECT. ACT. PROF', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('753000', 'JETONS PRESENCE ET REMUN. ADMINIST', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('754000', 'RISTOURNES PERCUES COOPERATIVES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('755000', 'QUOTES-PARTS RESULT. OP. EN COMMUN', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('755100', 'QUOTE-PART PERTE TRANSFEREE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('755500', 'QUOTE-PART BENEFICE ATTRIBUEE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('758000', 'PRODUITS DIVERS GESTION COURANTE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('761000', 'PRODUITS DE PARTICIPATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('761100', 'REVENUS TITRES DE PARTICIPATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('761600', 'REVENUS AUTRES FORMES PARTICIP.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('762000', 'PRODUITS AUTRES IMMOB. FINANC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('762100', 'REVENUS DES TITRES IMMOBILISES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('762400', 'REVENUS DES PRETS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('762700', 'REVENUS CREANCES IMMOBILISEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('763000', 'REVENUS DES AUTRES CREANCES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('763100', 'REVENUS CREANCES COMMERCIALES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('763800', 'REVENUS DES CREANCES DIVERSES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('764000', 'REVENUS VALEURS MOBIL. PLACEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('765000', 'ESCOMPTES OBTENUS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('767000', 'PROD. NETS SUR CESS. VALEURS MOB.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('767100', 'REVENUS CRE. RATT. PARTICIPATIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('768000', 'AUTRES PRODUITS FINANCIERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('771000', 'PRODUITS EXCEPT. SUR OPER. GESTION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('771100', 'DEDITS PENAL. SUR ACHATS & VENTES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('771300', 'LIBERALITES PERCUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('771400', 'RENTREES SUR CREANCES AMORTIES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('771500', 'SUBVENTIONS D\'EQUILIBRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('771700', 'DEGREVEM. IMPOTS (AUT. IMP. BENEF)', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('771800', 'AUTRES PROD. EXCEPT. SUR OP. GEST.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('772000', 'PRODUITS SUR EXERCICES ANTERIEURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('775000', 'PRODUITS CESSIONS ELEMENTS D\'ACTIF', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('775100', 'IMMOBILISATIONS INCORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('775200', 'IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('775600', 'IMMOBILISATIONS FINANCIERES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('775800', 'AUTRES ELEMENTS D\'ACTIF', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('777000', 'Q-P SUBV. INVEST. AU RESULT. EXERC', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('778000', 'AUTRES PRODUITS EXCEPTIONNELS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('778100', 'BONIS PROVENANT CLAUSES D\'INDEXAT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('778200', 'LOTS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('778300', 'BONIS RACHAT PAR ETS ACT. & OBLIG.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('778800', 'PRODUITS EXCEPTIONNELS DIVERS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781000', 'REPRISES SUR AMORTISS. & PROVIS.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781100', 'REPRIS. AMORT. IMMOB. CORP. & INC', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781110', 'IMMOBILISATIONS INCORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781120', 'IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781500', 'REPRIS. PROVIS. RISQ. & CH. EXPLOI', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781600', 'REP. PROV. DEPREC. IMM. CORP & INC', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781610', 'IMMOBILISATIONS INCORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781620', 'IMMOBILISATIONS CORPORELLES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781700', 'REPRIS. PROV. DEPREC. ACT. CIRCUL.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781730', 'STOCKS ET EN-COURS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('781740', 'CREANCES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('786000', 'REPRISES SUR PROVIS. POUR RISQUES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('786500', 'REP. PROV. RISQ. & CHARG. FINANC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('786600', 'REPRIS. PROV. DEPREC. ELEM. FINANC', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('786620', 'IMMOBILISATIONS FINANCIERES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('786650', 'VALEURS MOBILIERES DE PLACEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('787000', 'REPRISES SUR PROVISIONS', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('787200', 'REPRISES SUR PROV. REGLEMENTEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('787250', 'AMORTISSEMENTS DEROGATOIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('787260', 'PROVISION SPECIALE DE REEVALUATION', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('787270', 'PLUS-VALUES REINVESTIES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('787300', 'REPRISES SUR PROV. REGLEMENTEES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('787400', 'REPRIS. SUR AUTRES PROV. REGLEMENT', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('787500', 'REPRIS. PROV. RISQ. & CHARG. EXPL.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('787600', 'REPRIS. PROV. POUR DEPREC. EXCEPT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('791000', 'TRANSFERTS DE CHARGES D\'EXPLOIT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('796000', 'TRANSFERTS DE CHARGES FINANC.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('797000', 'TRANSFERTS DE CHARGES EXCEPT.', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('201000', 'FRAIS D\'ETABLISSEMENT', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('209000', 'SORTIE D\'IMMOBILISATION', 'A', '', 'I', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('474100', 'DIVERS A REINTEGRER', 'A', '', 'I', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('474200', 'BENEFICE SCM', 'A', '', 'I', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('475000', 'PLUS VALUES A COURT TERME', 'A', '', 'I', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('530000', 'CAISSE', 'A', '', 'I', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('760000', 'PRODUITS FINANCIERS', 'A', '', 'I', 'AR_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('770000', 'PRODUITS EXCEPTIONNELS', 'A', '', 'I', 'AR_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('530010', 'CAISSE', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('607000', 'ACHATS DE MARCHANDISES', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('622700', 'FRAIS D\'ACTES ET DE CONTENTIEUX', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('438600', 'AUTRES CHARGES A PAYER', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('473000', 'DIVERS A DEDUIRE', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('613200', 'LOCATIONS IMMOBILIERES', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('616000', 'PRIMES D\'ASSURANCE', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('633800', 'AUTRES', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('695000', 'IMPOTS SUR LES BENEFICES', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('108100', 'COMPTE DE LEXPLOITANT', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('512030', 'EPARGNE', 'A', '', 'A', 'AR_paid:AP_paid');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('100000', 'CLASSE 1', 'H', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('300000', 'CLASSE 3', 'H', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('500000', 'CLASSE 5', 'H', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('600000', 'CLASSE 6', 'H', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('700000', 'CLASSE 7', 'H', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('108000', 'COMPTE DE LEXPLOITANT', 'A', '', 'I', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('200001', 'IMMOBILISATION', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('200000', 'CLASSE 2', 'H', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('400001', 'FOURNISSEURS ET COMPTES RATTACHES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('400000', 'CLASSE 4', 'H', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('695100', 'IMPOTS DUS EN FRANCE', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('646000', 'COTIS. SOCIAL. PERSON. EXPLOITANT', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('645000', 'CHARGES DE SECUR. SOC. ET PREVOY.', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('617000', 'ETUDES ET RECHERCHES', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('615000', 'ENTRETIEN ET REPARATIONS', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('613500', 'LOCATIONS MOBILIERES', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('611000', 'SOUS-TRAITANCE GENERALE', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('695500', 'DEBOURS PAYES POUR LE COMPTE', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('690000', 'PARTICIP. SAL. / IMPOTS SUR BEN.', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('687600', 'DOTAT. AUX PROV. DEPREC. EXCEPT.', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681000', 'DOTATIONS AUX AMORT. & AUX PROVIS.', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('628100', 'CONCOURS DIVERS (COTISATIONS,...)', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('625600', 'MISSIONS', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('645800', 'COTISATIONS AUX AUTRES ORG. SOC.', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('641000', 'REMUNERATIONS DU PERSONNEL', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('625020', 'DEPLACEMENTS MOTO', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('622600', 'HONORAIRES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('621100', 'PERSONNEL INTERIMAIRE', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445500', 'TAXES SUR CA A DECAISSER', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('706000', 'PRESTATIONS DE SERVICES', 'A', '', 'I', 'IC_income');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('707000', 'VENTES DE MARCHANDISES', 'A', '', 'I', 'IC_sale');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445713', 'TVA COLLECTEE 19.6%', 'A', '', 'I', 'AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('512020', 'BANQUE DEBIT', 'A', '', 'E', 'AP');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445711', 'TVA COLLECTEE 5.5%', 'A', '', 'I', 'AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445661', 'TVA DEDUCTIBLE 5.5%', 'A', '', 'E', 'AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('512010', 'BANQUE CREDIT', 'A', '', 'I', 'AR:AR_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('681730', 'STOCKS ET EN-COURS', 'A', '', 'A', 'IC');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('580010', 'VIREMENT INTERNE', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('580000', 'VIREMENT INTERNE', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('766000', 'GAINS DE CHANGE', 'A', '', 'I', 'AR_amount:IC_income');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('472000', 'MOINS VALUES A COURT TERME', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('474000', 'DEFICIT SCM', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('670000', 'CHARGES FINANCIERES', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('645100', 'COTISATIONS A L\'URSSAF', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('645200', 'COTISATIONS AUX MUTUELES', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('645300', 'COTISATIONS AUX CAISSES RETR.', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('646400', 'COTISATIONS AUX ASSEDIC', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('623400', 'CADEAUX A LA CLIENTELE', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('437000', 'AUTRES ORGANISMES SOCIAUX', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('606100', 'FOURNITURES NON STOCK. EAU ENERG.', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('606300', 'FOURNIT. ENTRETIEN & PETIT EQUIP.', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('625010', 'DEPLACEMENTS AUTO', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('635110', 'TAXE PROFESSIONNELLE', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('645001', 'CSG', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('660000', 'CHARGES FINANCIERES', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('666000', 'PERTES DE CHANGE', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('512040', 'EXPLOITANT', 'A', '', 'E', 'AP_paid');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('431000', 'SECURITE SOCIALE', 'A', '', 'E', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('609400', 'D\'ETUDES & PRESTATIONS DE SERVICES', 'A', '', '', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('625100', 'VOYAGES ET DEPLACEMENTS', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('618300', 'DOCUMENTATION TECHNIQUE', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('445663', 'TVA DEDUCTIBLE 19.6%', 'A', '', 'E', 'AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('601000', 'ACHATS STOCKES MAT. PREM. (FOURN.)', 'A', '', 'E', 'AP_amount:IC_cogs');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('626000', 'FRAIS POSTAUX ET TELECOMMUNIC.', 'A', '', 'E', 'AP_amount');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('512000', 'BANQUE', 'A', '', 'A', 'AR_paid:AP_paid');
+--
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('999000', 'Foreign Exchange Gain', 'A', '', 'I', '');
+INSERT INTO "chart" ("accno", "description", "charttype", "gifi_accno", "category", "link") VALUES ('999010', 'Foreign Exchange Loss', 'A', '', 'E', '');
+--
+-- insert taxes
+--
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '445661'), 0.055);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '445663'), 0.196);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '445711'), 0.055);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '445713'), 0.196);
+--
+-- update defaults
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '681730'), income_accno_id = (select id from chart where accno = '707000'), expense_accno_id = (select id from chart where accno = '601000'), fxgain_accno_id = (select id from chart where accno = '999000'), fxloss_accno_id = (select id from chart where accno = '999010'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'EUR', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/German-Sample-chart.sql b/sql-ledger/sql/German-Sample-chart.sql
new file mode 100644
index 0000000..3ebfdec
--- /dev/null
+++ b/sql-ledger/sql/German-Sample-chart.sql
@@ -0,0 +1,216 @@
+-- Einfacher Deutscher Kontenrahmen => Very Easy German Default Chart
+-- Vorbereitet von / Prepared by Paul Tammes May 9th, 2002. Kommentar / Comments : finance@bermuda-holding.com
+-- Englische Texte für eigene Zwecke und um Refernz in SQL-Ledger Dokumentation zu erleichtern.
+-- English terms used mostly for my own reference and to make lookup in SQL-Ledger documentation easier.
+-- GIFI-codes werden benutzt/misbraucht um die art der Rechnung zu deuten, Fehler nicht ausgeschlossen denn
+-- Ich bin kein Deutscher Steuerberater ;-(
+-- GIFI field codes re-used for following specs:
+-- Link: Achtung, sehr wenig benutzt da mir die Kentnisse zum Deutschen System fehlen. Sehr gut aufpassen und wenn
+-- Ihr Fehler oder Praktische TIPS hat: gerne!
+-- Link: used to a minimum, update and customization may well be needed!
+-- A0 = Anlagevermögen / Fixed Assets
+-- A1-1 = Warenbestand / Inventory
+-- A1-2 = Forderungen / Liabilities
+-- A1-3 = Liquide Mittel / Assets
+-- A1-4 = Aktive Rechnungsabgrenzung / Closing Account results
+-- E = Erträge / Income
+-- K0 = Wareneinsatz / COGS
+-- K1 = Personalkosten / Salaries etc
+-- K2 = Raumkosten / Rental etc
+-- K3 = Sonstige Kosten / Various costs
+-- NA = Neutrale Aufwendungen / Neutral Costs
+-- NE - Neutrale Erlöse / Neutral Income
+-- P0 = Eigenkapital / Equity
+-- P1 = Rückstellungen / Reserves
+-- P2 = Fremdkapital Langfristig / Liabilities Long Term
+-- P3 = Fremdkapital Kurzfristig / Liabilities Short Term
+-- P4 = Passive Rechnungsabgrenzung / Closing Account results
+--
+-- A0
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0000','ANLAGEVERMÖGEN','H','A0','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0100','Konzessionen & Lizenzen','A','A0','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0135','EDV-Programme','A','A0','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0440','Maschinen','A','A0','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0500','Betriebsausstattung','A','A0','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0520','PKW','A','A0','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0650','Büroeinrichtung','A','A0','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0670','GWG','A','A0','A','');
+-- A1-1
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1100','WARENBESTAND','H','A1-1','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1140','Warenbestand','A','A1-1','A','IC');
+-- A1-2
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200','FORDERUNGEN','H','A1-2','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1201','Geleistete Anzahlungen','A','A1-2','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1210','Forderungen ohne Kontokorrent','A','A1-2','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1300','Sonstige Forderungen','A','A1-2','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1400','Anrechenbare Vorsteuer','A','A1-2','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1401','Anrechenbare Vorsteuer 7%','A','A1-2','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1402','Vorsteuer ig Erwerb','A','A1-2','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1403','Vorsteuer ig Erwerb 16%','A','A1-2','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1405','Anrechenbare Vorsteuer 16%','A','A1-2','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1406','Anrechenbare Vorsteuer 15%','A','A1-2','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1433','bezahlte Einfuhrumsatzsteuer','A','A1-2','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1370','Ungeklärte Posten','A','A1-2','A','');
+-- A1-3
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1600','LIQUIDE MITTEL','H','A1-3','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1601','Kasse','A','A1-3','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1700','Postgiro','A','A1-3','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800','Bank','A','A1-3','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1810','Bank USD','A','A1-3','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1820','Kreditkarten','A','A1-3','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1890','Geldtransit','A','A1-3','A','');
+-- A1-4
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1900','Aktive Rechnungsabgrenzung','A','A1-4','A','');
+-- P0
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000','EIGENKAPITAL','H','P0','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2001','Eigenkapital','A','P0','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2100','Privatentnahmen','A','P0','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2150','Privatsteuern','A','P0','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2180','Privateinlagen','A','P0','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2200','Sonderausgaben beschr.abzugsf.','A','P0','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2900','Gezeichnetes Kapital','A','P0','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2910','Ausstehende Einlagen','A','P0','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2970','Gewinnvortrag vor Verwendung','A','P0','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2978','Verlustvortrag vor Verwendung','A','P0','Q','');
+-- P1
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3000','RÜCKSTELLUNGEN','H','P1','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3030','Gewerbesteuerrückstellung','A','P1','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3070','Sonstige Rückstellungen','A','P1','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3095','Rückstellung für Abschlusskosten','A','P1','L','');
+-- P2
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3100','FREMDKAPITAL LANGFRISTIG','H','P2','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3160','Bankdarlehen','A','P2','L','');
+-- P3
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3200','FREMDKAPITAL KURZFRISTIG','H','P3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3280','Erhaltene Anzahlungen','A','P3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3310','Kreditoren ohne Kontokorrent','A','P3','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3500','Sonstige Verbindlichkeiten','A','P3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3560','Darlehen','A','P3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3700','Verbindl. Betr.steuern u.Abgaben','A','P3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3720','Verbindlichkeiten Löhne und Gehälter','A','P3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3730','Verbindlichkeiten Lohnsteuer','A','P3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3740','Verbindlichkeiten Sozialversicherung','A','P3','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3800','Umsatzsteuer','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3801','Umsatzsteuer 7%','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3802','Umsatzsteuer ig. Erwerb','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3803','Umsatzsteuer ig. Erwerb 16%','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3805','Umsatzsteuer 16%','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3806','Umsatzsteuer 15%','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3815','Umsatzsteuer nicht fällig 16%','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3816','Umsatzsteuer nicht fällig 15%','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3820','Umsatzsteuer-Vorauszahlungen','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3841','Umsatzsteuer Vorjahr','A','P3','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+-- P4
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3900','Aktive Rechnungsabgrenzung','A','P4','L','');
+-- K0
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5100','WARENEINGANG','H','K0','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5200','Wareneingang ohne Vorsteuer','A','K0','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5300','Wareneingang 7%','A','K0','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5400','Wareneingang 15%','A','K0','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5420','ig.Erwerb 7% VoSt. und 7% USt.','A','K0','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5425','ig.Erwerb 15% VoSt. und 15% USt.','A','K0','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5731','Erhaltene Skonti 7% Vorsteuer','A','K0','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5736','Erhaltene Skonti 15% Vorsteuer','A','K0','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5800','Anschaffungsnebenkosten','A','K0','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5900','Fremdarbeiten','A','K0','E','AP_amount:IC_cogs:IC_expense');
+-- K1
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6000','PERSONALKOSTEN','H','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6001','Personalkosten','H','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6010','Löhne','A','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6020','Gehälter','A','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6030','Aushilfslöhne','A','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6040','Lohnsteuer Aushilfen','A','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6080','Vermögenswirksame Leistungen','A','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6090','Fahrtkostenerst.Whg./Arbeitsstätte','A','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6110','Sozialversicherung','A','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6120','Berufsgenossenschaft','A','K1','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6130','Freiw. Soz. Aufw. LSt- u. Soz.Vers.frei','A','K1','E','');
+-- K2
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6300','RAUMKOSTEN','H','K2','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6310','Miete','A','K2','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6315','Pacht','A','K2','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6320','Heizung','A','K2','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6325','Gas Strom Wasser','A','K2','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6330','Reinigung','A','K2','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6335','Instandhaltung betriebliche Räume','A','K2','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6345','Sonstige Raumkosten','A','K2','E','AP_amount:IC_expense');
+-- K3
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6400','SONSTIGE KOSTEN','H','K3','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6402','Abschreibungen','A','K3','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6403','Kaufleasing','A','K3','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6404','Sofortabschreibung GWG','A','K3','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6405','Sonstige Kosten','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6410','Versicherung','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6420','Beiträge und Gebühren','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6430','Sonstige Abgaben','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6470','Rep. und Instandhaltung BGA','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6520','Kfz-Versicherung','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6530','Lfd. Kfz-Kosten','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6540','Kfz-Reparaturen','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6560','Fremdfahrzeuge','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6570','Sonstige Kfz-Kosten','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6600','Werbung','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6610','Kundengeschenke bis DM 75.','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6620','Kundengeschenke über DM 75.-','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6630','Repräsentationkosten','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6640','Bewirtungskosten','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6644','Nicht abzugsf.Bewirtungskosten','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6650','Reisekosten Arbeitnehmer','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6660','Reisekosten Arbeitnehmer 12.3%','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6665','Reisekosten Arbeitnehmer 9.8%','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6670','Reisekosten Unternehmer','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6680','Reisekosten Unternehmer 12.3%','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6685','Reisekosten Unternehmer 9.8%','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6688','Reisekosten Unternehmer 5.7%','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6690','Km-Geld-Erstattung 8.2%','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6710','Verpackungsmaterial','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6740','Ausgangsfrachten','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6780','Fremdarbeiten','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6800','Porto','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6805','Telefon','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6815','Bürobedarf','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6820','Zeitschriften & Bücher','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6825','Rechts- und Beratungskosten','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6835','Mieten für Einrichtungen','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6840','Mietleasing','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6845','Werkzeuge und Kleingeräte','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6850','Betriebsbedarf','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6852','Gastättenbedarf','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6855','Nebenkosten des Geldverkehrs','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6880','Aufwendungen aus Kursdifferenzen','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6885','Erlöse aus Anlageverk.(Buchverlust)','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7610','Gewerbesteuer','A','K3','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7685','Kfz-Steuer','A','K3','E','AP_amount:IC_cogs:IC_expense');
+-- E
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8100','ERTRÄGE','H','E','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8120','Steuerfreie Umsätze 4 Nr. 1a UStG.','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8125','Steuerfreie ig. Lieferungen 1b UStG.','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8200','Erlöse ohne Umsatzsteuer','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8300','Erlöse 7% Umsatzsteuer','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8400','Erlöse 15% Umsatzsteuer','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8500','Provisionserlöse','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8630','Entnahme sonstg. Leistungen 7% USt.','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8640','Entnahme sonstg. Leistungen 15% USt.','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8731','Gew. Skonti 7% USt.','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8736','Gew. Skonti 15% USt.','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8840','Erträge aus Kursdifferenzen','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8845','Erlöse aus Anlageverk. (Buchgewinn)','A','E','I','AR_amount:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8900','Erträge aus Abgang von Anlageverm.','A','E','I','AR_amount:IC_sale:IC_income');
+-- NA
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9300','NEUTRALE AUFWENDUNGEN','H','NA','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9310','Zinsen kurzfr. Verbindlichkeiten','A','NA','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9320','Zinsen langfr. Verbindlichkeiten','A','NA','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9500','Ausserordentl.Aufwendungen','A','NA','E','');
+-- NE
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9600','NEUTRALE ERTRÄGE','H','NE','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9610','Guthabenzinsen','H','NE','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9700','Ausserordentl.Erträge','H','NE','I','');
+--
+-- Default settings
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '3801'),0.07);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '3805'),0.16);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '3806'),0.15);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1140'), income_accno_id = (select id from chart where accno = '8120'), expense_accno_id = (select id from chart where accno = '5800'), fxgain_accno_id = (select id from chart where accno = '8840'), fxloss_accno_id = (select id from chart where accno = '6880'), invnumber = '0000', sonumber = '0000', ponumber = '0000', curr = 'EUR', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/German-Sample-gifi.sql b/sql-ledger/sql/German-Sample-gifi.sql
new file mode 100644
index 0000000..78eaed4
--- /dev/null
+++ b/sql-ledger/sql/German-Sample-gifi.sql
@@ -0,0 +1,19 @@
+-- Einfacher Kontoplan für Deutschland
+--
+INSERT INTO gifi (accno,description) VALUES ('A0', 'Anlagevermögen');
+INSERT INTO gifi (accno,description) VALUES ('A1-1', 'Warenbestand');
+INSERT INTO gifi (accno,description) VALUES ('A1-2', 'Forderungen');
+INSERT INTO gifi (accno,description) VALUES ('A1-3', 'Liquide Mittel');
+INSERT INTO gifi (accno,description) VALUES ('A1-4', 'Aktive Rechnungsabgrenzung');
+INSERT INTO gifi (accno,description) VALUES ('E', 'Erträge');
+INSERT INTO gifi (accno,description) VALUES ('K0', 'Wareneinsatz');
+INSERT INTO gifi (accno,description) VALUES ('K1', 'Personalkosten');
+INSERT INTO gifi (accno,description) VALUES ('K2', 'Raumkosten');
+INSERT INTO gifi (accno,description) VALUES ('K3', 'Sonstige Kosten');
+INSERT INTO gifi (accno,description) VALUES ('NA', 'Neutrale Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('NE', 'Neutrale Erlöse');
+INSERT INTO gifi (accno,description) VALUES ('P0', 'Eigenkapital');
+INSERT INTO gifi (accno,description) VALUES ('P1', 'Rückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('P2', 'Fremdkapital Langfristig');
+INSERT INTO gifi (accno,description) VALUES ('P3', 'Fremdkapital Kurzfristig');
+INSERT INTO gifi (accno,description) VALUES ('P4', 'Passive Rechnungsabgrenzung');
diff --git a/sql-ledger/sql/Germany-DATEV-SKR03-chart.sql b/sql-ledger/sql/Germany-DATEV-SKR03-chart.sql
new file mode 100644
index 0000000..126ce22
--- /dev/null
+++ b/sql-ledger/sql/Germany-DATEV-SKR03-chart.sql
@@ -0,0 +1,262 @@
+-- DATEV-SKR03 - Kontenrahmen
+-- Mon, 10 Feb 2003
+-- Yvonne Einberger
+
+
+-- Jetzt beginnt der Kontenrahmen !
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0002700','EDV-Software','A','A','','0002700');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0010000','Fabrikbauten','A','A','','0010000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0011000','Garagen','A','A','','0011000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0011100','Außenanlagen','A','A','','0011100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0011200','Hof-und Wegebefestigung','A','A','','0011200');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0011500','Andere Bauten','A','A','','0011500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0016500','Geschäftsbauten','A','A','','0016500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0008500','Grundstückswert eige.bebau.Grundst.','A','A','','0008500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0009000','Geschäftsbauten','A','A','','0009000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0017000','Fabrikbauten','A','A','','0017000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0017500','Garagen','A','A','','0017500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0017600','Außenanlage','A','A','','0017600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0021000','Maschinen','A','A','','0021000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0022000','Maschinengebundene Werkzeuge','A','A','','0022000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0024000','Maschinelle Anlagen','A','A','','0024000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0028000','Betriebsvorrichtung','A','A','','0028000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0031000','Andere Anlagen','A','A','','0031000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0032000','PKW','A','A','','0032000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0035000','LKW','A','A','','0035000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0040000','Betriebsausstattung','A','A','','0040000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0041000','Geschäftsausstattung','A','A','','0041000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0042000','Büroeinrichtung','A','A','','0042000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0043000','Ladeneinrichtung','A','A','','0043000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0049000','Sons.Betriebs- Geschäftsausstattung','A','A','','0049000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0050400','Ant.a.herr.o.m.Mehrh.bet.Ges.schaft','A','A','','0050400');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0051300','Typisch stille Beteiligungen','A','A','','0051300');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0063100','- Restlaufzeit bis 1 Jahr','A','L','','0063100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0051600','Atypische stille Beteiligungen','A','A','','0051600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0064000','- Restlaufzeit 1 bis 5 Jahre','A','L','','0064000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0065000','- Restlaufzeit größer als 5 Jahre','A','L','','0065000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0099600','Pauschalwertb.m.Restlaufzeit v. 1J.','A','A','','0099600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0140000','Ford. a.Lieferungen und Leistungen','A','A','AR','0140000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0153000','Forderungen gegen Personal','A','A','','0153000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0154500','Umsatzsteuerforderungen','A','A','','0154500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0100000','Kasse','A','A','AR_paid:AP_paid','0100000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0120000','Bank','A','A','AR_paid:AP_paid','0120000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0096300','Körperschaftssteuerrückstellung','A','Q','','0096300');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0095700','Gewerbesteuerrückstellung','A','Q','','0095700');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0051000','Beteiligungen','A','A','','0051000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0063000','Verbindl.gegenüber Kreditinstituten','A','L','','0063000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0097000','Sonstige Rückstellungen','A','L','','0097000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0097400','Rückstellungen für Gewährleistungen','A','L','','0097400');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0097800','Aufwandsrückstellungen','A','L','','0097800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0099800','Einzelwertber.m.Restlaufzeit v.1 J.','A','A','','0099800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0146000','Zweifelhafte Forderungen','A','A','','0146000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0151100','Geleistete Anzahlungen 7%','A','A','','0151100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0151700','Geleistete Anzahlung 16%','A','A','','0151700');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0152500','Kautionen','A','A','','0152500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0154000','Steuerüberzahlungen','A','A','','0154000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0157000','Abziehbare Vorsteuer','A','A','AR_tax:AP_tax','0157000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0160000','Verbindlichkeiten aus Lief.u.Leist.','A','L','AP','0160000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0174100','Verbindl.a.Lohn-und Kirchensteuer','A','L','','0174100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0178100','Umsatzsteuer-Vorauszahlung 1/11','A','L','','0178100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0178900','Umsatzsteuer laufendes Jahr','A','L','','0178900');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0179000','Umsatzsteuer Vorjahr','A','L','','0179000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0179100','Umsatzsteuer frühere Jahre','A','L','','0179100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0180000','Privatentnahme allgemein','A','Q','','0180000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0189000','Privateinlagen','A','Q','','0189000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0211000','Zinsaufwendung f.kurzf.Verbindlichk','A','E','','0211000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0212000','Zinsaufwendung f.langf.Verbindlichk','A','E','','0212000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0221000','Kapitalertragssteuer','A','E','','0221000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0231000','Anlagenabgänge - bei Buchverlust','A','E','','0231000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0231500','Anlagenabgänge-Buchgewinn','A','I','','0231500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0237500','Grundsteuer','A','E','','0237500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0245000','Einstell.i.d.Pauschalwertbe.z.Forde','A','E','','0245000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0245100','Einstell.i.d.Einzelwertb.z.Forderun','A','E','','0245100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0250000','Außerordentliche Erträge','A','I','','0250000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0251000','Betriebsfremde Erträge n.außerorden','A','I','','0251000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0252000','Periodenfremde Erträge nicht außero','A','I','','0252000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0273000','Ertr.a.Herab.d.Pauschal.z.Forderung','A','I','','0273000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0273100','Ertr.a.Herab.d.Einzelw.z.Forderunge','A','I','','0273100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0273200','Ertr. aus abgeschriebenen Forderung','A','I','','0273200');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0274200','Versicherungsentschädigungen','A','I','','0274200');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0286800','Verlustvortrag nach Verwendung','A','L','','0286800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0286900','Vortrag auf neue Rechnungen','A','L','','0286900');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0375000','Erhaltene Boni 7% Vorsteuer','A','I','','0375000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0376000','Erhaltene Boni 16% Vorsteuer','A','I','','0376000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0380000','Anschaffungsnebenkosten','A','E','IC_cogs:IC_expense','0380000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0385000','Zölle und Einfuhrabgaben','A','E','IC_cogs:IC_expense','0385000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0396000','Bestandsver.Roh-,Hilfs-.Betriebs.','A','E','','0396000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0397000','Bestand Roh-,Hilfs-,u.Betriebsstoff','A','A','IC','0397000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0399000','Verrechnete Stoffkosten','A','E','IC_cogs:IC_expense','0399000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0400000','Material-und Stoffverbrauch','A','E','IC_cogs:IC_expense','0400000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0410000','Löhne und Gehälter','A','E','AP_amount','0410000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0412500','Ehegattengehalt','A','E','AP_amount','0412500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0342000','Innergemein.Erwerb 7% VorSt u. Ust','A','E','AP_amount','0342000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0342500','Innergem.Erwerb 16% VorSt u. Ust','A','E','AP_amount','0342500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0373100','Erhaltene Skonti 7% Vorsteuer','A','I','AP_paid','0373100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0373500','Erhaltene Skonti 16% Vorsteuer','A','I','AP_paid','0373500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0330000','Wareneingang 7% Vorsteuer','A','E','AP_amount','0330000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0413000','Gesetzlich soziale Aufwendungen','A','E','AP_amount','0413000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0413800','Beiträge zur Berufsgenossenschaftr','A','E','AP_amount','0413800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0414500','Freiwillige sozi.Aufw.lohnsteuerfr.','A','E','AP_amount','0414500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0414900','Pauschale Lohnsteuera.sons.Bezüge','A','E','AP_amount','0414900');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0416500','Aufwendung f.Altersversorgung','A','E','AP_amount','0416500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0417000','Vermögenswirksame Leistungen','A','E','AP_amount','0417000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0420000','Raumkosten','A','E','AP_amount:AP_tax','0420000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0417500','Fahrtkostenerst.Wohnung/Arbeitsstät','A','E','AP_amount','0417500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0419000','Aushilfslöhne','A','E','AP_amount','0419000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0419900','Lohnsteuer für Aushilfe','A','E','AP_amount','0419900');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0159000','Durchlaufende Posten','A','A','','0159000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0422000','Pacht','A','E','AP_amount','0422000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0423000','Heizung','A','E','AP_amount','0423000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0424000','Gas,Strom, Wasser','A','E','AP_amount','0424000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0425000','Reinigung','A','E','AP_amount','0425000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0426000','Instandhaltung betrieb.Räume','A','E','AP_amount','0426000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0428000','Sonstige Raumkosten','A','E','AP_amount','0428000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0432000','Gewerbesteuer','A','E','AP_amount','0432000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0439000','Sonstige Abgaben','A','E','AP_amount','0439000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0453000','Laufende Kfz-Betriebskosten','A','E','AP_amount','0453000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0454000','Kfz-Reparaturen','A','E','AP_amount','0454000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0455000','Garagenmiete','A','E','AP_amount','0455000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0457000','Fremdfahrzeuge','A','E','AP_amount','0457000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0458000','Sonstige Kfz-Kosten','A','E','AP_amount','0458000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0461000','Werbekosten','A','E','AP_amount','0461000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0463000','Geschenke bis 40 EUR','A','E','AP_amount','0463000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0463500','Geschenke über 40 EUR','A','E','AP_amount','0463500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0464000','Repräsentationskosten','A','E','AP_amount','0464000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0465000','Bewirtungskosten','A','E','AP_amount','0465000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0465400','Nicht abzugsfähige Bewirtungskosten','A','E','AP_amount','0465400');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0465500','Nicht abzugsfähige Betriebsausgaben','A','E','','0465500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0466300','Reisekosten Arbeitn.m.Vorsteuerabzu','A','E','AP_amount','0466300');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0466600','Reisekosten Arbeitn.Übernachtungsau','A','E','','0466600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0466800','Kilometerentgelderstattung Arbeitne','A','E','','0466800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0467400','Reisekosten Untern.Verpflegungsmehr','A','E','','0467400');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0467600','Reisekosten Untern.Übernachtungsauf','A','E','','0467600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0467800','Kilometererstattungsgeld Unternehme','A','E','','0467800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0470000','Kosten der Warenabgabe','A','E','IC_cogs','0470000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0471000','Verpackungsmaterial','A','E','IC_cogs','0471000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0473000','Ausgangsfracht','A','E','IC_cogs','0473000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0475000','Transportversicherung','A','E','IC_cogs','0475000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0476000','Verkaufsprovision','A','E','IC_cogs','0476000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0478000','Fremdarbeiten','A','E','IC_cogs','0478000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0479000','Aufwand für Gewährleistungen','A','E','','0479000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0480900','Sonstige Reparaturen u.Instandhalt.','A','E','AP_amount','0480900');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0481000','Mietleasing','A','E','AP_amount','0481000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0481500','Kaufleasing','A','E','AP_amount','0481500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0482000','AfA a.Aufw.f.d.Inga.u.Erw.Geschäfts','A','E','AP_amount','0482000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0482100','AfA a.Aufw.f.d.Währungsumst.a.Euro','A','E','AP_amount','0482100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0483000','Abschreibungen auf Sachanlagen','A','E','AP_amount','0483000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0485500','Sofortabschreibung GWG','A','E','AP_amount','0485500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0491000','Porto','A','E','AP_amount','0491000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0492000','Telefon','A','E','AP_amount','0492000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0492500','Telefax','A','E','AP_amount','0492500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0493000','Bürobedarf','A','E','AP_amount','0493000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0494000','Zeitschriften, Bücher','A','E','AP_amount','0494000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0494500','Fortbildungskosten','A','E','AP_amount','0494500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0494600','Freiwillige Sozialleistungen','A','E','','0494600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0495000','Rechts- und Beratungskosten','A','E','AP_amount','0495000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0495500','Buchführungskosten','A','E','AP_amount','0495500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0495700','Abschluß- und Prüfungskosten','A','E','AP_amount','0495700');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0496000','Mieten für Einrichtungen','A','E','AP_amount','0496000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0497000','Nebenkosten des Geldverkehrs','A','E','','0497000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0498000','Betriebsbedarf','A','E','AP_amount','0498000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0498500','Werkzeuge und Kleingeräte','A','E','AP_amount','0498500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0498600','Sonstige Aufwendungen (Ausbuchung)','A','E','AP_amount','0498600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0136000','Geldtransit','A','A','','0136000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0705000','Unfertige Erzeugnisse','A','A','IC','0705000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0708000','Unfertige Leistungen','A','A','IC','0708000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0711000','Fertige Erzeugnisse (Bestand)','A','A','IC','0711000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0714000','Waren (Bestand)','A','A','IC','0714000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0873100','Gewährte Skonti 7% USt','A','I','AP_paid','0873100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0873500','Gewährte Skonti 16% USt.','A','I','AP_paid','0873500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0875000','Gewährte Boni 7% USt.','A','I','','0875000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0876000','Gewährte Boni 16% USt.','A','I','','0876000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0882000','Erlöse aus Anlageverkäufen 16%Ust','A','I','IC_sale','0882000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0895500','Umsatzsteuervergütungen','A','I','','0895500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0890500','Entnahme v. Gegenst.o.USt.','A','I','','0890500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0266000','Erträge aus Kursdifferenzen','A','I','','0266000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0215000','Aufwendungen aus Kursdifferenzen','A','E','','0215000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0850000','Provisionserlöse','A','I','AR_amount:IC_income','0850000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0830000','Erlöse 7%USt','A','I','AR_amount:IC_sale:IC_income','0830000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0840000','Erlöse 16% USt.','A','I','AR_amount:IC_sale:IC_income','0840000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0177100','Umsatzsteuer 7%','A','L','AR_tax:IC_taxpart:IC_taxservice:CT_tax','0177100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0177500','Umsatzsteuer 16%','A','L','AR_tax:IC_taxpart:IC_taxservice:CT_tax','0177500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0178000','Umsatzsteuer-Vorauszahlungen','A','L','AP_amount','0178000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0157100','Abziebare Vorsteuer 7%','A','A','AP_tax:IC_taxpart:IC_taxservice:CT_tax','0157100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0398000','Bestand Waren','A','A','IC','0398000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0340000','Wareneingang 16% Vorsteuer','A','E','AP_amount:IC_cogs','0340000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0383000','Leergut','A','E','IC_cogs','0383000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0492700','Internetkosten','A','E','AP_amount:IC_expense','0492700');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0451000','Kfz-Steuer','A','E','AP_amount','0451000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0452000','Kfz-Versicherungen','A','E','AP_amount','0452000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0492100','Telefon D1 Handy','A','E','AP_amount:IC_expense','0492000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0157500','Abziehbare Vorsteuer 16%','A','A','AP_tax:IC_taxpart:IC_taxservice:CT_tax','0157500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0900000','Saldenvorträge,Sachkonten','A','L','','0900000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0286000','Gewinnvortrag nach Verwendung','A','L','','0286000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0320000','Wareneingang o.Steuer','A','E','AP_amount','0320000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0084000','Kapitalrücklage','A','Q','','0084000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0086000','Gewinnvortrag vor Verwendung','A','Q','','0086000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0086800','Verlustvortrag vor Verwendung','A','L','','0086800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0086900','Vortrag auf neue Rechnungen','A','Q','','0086900');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0081000','Ausstehende Einlagen a.d.gez.Kapital eingefordert','A','A','','0081000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0080100','Ausst.Einl.a.d.gezeichnete Kapital n.eingef.','A','A','','0080100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0093000','Sonderposten mit Rücklagenanteil steuerf.Rückl.','A','L','','0093000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0095000','Rückstellungen f.Pensionen u.ähnl.Verpflichtungen','A','Q','','0095000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0098300','Abgrenzung aktive latente Steuern','A','A','','0098300');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0098600','Damnum/Disagio','A','A','','0098600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0099200','Wertberichtigungen','A','A','','0099200');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0016000','Bauten auf fremden Grundstücken','A','A','','0016000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0020000','Techn.Anlagen und Maschinen','A','A','','0020000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0030000','Andere Anlagen,Betrieb-und Geschäftsaus','A','A','','0030000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0050000','Finanzanlagen','A','A','','0050000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0060000','Verbindlichkeiten','A','L','','0060000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0080000','Gezeichnetes Kapital','A','Q','','0080000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0095500','Steuerrückstellung','A','Q','','0095500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0098000','Aktive Rechnungsabgrenzung','A','A','','0098000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0099000','Passive Rechnungsabgrenzung','A','L','','0099000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0134500','Eigene Anteile','A','A','','0134500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0134800','Sonstige Wertpapiere','A','A','','0134800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0150000','Sonstige Vermögensgegenstände','A','A','','0150000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0151000','Geleistete Anzahlung auf Vorräte','A','A','','0151000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0159400','Forderungen geg. verb. Unternehmen','A','A','','0159400');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0171000','Erhaltene Anzahlungen-Verbindlichke','A','L','','0171000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0175500','Lohn-und Gehaltsverrechnung','A','L','','0175500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0210000','Zinsen und ähnl.Aufwendungen','A','E','','0210000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0230000','Sonstige Aufwendungen','A','E','','0230000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0240000','Forderungsverlust-übliche Höhe','A','E','','0240000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0260000','Erträge aus Beteiligten','A','I','','0260000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0262000','Erträge a.and.Wertpap.u.Ausl.des FinanzAV','A','I','','0262000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0265000','Sonstige Zinsen und ähnliche Erträg','A','I','','0265000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0270000','Sonstige Erträge','A','I','','0270000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0310000','Fremdleistungen','A','E','','0310000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0421000','Miete','A','E','AP_amount','0421000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0048000','Geringwertige WG bis 410EUR','A','A','AP_amount','0048000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0097700','Rückstellung.f.Abschluß-u.Prüfungskosten','A','L','','0097700');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0087000','Festkapital','A','Q','','0087000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0088000','Variables Kapital','A','Q','','0088000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0093100','Sonderpost.m.Rücklageanteil nach §6bEStG','A','Q','','0093100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0093200','Sonderpost.m.Rücklageanteil n.35 EStR','A','Q','','0093200');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0130000','Wechsel a. Lieferungen u.Leistungen','A','A','','0130000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0131000','Besitzwechsel geg.verb.Unternehmen','A','A','','0131000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0132000','Besitzw.geg.Untern.m.Beteiligungsve','A','A','','0132000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0132700','Finanzwechsel','A','A','','0132700');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0133000','Schecks ','A','A','','0133000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0134000','Anteile verb.Untern.-Umlaufvermögen','A','A','','0134000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0272500','Erträge a.d.Abgang.v.Geg.d.UV','A','I','','0272500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0272000','Erträge a.d.Abgang v.Geg.d.AV','A','I','','0272000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0434000','Sonstige Betriebssteuern','A','E','AP_amount','0434000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0436000','Versicherungen','A','E','AP_amount','0436000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0438000','Beiträge','A','E','AP_amount','0438000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0450000','Fahrzugkosten','A','E','AP_amount','0450000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0700000','Unfertige Erzeugnisse unfert.Leistungen','A','A','','0700000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0900800','Saldenvorträge,Debitoren','A','L','','0900800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('0900900','Saldenvorträge,Kreditoren','A','L','','0900900');
+--
+-- Taxes
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '0397000'), income_accno_id = (select id from chart where accno = '0840000'), expense_accno_id = (select id from chart where accno = '0400000'), fxgain_accno_id = (select id from chart where accno = '0266000'), fxloss_accno_id = (select id from chart where accno = '0215000'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'EUR:USD', weightunit = 'kg';
+--
+INSERT INTO tax (chart_id,rate) VALUES ((SELECT id FROM chart WHERE accno = '0157100'),0.07);
+INSERT INTO tax (chart_id,rate) VALUES ((SELECT id FROM chart WHERE accno = '0157500'),0.16);
+INSERT INTO tax (chart_id,rate) VALUES ((SELECT id FROM chart WHERE accno = '0177100'),0.07);
+INSERT INTO tax (chart_id,rate) VALUES ((SELECT id FROM chart WHERE accno = '0177500'),0.16);
+
+
diff --git a/sql-ledger/sql/Germany-DATEV-SKR03-gifi.sql b/sql-ledger/sql/Germany-DATEV-SKR03-gifi.sql
new file mode 100644
index 0000000..36d11ab
--- /dev/null
+++ b/sql-ledger/sql/Germany-DATEV-SKR03-gifi.sql
@@ -0,0 +1,550 @@
+-- DATEV SKR03
+--
+INSERT INTO gifi (accno,description) VALUES ('0000100', 'Aufwand Geschäftsbetrieb');
+INSERT INTO gifi (accno,description) VALUES ('0000200', 'Aufwendungen Umstellung a.d.Euro');
+INSERT INTO gifi (accno,description) VALUES ('0001000', 'Konzession,gewerb.Schutzre.u.Werten');
+INSERT INTO gifi (accno,description) VALUES ('0001500', 'Konzessionen');
+INSERT INTO gifi (accno,description) VALUES ('0002700', 'EDV-Software');
+INSERT INTO gifi (accno,description) VALUES ('0003500', 'Geschäfts-oder Firmenwert');
+INSERT INTO gifi (accno,description) VALUES ('0003800', 'Anzahlungen a.Geschäft-o.Firmenwert');
+INSERT INTO gifi (accno,description) VALUES ('0003900', 'Anz.a.immaterielle Vermögsgegenstän');
+INSERT INTO gifi (accno,description) VALUES ('0004000', 'Verschmelzungsmehrwert');
+INSERT INTO gifi (accno,description) VALUES ('0005000', 'Grundstücke,grundstücksgl.Rechte..');
+INSERT INTO gifi (accno,description) VALUES ('0006000', 'Grundstücke u.grundstgl.Rech.o.Baut');
+INSERT INTO gifi (accno,description) VALUES ('0008000', 'Bauten a.eig. Grundstücken,Grgl.Rec');
+INSERT INTO gifi (accno,description) VALUES ('0008500', 'Grundstückswert eige.bebau.Grundst.');
+INSERT INTO gifi (accno,description) VALUES ('0009000', 'Geschäftsbauten');
+INSERT INTO gifi (accno,description) VALUES ('0010000', 'Fabrikbauten');
+INSERT INTO gifi (accno,description) VALUES ('0011000', 'Garagen');
+INSERT INTO gifi (accno,description) VALUES ('0011100', 'Außenanlagen');
+INSERT INTO gifi (accno,description) VALUES ('0011200', 'Hof-und Wegebefestigung');
+INSERT INTO gifi (accno,description) VALUES ('0011500', 'Andere Bauten');
+INSERT INTO gifi (accno,description) VALUES ('0012000', 'Geschäfts-,Fabrik-,andere Bau.imBau');
+INSERT INTO gifi (accno,description) VALUES ('0012900', 'Anz.Geschäfts-,Fabrik u. and.Bauten');
+INSERT INTO gifi (accno,description) VALUES ('0015000', 'Wohnbauten im Bau');
+INSERT INTO gifi (accno,description) VALUES ('0016000', 'Bauten auf fremden Grundstücken');
+INSERT INTO gifi (accno,description) VALUES ('0016500', 'Geschäftsbauten');
+INSERT INTO gifi (accno,description) VALUES ('0017000', 'Fabrikbauten');
+INSERT INTO gifi (accno,description) VALUES ('0017500', 'Garagen');
+INSERT INTO gifi (accno,description) VALUES ('0017600', 'Außenanlage');
+INSERT INTO gifi (accno,description) VALUES ('0020000', 'Techn.Anlagen und Maschinen');
+INSERT INTO gifi (accno,description) VALUES ('0021000', 'Maschinen');
+INSERT INTO gifi (accno,description) VALUES ('0022000', 'Maschinengebundene Werkzeuge');
+INSERT INTO gifi (accno,description) VALUES ('0024000', 'Maschinelle Anlagen');
+INSERT INTO gifi (accno,description) VALUES ('0028000', 'Betriebsvorrichtung');
+INSERT INTO gifi (accno,description) VALUES ('0029000', 'Techn.Anlagen u.Maschinen im Bau');
+INSERT INTO gifi (accno,description) VALUES ('0029900', 'Anz.a.techn.Anlagen und Maschinen');
+INSERT INTO gifi (accno,description) VALUES ('0030000', 'Andere Anlagen,Betrieb-Geschäftsaus');
+INSERT INTO gifi (accno,description) VALUES ('0031000', 'Andere Anlagen');
+INSERT INTO gifi (accno,description) VALUES ('0032000', 'PKW');
+INSERT INTO gifi (accno,description) VALUES ('0035000', 'LKW');
+INSERT INTO gifi (accno,description) VALUES ('0040000', 'Betriebsausstattung');
+INSERT INTO gifi (accno,description) VALUES ('0041000', 'Geschäftsausstattung');
+INSERT INTO gifi (accno,description) VALUES ('0042000', 'Büroeinrichtung');
+INSERT INTO gifi (accno,description) VALUES ('0043000', 'Ladeneinrichtung');
+INSERT INTO gifi (accno,description) VALUES ('0048000', 'Geringwertige Wirtschaftsg.b.800DM');
+INSERT INTO gifi (accno,description) VALUES ('0049000', 'Sons.Betriebs- Geschäftsausstattung');
+INSERT INTO gifi (accno,description) VALUES ('0049800', 'And. Anlagen,Betrieb/Geschäf.im Bau');
+INSERT INTO gifi (accno,description) VALUES ('0049900', 'Anz.and.Anlagen,Betrieb.Geschäftsau');
+INSERT INTO gifi (accno,description) VALUES ('0050000', 'Anteile a.verb.Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('0050400', 'Ant.a.herr.o.m.Mehrh.bet.Ges.schaft');
+INSERT INTO gifi (accno,description) VALUES ('0050500', 'Ausleihung an verb.Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('0051000', 'Beteiligungen');
+INSERT INTO gifi (accno,description) VALUES ('0051300', 'Typisch stille Beteiligungen');
+INSERT INTO gifi (accno,description) VALUES ('0051600', 'Atypische stille Beteiligungen');
+INSERT INTO gifi (accno,description) VALUES ('0052000', 'Ausl.a.Untern.m.Beteiligungsverhält');
+INSERT INTO gifi (accno,description) VALUES ('0052500', 'Wertpapiere des Anlagevermögens');
+INSERT INTO gifi (accno,description) VALUES ('0054000', 'Sonstige Ausleihungen');
+INSERT INTO gifi (accno,description) VALUES ('0057000', 'Genossenschaftsan.z.langf.Verbleib');
+INSERT INTO gifi (accno,description) VALUES ('0059500', 'Rückdeckansp.Lebensvers.langf.Verbl');
+INSERT INTO gifi (accno,description) VALUES ('0060000', 'Anleihen-nicht konvertibel');
+INSERT INTO gifi (accno,description) VALUES ('0063000', 'Verbindl.gegenüber Kreditinstituten');
+INSERT INTO gifi (accno,description) VALUES ('0070000', 'Verbind.gegenüber verb.Unternehmern');
+INSERT INTO gifi (accno,description) VALUES ('0071500', 'Verbind.gegen.Untern.m.Beteili.Verh');
+INSERT INTO gifi (accno,description) VALUES ('0073000', 'Verbindlichkeiten gegen. Gesellscha');
+INSERT INTO gifi (accno,description) VALUES ('0076000', 'Darl.typ.stiller Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('0078000', 'Partiarische Darlehen');
+INSERT INTO gifi (accno,description) VALUES ('0080000', 'Gezeichnetes Kapital');
+INSERT INTO gifi (accno,description) VALUES ('0080100', 'Ausst.Einl.a.d.gezeichnete Kapital');
+INSERT INTO gifi (accno,description) VALUES ('0084000', 'Kapitalrücklage');
+INSERT INTO gifi (accno,description) VALUES ('0084600', 'Gesetzliche Rücklage');
+INSERT INTO gifi (accno,description) VALUES ('0085000', 'Rücklage für eigene Anteile');
+INSERT INTO gifi (accno,description) VALUES ('0085100', 'Satzungsmäßige Rücklagen');
+INSERT INTO gifi (accno,description) VALUES ('0086000', 'Gewinnvortrag vor Verwendung');
+INSERT INTO gifi (accno,description) VALUES ('0086800', 'Verlustvortrag vor Verwendung');
+INSERT INTO gifi (accno,description) VALUES ('0086900', 'Vortrag auf neue Rechnungen');
+INSERT INTO gifi (accno,description) VALUES ('0087000', 'Festkapital');
+INSERT INTO gifi (accno,description) VALUES ('0088000', 'Variables Kapital');
+INSERT INTO gifi (accno,description) VALUES ('0089000', 'Gesellschafter-Darlehen');
+INSERT INTO gifi (accno,description) VALUES ('0090000', 'Kommandit-Kapital');
+INSERT INTO gifi (accno,description) VALUES ('0091000', 'Verlustausgleichskonto');
+INSERT INTO gifi (accno,description) VALUES ('0092000', 'Gesellschafter-Darlehen');
+INSERT INTO gifi (accno,description) VALUES ('0093000', 'Sonderposten mit Rücklagenanteil');
+INSERT INTO gifi (accno,description) VALUES ('0093100', 'Sopo m.Rückl.ant.nach §6b EstG');
+INSERT INTO gifi (accno,description) VALUES ('0093200', 'Sopo m.Rückl.ant.Abschn.35 EstR');
+INSERT INTO gifi (accno,description) VALUES ('0093500', 'Sopo aus Währungsumstellung Euro');
+INSERT INTO gifi (accno,description) VALUES ('0094700', 'Sopo m.Rückl.ant. §7g Abs.1 EstG');
+INSERT INTO gifi (accno,description) VALUES ('0094800', 'Sopo m.Rückl.ant. §7g Abs.3,7 EstG');
+INSERT INTO gifi (accno,description) VALUES ('0095500', 'Steuerrückstellung');
+INSERT INTO gifi (accno,description) VALUES ('0095700', 'Gewerbesteuerrückstellung');
+INSERT INTO gifi (accno,description) VALUES ('0096300', 'Körperschaftssteuerrückstellung');
+INSERT INTO gifi (accno,description) VALUES ('0096900', 'Rückstellung für latente Steuern');
+INSERT INTO gifi (accno,description) VALUES ('0097000', 'Sonstige Rückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('0097400', 'Rückstellungen für Gewährleistungen');
+INSERT INTO gifi (accno,description) VALUES ('0097600', 'Rücks.f.drohe.Verl.schweb.Geschäft');
+INSERT INTO gifi (accno,description) VALUES ('0097700', 'Rücks.f.Abschluß-u.Prüfungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0097800', 'Aufwandsrückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('0098000', 'Aktive Rechnungsabgrenzung');
+INSERT INTO gifi (accno,description) VALUES ('0098300', 'Abgrenzung aktive latente Steuern');
+INSERT INTO gifi (accno,description) VALUES ('0098600', 'Damnum/Disagio');
+INSERT INTO gifi (accno,description) VALUES ('0099000', 'Passive Rechnungsabgrenzung');
+INSERT INTO gifi (accno,description) VALUES ('0099200', 'Wertberichtigungen');
+INSERT INTO gifi (accno,description) VALUES ('0099600', 'Pauschalwertb.m.Restlaufzeit v. 1J.');
+INSERT INTO gifi (accno,description) VALUES ('0099800', 'Einzelwertber.m.Restlaufzeit v.1 J.');
+INSERT INTO gifi (accno,description) VALUES ('0100000', 'Kasse');
+INSERT INTO gifi (accno,description) VALUES ('0110000', 'Postbank');
+INSERT INTO gifi (accno,description) VALUES ('0120000', 'Bank');
+INSERT INTO gifi (accno,description) VALUES ('0121000', 'Dresdner Bank AG');
+INSERT INTO gifi (accno,description) VALUES ('0121009', 'Verrechnungskonto Dresdner Bank AG');
+INSERT INTO gifi (accno,description) VALUES ('0122000', 'Deutsche Bank AG');
+INSERT INTO gifi (accno,description) VALUES ('0130000', 'Wechsel a. Lieferungen u.Leistungen');
+INSERT INTO gifi (accno,description) VALUES ('0131000', 'Besitzwechsel geg.verb.Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('0132000', 'Besitzw.geg.Untern.m.Beteiligungsve');
+INSERT INTO gifi (accno,description) VALUES ('0132700', 'Finanzwechsel');
+INSERT INTO gifi (accno,description) VALUES ('0133000', 'Schecks (Eingang)');
+INSERT INTO gifi (accno,description) VALUES ('0133300', 'Schecks (Ausgang)');
+INSERT INTO gifi (accno,description) VALUES ('0133500', 'Überweisungen (unterwegs)');
+INSERT INTO gifi (accno,description) VALUES ('0134000', 'Anteile verb.Untern.-Umlaufvermögen');
+INSERT INTO gifi (accno,description) VALUES ('0134400', 'Anteil an herr.m.betei.Gesellschaft');
+INSERT INTO gifi (accno,description) VALUES ('0134500', 'Eigene Anteile');
+INSERT INTO gifi (accno,description) VALUES ('0134800', 'Sonstige Wertpapiere');
+INSERT INTO gifi (accno,description) VALUES ('0136000', 'Geldtransit');
+INSERT INTO gifi (accno,description) VALUES ('0136100', 'Geldtransit (Überweisungen)');
+INSERT INTO gifi (accno,description) VALUES ('0136200', 'Geldtransit,Bankeinzug/Lastschrift');
+INSERT INTO gifi (accno,description) VALUES ('0136300', 'Scheck / Wechsel');
+INSERT INTO gifi (accno,description) VALUES ('0140000', 'Ford. a.Lieferungen und Leistungen');
+INSERT INTO gifi (accno,description) VALUES ('0141100', 'Forderungssammelkonto Vorausre.');
+INSERT INTO gifi (accno,description) VALUES ('0141200', 'Forderungssammelkonto Anzahlungen');
+INSERT INTO gifi (accno,description) VALUES ('0146000', 'Zweifelhafte Forderungen');
+INSERT INTO gifi (accno,description) VALUES ('0147000', 'Forder.a.Liefe.u.Leis.geg.verb.Unte');
+INSERT INTO gifi (accno,description) VALUES ('0147800', 'Wertb.a.Ford.m.Rest.1j.geg.verb.Unt');
+INSERT INTO gifi (accno,description) VALUES ('0148000', 'Lief.u.Leis.geg.Untern.m.Beteiligve');
+INSERT INTO gifi (accno,description) VALUES ('0148800', 'Wertb.a.Ford.m.Rest.1j.Beteiligungs');
+INSERT INTO gifi (accno,description) VALUES ('0149000', 'Forderung a.Leis.u.Lief.geg.Gesells');
+INSERT INTO gifi (accno,description) VALUES ('0150000', 'Sonstige Vermögensgegenstände');
+INSERT INTO gifi (accno,description) VALUES ('0150300', 'Forde.geg.Vorstandsm.u.Geschäftsfüh');
+INSERT INTO gifi (accno,description) VALUES ('0150800', 'Forderungen gegen Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('0151000', 'Geleistete Anzahlung auf Vorräte');
+INSERT INTO gifi (accno,description) VALUES ('0151100', 'Geleistete Anzahlungen 7%');
+INSERT INTO gifi (accno,description) VALUES ('0151700', 'Geleistete Anzahlung 16%');
+INSERT INTO gifi (accno,description) VALUES ('0152500', 'Kautionen');
+INSERT INTO gifi (accno,description) VALUES ('0153000', 'Forderungen gegen Personal');
+INSERT INTO gifi (accno,description) VALUES ('0154000', 'Steuerüberzahlungen');
+INSERT INTO gifi (accno,description) VALUES ('0154500', 'Umsatzsteuerforderungen');
+INSERT INTO gifi (accno,description) VALUES ('0154800', 'Vorsteuer im Folgejahr abziehbar');
+INSERT INTO gifi (accno,description) VALUES ('0154900', 'Körperschaftsteuerrückforderung');
+INSERT INTO gifi (accno,description) VALUES ('0155000', 'Darlehen');
+INSERT INTO gifi (accno,description) VALUES ('0156000', 'Aufzuteilende Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0156500', 'Aufzuteilende Vorsteuer 16%');
+INSERT INTO gifi (accno,description) VALUES ('0157000', 'Abziehbare Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0157100', 'Abziebare Vorsteuer 7%');
+INSERT INTO gifi (accno,description) VALUES ('0157200', 'Abziehb. VorSt innergemein. Erwerb');
+INSERT INTO gifi (accno,description) VALUES ('0157300', 'Abziehb.VorSt. innergem.Erwerb 16%');
+INSERT INTO gifi (accno,description) VALUES ('0157500', 'Abziehbare Vorsteuer 16%');
+INSERT INTO gifi (accno,description) VALUES ('0157800', 'Berichtigung d.Vorstabzugs früh.J.');
+INSERT INTO gifi (accno,description) VALUES ('0157900', 'Vorsteuer 0%');
+INSERT INTO gifi (accno,description) VALUES ('0158400', 'abziehb.VorSt IG Erwerb Neufahrzeug');
+INSERT INTO gifi (accno,description) VALUES ('0158800', 'Bezahlte Einfuhrumsatzsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0159000', 'Durchlaufende Posten');
+INSERT INTO gifi (accno,description) VALUES ('0159400', 'Forderungen geg. verb. Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('0159700', 'Ford.geg.Untern.m.Beteiligungsverh.');
+INSERT INTO gifi (accno,description) VALUES ('0160000', 'Verbindlichkeiten aus Lief.u.Leist.');
+INSERT INTO gifi (accno,description) VALUES ('0160100', 'Verbindlichkeiten a.Lief.und Leist.');
+INSERT INTO gifi (accno,description) VALUES ('0163000', 'Verbindl.Lief.u.Leist.gegü.verb.Unt');
+INSERT INTO gifi (accno,description) VALUES ('0164000', 'Verb.L.u.L gegü.Unter.Beteiligungsv');
+INSERT INTO gifi (accno,description) VALUES ('0165000', 'Verb.L.u.L gegü.Gesellschaftern');
+INSERT INTO gifi (accno,description) VALUES ('0166000', 'Schuldwechsel');
+INSERT INTO gifi (accno,description) VALUES ('0170000', 'Sonstige Verbindlichkeiten');
+INSERT INTO gifi (accno,description) VALUES ('0170500', 'Darlehen');
+INSERT INTO gifi (accno,description) VALUES ('0170900', 'Gewinnverfügungskonto stiller Ges.');
+INSERT INTO gifi (accno,description) VALUES ('0171000', 'Erhaltene Anzahlungen-Verbindlichke');
+INSERT INTO gifi (accno,description) VALUES ('0171100', 'Erhaltene,versteuert Anzahlungen 7%');
+INSERT INTO gifi (accno,description) VALUES ('0171700', 'Erhaltene,versteuerte Anzahl. 16%');
+INSERT INTO gifi (accno,description) VALUES ('0171900', 'Erhaltene Anzahlungen bis 1j.');
+INSERT INTO gifi (accno,description) VALUES ('0172200', 'Erhaltene Anzahlung');
+INSERT INTO gifi (accno,description) VALUES ('0172300', 'Verbindlichkeiten S-konto Vorausre.');
+INSERT INTO gifi (accno,description) VALUES ('0173200', 'Erhaltene Kautionen');
+INSERT INTO gifi (accno,description) VALUES ('0174100', 'Verbindl.a.Lohn-und Kirchensteuer');
+INSERT INTO gifi (accno,description) VALUES ('0175500', 'Lohn-und Gehaltsverrechnung');
+INSERT INTO gifi (accno,description) VALUES ('0175800', 'USt-Abzugsverfahren 16%');
+INSERT INTO gifi (accno,description) VALUES ('0175900', 'Ust 0%');
+INSERT INTO gifi (accno,description) VALUES ('0176000', 'Umsatzsteuer nicht fällig');
+INSERT INTO gifi (accno,description) VALUES ('0176100', 'Umsatzsteuer nicht fällig 7%');
+INSERT INTO gifi (accno,description) VALUES ('0176200', 'Umsatzsteuer nicht fällig EG Lief.');
+INSERT INTO gifi (accno,description) VALUES ('0177000', 'Umsatzsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0177100', 'Umsatzsteuer 7%');
+INSERT INTO gifi (accno,description) VALUES ('0177200', 'Umsatzsteuer aus innergem. Erwerb');
+INSERT INTO gifi (accno,description) VALUES ('0177300', 'Umsatzsteuer innergem.Erwerb 16%');
+INSERT INTO gifi (accno,description) VALUES ('0177500', 'Umsatzsteuer 16%');
+INSERT INTO gifi (accno,description) VALUES ('0177700', 'Ust aus im Inland stpfl. EG-Lief16%');
+INSERT INTO gifi (accno,description) VALUES ('0178000', 'Umsatzsteuer-Vorauszahlungen');
+INSERT INTO gifi (accno,description) VALUES ('0178100', 'Umsatzsteuer-Vorauszahlung 1/11');
+INSERT INTO gifi (accno,description) VALUES ('0178300', 'In Rechn unberecht.ausgew.gesch Ust');
+INSERT INTO gifi (accno,description) VALUES ('0178400', 'Ust IG Erwerb Neufahrzeug o.Ust ID');
+INSERT INTO gifi (accno,description) VALUES ('0178800', 'Einfuhrumsatzsteuer augeschoben bis');
+INSERT INTO gifi (accno,description) VALUES ('0178900', 'Umsatzsteuer laufendes Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0179000', 'Umsatzsteuer Vorjahr');
+INSERT INTO gifi (accno,description) VALUES ('0179100', 'Umsatzsteuer frühere Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0179200', 'Sonstige Verrechnungskonten');
+INSERT INTO gifi (accno,description) VALUES ('0180000', 'Privatentnahme allgemein');
+INSERT INTO gifi (accno,description) VALUES ('0181000', 'Privatsteuern');
+INSERT INTO gifi (accno,description) VALUES ('0189000', 'Privateinlagen');
+INSERT INTO gifi (accno,description) VALUES ('0200000', 'Außerordentliche Aufwendung');
+INSERT INTO gifi (accno,description) VALUES ('0201000', 'Betriebsfremde Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('0202000', 'Periodenfremde Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('0210000', 'Zinsen und ähnl.Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('0210300', 'Steuerl.abzugsfähig,and.Nebenl.Steu');
+INSERT INTO gifi (accno,description) VALUES ('0210400', 'Steuerl.nicht.abzugsf.ande.Nl.z.Ste');
+INSERT INTO gifi (accno,description) VALUES ('0210700', 'Zinsaufwendung-betriebliche Steuern');
+INSERT INTO gifi (accno,description) VALUES ('0210800', 'Zinsaufwendung-Personsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0210900', 'Zinsaufwendungen an verb.Unternehm.');
+INSERT INTO gifi (accno,description) VALUES ('0211000', 'Zinsaufwendung f.kurzf.Verbindlichk');
+INSERT INTO gifi (accno,description) VALUES ('0212000', 'Zinsaufwendung f.langf.Verbindlichk');
+INSERT INTO gifi (accno,description) VALUES ('0213000', 'Diskontaufwendung');
+INSERT INTO gifi (accno,description) VALUES ('0215000', 'Aufwendungen aus Kursdifferenzen');
+INSERT INTO gifi (accno,description) VALUES ('0216500', 'Aufw.a.d.Währungsumstell.a.d.Euro');
+INSERT INTO gifi (accno,description) VALUES ('0217000', 'Nicht abziehbare Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0217100', 'Nicht abziehbare Vorsteuer 7%');
+INSERT INTO gifi (accno,description) VALUES ('0217500', 'Nicht abziehbare Vorsteuer 16%');
+INSERT INTO gifi (accno,description) VALUES ('0220000', 'Körperschaftssteuer');
+INSERT INTO gifi (accno,description) VALUES ('0220300', 'Körperschaftssteuer für Vorjahr');
+INSERT INTO gifi (accno,description) VALUES ('0220500', 'Anrechb.Körperschaftsst.vereinn.Kap');
+INSERT INTO gifi (accno,description) VALUES ('0220800', 'Solidaritätszuschlag');
+INSERT INTO gifi (accno,description) VALUES ('0220900', 'Solidaritätszuschlag für Vorjahr');
+INSERT INTO gifi (accno,description) VALUES ('0221000', 'Kapitalertragssteuer');
+INSERT INTO gifi (accno,description) VALUES ('0221300', 'Anrechb.Solidaritätszusch.a.Zinsabs');
+INSERT INTO gifi (accno,description) VALUES ('0221500', 'Zinsabschlagsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0221800', 'Anrechb.Solidari.zuschlag a.Zinsabs');
+INSERT INTO gifi (accno,description) VALUES ('0228000', 'Stnachzahl.Vorj.v.Einkomm u.Ertrag');
+INSERT INTO gifi (accno,description) VALUES ('0228200', 'Sterstat.Vorj.Steuer v.Eink.u.Ertra');
+INSERT INTO gifi (accno,description) VALUES ('0228400', 'Ertr.a.d.Aufl.v.Rücks.f.St.v.Ein.Er');
+INSERT INTO gifi (accno,description) VALUES ('0228500', 'Steuernachzahlung Vorj.f.sons.Steue');
+INSERT INTO gifi (accno,description) VALUES ('0228700', 'Steuererstattung Vorj.f.sons.Steuer');
+INSERT INTO gifi (accno,description) VALUES ('0228900', 'Erträge a.d.Aufl.v. Rück.f.sons.Ste');
+INSERT INTO gifi (accno,description) VALUES ('0230000', 'Sonstige Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('0231000', 'Anlagenabgänge - bei Buchverlust');
+INSERT INTO gifi (accno,description) VALUES ('0231500', 'Anlagenabgänge-Buchgewinn');
+INSERT INTO gifi (accno,description) VALUES ('0232000', 'Verluste Abgang Gegenst.d.Anlagever');
+INSERT INTO gifi (accno,description) VALUES ('0232500', 'Verlust a.d.Abg.v.Gegens.d.Umlaufve');
+INSERT INTO gifi (accno,description) VALUES ('0234000', 'Einstellungen Sopo m.Rückanlageant.');
+INSERT INTO gifi (accno,description) VALUES ('0234500', 'Einstellungen Sopo m.R.(Sonderafa)');
+INSERT INTO gifi (accno,description) VALUES ('0237500', 'Grundsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0240000', 'Forderungsverlust-übliche Höhe');
+INSERT INTO gifi (accno,description) VALUES ('0241000', 'Einstellungen Sopo m.Rückl.(§7g )');
+INSERT INTO gifi (accno,description) VALUES ('0243000', 'Forderungsverluste-unüblich hoch');
+INSERT INTO gifi (accno,description) VALUES ('0245000', 'Einstell.i.d.Pauschalwertbe.z.Forde');
+INSERT INTO gifi (accno,description) VALUES ('0245100', 'Einstell.i.d.Einzelwertb.z.Forderun');
+INSERT INTO gifi (accno,description) VALUES ('0249000', 'Aufwendung aus Verlustübernahme');
+INSERT INTO gifi (accno,description) VALUES ('0249200', 'Abgef.Gewinn aufgr.e.Gewinngemeinsc');
+INSERT INTO gifi (accno,description) VALUES ('0249300', 'Abgef.Gewinnant.an stille Gesellsch');
+INSERT INTO gifi (accno,description) VALUES ('0249500', 'Einst.Kapitalrückl.n.Vorschr.vere.K');
+INSERT INTO gifi (accno,description) VALUES ('0249600', 'Einstellungen in die gesetzl.Rückla');
+INSERT INTO gifi (accno,description) VALUES ('0250000', 'Außerordentliche Erträge');
+INSERT INTO gifi (accno,description) VALUES ('0251000', 'Betriebsfremde Erträge n.außerorden');
+INSERT INTO gifi (accno,description) VALUES ('0252000', 'Periodenfremde Erträge nicht außero');
+INSERT INTO gifi (accno,description) VALUES ('0260000', 'Erträge aus Beteiligten');
+INSERT INTO gifi (accno,description) VALUES ('0261700', 'Gewinn a.Anteila.nicht stbef.Kapita');
+INSERT INTO gifi (accno,description) VALUES ('0261900', 'Erträge a.Beteil.a.verb.Untérnehmer');
+INSERT INTO gifi (accno,description) VALUES ('0262000', 'Erträge a.anderen Wertp u.Ausl.Fina');
+INSERT INTO gifi (accno,description) VALUES ('0265000', 'Sonstige Zinsen und ähnliche Erträg');
+INSERT INTO gifi (accno,description) VALUES ('0265700', 'Zinserträge-betriebliche Steuern');
+INSERT INTO gifi (accno,description) VALUES ('0265800', 'Zinserträge-Körperschaftssteuer');
+INSERT INTO gifi (accno,description) VALUES ('0265900', 'Sons.Zinsen u.ähl.Ertr.a.verb.Unter');
+INSERT INTO gifi (accno,description) VALUES ('0266000', 'Erträge aus Kursdifferenzen');
+INSERT INTO gifi (accno,description) VALUES ('0266500', 'Erträge a.d.Währungumst.a.d. Euro');
+INSERT INTO gifi (accno,description) VALUES ('0267000', 'Diskonerträge');
+INSERT INTO gifi (accno,description) VALUES ('0270000', 'Sonstige Erträge');
+INSERT INTO gifi (accno,description) VALUES ('0270500', 'Sons.Erträge betrieb. u. regelmäßig');
+INSERT INTO gifi (accno,description) VALUES ('0271000', 'Ertrag a.d.Zuschreib.d.Anlagevermög');
+INSERT INTO gifi (accno,description) VALUES ('0271500', 'Ertr.a.Zuschreib.d.Umlaufvermögens');
+INSERT INTO gifi (accno,description) VALUES ('0272000', 'Ertr.a.d.Abgang v.Gegens.d.Anlageve');
+INSERT INTO gifi (accno,description) VALUES ('0272500', 'Ertä.a.d.Abg.v.Gegenst.d.Umlaufverm');
+INSERT INTO gifi (accno,description) VALUES ('0273000', 'Ertr.a.Herab.d.Pauschal.z.Forderung');
+INSERT INTO gifi (accno,description) VALUES ('0273100', 'Ertr.a.Herab.d.Einzelw.z.Forderunge');
+INSERT INTO gifi (accno,description) VALUES ('0273200', 'Ertr. aus abgeschriebenen Forderung');
+INSERT INTO gifi (accno,description) VALUES ('0273500', 'Ertr.a.d.Auflösung v.Rückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('0273600', 'Ertr.a.d.steuerl.niedrig.Bewertung');
+INSERT INTO gifi (accno,description) VALUES ('0273700', 'Ertr.a.d..Aufl.v.Sonderp.m.Rücklage');
+INSERT INTO gifi (accno,description) VALUES ('0273800', 'Ertr.a.d.Aufl.v.Sopo.m.Rücklageant.');
+INSERT INTO gifi (accno,description) VALUES ('0273900', 'Erträge Aufl. Sopo m.R.(Ansparafa)');
+INSERT INTO gifi (accno,description) VALUES ('0274000', 'Erträge Auflösung Sopo (stfreie Rü)');
+INSERT INTO gifi (accno,description) VALUES ('0274100', 'Ertr.a.d.Aufl.v.Sonderp.m.Rücklagen');
+INSERT INTO gifi (accno,description) VALUES ('0274200', 'Versicherungsentschädigungen');
+INSERT INTO gifi (accno,description) VALUES ('0274300', 'Investitionszuschüsse-steuerpflicht');
+INSERT INTO gifi (accno,description) VALUES ('0274400', 'Investitionszulage-steuerfrei');
+INSERT INTO gifi (accno,description) VALUES ('0274500', 'Erträge aus Kapitalherabsetzung');
+INSERT INTO gifi (accno,description) VALUES ('0279000', 'Erträge aus Verlustübernahme');
+INSERT INTO gifi (accno,description) VALUES ('0279200', 'Erhalt.Gewinne aufgr.e.Gewinngemein');
+INSERT INTO gifi (accno,description) VALUES ('0279400', 'Erhalt.Gewinn aufgr.e.GAV-TeilGAV');
+INSERT INTO gifi (accno,description) VALUES ('0279500', 'Entnahme aus der Kapitalrücklage');
+INSERT INTO gifi (accno,description) VALUES ('0279600', 'Entnahme a.d. gesetzlichen Rücklage');
+INSERT INTO gifi (accno,description) VALUES ('0286000', 'Gewinnvortrag nach Verwendung');
+INSERT INTO gifi (accno,description) VALUES ('0286800', 'Verlustvortrag nach Verwendung');
+INSERT INTO gifi (accno,description) VALUES ('0286900', 'Vortrag auf neue Rechnungen');
+INSERT INTO gifi (accno,description) VALUES ('0287000', 'Vorabausschüttung');
+INSERT INTO gifi (accno,description) VALUES ('0289200', 'Verrechnete kalkulatorische Zinsen');
+INSERT INTO gifi (accno,description) VALUES ('0289300', 'Verrechnete kalkulatorische AfA');
+INSERT INTO gifi (accno,description) VALUES ('0299000', 'Aufwendung/Erträge Umrechnungsdiff');
+INSERT INTO gifi (accno,description) VALUES ('0300000', 'Roh,-Hilfs,-und Betriebsstoffe');
+INSERT INTO gifi (accno,description) VALUES ('0309000', 'Energiestoffe (Fertigung)');
+INSERT INTO gifi (accno,description) VALUES ('0310000', 'Fremdleistungen');
+INSERT INTO gifi (accno,description) VALUES ('0315000', 'Leist.v.ausländ.Untern.(0-Regelung)');
+INSERT INTO gifi (accno,description) VALUES ('0320000', 'Wareneingang');
+INSERT INTO gifi (accno,description) VALUES ('0330000', 'Wareneingang 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0340000', 'Wareneingang 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0342000', 'Innergemein.Erwerb 7% VorSt u. Ust');
+INSERT INTO gifi (accno,description) VALUES ('0342500', 'Innergem.Erwerb 16% VorSt u. Ust');
+INSERT INTO gifi (accno,description) VALUES ('0355000', 'Steuerfreier innergem.Erwerb');
+INSERT INTO gifi (accno,description) VALUES ('0360000', 'Nicht abziehbare Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0370000', 'Nachlässe');
+INSERT INTO gifi (accno,description) VALUES ('0371000', 'Nachlässe 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0372000', 'Nachlässe 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0373000', 'Erhaltene Skonti');
+INSERT INTO gifi (accno,description) VALUES ('0373100', 'Erhaltene Skonti 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0373500', 'Erhaltene Skonti 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0374000', 'Erhaltene Boni');
+INSERT INTO gifi (accno,description) VALUES ('0375000', 'Erhaltene Boni 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0376000', 'Erhaltene Boni 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0377000', 'Erhaltene Rabatte');
+INSERT INTO gifi (accno,description) VALUES ('0378000', 'Erhaltene Rabatte 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0379000', 'Erhaltene Rabatte 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0380000', 'Anschaffungsnebenkosten');
+INSERT INTO gifi (accno,description) VALUES ('0383000', 'Leergut');
+INSERT INTO gifi (accno,description) VALUES ('0385000', 'Zölle und Einfuhrabgaben');
+INSERT INTO gifi (accno,description) VALUES ('0396000', 'Bestandsver.Roh-,Hilfs-.Betriebs.');
+INSERT INTO gifi (accno,description) VALUES ('0397000', 'Bestand Roh-,Hilfs-,u.Betriebsstoff');
+INSERT INTO gifi (accno,description) VALUES ('0398000', 'Bestand Waren');
+INSERT INTO gifi (accno,description) VALUES ('0399000', 'Verrechnete Stoffkosten');
+INSERT INTO gifi (accno,description) VALUES ('0400000', 'Material-und Stoffverbrauch');
+INSERT INTO gifi (accno,description) VALUES ('0410000', 'Löhne und Gehälter');
+INSERT INTO gifi (accno,description) VALUES ('0412400', 'Geschäftsführ.gehälter GmbH-Gesell.');
+INSERT INTO gifi (accno,description) VALUES ('0412500', 'Ehegattengehalt');
+INSERT INTO gifi (accno,description) VALUES ('0412600', 'Tantiemen');
+INSERT INTO gifi (accno,description) VALUES ('0412700', 'Geschäftsführergehälter');
+INSERT INTO gifi (accno,description) VALUES ('0412800', 'Vergütung a.angestellte Mitunterneh');
+INSERT INTO gifi (accno,description) VALUES ('0413000', 'Gesetzlich soziale Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('0413700', 'Gesetz.sozi.Aufw.f.Mitunternehmen');
+INSERT INTO gifi (accno,description) VALUES ('0413800', 'Beiträge zur Berufsgenossenschaftr');
+INSERT INTO gifi (accno,description) VALUES ('0414500', 'Freiwillige sozi.Aufw.lohnsteuerfr.');
+INSERT INTO gifi (accno,description) VALUES ('0414900', 'Pauschale Lohnsteuera.sons.Bezüge');
+INSERT INTO gifi (accno,description) VALUES ('0415000', 'Krankengeldzuschüsse');
+INSERT INTO gifi (accno,description) VALUES ('0416000', 'Versorgungskasse');
+INSERT INTO gifi (accno,description) VALUES ('0416500', 'Aufwendung f.Altersversorgung');
+INSERT INTO gifi (accno,description) VALUES ('0417000', 'Vermögenswirksame Leistungen');
+INSERT INTO gifi (accno,description) VALUES ('0417500', 'Fahrtkostenerst.Wohnung/Arbeitsstät');
+INSERT INTO gifi (accno,description) VALUES ('0419000', 'Aushilfslöhne');
+INSERT INTO gifi (accno,description) VALUES ('0419900', 'Lohnsteuer für Aushilfe');
+INSERT INTO gifi (accno,description) VALUES ('0420000', 'Raumkosten');
+INSERT INTO gifi (accno,description) VALUES ('0421000', 'Miete');
+INSERT INTO gifi (accno,description) VALUES ('0422000', 'Pacht');
+INSERT INTO gifi (accno,description) VALUES ('0423000', 'Heizung');
+INSERT INTO gifi (accno,description) VALUES ('0424000', 'Gas,Strom, Wasser');
+INSERT INTO gifi (accno,description) VALUES ('0425000', 'Reinigung');
+INSERT INTO gifi (accno,description) VALUES ('0426000', 'Instandhaltung betrieb.Räume');
+INSERT INTO gifi (accno,description) VALUES ('0427000', 'Abgaben f.betrieb.genutz.Grundstück');
+INSERT INTO gifi (accno,description) VALUES ('0428000', 'Sonstige Raumkosten');
+INSERT INTO gifi (accno,description) VALUES ('0430000', 'Nicht abziehbare Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('0430100', 'Nicht abziehbare Vorsteuer 7%');
+INSERT INTO gifi (accno,description) VALUES ('0430500', 'Nicht abziehbare Vorsteuer 16%');
+INSERT INTO gifi (accno,description) VALUES ('0432000', 'Gewerbesteuer');
+INSERT INTO gifi (accno,description) VALUES ('0434000', 'Sonstige Betriebssteuern');
+INSERT INTO gifi (accno,description) VALUES ('0435000', 'Verbrauchssteuer');
+INSERT INTO gifi (accno,description) VALUES ('0435500', 'Ökosteuer');
+INSERT INTO gifi (accno,description) VALUES ('0436000', 'Versicherungen');
+INSERT INTO gifi (accno,description) VALUES ('0437000', 'Nettoprä.f.Rückd.künf.Versorgungsle');
+INSERT INTO gifi (accno,description) VALUES ('0438000', 'Beiträge');
+INSERT INTO gifi (accno,description) VALUES ('0439000', 'Sonstige Abgaben');
+INSERT INTO gifi (accno,description) VALUES ('0439600', 'Steuerl.abzugs.Verspä.u.Zwangsgelde');
+INSERT INTO gifi (accno,description) VALUES ('0450000', 'Fahrzugkosten');
+INSERT INTO gifi (accno,description) VALUES ('0451000', 'Kfz-Steuer');
+INSERT INTO gifi (accno,description) VALUES ('0452000', 'Kfz-Versicherungen');
+INSERT INTO gifi (accno,description) VALUES ('0453000', 'Laufende Kfz-Betriebskosten');
+INSERT INTO gifi (accno,description) VALUES ('0454000', 'Kfz-Reparaturen');
+INSERT INTO gifi (accno,description) VALUES ('0455000', 'Garagenmiete');
+INSERT INTO gifi (accno,description) VALUES ('0457000', 'Fremdfahrzeuge');
+INSERT INTO gifi (accno,description) VALUES ('0458000', 'Sonstige Kfz-Kosten');
+INSERT INTO gifi (accno,description) VALUES ('0460000', 'Werbe-und Reisekosten');
+INSERT INTO gifi (accno,description) VALUES ('0461000', 'Werbekosten');
+INSERT INTO gifi (accno,description) VALUES ('0463000', 'Geschenke bis 75 DM');
+INSERT INTO gifi (accno,description) VALUES ('0463500', 'Geschenke bis 75 DM');
+INSERT INTO gifi (accno,description) VALUES ('0463800', 'Geschenke ausschließl.betrieb.genut');
+INSERT INTO gifi (accno,description) VALUES ('0464000', 'Repräsentationskosten');
+INSERT INTO gifi (accno,description) VALUES ('0465000', 'Bewirtungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0465300', 'Aufmerksamkeiten');
+INSERT INTO gifi (accno,description) VALUES ('0465400', 'Nicht abzugsfähige Bewirtungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0465500', 'Nicht abzugsfähige Betriebsausgaben');
+INSERT INTO gifi (accno,description) VALUES ('0466000', 'Reisekosten Arbeitnehmer');
+INSERT INTO gifi (accno,description) VALUES ('0466300', 'Reisekosten Arbeitn.m.Vorsteuerabzu');
+INSERT INTO gifi (accno,description) VALUES ('0466400', 'Reisekosten Arbeitn.Verpflegungmehr');
+INSERT INTO gifi (accno,description) VALUES ('0466600', 'Reisekosten Arbeitn.Übernachtungsau');
+INSERT INTO gifi (accno,description) VALUES ('0466800', 'Kilometerentgelderstattung Arbeitne');
+INSERT INTO gifi (accno,description) VALUES ('0467000', 'Reisekosten Unternehmer');
+INSERT INTO gifi (accno,description) VALUES ('0467400', 'Reisekosten Untern.Verpflegungsmehr');
+INSERT INTO gifi (accno,description) VALUES ('0467600', 'Reisekosten Untern.Übernachtungsauf');
+INSERT INTO gifi (accno,description) VALUES ('0467800', 'Kilometererstattungsgeld Unternehme');
+INSERT INTO gifi (accno,description) VALUES ('0470000', 'Kosten der Warenabgabe');
+INSERT INTO gifi (accno,description) VALUES ('0471000', 'Verpackungsmaterial');
+INSERT INTO gifi (accno,description) VALUES ('0473000', 'Ausgangsfracht');
+INSERT INTO gifi (accno,description) VALUES ('0475000', 'Transportversicherung');
+INSERT INTO gifi (accno,description) VALUES ('0476000', 'Verkaufsprovision');
+INSERT INTO gifi (accno,description) VALUES ('0478000', 'Fremdarbeiten');
+INSERT INTO gifi (accno,description) VALUES ('0479000', 'Aufwand für Gewährleistungen');
+INSERT INTO gifi (accno,description) VALUES ('0480900', 'Sonstige Reparaturen u.Instandhalt.');
+INSERT INTO gifi (accno,description) VALUES ('0481000', 'Mietleasing');
+INSERT INTO gifi (accno,description) VALUES ('0481500', 'Kaufleasing');
+INSERT INTO gifi (accno,description) VALUES ('0482000', 'AfA a.Aufw.f.d.Inga.u.Erw.Geschäfts');
+INSERT INTO gifi (accno,description) VALUES ('0482100', 'AfA a.Aufw.f.d.Währungsumst.a.Euro');
+INSERT INTO gifi (accno,description) VALUES ('0482200', 'Abschreibungen a.immat.Vermögensgeg');
+INSERT INTO gifi (accno,description) VALUES ('0482400', 'Abschreibung a.d.Geschäft-o.Firmenw');
+INSERT INTO gifi (accno,description) VALUES ('0482600', 'Außerplan.AfA a.immat.Vermögensgeg.');
+INSERT INTO gifi (accno,description) VALUES ('0483000', 'Abschreibungen auf Sachanlagen');
+INSERT INTO gifi (accno,description) VALUES ('0484000', 'Außerplanmäßig Abschr.a.Sachanlagen');
+INSERT INTO gifi (accno,description) VALUES ('0485000', 'Abschr.a.Sachanl.steuerl.Sondervors');
+INSERT INTO gifi (accno,description) VALUES ('0485500', 'Sofortabschreibung GWG');
+INSERT INTO gifi (accno,description) VALUES ('0486000', 'Abschreibungen auf aktivierte GWG');
+INSERT INTO gifi (accno,description) VALUES ('0487000', 'Abschreibungen auf Finanzanlagen');
+INSERT INTO gifi (accno,description) VALUES ('0487500', 'Abschr.a.Wertp.d.Umlaufvermögens');
+INSERT INTO gifi (accno,description) VALUES ('0490000', 'Sonstige betriebliche Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('0490500', 'Sons.Aufw.betriebl. und regelmäßig');
+INSERT INTO gifi (accno,description) VALUES ('0490900', 'Fremdleistungen');
+INSERT INTO gifi (accno,description) VALUES ('0491000', 'Porto');
+INSERT INTO gifi (accno,description) VALUES ('0492000', 'Telefon');
+INSERT INTO gifi (accno,description) VALUES ('0492500', 'Telefax');
+INSERT INTO gifi (accno,description) VALUES ('0493000', 'Bürobedarf');
+INSERT INTO gifi (accno,description) VALUES ('0494000', 'Zeitschriften, Bücher');
+INSERT INTO gifi (accno,description) VALUES ('0494500', 'Fortbildungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0494600', 'Freiwillige Sozialleistungen');
+INSERT INTO gifi (accno,description) VALUES ('0495000', 'Rechts- und Beratungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0495500', 'Buchführungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0495700', 'Abschluß- und Prüfungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0496000', 'Mieten für Einrichtungen');
+INSERT INTO gifi (accno,description) VALUES ('0497000', 'Nebenkosten des Geldverkehrs');
+INSERT INTO gifi (accno,description) VALUES ('0498000', 'Betriebsbedarf');
+INSERT INTO gifi (accno,description) VALUES ('0498500', 'Werkzeuge und Kleingeräte');
+INSERT INTO gifi (accno,description) VALUES ('0498600', 'Sonstige Aufwendungen (Ausbuchung)');
+INSERT INTO gifi (accno,description) VALUES ('0499000', 'Kalkulatorischer Unternehmerlohn');
+INSERT INTO gifi (accno,description) VALUES ('0499200', 'Kalkulatorische Zinsen');
+INSERT INTO gifi (accno,description) VALUES ('0499300', 'Kalkulatorische Aschreibungen');
+INSERT INTO gifi (accno,description) VALUES ('0499600', 'Herstellungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0499700', 'Verwaltungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0499800', 'Vertriebskosten');
+INSERT INTO gifi (accno,description) VALUES ('0700000', 'Unfertige Erzeu.unfert.Leistungen');
+INSERT INTO gifi (accno,description) VALUES ('0705000', 'Unfertige Erzeugnisse');
+INSERT INTO gifi (accno,description) VALUES ('0708000', 'Unfertige Leistungen');
+INSERT INTO gifi (accno,description) VALUES ('0709000', 'In Ausführung befindl. Bauaufträge');
+INSERT INTO gifi (accno,description) VALUES ('0709500', 'In Arbeit befindliche Aufträge');
+INSERT INTO gifi (accno,description) VALUES ('0710000', 'Fertige Erzeugnisse und Waren');
+INSERT INTO gifi (accno,description) VALUES ('0711000', 'Fertige Erzeugnisse (Bestand)');
+INSERT INTO gifi (accno,description) VALUES ('0714000', 'Waren (Bestand)');
+INSERT INTO gifi (accno,description) VALUES ('0810000', 'Steuerfreie Umsätze §4Nr.8ff UstG');
+INSERT INTO gifi (accno,description) VALUES ('0811000', 'Sonstige steuerfreie Umsätze Inland');
+INSERT INTO gifi (accno,description) VALUES ('0812000', 'Steuerfreie Umsätze §4Nr.1a UstG');
+INSERT INTO gifi (accno,description) VALUES ('0812500', 'Steuerfrei innergem. Lieferungen');
+INSERT INTO gifi (accno,description) VALUES ('0813000', 'Liefe.d.1.Abnehm.innergem.Dreiecksg');
+INSERT INTO gifi (accno,description) VALUES ('0815000', 'Sonstige steuerfreie Umsätze');
+INSERT INTO gifi (accno,description) VALUES ('0819000', 'Sonstige Erlöse (Ausbuchung 0%)');
+INSERT INTO gifi (accno,description) VALUES ('0819100', 'Sonstige Erlöse (Ausbuchung 16%)');
+INSERT INTO gifi (accno,description) VALUES ('0819200', 'Sonstige Erlöse (Ausbuchung 7%)');
+INSERT INTO gifi (accno,description) VALUES ('0820000', 'Erlöse');
+INSERT INTO gifi (accno,description) VALUES ('0830000', 'Erlöse 7%USt');
+INSERT INTO gifi (accno,description) VALUES ('0831000', 'Erlöse Inland stpfl. EG-Lieferung7%');
+INSERT INTO gifi (accno,description) VALUES ('0831500', 'Erlös Inland stpfl.EG-Lieferung 16%');
+INSERT INTO gifi (accno,description) VALUES ('0833900', 'Erl.EG-Land stpfl.so.Leist.(0-Regl)');
+INSERT INTO gifi (accno,description) VALUES ('0840000', 'Erlöse 16% USt.');
+INSERT INTO gifi (accno,description) VALUES ('0850000', 'Provisionserlöse');
+INSERT INTO gifi (accno,description) VALUES ('0852000', 'Erlöse Abfallverwertung');
+INSERT INTO gifi (accno,description) VALUES ('0854000', 'Erlös Leergut');
+INSERT INTO gifi (accno,description) VALUES ('0859000', 'Verrechnete sons. Sachbezüge');
+INSERT INTO gifi (accno,description) VALUES ('0859100', 'Sachbezüge 7% Ust (Waren)');
+INSERT INTO gifi (accno,description) VALUES ('0859500', 'Sachbezüge 16% Ust (Waren)');
+INSERT INTO gifi (accno,description) VALUES ('0860000', 'Sonstige Erlöse betriebl.u.regelmäß');
+INSERT INTO gifi (accno,description) VALUES ('0861000', 'Verrechnete sonstige Sachbezüge');
+INSERT INTO gifi (accno,description) VALUES ('0861100', 'Verr.sons.Sachbezüge 16%USt(Kfz-Ge)');
+INSERT INTO gifi (accno,description) VALUES ('0861400', 'Verrechnete sons.Sachbezüge o. USt');
+INSERT INTO gifi (accno,description) VALUES ('0862500', 'Sons. Erlöse betriebl.u.reg.steuerf');
+INSERT INTO gifi (accno,description) VALUES ('0865000', 'Erlöse Zinsen und Diskotspesen');
+INSERT INTO gifi (accno,description) VALUES ('0870000', 'Erlösschmälerungen');
+INSERT INTO gifi (accno,description) VALUES ('0871000', 'Erlösschmälerung 7% USt.');
+INSERT INTO gifi (accno,description) VALUES ('0872000', 'Erlösschmälerung 16% USt.');
+INSERT INTO gifi (accno,description) VALUES ('0872400', 'Erlösschmäler.a.stfrei.IG Lieferung');
+INSERT INTO gifi (accno,description) VALUES ('0872500', 'Erlösschmä.Inl.stpfl.EG-Lief. 7%USt');
+INSERT INTO gifi (accno,description) VALUES ('0872600', 'Erlösschmä.Inl.stpfl.EG-Lief.16%USt');
+INSERT INTO gifi (accno,description) VALUES ('0872700', 'Erlösschmä.and.EG Land stpfl.Liefer');
+INSERT INTO gifi (accno,description) VALUES ('0873000', 'Gewährte Skonti');
+INSERT INTO gifi (accno,description) VALUES ('0873100', 'Gewährte Skonti 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('0873500', 'Gewährte Skonti 16% USt.');
+INSERT INTO gifi (accno,description) VALUES ('0874000', 'Gewährte Boni');
+INSERT INTO gifi (accno,description) VALUES ('0875000', 'Gewährte Boni 7% USt.');
+INSERT INTO gifi (accno,description) VALUES ('0876000', 'Gewährte Boni 16% USt.');
+INSERT INTO gifi (accno,description) VALUES ('0877000', 'Gewährte Rabatte');
+INSERT INTO gifi (accno,description) VALUES ('0878000', 'Gewährte Rabatte 7% USt.');
+INSERT INTO gifi (accno,description) VALUES ('0879000', 'Gewährte Rabatte 16% Ust.');
+INSERT INTO gifi (accno,description) VALUES ('0880000', 'Erlöse aus Anlagenverkäufen');
+INSERT INTO gifi (accno,description) VALUES ('0880100', 'Erlöse aus Anlagenverkäufen 16%USt.');
+INSERT INTO gifi (accno,description) VALUES ('0882000', 'Erlöse aus Anlageverkäufen 16%Ust');
+INSERT INTO gifi (accno,description) VALUES ('0882900', 'Erl.a.Anlagenverk.bei Buchgewinn');
+INSERT INTO gifi (accno,description) VALUES ('0890000', 'Unentgeldliche Wertabgaben');
+INSERT INTO gifi (accno,description) VALUES ('0890500', 'Entnahme v. Gegenst.o.USt.');
+INSERT INTO gifi (accno,description) VALUES ('0891000', 'Entnahme außerhalb d.Untern.16%USt.');
+INSERT INTO gifi (accno,description) VALUES ('0891500', 'Entnah.d.U.Zweckaußerh.d.Untn 7%USt');
+INSERT INTO gifi (accno,description) VALUES ('0891800', 'Entn.d.Untern.außerh.d.Untern.o.USt');
+INSERT INTO gifi (accno,description) VALUES ('0892000', 'Verw.v.Gegens.außerh.Untern.16%USt.');
+INSERT INTO gifi (accno,description) VALUES ('0892500', 'Unentgeldl.Erbring.sons.Leis.16%USt');
+INSERT INTO gifi (accno,description) VALUES ('0893200', 'Unentgelt.Erbring.sons.Leist. 7%Ust');
+INSERT INTO gifi (accno,description) VALUES ('0893500', 'Unentgeltl.Zuwend.v.Gegens. 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('0893900', 'Unentgeldl.Zuw.v.Gegens.ohne Ust');
+INSERT INTO gifi (accno,description) VALUES ('0894000', 'Unentgeltl.Zuw.v Waren 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('0894500', 'Unentgeltl.Zuw.von Waren 7% Ust');
+INSERT INTO gifi (accno,description) VALUES ('0895000', 'Nicht steuerbare Umsätze');
+INSERT INTO gifi (accno,description) VALUES ('0895500', 'Umsatzsteuervergütungen');
+INSERT INTO gifi (accno,description) VALUES ('0896000', 'Bestandsveränderung-unfertige Erzeu');
+INSERT INTO gifi (accno,description) VALUES ('0897000', 'Bestandsveränderung-unfertige Leist');
+INSERT INTO gifi (accno,description) VALUES ('0897500', 'Bestandsverä.i.Ausfü.befi.Bauaufträ');
+INSERT INTO gifi (accno,description) VALUES ('0897700', 'Bestandsverä.i.Arbeit befindl.Auftr');
+INSERT INTO gifi (accno,description) VALUES ('0898000', 'Bestandsverä.fertige Erzeugnisse');
+INSERT INTO gifi (accno,description) VALUES ('0899000', 'Andere aktivierte Eigenleistungen');
+INSERT INTO gifi (accno,description) VALUES ('0900000', 'Saldenverträge,Sachkonten');
+INSERT INTO gifi (accno,description) VALUES ('0900800', 'Saldenverträge,Debitoren');
+INSERT INTO gifi (accno,description) VALUES ('0900900', 'Saldenverträge,Kreditoren');
+INSERT INTO gifi (accno,description) VALUES ('0906000', 'Offene Posten aus 1990');
+INSERT INTO gifi (accno,description) VALUES ('0906900', 'Offene Posten aus 1999');
+INSERT INTO gifi (accno,description) VALUES ('0907000', 'Offene Posten aus 2000');
+INSERT INTO gifi (accno,description) VALUES ('0909000', 'Summenvortragskonto');
+INSERT INTO gifi (accno,description) VALUES ('0922000', 'Gezeichnetes kapital in DM');
+INSERT INTO gifi (accno,description) VALUES ('0922100', 'Gezeichnetes Kapital in Euro');
+INSERT INTO gifi (accno,description) VALUES ('0923000', 'Baukostenzuschüsse');
+INSERT INTO gifi (accno,description) VALUES ('0923200', 'Investitionszulagen');
+INSERT INTO gifi (accno,description) VALUES ('0923400', 'Investitionszuschüsse');
+INSERT INTO gifi (accno,description) VALUES ('0924500', 'Forde.a.Anlageverk.sons.Vermögensge');
+INSERT INTO gifi (accno,description) VALUES ('0925000', 'Eigenkapitalersetzende Ges''terdarl.');
+INSERT INTO gifi (accno,description) VALUES ('0926000', 'Kurzfristige Rückstellung');
+INSERT INTO gifi (accno,description) VALUES ('0926200', 'Mittelfristige Rückstellung');
+INSERT INTO gifi (accno,description) VALUES ('0926400', 'Langfristige Rückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('0928000', 'Bemessungsgrundlage IG Erwerb 16%');
+INSERT INTO gifi (accno,description) VALUES ('0928100', 'Gegenkonto Bmsgrl. IG Erwerb 16%');
+INSERT INTO gifi (accno,description) VALUES ('0928200', 'Bemessungsgrundlage IG Erwerb 7%');
+INSERT INTO gifi (accno,description) VALUES ('0928400', 'Gegenkonto Bmsgrl. IG Erwerb 7%');
+INSERT INTO gifi (accno,description) VALUES ('0988100', 'Verrechnungskonto Abgang');
+INSERT INTO gifi (accno,description) VALUES ('0988200', 'Verrechnungskonto erh. Anzahlungen');
+INSERT INTO gifi (accno,description) VALUES ('0988210', 'Verrechnungskto Anzahlungen netto');
+INSERT INTO gifi (accno,description) VALUES ('0988220', 'Verrechnungskto.Anzahlungen brutto');
+INSERT INTO gifi (accno,description) VALUES ('0988300', 'Verrechnungskonto gel.Anzahlungen');
+INSERT INTO gifi (accno,description) VALUES ('0988400', 'Statistisches Konto Konzern AfA');
+INSERT INTO gifi (accno,description) VALUES ('0988500', 'Statistisches Konto kalkulator.AfA');
+INSERT INTO gifi (accno,description) VALUES ('0988600', 'Statistisches Konto außerplanm AfA');
+INSERT INTO gifi (accno,description) VALUES ('0988700', 'Statistisches Konto AfA (Konzern)');
+INSERT INTO gifi (accno,description) VALUES ('0988800', 'Statistisches Konto Sonderafa');
+INSERT INTO gifi (accno,description) VALUES ('0988900', 'Statistisches Konto AfA (SBil)');
+INSERT INTO gifi (accno,description) VALUES ('0989800', 'Statistisches Konto AfA (Kalkul.)');
+INSERT INTO gifi (accno,description) VALUES ('0989900', 'Statistisches Konto AfA');
+INSERT INTO gifi (accno,description) VALUES ('0999999', 'Fehlerauffangkonto');
diff --git a/sql-ledger/sql/Germany-SKR03-chart.sql b/sql-ledger/sql/Germany-SKR03-chart.sql
new file mode 100644
index 0000000..a7f87e2
--- /dev/null
+++ b/sql-ledger/sql/Germany-SKR03-chart.sql
@@ -0,0 +1,267 @@
+-- General COA
+-- provided by Yvonne
+-- June 13, 2002
+--
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('420','Büroeinrichtung','A','A','','420');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('430','Ladeneinrichtung','A','A','','430');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('440','Werkzeuge','A','A','','440');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('450','Einbauten','A','A','','450');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('460','Gerüst- und Schalungsmaterial','A','A','','460');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('480','Geringwertige Wirtschaftsgüter bis DM 800,-','A','A','','480');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('490','Sonstige Betriebs- und Geschäftsausstattung','A','A','','490');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('650','Verb. gg. Kreditinstituten - Restlaufz. größer 5 Jahre','A','L','','650');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1000','Kasse','A','A','AR_paid:AP_paid','1000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1200','Bank-Giro','A','A','AR_paid:AP_paid','1200');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1400','Forderungen aus Lief. und Leist. Kundengruppe 0','A','A','AR','1400');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1540','Steuerüberzahlungen','A','A','AR','1540');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1542','Steuererstattungsansprüche gg. anderen EU-Ländern','A','A','AR','1542');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1545','Umsatzsteuerforderungen','A','A','AR','1545');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1548','Vorsteuer im Folgejahr abziehbar','A','A','AR','1548');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1570','Abziehbare Vorsteuer','A','A','AR_tax:AP_tax:CT_tax','1570');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1571','Abziehbare Vorsteuer, 7%','A','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax','1571');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1575','Abziehbare Vorsteuer, 16%','A','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax','1575');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1576','Abziehbare Vorsteuer, 15%','A','A','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax','1576');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1577','Vorsteuer nach allg. Durchschnittssätzen UStVA KZ 63','A','A','AR_tax:AP_tax:CT_tax','1577');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1775','Umsatzsteuer, 16%','A','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax','1775');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1776','Umsatzsteuer, 15%','A','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax','1776');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1780','Umsatzsteuer - Vorauszahlungen','A','L','','1780');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1781','Umsatzsteuer - Vorauszahlungen 1/11','A','L','','1781');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1782','Nachsteuer, UStVA KZ 65','A','L','','1782');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1789','Umsatzsteuer laufendes Jahr','A','L','','1789');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1790','Umsatzsteuer Vorjahr','A','L','','1790');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1791','Umsatzsteuer frühere Jahre','A','L','','1791');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1820','Sonderausg. beschr. abzugsf. (Privat Vollhaft./Einzelu.)','A','','','1820');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1830','Sonderausg. unbeschr. abzugsf. (Privat Vollhaft./Einzelu.)','A','','','1830');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1840','Privatspenden (Privat Vollhafter / Einzelunternehmer)','A','','','1840');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1850','Außergewöhnliche Belastungen (Privat Vollhaft. / Einzelunt.)','A','','','1850');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1890','Privateinlagen (Privat Vollhafter / Einzelunternehmer)','A','','','1890');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2010','Betriebsfremde Aufw. (soweit nicht außerordentlich)','A','','','2010');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2020','Periodenfremde Aufw. (soweit nicht außerordentlich)','A','','','2020');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2100','Zinsen und ähnliche Aufwendungen','A','','','2100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2103','Steuerlich abzugsfähige, andere Nebenleistungen zu Steuern','A','','','2103');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2104','Steuerlich nicht abzugsfähige, andere Nebenleistungen zu Steuern','A','','','2104');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2107','Zinsaufwendungen §233a AO betriebliche Steuern','A','','','2107');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2108','Zinsaufw. §233a, §234, §237 AO Personenst. §8 GewStG','A','','','2108');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2109','Zinsaufwendungen an verbundene Unternehmen','A','','','2109');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2110','Zinsaufwendungen für kurzfristige Verbindlichkeiten','A','','','2110');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3410','Wareneingang, 16% Vorsteuer','A','','','3410');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3736','Erhaltene Skonti, 16% Vorsteuer','A','','','3736');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3740','Erhaltene Boni','A','','','3740');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3750','Erhaltene Boni, 7% Vorsteuer','A','','','3750');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3760','Erhaltene Boni, 15%+16% Vorsteuer','A','','','3760');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3762','Erhaltene Boni, 16% Vorsteuer','A','','','3762');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3764','Erhaltene Boni, 15% Vorsteuer','A','','','3764');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3800','Anschaffungsnebenkosten','A','','','3800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3830','Leergut','A','','','3830');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3850','Zölle und Einfuhrabgaben','A','','','3850');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3960','Bestandsv. Roh-, Hilfs- u. Betriebsstoffe / bezogene Waren','A','','','3960');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3970','Bestand Roh-, Hilfs- und Betriebsstoffe','A','','','3970');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3980','Bestand Waren','A','','','3980');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3990','Verrechnete Stoffkosten','A','','','3990');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4000','Material- und Stoffverbrauch','A','E','AP_amount','4000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4100','Löhne und Gehälter','A','E','AP_amount','4100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4110','Löhne','A','E','AP_amount','4110');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4120','Gehälter','A','E','AP_amount','4120');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4124','Geschäftsführergehälter der GmbH-Gesellschafter','A','E','AP_amount','4124');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4125','Ehegattengehalt','A','E','AP_amount','4125');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4126','Tantiemen','A','E','AP_amount','4126');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4127','Geschäftsführergehälter','A','E','AP_amount','4127');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4128','Vergütungen an angestellte Mitunternehmer §15 EStG','A','E','AP_amount','4128');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4130','Gesetzliche soziale Aufwendungen','A','E','AP_amount','4130');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4137','Gesetzliche soziale Aufw. für Mitunternehmer §15 EStG','A','E','AP_amount','4137');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4138','Beiträge zur Berufsgenossenschaft','A','E','AP_amount','4138');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1360','Geldtransit Bank 1','A','A','','1360');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4140','Freiw. soziale Aufwendungen (lohnsteuerfrei)','A','E','AP_amount','4140');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4145','Freiw. soziale Aufwendungen (lohnsteuerpflichtig)','A','E','AP_amount','4145');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4149','Pauschale Lohnsteuer auf s. Bezüge (z.B. Fahrtkostenzuschuß)','A','E','AP_amount','4149');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4150','Krankengeldzuschüsse','A','E','AP_amount','4150');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4160','Versorgungskassen','A','E','AP_amount','4160');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4165','Aufwendungen für die Altersversorgung','A','E','AP_amount','4165');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4167','Pauschale Lohnsteuer auf s. Bezüge (z.B. Direktversicherung)','A','E','AP_amount','4167');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4168','Aufw. f. die Altersversorgung f. Mitunternehmer §15 EStG','A','E','AP_amount','4168');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4169','Aufwendungen für Unterstützung','A','E','AP_amount','4169');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4170','Vermögenswirksame Leistungen','A','E','AP_amount','4170');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4175','Fahrtkostenerstattung - Wohnung / Arbeitsstätte','A','E','AP_amount','4175');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4180','Bedienungsgelder','A','E','AP_amount','4180');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4190','Aushilfslöhne','A','E','AP_amount','4190');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4199','Lohnsteuer für Aushilfen','A','E','AP_amount','4199');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4200','Raumkosten','A','E','AP_amount','4200');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4210','Miete','A','E','AP_amount','4210');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4218','Gewerbesteuerlich zu berücks. Miete §8 GewStG','A','E','AP_amount','4218');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4219','Vergütung an Mitu. f. mietw. Überl. v. Wirtschaftsg. §15EStG','A','E','AP_amount','4219');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4220','Pacht','A','E','AP_amount','4220');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4228','Gewerbesteuerlich zu berücks. Pacht §8 GewStG','A','E','AP_amount','4228');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4229','Vergütung an Mitu. f. pachtw. Überl. v. Wirtschaftsg.§15EStG','A','E','AP_amount','4229');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4230','Heizung','A','E','AP_amount','4230');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4240','Gas, Strom, Wasser (Verwaltung, Vertrieb)','A','E','AP_amount','4240');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4250','Reinigung','A','E','AP_amount','4250');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4260','Instandhaltung betrieblicher Räume','A','E','AP_amount','4260');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4270','Abgaben für betrieblich genutzten Grundbesitz','A','E','AP_amount','4270');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4280','Sonstige Raumkosten','A','E','AP_amount','4280');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4320','Gewerbesteuer (Vorauszahlung)','A','E','AP_amount','4320');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4330','Gewerbeertragsteuer','A','E','AP_amount','4330');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4335','Gewerbekapitalsteuer','A','E','AP_amount','4335');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4340','Sonstige Betriebsteuern','A','E','AP_amount','4340');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4350','Verbrauchsteuer','A','E','AP_amount','4350');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4360','Versicherungen','A','E','AP_amount','4360');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4380','Beiträge','A','E','AP_amount','4380');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4390','Sonstige Abgaben','A','E','AP_amount','4390');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4396','Steuerlich abzugsfähige Verspätungszuschläge und Zwangsgelder','A','E','AP_amount','4396');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4397','Steuerlich nicht abzugsfähige Verspätungszuschläge und Zwangsgelder','A','E','AP_amount','4397');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4400','Besondere Kosten (zur freien Verfügung)','A','E','AP_amount','4400');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4500','Fahrzeugkosten','A','E','AP_amount','4500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4510','Kfz-Steuern','A','E','AP_amount','4510');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4520','Kfz-Versicherungen','A','E','AP_amount','4520');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4530','Laufende Kfz-Betriebskosten','A','E','AP_amount','4530');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4540','Kfz-Reparaturen','A','E','AP_amount','4540');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4550','Garagenmieten','A','E','AP_amount','4550');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4570','Fremdfahrzeuge','A','E','AP_amount','4570');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4580','Sonstige Kfz-Kosten','A','E','AP_amount','4580');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4600','Werbe- und Reisekosten','A','E','AP_amount','4600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4610','Werbekosten','A','E','AP_amount','4610');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4630','Geschenke bis DM 75,00','A','E','AP_amount','4630');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4635','Geschenke über DM 75,00','A','E','AP_amount','4635');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4638','Geschenke ausschließlich betrieblich genutzt','A','E','AP_amount','4638');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4640','Repräsentationskosten','A','E','AP_amount','4640');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4650','Bewirtungskosten','A','E','AP_amount','4650');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4653','Aufwerksamkeiten','A','E','AP_amount','4653');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4654','Nicht abzugsfähige Bewirtungskosten','A','E','AP_amount','4654');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4655','Nicht abzugsfähige Betriebsausgaben','A','E','AP_amount','4655');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4660','Reisekosten Arbeitnehmer','A','E','AP_amount','4660');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4666','Reisekost. Arbeitn., 12,3%/13,1% VSt Verpfl.Mehr- / Übern.Aufw.','A','E','AP_amount','4666');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4667','Reisekost. Arbeitn., 9,8%/10,5% VSt Gesamtpauschal.','A','E','AP_amount','4667');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4670','Reisekosten Unternehmer','A','E','AP_amount','4670');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4675','Reisekosten Unternehmer, 9,8/10,5% VSt sonst.Gesamtpauschal.','A','E','AP_amount','4675');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4676','Reisekost. Untern., 12,3%/13,1% VSt Verpfl.Mehr- / Übern.Aufw.','A','E','AP_amount','4676');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4677','Reisekosten Unternehmer, 9,8%/10,5% VSt Verpfl.Mehraufw. Gesamtpauschal.','A','E','AP_amount','4677');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4678','Km-Geld Erstattung, Unternehmer, 5,7%/6,1% VSt','A','E','AP_amount','4678');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4685','Km-Geld-Erstattung, Arbeitnehmer 8,2%/8,7% VSt','A','E','AP_amount','4685');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4700','Kosten der Warenabgabe','A','E','AP_amount:IC_expense:IC_cogs','4700');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4710','Verpackungsmaterial','A','E','AP_amount','4710');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4730','Ausgangsfrachten','A','E','AP_amount','4730');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4750','Transportversicherungen','A','E','AP_amount','4750');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4760','Verkaufsprovisionen','A','E','AP_amount','4760');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4780','Fremdarbeiten','A','E','AP_amount','4780');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4790','Aufwand für Gewährleistungen','A','E','AP_amount','4790');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4800','Reparat. u. Inst. v. Maschinen u. technischen Anlagen','A','E','AP_amount','4800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4805','Reparat. u. Inst. v. and. Anl. d. Betr.- u. Geschäftsausst.','A','E','AP_amount','4805');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4809','Sonstige Reparaturen und Instandhaltungen','A','E','AP_amount','4809');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4810','Mietleasing','A','E','AP_amount','4810');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4815','Kaufleasing','A','E','AP_amount','4815');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4820','Abschr. a. Aufw. f.d. Ingangs. u. Erw. des Geschäftsbetr.','A','E','AP_amount','4820');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4822','Abschr. a. immaterielle Vermögensgegenstände','A','E','AP_amount','4822');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4824','Abschreibung auf den Geschäfts- oder Firmenwert','A','E','AP_amount','4824');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4826','Außerplanm. Abschr. a. immaterielle Vermögensgegenstände','A','E','AP_amount','4826');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4830','Abschreibungen auf Sachanlagen','A','E','AP_amount','4830');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4840','Außerplanm. Abschreibungen auf Sachanlagen','A','E','AP_amount','4840');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4850','Abschr. a. Sachanl. aufgrund steuerl. Sondervorschriften','A','E','AP_amount','4850');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4855','Sofortabschreibung geringwertiger Wirtschaftsgüter','A','E','AP_amount','4855');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4860','Abschreibung auf aktivierte, geringwertige Wirtschaftsgüter','A','E','AP_amount','4860');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4865','Außerplanmäßige Abschr. a. aktivierte GWG','A','E','AP_amount','4865');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4870','Abschreibungen auf Finanzanlagen','A','E','AP_amount','4870');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4872','Abschr. aufgrund v. Verlustant. an Mitunt. §8 GewStG','A','E','AP_amount','4872');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4874','Abschr. a. Finanzanl. aufgrund steuerl. Sondervorschriften','A','E','AP_amount','4874');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4875','Abschreibungen auf Wertpapiere des Umlaufvermögens','A','E','AP_amount','4875');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4880','Abschr. a. Umlaufv. ohne Wertpapiere (soweit unübl. Höhe)','A','E','AP_amount','4880');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4882','Abschr. a. Umlaufv. steuerrechtl. bedingt (unübl. Höhe)','A','E','AP_amount','4882');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4887','Abschr. a. Umlaufv., steuerrechtlich bedingt (übl. Höhe)','A','E','AP_amount','4887');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4890','Vorwegn. künftiger Wertschw. im Umlaufv. (unübl. Höhe)','A','E','AP_amount','4890');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4900','Sonstige betriebliche Aufwendungen','A','E','AP_amount','4900');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4905','Sonstige Aufwendungen betrieblich und regelmäßig','A','E','AP_amount','4905');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4910','Porto','A','E','AP_amount','4910');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4920','Telefon','A','E','AP_amount','4920');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4925','Telefax, Fernschreiber','A','E','AP_amount','4925');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4930','Bürobedarf','A','E','AP_amount','4930');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4940','Zeitschriften, Bücher','A','E','AP_amount','4940');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4945','Fortbildungskosten','A','E','AP_amount','4945');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4946','Freiwillige Sozialleistungen','A','E','AP_amount','4946');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4948','Vergütungen an freiberufliche Mitunternehmer §15 EStG','A','E','AP_amount','4948');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4950','Rechts- und Beratungskosten','A','E','AP_amount','4950');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4955','Buchführungskosten','A','E','AP_amount','4955');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4957','Abschluß- und Prüfungskosten','A','E','AP_amount','4957');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4960','Mieten für Einrichtungen','A','E','AP_amount','4960');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4968','Gewerbest. zu berücks. Miete f. Einrichtungen §8 GewStG','A','','','4968');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4969','Aufwendungen für Abraum- und Abfallbeseitigung','A','E','AP_amount','4969');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4970','Nebenkosten des Geldverkehrs','A','E','AP_amount','4970');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4980','Betriebsbedarf','A','E','AP_amount','4980');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4985','Werkzeuge und Kleingeräte','A','E','AP_amount','4985');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4996','Herstellungskosten','A','E','AP_amount','4996');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4997','Verwaltungskosten','A','E','AP_amount','4997');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4998','Vertriebskosten','A','E','AP_amount','4998');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('4999','Gegenkonto 49960-49980','A','','','4999');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('7140','Fertige Waren (Bestand)','A','A','IC','7140');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8100','Steuerfreie Umsätze o. VSt-Abzug §4 Nr.8 ff. UStG','A','I','AR_amount:IC_sale','8100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8500','Provisionserlöse','A','I','AR_amount:IC_sale','8500');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8504','Provisionserlöse steuerfrei (§4 Nr.8ff UStG)','A','I','AR_amount:IC_sale','8504');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8505','Provisionserlöse steuerfrei (§4 Nr.5 UStG)','A','I','AR_amount:IC_sale','8505');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8506','Provisionserlöse, 7% USt','A','I','AR_amount:IC_sale','8506');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8507','Provisionserlöse, 15% Ust','A','I','AR_amount:IC_sale','8507');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8508','Provisionserlöse, 15%/16% USt','A','I','AR_amount:IC_sale','8508');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8509','Provisionserlöse, 16% Ust','A','I','AR_amount:IC_sale','8509');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8591','Sachbezüge, 7% USt (Waren)','A','I','AR_amount:IC_sale','8591');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8595','Sachbezüge, 15%/16% USt (Waren)','A','I','AR_amount:IC_sale','8595');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8596','Sachbezüge, 16% USt (Waren)','A','I','AR_amount:IC_sale','8596');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8597','Sachbezüge, 15% USt (Waren)','A','I','AR_amount:IC_sale','8597');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8630','Sonstige Erlöse betrieblich und regelmäßig, 7% USt','A','I','AR_amount:IC_sale','8630');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8645','Sonstige Erlöse betrieblich und regelmäßig, 16% Ust','A','I','AR_amount:IC_sale','8645');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8730','Gewährte Skonti','A','','','8730');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8731','Gewährte Skonti, 7% USt','A','','','8731');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8735','Gewährte Skonti, 16% Ust','A','','','8735');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8740','Gewährte Boni','A','','','8740');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8750','Gewährte Boni, 7% USt','A','','','8750');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8762','Gewährte Boni, 16% Ust','A','','','8762');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8770','Gewährte Rabatte','A','','','8770');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8780','Gewährte Rabatte, 7% USt','A','','','8780');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8792','Gewährte Rabatte, 16% Ust','A','','','8792');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8800','Erlöse aus Anlagenverkäufen','A','','','8800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8801','Erlöse aus Anlagenverkäufen 15%/16% USt (bei Buchverlust)','A','','','8801');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8810','Erlöse aus Anlagenverkäufen 16% USt (bei Buchverlust)','A','','','8810');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8815','Erlöse aus Anlagenverkäufen 15% USt (bei Buchverlust)','A','','','8815');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8820','Erlöse aus Anlagenverkäufen 15%/16% USt (bei Buchgewinn)','A','','','8820');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8829','Erlöse aus Anlagenverkäufen (bei Buchgewinn)','A','','','8829');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8830','Erlöse aus Anlagenverkäufen 16% USt (bei Buchgewinn)','A','','','8830');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8835','Erlöse aus Anlagenverkäufen 15% USt (bei Buchgewinn)','A','','','8835');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8900','Eigenverbrauch','A','','','8900');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8905','Entnahme Gegenstände ohne USt','A','','','8905');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8908','Entnahme von Gegenstände, 16% USt §1 Abs.1 Nr.2a UStG','A','','','8908');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8909','Entnahme von Gegenstände, 15% USt §1 Abs.1 Nr.2a UStG','A','','','8909');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8910','Entnahme von Gegenstände, 15%/16% USt §1 Abs.1 Nr.2a UStG','A','','','8910');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8915','Entnahme von Gegenstände, 7% USt §1 Abs.1 Nr.2a UStG','A','','','8915');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8920','Entnahme v. sonst. Leist., 15%/16% USt §1 A.1 Nr.2b UStG','A','','','8920');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8930','Entnahme v. sonst. Leist., 7% USt §1 A.1 Nr.2b UStG','A','','','8930');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8937','Entnahme v. sonst. Leist., 16% USt §1 A.1 Nr.2b UStG','A','','','8937');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8938','Entnahme v. sonst. Leist., 15% USt §1 A.1 Nr.2b UStG','A','','','8938');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8939','Entnahme v. sonst. Leist., ohne USt §1 A.1 Nr.2b UStG','A','','','8939');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8941','Eigenverbr., 7% Ust §4 A.1 Nr.5 1-7, A.7 EStG','A','','','8941');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8942','Eigenverbr., 16% Ust §4 A.1 Nr.5 1-7, A.7 EStG','A','','','8942');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8944','Eigenverbr., ohne Ust §4 A.1 Nr.5 1-7, A.7 EStG','A','','','8944');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8950','Nicht steuerbare Umsätze','A','','','8950');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8955','Umsatzsteuervergütungen','A','','','8955');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8960','Bestandsveränd. - unfertige Erzeugnisse','A','','','8960');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8970','Bestandsveränd. - unfertige Leistungen','A','','','8970');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8975','Bestandsveränd. - in Ausführung befindliche Bauaufträge','A','','','8975');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8977','Bestandsveränd. - in Arbeit befindliche Aufträge','A','','','8977');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8980','Bestandsveränd. - fertige Erzeugnisse','A','','','8980');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8990','Bestandsveränd. - andere aktivierte Eigenleistungen','A','','','8990');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('9000','Saldenvorträge Sachkonten','A','','','9000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('9008','Saldenvorträge Debitoren','A','','','9008');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('9009','Saldenvorträge Kreditoren','A','','','9009');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('9100','Saldovortragskonto der Statistikkonten','A','','','9100');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1800','Privatentn. allg. (Privat Vollhafter / Einzelunternehmer)','A','Q','','1800');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('2000','Außerordentliche Aufwendungen','A','A','','2000');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('1600','Verb. aus Lief. und Leist. Lieferantengruppe 0','A','L','AP:CT_tax','1600');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('3400','Wareneingang, 16% Vorsteuer','A','E','AP_amount:CT_tax','3400');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8400','Umsatzerlöse 16%','A','I','AR_amount:IC_sale:CT_tax','8400');
+INSERT INTO chart (accno,description,charttype,category,link,gifi_accno) VALUES ('8840','Ertrge aus Kursdifferenzen','A','I','AR_amount:IC_sale:IC_income','8840');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1571'),0.07);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1575'),0.16);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1576'),0.15);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1775'),0.16);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '1776'),0.15);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '3400'),0.16);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '8400'),0.16);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '7140'), income_accno_id = (select id from chart where accno = '8400'), expense_accno_id = (select id from chart where accno = '4700'), fxgain_accno_id = (select id from chart where accno = '8840'), fxloss_accno_id = (select id from chart where accno = '8840'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'EUR:USD', weightunit = 'kg';
+--
+
diff --git a/sql-ledger/sql/Germany-SKR03-gifi.sql b/sql-ledger/sql/Germany-SKR03-gifi.sql
new file mode 100644
index 0000000..7fc0ff6
--- /dev/null
+++ b/sql-ledger/sql/Germany-SKR03-gifi.sql
@@ -0,0 +1,1083 @@
+-- Kontenrahmen für Deutschland
+--
+INSERT INTO gifi (accno,description) VALUES ('0001', 'Aufw. f. die Ingangsetzung u. Erweit. des Geschäftsbetr.');
+INSERT INTO gifi (accno,description) VALUES ('0002', 'Aufw. f. die Währungsumstellung auf den EURO');
+INSERT INTO gifi (accno,description) VALUES ('0010', 'Konzess., gew. Schutzr. u. ähnl. Rechte/Werte sowie Liz.');
+INSERT INTO gifi (accno,description) VALUES ('0015', 'Konzessionen');
+INSERT INTO gifi (accno,description) VALUES ('0020', 'Gewerbliche Schutzrechte');
+INSERT INTO gifi (accno,description) VALUES ('0025', 'Ähnliche Rechte und Werte');
+INSERT INTO gifi (accno,description) VALUES ('0027', 'EDV-Software');
+INSERT INTO gifi (accno,description) VALUES ('0030', 'Lizenzen an gewerbl. Schutzr. u. ähnl. Rechten u. Werten');
+INSERT INTO gifi (accno,description) VALUES ('0035', 'Geschäfts- oder Firmenwert');
+INSERT INTO gifi (accno,description) VALUES ('0038', 'Anzahlungen auf Geschäfts- oder Firmenwert');
+INSERT INTO gifi (accno,description) VALUES ('0039', 'Anzahlungen auf immaterielle Vermögensgegenstände');
+INSERT INTO gifi (accno,description) VALUES ('0040', 'Verschmelzungsmehrwert');
+INSERT INTO gifi (accno,description) VALUES ('0050', 'Grundst., gl. Rechte/Bauten einschl. Bauten a. fr. Grundst.');
+INSERT INTO gifi (accno,description) VALUES ('0060', 'Grundstücke und grundstücksgleiche Rechte ohne Bauten');
+INSERT INTO gifi (accno,description) VALUES ('0065', 'Unbebaute Grundstücke');
+INSERT INTO gifi (accno,description) VALUES ('0070', 'Grundstücksgleiche Rechte (Erbbaurecht, Dauerwohnrecht)');
+INSERT INTO gifi (accno,description) VALUES ('0075', 'Grundstücke mit Substanzverzehr');
+INSERT INTO gifi (accno,description) VALUES ('0079', 'Anzahl. a. Grundst. u. grundstücksgl. Rechte ohne Bauten');
+INSERT INTO gifi (accno,description) VALUES ('0080', 'Bauten auf eigenen Grundst. und grundstücksgl. Rechten');
+INSERT INTO gifi (accno,description) VALUES ('0085', 'Grundstückswerte eigener bebauter Grundsstücke');
+INSERT INTO gifi (accno,description) VALUES ('0090', 'Geschäftsbauten');
+INSERT INTO gifi (accno,description) VALUES ('0100', 'Fabrikbauten');
+INSERT INTO gifi (accno,description) VALUES ('0110', 'Garagen');
+INSERT INTO gifi (accno,description) VALUES ('0111', 'Außenanlagen');
+INSERT INTO gifi (accno,description) VALUES ('0112', 'Hof- u. Wegebefestigungen');
+INSERT INTO gifi (accno,description) VALUES ('0113', 'Einrichtungen für Geschäfts- u. Fabrikbauten');
+INSERT INTO gifi (accno,description) VALUES ('0115', 'Andere Bauten');
+INSERT INTO gifi (accno,description) VALUES ('0120', 'Geschäfts-, Fabrik- u. andere Bauten im Bau');
+INSERT INTO gifi (accno,description) VALUES ('0129', 'Anz. a. Geschäfts-, Fabrik-, u.a. Bauten a. eig. Grundst+Rechte');
+INSERT INTO gifi (accno,description) VALUES ('0140', 'Wohnbauten');
+INSERT INTO gifi (accno,description) VALUES ('0145', 'Garagen');
+INSERT INTO gifi (accno,description) VALUES ('0146', 'Außenanlagen');
+INSERT INTO gifi (accno,description) VALUES ('0147', 'Hof- und Wegebefestigungen');
+INSERT INTO gifi (accno,description) VALUES ('0148', 'Einrichtungen für Wohnbauten');
+INSERT INTO gifi (accno,description) VALUES ('0150', 'Wohnbauten im Bau');
+INSERT INTO gifi (accno,description) VALUES ('0159', 'Anz. auf Wohnbauten auf eig. Grundstücken u. grundst.gl. Rechten');
+INSERT INTO gifi (accno,description) VALUES ('0160', 'Bauten auf fremden Grundstücken');
+INSERT INTO gifi (accno,description) VALUES ('0165', 'Geschäftsbauten');
+INSERT INTO gifi (accno,description) VALUES ('0170', 'Fabrikbauten');
+INSERT INTO gifi (accno,description) VALUES ('0175', 'Garagen');
+INSERT INTO gifi (accno,description) VALUES ('0176', 'Außenanlagen');
+INSERT INTO gifi (accno,description) VALUES ('0177', 'Hof- und Wegebefestigen');
+INSERT INTO gifi (accno,description) VALUES ('0178', 'Einrichtungen für Geschäfts- und Fabrikbauten');
+INSERT INTO gifi (accno,description) VALUES ('0179', 'Andere Bauten');
+INSERT INTO gifi (accno,description) VALUES ('0180', 'Geschäfts-, Fabrik- und andere Bauten im Bau');
+INSERT INTO gifi (accno,description) VALUES ('0189', 'Anzahl. a. Geschäfts-, Fabrik-, u.a. Bauten a. fr. Grundst.');
+INSERT INTO gifi (accno,description) VALUES ('0190', 'Wohnbauten');
+INSERT INTO gifi (accno,description) VALUES ('0191', 'Garagen');
+INSERT INTO gifi (accno,description) VALUES ('0192', 'Außenanlagen');
+INSERT INTO gifi (accno,description) VALUES ('0193', 'Hof- und Wegebefestigungen');
+INSERT INTO gifi (accno,description) VALUES ('0194', 'Einrichtungen für Wohnbauten');
+INSERT INTO gifi (accno,description) VALUES ('0195', 'Wohnbauten im Bau');
+INSERT INTO gifi (accno,description) VALUES ('0199', 'Anzahlungen auf Wohnbauten auf fremden Grundstücken');
+INSERT INTO gifi (accno,description) VALUES ('0200', 'Technische Anlagen und Maschinen');
+INSERT INTO gifi (accno,description) VALUES ('0210', 'Maschinen');
+INSERT INTO gifi (accno,description) VALUES ('0220', 'Maschinengebundene Werkzeuge');
+INSERT INTO gifi (accno,description) VALUES ('0240', 'Maschinelle Anlagen');
+INSERT INTO gifi (accno,description) VALUES ('0260', 'Transportanlagen und ähnliches');
+INSERT INTO gifi (accno,description) VALUES ('0280', 'Betriebsvorrichtungen');
+INSERT INTO gifi (accno,description) VALUES ('0290', 'Technische Anlagen und Maschinen im Bau');
+INSERT INTO gifi (accno,description) VALUES ('0299', 'Anzahlungen auf technische Anlagen und Maschinen');
+INSERT INTO gifi (accno,description) VALUES ('0300', 'Andere Anlagen, Betriebs- und Geschäftsausstattung');
+INSERT INTO gifi (accno,description) VALUES ('0310', 'Andere Anlagen');
+INSERT INTO gifi (accno,description) VALUES ('0320', 'Pkw');
+INSERT INTO gifi (accno,description) VALUES ('0350', 'Lkw');
+INSERT INTO gifi (accno,description) VALUES ('0380', 'Sonstige Transportmittel');
+INSERT INTO gifi (accno,description) VALUES ('0400', 'Betriebsausstattung');
+INSERT INTO gifi (accno,description) VALUES ('0410', 'Geschäftsausstattung');
+INSERT INTO gifi (accno,description) VALUES ('0420', 'Büroeinrichtung');
+INSERT INTO gifi (accno,description) VALUES ('0430', 'Ladeneinrichtung');
+INSERT INTO gifi (accno,description) VALUES ('0440', 'Werkzeuge');
+INSERT INTO gifi (accno,description) VALUES ('0450', 'Einbauten');
+INSERT INTO gifi (accno,description) VALUES ('0460', 'Gerüst- und Schalungsmaterial');
+INSERT INTO gifi (accno,description) VALUES ('0480', 'Geringwertige Wirtschaftsgüter bis DM 800,-');
+INSERT INTO gifi (accno,description) VALUES ('0490', 'Sonstige Betriebs- und Geschäftsausstattung');
+INSERT INTO gifi (accno,description) VALUES ('0498', 'Andere Anlagen, Betriebs- und Geschäftsausstatt. im Bau');
+INSERT INTO gifi (accno,description) VALUES ('0499', 'Anzahl. a. andere Anlagen, Betriebs- u. Geschäftsausstatt.');
+INSERT INTO gifi (accno,description) VALUES ('0500', 'Anteile an verbundenen Unternehmen (Anlagevermögen)');
+INSERT INTO gifi (accno,description) VALUES ('0504', 'Anteile an herrschender oder mit Mehrheit beteiligter Gesellschaft');
+INSERT INTO gifi (accno,description) VALUES ('0505', 'Ausleihungen an verbundene Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('0510', 'Beteiligungen');
+INSERT INTO gifi (accno,description) VALUES ('0513', 'Typisch stille Beteiligungen');
+INSERT INTO gifi (accno,description) VALUES ('0516', 'Atypisch stille Beteiligungen');
+INSERT INTO gifi (accno,description) VALUES ('0517', 'Andere Beteiligungen an Kapitalgesellschaften');
+INSERT INTO gifi (accno,description) VALUES ('0518', 'Andere Beteiligungen an Personengesellschaften');
+INSERT INTO gifi (accno,description) VALUES ('0519', 'Beteiligung einer GmbH&CoKG an einer Komplementär GmbH');
+INSERT INTO gifi (accno,description) VALUES ('0520', 'Ausleihung an Untern. m.d.e. Beteiligungsverhältnis besteht');
+INSERT INTO gifi (accno,description) VALUES ('0525', 'Wertpapiere des Anlagevermögens');
+INSERT INTO gifi (accno,description) VALUES ('0530', 'Wertpapiere mit Gewinnbeteiligungsansprüchen');
+INSERT INTO gifi (accno,description) VALUES ('0535', 'Festverzinsliche Wertpapiere');
+INSERT INTO gifi (accno,description) VALUES ('0540', 'Sonstige Ausleihungen');
+INSERT INTO gifi (accno,description) VALUES ('0550', 'Darlehen / Sonstige Ausleihungen');
+INSERT INTO gifi (accno,description) VALUES ('0570', 'Genossenschaftsanteile zum langfristigen Verbleib');
+INSERT INTO gifi (accno,description) VALUES ('0580', 'Ausleihungen an Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('0590', 'Ausleihungen an nahestehende Personen');
+INSERT INTO gifi (accno,description) VALUES ('0595', 'Rückdeckungsanspr. a. Lebensvers. z. langfrist. Verbleib');
+INSERT INTO gifi (accno,description) VALUES ('0600', 'Anleihen nicht konvertibel');
+INSERT INTO gifi (accno,description) VALUES ('0601', 'Anleihen nicht konvertibel - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0605', 'Anleihen nicht konvertibel - Restlaufzeit 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0610', 'Anleihen nicht konvertibel - Restlaufzeit größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0615', 'Anleihen konvertibel');
+INSERT INTO gifi (accno,description) VALUES ('0616', 'Anleihen konvertibel - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0620', 'Anleihen konvertibel - Restlaufzeit 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0625', 'Anleihen konvertibel - Restlaufzeit größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0630', 'Verbindlichkeiten gegenüber Kreditinstituten');
+INSERT INTO gifi (accno,description) VALUES ('0631', 'Verb. gg. Kreditinstituten - Restlaufz. bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0640', 'Verb. gg. Kreditinstituten - Restlaufz. 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0650', 'Verb. gg. Kreditinstituten - Restlaufz. größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0660', 'Verbindlichkeiten gg. Kreditinst. aus TZ-Verträgen');
+INSERT INTO gifi (accno,description) VALUES ('0661', 'Verb. gg. Kreditinst. aus TZ-Verträgen - Restl. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('0670', 'Verb. gg. Kreditinst. aus TZ-Verträgen - Restl. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('0680', 'Verb. gg. Kreditinst. aus TZ-Verträgen - Restl. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('0700', 'Verbindlichkeiten gg. verbundenen Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('0701', 'Verb. gg. verbundenen Unternehmen - Restlaufz. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('0705', 'Verb. gg. verbundenen Unternehmen - Restlaufz. 1 b. 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('0710', 'Verb. gg. verb. Untern. - Restlaufz. gr. 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('0715', 'Verb. gg. Untern. mit denen ein Beteiligungsverh. besteht');
+INSERT INTO gifi (accno,description) VALUES ('0716', 'Verb. gg. U. m.d.e. Beteiligungsv. best. - Restl. b. 1 J');
+INSERT INTO gifi (accno,description) VALUES ('0720', 'Verb. gg. U. m.d.e. Beteiligungsv. best. - Restl. 1 b. 5 J');
+INSERT INTO gifi (accno,description) VALUES ('0725', 'Verb. gg. U. m.d.e. Beteiligungsv. best. - Restl. gr. 5 J');
+INSERT INTO gifi (accno,description) VALUES ('0730', 'Verbindlichkeiten gegenüber Gesellschaftern');
+INSERT INTO gifi (accno,description) VALUES ('0731', 'Verb. gg. Gesellschaftern - Restlaufz. bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0740', 'Verb. gg. Gesellschaftern - Restlaufz. 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0750', 'Verb. gg. Gesellschaftern - Restlaufz. größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0755', 'Verb. gg. Gesellschaftern für offene Ausschüttungen');
+INSERT INTO gifi (accno,description) VALUES ('0760', 'Darlehen typisch stiller Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('0761', 'Darlehen typ. stiller Gesellschafter - Restlaufz. bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0764', 'Darlehen typ. stiller Gesellschafter - Restlaufz. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('0767', 'Darlehen typ. stiller Gesellschafter - Restlaufz. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('0770', 'Darlehen atypisch stiller Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('0771', 'Darlehen atyp. stiller Gesellsch.- Restlaufz. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('0774', 'Darlehen atyp. stiller Gesellsch.- Restlaufz. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('0777', 'Darlehen atyp. stiller Gesellsch.- Restlaufz. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('0780', 'Partiarische Darlehen');
+INSERT INTO gifi (accno,description) VALUES ('0781', 'Partiarische Darlehen - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0784', 'Partiarische Darlehen - Restlaufzeit 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0787', 'Partiarische Darlehen - Restlaufzeit größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('0800', 'Gezeichnetes Kapital');
+INSERT INTO gifi (accno,description) VALUES ('0801', 'Ausst. Einl. a.d. gez. Kapital, nicht eingef. (Aktivausw.)');
+INSERT INTO gifi (accno,description) VALUES ('0810', 'Ausst. Einl. a.d. gez. Kapital, eingeford. (Aktivausw.)');
+INSERT INTO gifi (accno,description) VALUES ('0820', 'Ausst. Einl. a.d. gez. Kapital, nicht eingef. (Passivausw.)');
+INSERT INTO gifi (accno,description) VALUES ('0830', 'Ausst. Einl. a.d. gez. Kapital, eingef. (Passivausw.)');
+INSERT INTO gifi (accno,description) VALUES ('0839', 'Eingeforderte Nachschüsse');
+INSERT INTO gifi (accno,description) VALUES ('0840', 'Kapitalrücklage');
+INSERT INTO gifi (accno,description) VALUES ('0841', 'Kapitalrückl. durch Ausgabe von Anteilen über Nennbetrag');
+INSERT INTO gifi (accno,description) VALUES ('0842', 'Kap.Rückl. Schuldver. f. Wandl.- u. Optionsr. z. Erw. v. Ant');
+INSERT INTO gifi (accno,description) VALUES ('0843', 'Kapitalrückl. d. Zuzahl. gg. Gewähr e. Vorzuges f. Anteile');
+INSERT INTO gifi (accno,description) VALUES ('0844', 'Kapitalrückl. d. andere Zuzahlungen in das Eigenkapital');
+INSERT INTO gifi (accno,description) VALUES ('0845', 'Eingefordertes Nachschußkapital');
+INSERT INTO gifi (accno,description) VALUES ('0846', 'Gesetzliche Rücklage');
+INSERT INTO gifi (accno,description) VALUES ('0847', 'Gesetzliche Rücklage 50/45% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0848', 'Gesetzliche Rücklage 30% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0849', 'Gesetzliche Rücklage 0% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0850', 'Rücklage für eigene Anteile');
+INSERT INTO gifi (accno,description) VALUES ('0851', 'Satzungsmäßige Rücklagen');
+INSERT INTO gifi (accno,description) VALUES ('0852', 'Satzungsmäßige Rücklage 50/45% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0853', 'Satzungsmäßige Rücklage 30% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0854', 'Satzungsmäßige Rücklage 0% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0855', 'Andere Gewinnrücklagen 50/45% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0856', 'Eigenkapitalanteil von Wertaufholungen');
+INSERT INTO gifi (accno,description) VALUES ('0857', 'Eigenkapitalanteil von Preissteigerungsrücklagen');
+INSERT INTO gifi (accno,description) VALUES ('0858', 'Andere Gewinnrücklagen 30% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0859', 'Andere Gewinnrücklagen 0% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0860', 'Gewinnvortrag vor Verwendung');
+INSERT INTO gifi (accno,description) VALUES ('0862', 'Gewinnvortrag 50/45% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0864', 'Gewinnvortrag 30% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0866', 'Gewinnvortrag 0% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('0868', 'Verlustvortrag vor Verwendung');
+INSERT INTO gifi (accno,description) VALUES ('0869', 'Vorträge auf neue Rechnung (Bilanz)');
+INSERT INTO gifi (accno,description) VALUES ('0870', 'Festkapital (Personenges. Vollhafter / Einzelu.)');
+INSERT INTO gifi (accno,description) VALUES ('0880', 'Variables Kapital (Personenges. Vollhaft. / Einzelu.)');
+INSERT INTO gifi (accno,description) VALUES ('0890', 'Gesellsch.-Darlehen (Personenges. Vollhaft. / Einzelu.)');
+INSERT INTO gifi (accno,description) VALUES ('0900', 'Kommandit-Kapital (Personenges. Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('0910', 'Verlustausgleichskonto (Personenges. Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('0920', 'Gesellschafter-Darlehen (Personenges. Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('0930', 'Sonderposten mit Rücklageanteil');
+INSERT INTO gifi (accno,description) VALUES ('0931', 'Sonderposten mit Rücklageanteil §6b EStG');
+INSERT INTO gifi (accno,description) VALUES ('0932', 'Sonderposten mit Rücklageanteil Abschnitt 35 EStR');
+INSERT INTO gifi (accno,description) VALUES ('0933', 'Sonderposten mit Rücklageanteil §6dEStG');
+INSERT INTO gifi (accno,description) VALUES ('0934', 'Sonderposten mit Rücklageanteil §1 EntwLStG');
+INSERT INTO gifi (accno,description) VALUES ('0935', 'Sonderposten mit Rücklageanteil §3 Ausl-InvG');
+INSERT INTO gifi (accno,description) VALUES ('0936', 'Sonderposten mit Rücklageanteil §7d EStG');
+INSERT INTO gifi (accno,description) VALUES ('0937', 'Sonderposten mit Rücklageanteil §79 EStDV');
+INSERT INTO gifi (accno,description) VALUES ('0938', 'Sonderposten mit Rücklageanteil §80 EStDV');
+INSERT INTO gifi (accno,description) VALUES ('0939', 'Sonderposten mit Rücklageanteil §81 EStDV');
+INSERT INTO gifi (accno,description) VALUES ('0940', 'Sonderposten mit Rücklageanteil §82 EStDV');
+INSERT INTO gifi (accno,description) VALUES ('0941', 'Sonderposten mit Rücklageanteil §82a EStDV');
+INSERT INTO gifi (accno,description) VALUES ('0942', 'Sonderposten mit Rücklageanteil §82d EStDV');
+INSERT INTO gifi (accno,description) VALUES ('0943', 'Sonderposten mit Rücklageanteil §82e EStDV');
+INSERT INTO gifi (accno,description) VALUES ('0944', 'Sonderposten mit Rücklageanteil §14 BerlinFG');
+INSERT INTO gifi (accno,description) VALUES ('0945', 'Sonderposten mit Rücklageanteil §3 ZonenRFG / §4-6 FördergebietsG');
+INSERT INTO gifi (accno,description) VALUES ('0946', 'Sonderposten mit Rücklageanteil §52 Abs. 5 EStG');
+INSERT INTO gifi (accno,description) VALUES ('0947', 'Sonderposten mit Rücklageanteil §7g Abs. 1 EStG');
+INSERT INTO gifi (accno,description) VALUES ('0948', 'Sonderposten mit Rücklageanteil §7g Abs. 3 EStG');
+INSERT INTO gifi (accno,description) VALUES ('0949', 'Sonderposten mit Rücklageanteil §74 EStDV');
+INSERT INTO gifi (accno,description) VALUES ('0950', 'Rückstellungen für Pensionen und ähnliche Verpflichtungen');
+INSERT INTO gifi (accno,description) VALUES ('0955', 'Steuerrückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('0957', 'Gewerbesteuerrückstellung');
+INSERT INTO gifi (accno,description) VALUES ('0963', 'Körperschaftsteuerrückstellung');
+INSERT INTO gifi (accno,description) VALUES ('0969', 'Rückstellungen für latente Steuern');
+INSERT INTO gifi (accno,description) VALUES ('0970', 'Sonstige Rückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('0971', 'Rückst. unterl. Aufw. Instandhalt., Nachhol. in 3 Mon');
+INSERT INTO gifi (accno,description) VALUES ('0972', 'Rückst. unterl. Aufw. Instandhalt., Nachhol. in 4-12 Mon');
+INSERT INTO gifi (accno,description) VALUES ('0973', 'Rückstellungen für Abraum- und Abfallbeseitigung');
+INSERT INTO gifi (accno,description) VALUES ('0974', 'Rückstellungen für Gewährleistungen');
+INSERT INTO gifi (accno,description) VALUES ('0976', 'Rückst. f. drohende Verluste a. schwebenden Geschäften');
+INSERT INTO gifi (accno,description) VALUES ('0977', 'Rückstellungen für Abschluß- und Prüfungskosten');
+INSERT INTO gifi (accno,description) VALUES ('0978', 'Aufwandsrückstellungen gemäß § 249 Abs. 2 HGB');
+INSERT INTO gifi (accno,description) VALUES ('0979', 'Rückstellungen für den Umweltschutz');
+INSERT INTO gifi (accno,description) VALUES ('0980', 'Aktive Rechnungsabgrenzung');
+INSERT INTO gifi (accno,description) VALUES ('0983', 'Abgrenzung aktive latente Steuern');
+INSERT INTO gifi (accno,description) VALUES ('0984', 'Als Aufwand berücks. Zölle u. Verbrauchsst. a. Vorräte');
+INSERT INTO gifi (accno,description) VALUES ('0985', 'Als Aufwand berücks. Umsatzsteuer auf Anzahlungen');
+INSERT INTO gifi (accno,description) VALUES ('0986', 'Damnum / Disagio');
+INSERT INTO gifi (accno,description) VALUES ('0990', 'Passive Rechnungsabgrenzung');
+INSERT INTO gifi (accno,description) VALUES ('0992', 'Wertber.n (zur unterjährigen Kostenverrechnung f. BWA)');
+INSERT INTO gifi (accno,description) VALUES ('0996', 'Pauschalwertberichtigung a. Ford. - Restlaufz. bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0997', 'Pauschalwertberichtigung a. Ford. - Restlaufz. größer 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0998', 'Einzelwertberichtigung a. Ford. - Restlaufz. bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('0999', 'Einzelwertberichtigung a. Ford. - Restlaufz. größer 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1000', 'Kasse');
+INSERT INTO gifi (accno,description) VALUES ('1010', 'Nebenkasse 1');
+INSERT INTO gifi (accno,description) VALUES ('1020', 'Nebenkasse 2');
+INSERT INTO gifi (accno,description) VALUES ('1100', 'Postgiro');
+INSERT INTO gifi (accno,description) VALUES ('1110', 'Postgiro 1');
+INSERT INTO gifi (accno,description) VALUES ('1120', 'Postgiro 2');
+INSERT INTO gifi (accno,description) VALUES ('1130', 'Postgiro 3');
+INSERT INTO gifi (accno,description) VALUES ('1190', 'LZB-Guthaben');
+INSERT INTO gifi (accno,description) VALUES ('1195', 'Bundesbankguthaben');
+INSERT INTO gifi (accno,description) VALUES ('1200', 'Bank-Giro');
+INSERT INTO gifi (accno,description) VALUES ('1210', 'Bank-Giro 1');
+INSERT INTO gifi (accno,description) VALUES ('1220', 'Bank-Giro 2');
+INSERT INTO gifi (accno,description) VALUES ('1230', 'Bank-Giro 3');
+INSERT INTO gifi (accno,description) VALUES ('1300', 'Wechsel aus Lieferungen und Leistungen');
+INSERT INTO gifi (accno,description) VALUES ('1301', 'Wechsel aus Lieferungen u. Leistungen - Restlaufz. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1302', 'Wechsel aus Lieferungen u. Leistungen - Restl. größer 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1305', 'Wechsel aus Lieferungen u. Leistungen, bundesbankfähig');
+INSERT INTO gifi (accno,description) VALUES ('1310', 'Besitzwechsel gg. verbundenen Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('1311', 'Besitzwechsel gg. verbundenen Untern. - Restl. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1312', 'Besitzwechsel gg. verbundenen Untern. - Restl. gr. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1315', 'Besitzwechsel gg. verb. Unternehmen, bundesbankfähig');
+INSERT INTO gifi (accno,description) VALUES ('1320', 'Besitzwechsel gg. Untern. m.d.e. Beteiligungsverh. best.');
+INSERT INTO gifi (accno,description) VALUES ('1321', 'Besitzwechsel gg. U. m.d.e. Beteilig. best. - Restl. b. 1 J');
+INSERT INTO gifi (accno,description) VALUES ('1322', 'Besitzwechsel gg. U. m.d.e. Beteilig. best. - Restl. gr. 1 J');
+INSERT INTO gifi (accno,description) VALUES ('1325', 'Besitzwechsel gg. U. m.d.e. Beteilig. best., bundsbankfähig');
+INSERT INTO gifi (accno,description) VALUES ('1327', 'Finanzwechsel');
+INSERT INTO gifi (accno,description) VALUES ('1330', 'Schecks');
+INSERT INTO gifi (accno,description) VALUES ('1340', 'Anteile an verb. Unternehmen (Umlaufvermögen)');
+INSERT INTO gifi (accno,description) VALUES ('1344', 'Anteile an herrschender oder mit Mehrheit beteiligter Gesellschaft');
+INSERT INTO gifi (accno,description) VALUES ('1345', 'Eigene Anteile');
+INSERT INTO gifi (accno,description) VALUES ('1348', 'Sonstige Wertpapiere');
+INSERT INTO gifi (accno,description) VALUES ('1350', 'GmbH-Anteile zum kurzfristigen Verbleib');
+INSERT INTO gifi (accno,description) VALUES ('1352', 'Genossenschaftsanteile zum kurzfristigen Verbleib');
+INSERT INTO gifi (accno,description) VALUES ('1355', 'Ansprüche aus Rückdeckungsversicherungen');
+INSERT INTO gifi (accno,description) VALUES ('1360', 'Geldtransit Bank');
+INSERT INTO gifi (accno,description) VALUES ('1361', 'Geldtransit Bank 1');
+INSERT INTO gifi (accno,description) VALUES ('1362', 'Geldtransit Bank 2');
+INSERT INTO gifi (accno,description) VALUES ('1363', 'Geldtransit Bank 3');
+INSERT INTO gifi (accno,description) VALUES ('1369', 'Interne Umbuchung');
+INSERT INTO gifi (accno,description) VALUES ('1370', 'Verrechnungskonto Gewinnermittlung §4/3 EStG, ergebniswirksam');
+INSERT INTO gifi (accno,description) VALUES ('1371', 'Verrechnungskonto für Gewinnermittl. §4/3EStG, nicht ergebniswirksam');
+INSERT INTO gifi (accno,description) VALUES ('1380', 'Überleitungskonto Kostenstelle');
+INSERT INTO gifi (accno,description) VALUES ('1390', 'Verrechnungskonto Ist-Versteuerung');
+INSERT INTO gifi (accno,description) VALUES ('1400', 'Forderungen aus Lief. und Leist. Kundengruppe 0');
+INSERT INTO gifi (accno,description) VALUES ('1401', 'Forderungen aus Lief. und Leist. Kundengruppe 1');
+INSERT INTO gifi (accno,description) VALUES ('1402', 'Forderungen aus Lief. und Leist. Kundengruppe 2');
+INSERT INTO gifi (accno,description) VALUES ('1410', 'Forderungen aus Lief. und Leist. ohne Kontokorrent');
+INSERT INTO gifi (accno,description) VALUES ('1450', 'Forderungen nach §11, Abs.1 Satz 2 EStG für § 4/3 EStG');
+INSERT INTO gifi (accno,description) VALUES ('1451', 'Ford.a.Lief.u.Leist. ohne Kontokorrent - Restlaufz. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1455', 'Ford.a.Lief.u.Leist. ohne Kontokorrent - Restlaufz. gr.1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1460', 'Zweifelhafte Forderungen');
+INSERT INTO gifi (accno,description) VALUES ('1461', 'Zweifelhafte Forderungen - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1465', 'Zweifelhafte Forderungen - Restlaufzeit größer 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1470', 'Ford.a.Lief.u.Leist. gg. verbundenen Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('1471', 'Ford.a.Lief.u.Leist. gg. verb. Untern. - Restl. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1475', 'Ford.a.Lief.u.Leist. gg. verb. Untern. - Restl. größer 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1478', 'Wertber. a. Ford.a.L.u.L. gg. verb. U. - Restl. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1479', 'Wertber. a. Ford.a.L.u.L. gg. verb. U. - Restl. gr. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1480', 'Ford.a.L.u.L. gg. Untern. m.d.e. Beteiligungsverh. best.');
+INSERT INTO gifi (accno,description) VALUES ('1481', 'Ford.a.L.u.L. gg. U. m.d.e. Beteilig. best. - Restl. b. 1 J');
+INSERT INTO gifi (accno,description) VALUES ('1485', 'Ford.a.L.u.L. gg. U. m.d.e. Beteilig. best. - Restl. gr. 1 J');
+INSERT INTO gifi (accno,description) VALUES ('1488', 'Wertber. a. Ford. Restl. b. 1 J. gg. U. m.d.e. Beteilig.');
+INSERT INTO gifi (accno,description) VALUES ('1489', 'Wertber. a. Ford. Restl. gr. 1 J. gg. U. m.d.e. Beteilig.');
+INSERT INTO gifi (accno,description) VALUES ('1490', 'Ford.a.Lief.u.Leist. gegen Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('1491', 'Ford.a.Lief.u.Leist. gg. Gesellsch.- Restlaufz. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1495', 'Ford.a.Lief.u.Leist. gg. Gesellsch.- Restlaufz. größer 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1499', 'Gegenkonto 14510-14980 bei Aufteilung Debitoren');
+INSERT INTO gifi (accno,description) VALUES ('1500', 'Sonstige Vermögensgegenstände');
+INSERT INTO gifi (accno,description) VALUES ('1501', 'Sonstige Vermögensgegenstände - Restlaufz. bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1502', 'Sonstige Vermögensgegenstände - Restlaufz. größer 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1503', 'Ford. gg. Vorstandsmitgl. u. Geschäftsf. - Restl. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1504', 'Ford. gg. Vorstandsmitgl. u. Geschäftsf. - Restl. gr. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1505', 'Ford. gg. Aufsichtsrats- u. Beiratsmitgl. - Restl. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1506', 'Ford. gg. Aufsichtsrats- u. Beiratsmitgl. - Restl. gr. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1507', 'Ford. gg. Gesellschafter - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1508', 'Ford. gg. Gesellschafter - Restlaufzeit größer 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1510', 'Geleistete Anzahlungen auf Vorräte');
+INSERT INTO gifi (accno,description) VALUES ('1511', 'Geleistete Anzahlungen, 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('1516', 'Geleistete Anzahlungen, 15% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('1517', 'Geleistete Anzahlungen, 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('1521', 'Agenturwarenabrechnung');
+INSERT INTO gifi (accno,description) VALUES ('1525', 'Kautionen');
+INSERT INTO gifi (accno,description) VALUES ('1526', 'Kautionen - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1527', 'Kautionen - Restlaufzeit größer 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1530', 'Forderungen gegen Personal');
+INSERT INTO gifi (accno,description) VALUES ('1531', 'Forderungen gegen Personal - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1537', 'Forderungen gegen Personal - Restlaufzeit größer 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1540', 'Steuerüberzahlungen');
+INSERT INTO gifi (accno,description) VALUES ('1542', 'Steuererstattungsansprüche gg. anderen EU-Ländern');
+INSERT INTO gifi (accno,description) VALUES ('1545', 'Umsatzsteuerforderungen');
+INSERT INTO gifi (accno,description) VALUES ('1547', 'Forderungen aus entrichteten Verbrauchssteuern');
+INSERT INTO gifi (accno,description) VALUES ('1548', 'Vorsteuer im Folgejahr abziehbar');
+INSERT INTO gifi (accno,description) VALUES ('1549', 'Körperschaftsteuerrückforderung');
+INSERT INTO gifi (accno,description) VALUES ('1550', 'Darlehen');
+INSERT INTO gifi (accno,description) VALUES ('1551', 'Darlehen - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1555', 'Darlehen - Restlaufzeit größer 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1560', 'Aufzuteilende Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('1561', 'Aufzuteilende Vorsteuer, 7%');
+INSERT INTO gifi (accno,description) VALUES ('1562', 'Aufzuteilende Vorsteuer aus ig. Erwerb');
+INSERT INTO gifi (accno,description) VALUES ('1565', 'Aufzuteilende Vorsteuer, 16 %');
+INSERT INTO gifi (accno,description) VALUES ('1566', 'Aufzuteilende Vorsteuer, 15 %');
+INSERT INTO gifi (accno,description) VALUES ('1570', 'Abziehbare Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('1571', 'Abziehbare Vorsteuer, 7%');
+INSERT INTO gifi (accno,description) VALUES ('1572', 'Abziehbare Vorsteuer aus ig. Erwerb');
+INSERT INTO gifi (accno,description) VALUES ('1573', 'Abziehbare Vorsteuer aus ig. Erwerb, 16%');
+INSERT INTO gifi (accno,description) VALUES ('1575', 'Abziehbare Vorsteuer, 16%');
+INSERT INTO gifi (accno,description) VALUES ('1576', 'Abziehbare Vorsteuer, 15%');
+INSERT INTO gifi (accno,description) VALUES ('1577', 'Vorsteuer nach allg. Durchschnittssätzen UStVA KZ 63');
+INSERT INTO gifi (accno,description) VALUES ('1578', 'Berichtigung des VSt-Abzugs früherer Jahre UStVA KZ 64');
+INSERT INTO gifi (accno,description) VALUES ('1580', 'Gegenkonto Vorsteuer § 4/3 EStG');
+INSERT INTO gifi (accno,description) VALUES ('1581', 'Auflösung Vorsteuer aus Vorjahr § 4/3 EStG');
+INSERT INTO gifi (accno,description) VALUES ('1584', 'Abziehb. VSt. a. ig. Erw. v. Neufahrz. v. Lief. ohne USt-ID');
+INSERT INTO gifi (accno,description) VALUES ('1586', 'Kürzung BerlinFG');
+INSERT INTO gifi (accno,description) VALUES ('1588', 'Bezahlte Einfuhrumsatzsteuer');
+INSERT INTO gifi (accno,description) VALUES ('1590', 'Durchlaufende Posten');
+INSERT INTO gifi (accno,description) VALUES ('1593', 'Verrechnungskto erhalt. Anzahl. b. Buchung ü. Kundenkto');
+INSERT INTO gifi (accno,description) VALUES ('1594', 'Forderungen gegen verbundene Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('1595', 'Ford. gg. verbundene Unternehmen - Restlaufz. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1596', 'Ford. gg. verbundene Unternehmen - Restlaufz. gr. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1597', 'Ford. gg. Untern. mit denen ein Beteiligungsverh. besteht');
+INSERT INTO gifi (accno,description) VALUES ('1598', 'Ford. gg. U. m.d.e. Beteiligungsv. best. - Restl. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1599', 'Ford. gg. U. m.d.e. Beteiligungsv. best. - Restl. gr. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1600', 'Verb. aus Lief. und Leist. Lieferantengruppe 0');
+INSERT INTO gifi (accno,description) VALUES ('1601', 'Verb. aus Lief. und Leist. Lieferantengruppe 1');
+INSERT INTO gifi (accno,description) VALUES ('1602', 'Verb. aus Lief. und Leist. Lieferantengruppe 2');
+INSERT INTO gifi (accno,description) VALUES ('1610', 'Verb.a.L.u.L. ohne Kontokorrent');
+INSERT INTO gifi (accno,description) VALUES ('1624', 'Verbindlichkeiten aus Lief. u. Leist. für Investitionen für §4/3 EStG');
+INSERT INTO gifi (accno,description) VALUES ('1625', 'Verb.a.L.u.L. ohne Kontokorrent - Restl. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1626', 'Verb.a.L.u.L. ohne Kontokorrent - Restlaufz. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1628', 'Verb.a.L.u.L. ohne Kontokorrent - Restlaufz. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1630', 'Verb.a.Lief.u.Leist. gg. verbundenen Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('1631', 'Verb.a.L.u.L. gg. verb. Untern. - Restlaufz. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1635', 'Verb.a.L.u.L. gg. verb. Untern. - Restlaufz. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1638', 'Verb.a.L.u.L. gg. verb. Untern. - Restlaufz. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1640', 'Verb.a.L.u.L. gg. Untern. m.d.e. Beteiligungsverh. best.');
+INSERT INTO gifi (accno,description) VALUES ('1641', 'Verb.a.L.u.L. gg. U. m.d.e. Beteilig. best. - Restl. b. 1 J');
+INSERT INTO gifi (accno,description) VALUES ('1645', 'Verb.a.L.u.L. gg. U. m.d.e. Beteilig. best. - Restl. 1 b 5 J');
+INSERT INTO gifi (accno,description) VALUES ('1648', 'Verb.a.L.u.L. gg. U. m.d.e. Beteilig. best. - Restl. gr. 5 J');
+INSERT INTO gifi (accno,description) VALUES ('1650', 'Verb.a.Lief.u.Leist. gegen Gesellschaftern');
+INSERT INTO gifi (accno,description) VALUES ('1651', 'Verb.a.Lief.u.Leist. gg. Gesellsch. - Restl. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1655', 'Verb.a.Lief.u.Leist. gg. Gesellsch. - Restl. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1658', 'Verb.a.Lief.u.Leist. gg. Gesellsch. - Restl. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1659', 'Gegenkonto 16250-16580 bei Aufteilung Kreditoren-Konto');
+INSERT INTO gifi (accno,description) VALUES ('1660', 'Schuldwechsel');
+INSERT INTO gifi (accno,description) VALUES ('1661', 'Schuldwechsel - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1680', 'Schuldwechsel - Restlaufzeit 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1690', 'Schuldwechsel - Restlaufzeit größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1700', 'Sonstige Verbindlichkeiten');
+INSERT INTO gifi (accno,description) VALUES ('1701', 'Sonstige Verbindlichkeiten - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1702', 'Sonstige Verbindlichkeiten - Restlaufzeit 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1703', 'Sonstige Verbindlichkeiten - Restlaufzeit größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1704', 'Sonstige Verbindlichkeiten, z.B. nach §11,Abs.2,2 EStG für §4/3');
+INSERT INTO gifi (accno,description) VALUES ('1705', 'Darlehen');
+INSERT INTO gifi (accno,description) VALUES ('1706', 'Darlehen - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1707', 'Darlehen - Restlaufzeit 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1708', 'Darlehen - Restlaufzeit größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1709', 'Gewinnverfügungskonto stiller Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('1710', 'Erhaltene Anzahlungen (Verbindlichkeiten)');
+INSERT INTO gifi (accno,description) VALUES ('1711', 'Erhaltene verst. Anzahl., 7% USt (Verbindlichkeiten)');
+INSERT INTO gifi (accno,description) VALUES ('1716', 'Erhaltene verst. Anzahl., 15% USt (Verbindlichkeiten)');
+INSERT INTO gifi (accno,description) VALUES ('1717', 'Erhaltene verst. Anzahl., 16% USt (Verbindlichkeiten)');
+INSERT INTO gifi (accno,description) VALUES ('1719', 'Erhaltene Anzahlungen - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1720', 'Erhaltene Anzahlungen - Restlaufzeit 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1721', 'Erhaltene Anzahlungen - Restlaufzeit größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1722', 'Erhaltene Anzahlungen (von Vorräten offen abgesetzt)');
+INSERT INTO gifi (accno,description) VALUES ('1731', 'Agenturwarenabrechnung');
+INSERT INTO gifi (accno,description) VALUES ('1732', 'Erhaltene Kautionen');
+INSERT INTO gifi (accno,description) VALUES ('1733', 'Erhaltene Kautionen - Restlaufzeit bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1734', 'Erhaltene Kautionen - Restlaufzeit 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1735', 'Erhaltene Kautionen - Restlaufzeit größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1736', 'Verbindlichkeiten aus Betriebsteuern und Abgaben');
+INSERT INTO gifi (accno,description) VALUES ('1737', 'Verb. aus Betriebsteuern u. Abgaben - Restlaufz. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1738', 'Verb. aus Betriebsteuern u. Abgaben - Restlaufz. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1739', 'Verb. aus Betriebsteuern u. Abgaben - Restl. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1740', 'Verbindlichkeiten aus Lohn und Gehalt');
+INSERT INTO gifi (accno,description) VALUES ('1741', 'Verbindlichkeiten aus Lohn- und Kirchensteuer');
+INSERT INTO gifi (accno,description) VALUES ('1742', 'Verbindlichkeiten im Rahmen der sozialen Sicherheit');
+INSERT INTO gifi (accno,description) VALUES ('1743', 'Verb. im Rahmen der sozialen Sicherheit - Restl. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('1744', 'Verb. im Rahmen der sozialen Sicherheit - Restl. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1745', 'Verb. im Rahmen der sozialen Sicherheit - Restl. gr. 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('1746', 'Verbindlichkeiten aus Einbehaltungen');
+INSERT INTO gifi (accno,description) VALUES ('1747', 'Verbindlichkeiten für Verbrauchssteuern');
+INSERT INTO gifi (accno,description) VALUES ('1750', 'Verbindlichkeiten aus Vermögensbildung');
+INSERT INTO gifi (accno,description) VALUES ('1751', 'Verb. aus Vermögensbildung - Restlaufz. bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1752', 'Verb. aus Vermögensbildung - Restlaufz. 1 bis 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1753', 'Verb. aus Vermögensbildung - Restlaufz. größer 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1755', 'Lohn- und Gehaltsverrechnung');
+INSERT INTO gifi (accno,description) VALUES ('1758', 'Umsatzsteuerabzugsverfahren, 16% Umsatzsteuer');
+INSERT INTO gifi (accno,description) VALUES ('1759', 'Umsatzsteuerabzugsverfahren, 15% Umsatzsteuer');
+INSERT INTO gifi (accno,description) VALUES ('1760', 'Umsatzsteuer nicht fällig');
+INSERT INTO gifi (accno,description) VALUES ('1761', 'Umsatzsteuer nicht fällig , 7%');
+INSERT INTO gifi (accno,description) VALUES ('1762', 'Umsatzsteuer nicht fällig a.i. Inland steuerpfl. EU-Lief.');
+INSERT INTO gifi (accno,description) VALUES ('1763', 'Umsatzsteuer nicht fällig a.i. Inland steuerpfl. EU-Lief., 16%');
+INSERT INTO gifi (accno,description) VALUES ('1765', 'Umsatzsteuer nicht fällig, 16%');
+INSERT INTO gifi (accno,description) VALUES ('1766', 'Umsatzsteuer nicht fällig, 15%');
+INSERT INTO gifi (accno,description) VALUES ('1767', 'Umsatzsteuer a.i. and. EU-Land steuerpfl. Lief.');
+INSERT INTO gifi (accno,description) VALUES ('1768', 'Umsatzsteuer a.i. and. EU-Land steuerpfl. sonst. Lief./Werkl.');
+INSERT INTO gifi (accno,description) VALUES ('1769', 'Steuerzahlungen an andere EU-Länder');
+INSERT INTO gifi (accno,description) VALUES ('1770', 'Umsatzsteuer');
+INSERT INTO gifi (accno,description) VALUES ('1771', 'Umsatzsteuer, 7%');
+INSERT INTO gifi (accno,description) VALUES ('1772', 'Umsatzsteuer aus ig. Erwerb');
+INSERT INTO gifi (accno,description) VALUES ('1773', 'Umsatzsteuer aus ig. Erwerb, 16%');
+INSERT INTO gifi (accno,description) VALUES ('1775', 'Umsatzsteuer, 16%');
+INSERT INTO gifi (accno,description) VALUES ('1776', 'Umsatzsteuer, 15%');
+INSERT INTO gifi (accno,description) VALUES ('1777', 'Umsatzsteuer aus im Inland steuerpfl. EU-Lieferungen');
+INSERT INTO gifi (accno,description) VALUES ('1778', 'Umsatzsteuer aus im Inland steuerpfl. EU-Lieferungen, 16%');
+INSERT INTO gifi (accno,description) VALUES ('1779', 'Umsatzsteuer aus ig. Erwerb ohne Vorsteuerabzug');
+INSERT INTO gifi (accno,description) VALUES ('1780', 'Umsatzsteuer - Vorauszahlungen');
+INSERT INTO gifi (accno,description) VALUES ('1781', 'Umsatzsteuer - Vorauszahlungen 1/11');
+INSERT INTO gifi (accno,description) VALUES ('1782', 'Nachsteuer, UStVA KZ 65');
+INSERT INTO gifi (accno,description) VALUES ('1783', 'In Rechnung unber. ausgewiesene und geschuldete Steuer, UStVA KZ 69');
+INSERT INTO gifi (accno,description) VALUES ('1784', 'Umsatzsteuer aus ig. Erw. v. Neufahrz. v. Lief. ohne USt-ID');
+INSERT INTO gifi (accno,description) VALUES ('1788', 'Einfuhrumsatzsteuer aufgeschoben bis');
+INSERT INTO gifi (accno,description) VALUES ('1789', 'Umsatzsteuer laufendes Jahr');
+INSERT INTO gifi (accno,description) VALUES ('1790', 'Umsatzsteuer Vorjahr');
+INSERT INTO gifi (accno,description) VALUES ('1791', 'Umsatzsteuer frühere Jahre');
+INSERT INTO gifi (accno,description) VALUES ('1792', 'Abgrenzung für Grundstücke');
+INSERT INTO gifi (accno,description) VALUES ('1794', 'Abgrenzung für immaterielle Vermögensgegenstände');
+INSERT INTO gifi (accno,description) VALUES ('1795', 'Abgrenzung für Bauten auf eigenen Grundstücken');
+INSERT INTO gifi (accno,description) VALUES ('1796', 'Abgrenzung für andere Anlagen, B.u.G. Ausstattung');
+INSERT INTO gifi (accno,description) VALUES ('1797', 'Abgrenzung für Bauten auf fremden Grundstücken');
+INSERT INTO gifi (accno,description) VALUES ('1798', 'Abgrenzung für technische Anlagen und Maschinen');
+INSERT INTO gifi (accno,description) VALUES ('1799', 'Sonstige Verrechnungskonten (Interimskonten)');
+INSERT INTO gifi (accno,description) VALUES ('1793', 'Verrechnungskto geleist. Anzahl. bei Buchung über Lief.Kto.');
+INSERT INTO gifi (accno,description) VALUES ('1800', 'Privatentn. allg. (Privat Vollhafter / Einzelunternehmer)');
+INSERT INTO gifi (accno,description) VALUES ('1810', 'Privatsteuern (Privat Vollhafter / Einzelunternehmer)');
+INSERT INTO gifi (accno,description) VALUES ('1820', 'Sonderausg. beschr. abzugsf. (Privat Vollhaft./Einzelu.)');
+INSERT INTO gifi (accno,description) VALUES ('1830', 'Sonderausg. unbeschr. abzugsf. (Privat Vollhaft./Einzelu.)');
+INSERT INTO gifi (accno,description) VALUES ('1840', 'Privatspenden (Privat Vollhafter / Einzelunternehmer)');
+INSERT INTO gifi (accno,description) VALUES ('1850', 'Außergewöhnliche Belastungen (Privat Vollhaft. / Einzelunt.)');
+INSERT INTO gifi (accno,description) VALUES ('1860', 'Grundstücksaufwand (Privat Vollhafter / Einzelunternehmer)');
+INSERT INTO gifi (accno,description) VALUES ('1870', 'Grundstücksertrag (Privat Vollhafter / Einzelunternehmer)');
+INSERT INTO gifi (accno,description) VALUES ('1880', 'Eigenverbrauch (Privat Vollhafter / Einzelunternehmer)');
+INSERT INTO gifi (accno,description) VALUES ('1890', 'Privateinlagen (Privat Vollhafter / Einzelunternehmer)');
+INSERT INTO gifi (accno,description) VALUES ('1900', 'Privatentnahmen allgemein (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('1910', 'Privatsteuern (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('1920', 'Sonderausgaben beschränkt abzugsf. (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('1930', 'Sonderausgaben unbeschränkt abzugsf. (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('1940', 'Privatspenden (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('1950', 'Außergewöhnliche Belastungen (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('1960', 'Grundstücksaufwand (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('1970', 'Grundstücksertrag (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('1980', 'Eigenverbrauch (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('1990', 'Privateinlagen (Privat Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('2000', 'Außerordentliche Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('2010', 'Betriebsfremde Aufw. (soweit nicht außerordentlich)');
+INSERT INTO gifi (accno,description) VALUES ('2020', 'Periodenfremde Aufw. (soweit nicht außerordentlich)');
+INSERT INTO gifi (accno,description) VALUES ('2100', 'Zinsen und ähnliche Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('2103', 'Steuerlich abzugsfähige, andere Nebenleistungen zu Steuern');
+INSERT INTO gifi (accno,description) VALUES ('2104', 'Steuerlich nicht abzugsfähige, andere Nebenleistungen zu Steuern');
+INSERT INTO gifi (accno,description) VALUES ('2107', 'Zinsaufwendungen §233a AO betriebliche Steuern');
+INSERT INTO gifi (accno,description) VALUES ('2108', 'Zinsaufw. §233a, §234, §237 AO Personenst. §8 GewStG');
+INSERT INTO gifi (accno,description) VALUES ('2109', 'Zinsaufwendungen an verbundene Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('2110', 'Zinsaufwendungen für kurzfristige Verbindlichkeiten');
+INSERT INTO gifi (accno,description) VALUES ('2118', 'In Dauerschuldzins. umqualif. Zinsen a. kurzfristige Verb.');
+INSERT INTO gifi (accno,description) VALUES ('2119', 'Zinsaufw. f. kurzfristige Verb. an verbunden Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('2120', 'Zinsaufwendungen für langfristige Verbindlichkeiten');
+INSERT INTO gifi (accno,description) VALUES ('2127', 'Renten u. dauernde Last. a. Gründung/Erwerb §8GewStG');
+INSERT INTO gifi (accno,description) VALUES ('2128', 'Zinsaufw. an Mitu. f. Hingabe v. langfrist. Kapital §15 EStG');
+INSERT INTO gifi (accno,description) VALUES ('2129', 'Zinsaufw. f. langfristige Verb. an verbundene Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('2130', 'Diskontaufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('2139', 'Diskontaufwendungen an verbundene Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('2140', 'Zinsähnliche Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('2149', 'Zinsähnliche Aufwendungen an verbundene Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('2150', 'Aufwendungen aus Kursdifferenzen');
+INSERT INTO gifi (accno,description) VALUES ('2170', 'Nicht abziehb. VSt a. Zinsen u. ähnl. Aufw.');
+INSERT INTO gifi (accno,description) VALUES ('2171', 'Nicht abziehb. VSt, 7% a. Zinsen u. ähnl. Aufw.');
+INSERT INTO gifi (accno,description) VALUES ('2175', 'Nicht abziehb. VSt. 16% a. Zinsen u. ähnl. Aufw.');
+INSERT INTO gifi (accno,description) VALUES ('2176', 'Nicht abziehb. VSt, 15% a. Zinsen u. ähnl. Aufw.');
+INSERT INTO gifi (accno,description) VALUES ('2200', 'Körperschaftsteuer');
+INSERT INTO gifi (accno,description) VALUES ('2203', 'Körperschaftsteuer für Vorjahre');
+INSERT INTO gifi (accno,description) VALUES ('2205', 'Anrechenbare Körperschaftssteuer auf vereinnahmte Kapitalerträge');
+INSERT INTO gifi (accno,description) VALUES ('2208', 'Solidaritätszuschlag');
+INSERT INTO gifi (accno,description) VALUES ('2209', 'Solidaritätszuschlag für Vorjahre');
+INSERT INTO gifi (accno,description) VALUES ('2210', 'Kapitalertragsteuer');
+INSERT INTO gifi (accno,description) VALUES ('2213', 'Anrechenbarer Solidaritätszuschlag auf Kapitalertragssteuer');
+INSERT INTO gifi (accno,description) VALUES ('2215', 'Zinsabschlagsteuer');
+INSERT INTO gifi (accno,description) VALUES ('2218', 'Anrechenbarer Solidaritätszuschlag auf Zinsabschlagsteuer');
+INSERT INTO gifi (accno,description) VALUES ('2223', 'Vermögensteuer für Vorjahre');
+INSERT INTO gifi (accno,description) VALUES ('2280', 'Steuernachz. Vorjahre f. Steuern v. Einkommen u. Ertrag');
+INSERT INTO gifi (accno,description) VALUES ('2282', 'Steuererstatt. Vorjahre f. Steuern v. Einkommen u. Ertrag');
+INSERT INTO gifi (accno,description) VALUES ('2284', 'Erträge a. Aufl. v. Rückst. f. Steuern v. Eink. u. Ertrag');
+INSERT INTO gifi (accno,description) VALUES ('2285', 'Steuernachzahlung Vorjahre für sonstige Steuern');
+INSERT INTO gifi (accno,description) VALUES ('2287', 'Steuererstattung Vorjahre für sonstige Steuern');
+INSERT INTO gifi (accno,description) VALUES ('2289', 'Erträge a. d. Auflösung v. Rückstell. f. sonstige Steuern');
+INSERT INTO gifi (accno,description) VALUES ('2300', 'Sonstige Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('2307', 'Sonstige Aufwendungen betriebsfremd und regelmäßig');
+INSERT INTO gifi (accno,description) VALUES ('2309', 'Sonstige Aufwendungen unregelmäßig');
+INSERT INTO gifi (accno,description) VALUES ('2310', 'Anlagenabgänge (Restbuchwert und Buchverlust)');
+INSERT INTO gifi (accno,description) VALUES ('2315', 'Anlagenabgänge (Restbuchwert bei Buchgewinn)');
+INSERT INTO gifi (accno,description) VALUES ('2320', 'Verluste a. Abgang v. Gegenst. d. Anlagevermögens');
+INSERT INTO gifi (accno,description) VALUES ('2325', 'Verluste a. Abgang v. Gegenst. d. Umlaufv. (außer Vorräte)');
+INSERT INTO gifi (accno,description) VALUES ('2340', 'Einstell. in Sonderpost. m. Rücklageant. (steuerfr. Rückl.)');
+INSERT INTO gifi (accno,description) VALUES ('2341', 'Einstell. in Sonderpost. m. Rücklageant. (Ansparabschreibungen)');
+INSERT INTO gifi (accno,description) VALUES ('2345', 'Einstell. in Sonderpost. m. Rücklageant. (Sonderabschr.)');
+INSERT INTO gifi (accno,description) VALUES ('2350', 'Grundstücksaufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('2375', 'Grundsteuer');
+INSERT INTO gifi (accno,description) VALUES ('2380', 'Spenden, steuerlich nicht absetzbar');
+INSERT INTO gifi (accno,description) VALUES ('2381', 'Beiträge u. Spenden f. wissenschaftl. u. kulturelle Zwecke');
+INSERT INTO gifi (accno,description) VALUES ('2382', 'Beiträge u. Spenden f. mildtätige Zwecke');
+INSERT INTO gifi (accno,description) VALUES ('2383', 'Beiträge u. Spenden f. kirchl., religiöse u. gemeinn. Zwecke');
+INSERT INTO gifi (accno,description) VALUES ('2384', 'Beiträge u. Spenden an politische Parteien');
+INSERT INTO gifi (accno,description) VALUES ('2385', 'Nicht abziehbare Hälfte der Aufsichtsratsvergütungen');
+INSERT INTO gifi (accno,description) VALUES ('2386', 'Abziehbare Aufsichtsratsvergütungen');
+INSERT INTO gifi (accno,description) VALUES ('2400', 'Forderungsverluste (übliche Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2401', 'Forderungsverluste, 7% USt (übliche Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2402', 'Ford.Verl. a. steuerfr. EU-Lief. (übliche Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2403', 'Ford.Verl. a.i. Inl. steuerpfl. EU-Lief., 7% USt (übl. Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2404', 'Ford.Verl. a.i. Inl. steuerpfl. EU-Lief., 15%+16%USt (übl. Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2405', 'Forderungsverluste, 15%+16% USt (übliche Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2406', 'Forderungsverluste, 16% USt (übliche Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2407', 'Forderungsverluste, 15% USt (übliche Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2408', 'Ford.Verl. a.i. Inl. steuerpfl. EU-Lief., 16%USt (übl. Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2409', 'Ford.Verl. a.i. Inl. steuerpfl. EU-Lief., 15%USt (übl. Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('2430', 'Forderungsverlust unüblich hoch');
+INSERT INTO gifi (accno,description) VALUES ('2450', 'Einstellungen in Pauschalwertberichtigung zu Forderungen');
+INSERT INTO gifi (accno,description) VALUES ('2451', 'Einstellungen in Einzelwertberichtigung zu Forderungen');
+INSERT INTO gifi (accno,description) VALUES ('2490', 'Aufwendungen aus Verlustübernahme');
+INSERT INTO gifi (accno,description) VALUES ('2492', 'Abgef. Gew. aufgrund einer Gewinngemeinschaft');
+INSERT INTO gifi (accno,description) VALUES ('2493', 'Abgef. Gew. a. stille Gesellschafter §8 GewStG');
+INSERT INTO gifi (accno,description) VALUES ('2494', 'Abgef. Gew. a. Gewinn- oder Teilgewinnabführungsvertr.');
+INSERT INTO gifi (accno,description) VALUES ('2495', 'Einst. in die Kapitalrückl. n. Vorschr. d. vereinf. Kap.Herabs.');
+INSERT INTO gifi (accno,description) VALUES ('2496', 'Einst. in die gesetzliche Rücklage');
+INSERT INTO gifi (accno,description) VALUES ('2497', 'Einst. in die satzungsmäßige Rücklage');
+INSERT INTO gifi (accno,description) VALUES ('2498', 'Einst. in die Rücklage für eigene Anteile');
+INSERT INTO gifi (accno,description) VALUES ('2499', 'Einst. in andere Gewinnrücklagen');
+INSERT INTO gifi (accno,description) VALUES ('2500', 'Außerordentliche Erträge');
+INSERT INTO gifi (accno,description) VALUES ('2510', 'Betriebsfremde Erträge (soweit nicht außerordentlich)');
+INSERT INTO gifi (accno,description) VALUES ('2520', 'Periodenfremde Erträge (soweit nicht außerordentlich)');
+INSERT INTO gifi (accno,description) VALUES ('2600', 'Erträge aus Beteiligungen');
+INSERT INTO gifi (accno,description) VALUES ('2617', 'Gewinne a.Ant. an nicht steuerbefr. inländischen KG §9Nr.2aGewStG');
+INSERT INTO gifi (accno,description) VALUES ('2618', 'Gewinnanteile aus Mitunternehmerschaften §9 GewStG');
+INSERT INTO gifi (accno,description) VALUES ('2619', 'Erträge aus Beteiligungen an verbundenen Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('2620', 'Ertr. a. and. Wertpap. u. Ausl. d. Finanzanlageverm.');
+INSERT INTO gifi (accno,description) VALUES ('2649', 'Ertr. a. and. Wertpap. u. Ausl. d. Fin.Anl.Verm. a. verb. U.');
+INSERT INTO gifi (accno,description) VALUES ('2650', 'Sonstige Zinsen und ähnliche Erträge');
+INSERT INTO gifi (accno,description) VALUES ('2657', 'Zinserträge §233a AO betriebliche Steuern');
+INSERT INTO gifi (accno,description) VALUES ('2658', 'Zinserträge §233a AO Körperschaftsteuer / Vermögensteuer');
+INSERT INTO gifi (accno,description) VALUES ('2659', 'Sonstige Zinsen u. ähnliche Erträge aus verb. Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('2660', 'Erträge aus Kursdifferenzen');
+INSERT INTO gifi (accno,description) VALUES ('2670', 'Diskonterträge');
+INSERT INTO gifi (accno,description) VALUES ('2679', 'Diskonterträge aus verbundenen Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('2680', 'Zinsähnliche Erträge');
+INSERT INTO gifi (accno,description) VALUES ('2689', 'Zinsähnliche Erträge aus verbundenen Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('2700', 'Sonstige Erträge');
+INSERT INTO gifi (accno,description) VALUES ('2705', 'Sonstige Erträge betrieblich und regelmäßig');
+INSERT INTO gifi (accno,description) VALUES ('2707', 'Sonstige Erträge betriebsfremd und regelmäßig');
+INSERT INTO gifi (accno,description) VALUES ('2709', 'Sonstige Erträge unregelmäßig');
+INSERT INTO gifi (accno,description) VALUES ('2710', 'Erträge aus Zuschreibungen des Anlagevermögens');
+INSERT INTO gifi (accno,description) VALUES ('2715', 'Erträge aus Zuschreibungen des Umlaufvermögens');
+INSERT INTO gifi (accno,description) VALUES ('2720', 'Ertr. a. Abgang v. Gegenst. d. Anlagevermögens');
+INSERT INTO gifi (accno,description) VALUES ('2725', 'Ertr. a. Abgang v. Gegenst. d. Umlaufv.s (außer Vorräte)');
+INSERT INTO gifi (accno,description) VALUES ('2730', 'Ertr. a. Herabs. d. Pauschalwertber. zu Forderungen');
+INSERT INTO gifi (accno,description) VALUES ('2731', 'Ertr. a. Herabs. d. Einzelwertber. zu Forderungen');
+INSERT INTO gifi (accno,description) VALUES ('2732', 'Erträge aus abgeschriebenen Forderungen');
+INSERT INTO gifi (accno,description) VALUES ('2735', 'Erträge aus der Auflösung von Rückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('2739', 'Erträge aus der Auflösung von Sonderpost. m. Rücklageant. (Ansparabschr.)');
+INSERT INTO gifi (accno,description) VALUES ('2740', 'Ertr. a. Aufl. v. Sonderp. m. Rückl.Ant. (steuerfr. Rückl.)');
+INSERT INTO gifi (accno,description) VALUES ('2741', 'Ertr. a. Aufl. v. Sonderp. m. Rückl.Ant. (Sonderabschr.)');
+INSERT INTO gifi (accno,description) VALUES ('2742', 'Versicherungsentschädigungen');
+INSERT INTO gifi (accno,description) VALUES ('2743', 'Investitionszuschüsse (steuerpflichtig)');
+INSERT INTO gifi (accno,description) VALUES ('2744', 'Investitionszulagen (steuerfrei)');
+INSERT INTO gifi (accno,description) VALUES ('2745', 'Erträge aus Kapitalherabsetzung');
+INSERT INTO gifi (accno,description) VALUES ('2750', 'Grundstückserträge');
+INSERT INTO gifi (accno,description) VALUES ('2780', 'Steuererstattung Vorjahre f. Steuern vom Eink. u. Ertrag');
+INSERT INTO gifi (accno,description) VALUES ('2785', 'Steuererstattung Vorjahre f. sonstige Steuern');
+INSERT INTO gifi (accno,description) VALUES ('2790', 'Erträge aus Verlustübernahme');
+INSERT INTO gifi (accno,description) VALUES ('2792', 'Erh. Gew. aufgrund einer Gewinngemeinschaft');
+INSERT INTO gifi (accno,description) VALUES ('2794', 'Erh. Gew. aufgrund eines Gew.- oder Teilgew.Abführ.Vertr.');
+INSERT INTO gifi (accno,description) VALUES ('2795', 'Entnahmen aus der Kapitalrücklage');
+INSERT INTO gifi (accno,description) VALUES ('2796', 'Entnahmen aus der gesetzlichen Rücklage');
+INSERT INTO gifi (accno,description) VALUES ('2797', 'Entnahmen aus satzungsgemäßen Rücklagen');
+INSERT INTO gifi (accno,description) VALUES ('2798', 'Entnahmen aus der Rücklage für eigene Anteile');
+INSERT INTO gifi (accno,description) VALUES ('2799', 'Entnahmen aus anderen Gewinnrücklagen');
+INSERT INTO gifi (accno,description) VALUES ('2860', 'Gewinnvortrag nach Verwendung');
+INSERT INTO gifi (accno,description) VALUES ('2862', 'Gewinnvortrag 50/45% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('2864', 'Gewinnvortrag 30% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('2866', 'Gewinnvortrag 0% Vorbelastung');
+INSERT INTO gifi (accno,description) VALUES ('2868', 'Verlustvortrag nach Verwendung');
+INSERT INTO gifi (accno,description) VALUES ('2869', 'Vorträge auf neue Rechnung (GuV)');
+INSERT INTO gifi (accno,description) VALUES ('2870', 'Ausschüttung');
+INSERT INTO gifi (accno,description) VALUES ('2890', 'Verrechneter kalkulatorischer Unternehmerlohn');
+INSERT INTO gifi (accno,description) VALUES ('2891', 'Verrechnete kalkulatorische Miete und Pacht');
+INSERT INTO gifi (accno,description) VALUES ('2892', 'Verrechnete kalkulatorische Zinsen');
+INSERT INTO gifi (accno,description) VALUES ('2893', 'Verrechnete kalkulatorische Abschreibung');
+INSERT INTO gifi (accno,description) VALUES ('2894', 'Verrechnete kalkulatorische Wagnisse');
+INSERT INTO gifi (accno,description) VALUES ('2895', 'Verrechneter kalkulatorischer Lohn für unentgeltliche Mitarbeiter');
+INSERT INTO gifi (accno,description) VALUES ('3000', 'Roh-, Hilfs- und Betriebsstoffe');
+INSERT INTO gifi (accno,description) VALUES ('3090', 'Energiestoffe (Fertigung)');
+INSERT INTO gifi (accno,description) VALUES ('3100', 'Fremdleistungen');
+INSERT INTO gifi (accno,description) VALUES ('3150', 'Leistungen von ausländischen Unternehmen (Nullregelung)');
+INSERT INTO gifi (accno,description) VALUES ('3200', 'Wareneingang');
+INSERT INTO gifi (accno,description) VALUES ('3300', 'Wareneingang, 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3340', 'Wareneingang, 15% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3400', 'Wareneingang, 15%+16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3410', 'Wareneingang, 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3420', 'Innergem. Erwerb, 7% VSt u. 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('3425', 'Innergem. Erwerb, 15%+16% VSt u. 15%+16% USt');
+INSERT INTO gifi (accno,description) VALUES ('3430', 'Innergem. Erwerb, ohne VSt-Abzug u. 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('3431', 'Innergem. Erwerb, 16% VSt u. 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('3433', 'Innergem. Erwerb, 15% VSt u. 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('3435', 'Innergem. Erwerb, ohne VSt-Abzug u. 15%+16% USt');
+INSERT INTO gifi (accno,description) VALUES ('3436', 'Innergem. Erwerb, ohne VSt-Abzug u. 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('3437', 'Innergem. Erwerb, ohne VSt-Abzug u. 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('3440', 'Innergem. Erw. v. Neufahrz. v. Lief. ohne USt-ID, 15%+16% USt');
+INSERT INTO gifi (accno,description) VALUES ('3441', 'Innergem. Erw. v. Neufahrz. v. Lief. ohne USt-ID, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('3442', 'Innergem. Erw. v. Neufahrz. v. Lief. ohne USt-ID, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('3500', 'Wareneingang, 5% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3530', 'Wareneingang, 9% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3540', 'Wareneingang, 9,5% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3550', 'Steuerfreier innergemeinschaftlicher Erwerb');
+INSERT INTO gifi (accno,description) VALUES ('3600', 'Nicht abziehbare Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3610', 'Nicht abziehbare Vorsteuer, 7%');
+INSERT INTO gifi (accno,description) VALUES ('3650', 'Nicht abziehbare Vorsteuer, 16%');
+INSERT INTO gifi (accno,description) VALUES ('3660', 'Nicht abziehbare Vorsteuer, 15%');
+INSERT INTO gifi (accno,description) VALUES ('3700', 'Nachlässe');
+INSERT INTO gifi (accno,description) VALUES ('3710', 'Nachlässe, 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3720', 'Nachlässe, 15%+16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3722', 'Nachlässe, 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3723', 'Nachlässe, 15% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3724', 'Nachlässe aus ig. Erwerb, 7% VSt und 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('3725', 'Nachlässe aus ig. Erwerb, 15%+16% VSt und 15%+16% USt');
+INSERT INTO gifi (accno,description) VALUES ('3726', 'Nachlässe aus ig. Erwerb, 16% VSt und 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('3727', 'Nachlässe aus ig. Erwerb, 15% VSt und 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('3730', 'Erhaltene Skonti');
+INSERT INTO gifi (accno,description) VALUES ('3731', 'Erhaltene Skonti, 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3735', 'Erhaltene Skonti, 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3736', 'Erhaltene Skonti, 15% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3740', 'Erhaltene Boni');
+INSERT INTO gifi (accno,description) VALUES ('3750', 'Erhaltene Boni, 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3760', 'Erhaltene Boni, 15%+16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3762', 'Erhaltene Boni, 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3764', 'Erhaltene Boni, 15% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3770', 'Erhaltene Rabatte');
+INSERT INTO gifi (accno,description) VALUES ('3780', 'Erhaltene Rabatte, 7% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3790', 'Erhaltene Rabatte, 15%+16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3792', 'Erhaltene Rabatte, 16% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3794', 'Erhaltene Rabatte, 15% Vorsteuer');
+INSERT INTO gifi (accno,description) VALUES ('3800', 'Anschaffungsnebenkosten');
+INSERT INTO gifi (accno,description) VALUES ('3830', 'Leergut');
+INSERT INTO gifi (accno,description) VALUES ('3850', 'Zölle und Einfuhrabgaben');
+INSERT INTO gifi (accno,description) VALUES ('3960', 'Bestandsv. Roh-, Hilfs- u. Betriebsstoffe / bezogene Waren');
+INSERT INTO gifi (accno,description) VALUES ('3970', 'Bestand Roh-, Hilfs- und Betriebsstoffe');
+INSERT INTO gifi (accno,description) VALUES ('3980', 'Bestand Waren');
+INSERT INTO gifi (accno,description) VALUES ('3990', 'Verrechnete Stoffkosten');
+INSERT INTO gifi (accno,description) VALUES ('4000', 'Material- und Stoffverbrauch');
+INSERT INTO gifi (accno,description) VALUES ('4100', 'Löhne und Gehälter');
+INSERT INTO gifi (accno,description) VALUES ('4110', 'Löhne');
+INSERT INTO gifi (accno,description) VALUES ('4120', 'Gehälter');
+INSERT INTO gifi (accno,description) VALUES ('4124', 'Geschäftsführergehälter der GmbH-Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('4125', 'Ehegattengehalt');
+INSERT INTO gifi (accno,description) VALUES ('4126', 'Tantiemen');
+INSERT INTO gifi (accno,description) VALUES ('4127', 'Geschäftsführergehälter');
+INSERT INTO gifi (accno,description) VALUES ('4128', 'Vergütungen an angestellte Mitunternehmer §15 EStG');
+INSERT INTO gifi (accno,description) VALUES ('4130', 'Gesetzliche soziale Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('4137', 'Gesetzliche soziale Aufw. für Mitunternehmer §15 EStG');
+INSERT INTO gifi (accno,description) VALUES ('4138', 'Beiträge zur Berufsgenossenschaft');
+INSERT INTO gifi (accno,description) VALUES ('4139', 'Ausgleichsabgabe i. S. d. Schwerbehindertengesetzes');
+INSERT INTO gifi (accno,description) VALUES ('4140', 'Freiw. soziale Aufwendungen (lohnsteuerfrei)');
+INSERT INTO gifi (accno,description) VALUES ('4145', 'Freiw. soziale Aufwendungen (lohnsteuerpflichtig)');
+INSERT INTO gifi (accno,description) VALUES ('4149', 'Pauschale Lohnsteuer auf s. Bezüge (z.B. Fahrtkostenzuschuß)');
+INSERT INTO gifi (accno,description) VALUES ('4150', 'Krankengeldzuschüsse');
+INSERT INTO gifi (accno,description) VALUES ('4160', 'Versorgungskassen');
+INSERT INTO gifi (accno,description) VALUES ('4165', 'Aufwendungen für die Altersversorgung');
+INSERT INTO gifi (accno,description) VALUES ('4167', 'Pauschale Lohnsteuer auf s. Bezüge (z.B. Direktversicherung)');
+INSERT INTO gifi (accno,description) VALUES ('4168', 'Aufw. f. die Altersversorgung f. Mitunternehmer §15 EStG');
+INSERT INTO gifi (accno,description) VALUES ('4169', 'Aufwendungen für Unterstützung');
+INSERT INTO gifi (accno,description) VALUES ('4170', 'Vermögenswirksame Leistungen');
+INSERT INTO gifi (accno,description) VALUES ('4175', 'Fahrtkostenerstattung - Wohnung / Arbeitsstätte');
+INSERT INTO gifi (accno,description) VALUES ('4180', 'Bedienungsgelder');
+INSERT INTO gifi (accno,description) VALUES ('4190', 'Aushilfslöhne');
+INSERT INTO gifi (accno,description) VALUES ('4199', 'Lohnsteuer für Aushilfen');
+INSERT INTO gifi (accno,description) VALUES ('4200', 'Raumkosten');
+INSERT INTO gifi (accno,description) VALUES ('4210', 'Miete');
+INSERT INTO gifi (accno,description) VALUES ('4218', 'Gewerbesteuerlich zu berücks. Miete §8 GewStG');
+INSERT INTO gifi (accno,description) VALUES ('4219', 'Vergütung an Mitu. f. mietw. Überl. v. Wirtschaftsg. §15EStG');
+INSERT INTO gifi (accno,description) VALUES ('4220', 'Pacht');
+INSERT INTO gifi (accno,description) VALUES ('4228', 'Gewerbesteuerlich zu berücks. Pacht §8 GewStG');
+INSERT INTO gifi (accno,description) VALUES ('4229', 'Vergütung an Mitu. f. pachtw. Überl. v. Wirtschaftsg.§15EStG');
+INSERT INTO gifi (accno,description) VALUES ('4230', 'Heizung');
+INSERT INTO gifi (accno,description) VALUES ('4240', 'Gas, Strom, Wasser (Verwaltung, Vertrieb)');
+INSERT INTO gifi (accno,description) VALUES ('4250', 'Reinigung');
+INSERT INTO gifi (accno,description) VALUES ('4260', 'Instandhaltung betrieblicher Räume');
+INSERT INTO gifi (accno,description) VALUES ('4270', 'Abgaben für betrieblich genutzten Grundbesitz');
+INSERT INTO gifi (accno,description) VALUES ('4280', 'Sonstige Raumkosten');
+INSERT INTO gifi (accno,description) VALUES ('4300', 'Nicht abziehb. VSt a. sonst. betriebl. Aufw./AfA');
+INSERT INTO gifi (accno,description) VALUES ('4301', 'Nicht abziehb. VSt, 7% a. sonst. betriebl. Aufw./AfA');
+INSERT INTO gifi (accno,description) VALUES ('4305', 'Nicht abziehb. VSt, 16% a. sonst. betriebl. Aufw./AfA');
+INSERT INTO gifi (accno,description) VALUES ('4306', 'Nicht abziehb. VSt, 15% a. sonst. betriebl. Aufw./AfA');
+INSERT INTO gifi (accno,description) VALUES ('4320', 'Gewerbesteuer (Vorauszahlung)');
+INSERT INTO gifi (accno,description) VALUES ('4330', 'Gewerbeertragsteuer');
+INSERT INTO gifi (accno,description) VALUES ('4335', 'Gewerbekapitalsteuer');
+INSERT INTO gifi (accno,description) VALUES ('4340', 'Sonstige Betriebsteuern');
+INSERT INTO gifi (accno,description) VALUES ('4350', 'Verbrauchsteuer');
+INSERT INTO gifi (accno,description) VALUES ('4360', 'Versicherungen');
+INSERT INTO gifi (accno,description) VALUES ('4370', 'Nettoprämie für Rückdeckung künftiger Versorgungsleistungen');
+INSERT INTO gifi (accno,description) VALUES ('4380', 'Beiträge');
+INSERT INTO gifi (accno,description) VALUES ('4390', 'Sonstige Abgaben');
+INSERT INTO gifi (accno,description) VALUES ('4396', 'Steuerlich abzugsfähige Verspätungszuschläge und Zwangsgelder');
+INSERT INTO gifi (accno,description) VALUES ('4397', 'Steuerlich nicht abzugsfähige Verspätungszuschläge und Zwangsgelder');
+INSERT INTO gifi (accno,description) VALUES ('4400', 'Besondere Kosten (zur freien Verfügung)');
+INSERT INTO gifi (accno,description) VALUES ('4500', 'Fahrzeugkosten');
+INSERT INTO gifi (accno,description) VALUES ('4510', 'Kfz-Steuern');
+INSERT INTO gifi (accno,description) VALUES ('4520', 'Kfz-Versicherungen');
+INSERT INTO gifi (accno,description) VALUES ('4530', 'Laufende Kfz-Betriebskosten');
+INSERT INTO gifi (accno,description) VALUES ('4540', 'Kfz-Reparaturen');
+INSERT INTO gifi (accno,description) VALUES ('4550', 'Garagenmieten');
+INSERT INTO gifi (accno,description) VALUES ('4570', 'Fremdfahrzeuge');
+INSERT INTO gifi (accno,description) VALUES ('4580', 'Sonstige Kfz-Kosten');
+INSERT INTO gifi (accno,description) VALUES ('4600', 'Werbe- und Reisekosten');
+INSERT INTO gifi (accno,description) VALUES ('4610', 'Werbekosten');
+INSERT INTO gifi (accno,description) VALUES ('4630', 'Geschenke bis DM 75,00');
+INSERT INTO gifi (accno,description) VALUES ('4635', 'Geschenke über DM 75,00');
+INSERT INTO gifi (accno,description) VALUES ('4638', 'Geschenke ausschließlich betrieblich genutzt');
+INSERT INTO gifi (accno,description) VALUES ('4640', 'Repräsentationskosten');
+INSERT INTO gifi (accno,description) VALUES ('4650', 'Bewirtungskosten');
+INSERT INTO gifi (accno,description) VALUES ('4653', 'Aufwerksamkeiten');
+INSERT INTO gifi (accno,description) VALUES ('4654', 'Nicht abzugsfähige Bewirtungskosten');
+INSERT INTO gifi (accno,description) VALUES ('4655', 'Nicht abzugsfähige Betriebsausgaben');
+INSERT INTO gifi (accno,description) VALUES ('4660', 'Reisekosten Arbeitnehmer');
+INSERT INTO gifi (accno,description) VALUES ('4666', 'Reisekost. Arbeitn., 12,3%/13,1% VSt Verpfl.Mehr- / Übern.Aufw.');
+INSERT INTO gifi (accno,description) VALUES ('4667', 'Reisekost. Arbeitn., 9,8%/10,5% VSt Gesamtpauschal.');
+INSERT INTO gifi (accno,description) VALUES ('4670', 'Reisekosten Unternehmer');
+INSERT INTO gifi (accno,description) VALUES ('4675', 'Reisekosten Unternehmer, 9,8/10,5% VSt sonst.Gesamtpauschal.');
+INSERT INTO gifi (accno,description) VALUES ('4676', 'Reisekost. Untern., 12,3%/13,1% VSt Verpfl.Mehr- / Übern.Aufw.');
+INSERT INTO gifi (accno,description) VALUES ('4677', 'Reisekosten Unternehmer, 9,8%/10,5% VSt Verpfl.Mehraufw. Gesamtpauschal.');
+INSERT INTO gifi (accno,description) VALUES ('4678', 'Km-Geld Erstattung, Unternehmer, 5,7%/6,1% VSt');
+INSERT INTO gifi (accno,description) VALUES ('4685', 'Km-Geld-Erstattung, Arbeitnehmer 8,2%/8,7% VSt');
+INSERT INTO gifi (accno,description) VALUES ('4700', 'Kosten der Warenabgabe');
+INSERT INTO gifi (accno,description) VALUES ('4710', 'Verpackungsmaterial');
+INSERT INTO gifi (accno,description) VALUES ('4730', 'Ausgangsfrachten');
+INSERT INTO gifi (accno,description) VALUES ('4750', 'Transportversicherungen');
+INSERT INTO gifi (accno,description) VALUES ('4760', 'Verkaufsprovisionen');
+INSERT INTO gifi (accno,description) VALUES ('4780', 'Fremdarbeiten');
+INSERT INTO gifi (accno,description) VALUES ('4790', 'Aufwand für Gewährleistungen');
+INSERT INTO gifi (accno,description) VALUES ('4800', 'Reparat. u. Inst. v. Maschinen u. technischen Anlagen');
+INSERT INTO gifi (accno,description) VALUES ('4805', 'Reparat. u. Inst. v. and. Anl. d. Betr.- u. Geschäftsausst.');
+INSERT INTO gifi (accno,description) VALUES ('4809', 'Sonstige Reparaturen und Instandhaltungen');
+INSERT INTO gifi (accno,description) VALUES ('4810', 'Mietleasing');
+INSERT INTO gifi (accno,description) VALUES ('4814', 'Gewerbesteuerl. zu berücksicht. Mietleasing §8 GewStG');
+INSERT INTO gifi (accno,description) VALUES ('4815', 'Kaufleasing');
+INSERT INTO gifi (accno,description) VALUES ('4820', 'Abschr. a. Aufw. f.d. Ingangs. u. Erw. des Geschäftsbetr.');
+INSERT INTO gifi (accno,description) VALUES ('4822', 'Abschr. a. immaterielle Vermögensgegenstände');
+INSERT INTO gifi (accno,description) VALUES ('4824', 'Abschreibung auf den Geschäfts- oder Firmenwert');
+INSERT INTO gifi (accno,description) VALUES ('4826', 'Außerplanm. Abschr. a. immaterielle Vermögensgegenstände');
+INSERT INTO gifi (accno,description) VALUES ('4830', 'Abschreibungen auf Sachanlagen');
+INSERT INTO gifi (accno,description) VALUES ('4840', 'Außerplanm. Abschreibungen auf Sachanlagen');
+INSERT INTO gifi (accno,description) VALUES ('4850', 'Abschr. a. Sachanl. aufgrund steuerl. Sondervorschriften');
+INSERT INTO gifi (accno,description) VALUES ('4855', 'Sofortabschreibung geringwertiger Wirtschaftsgüter');
+INSERT INTO gifi (accno,description) VALUES ('4860', 'Abschreibung auf aktivierte, geringwertige Wirtschaftsgüter');
+INSERT INTO gifi (accno,description) VALUES ('4865', 'Außerplanmäßige Abschr. a. aktivierte GWG');
+INSERT INTO gifi (accno,description) VALUES ('4870', 'Abschreibungen auf Finanzanlagen');
+INSERT INTO gifi (accno,description) VALUES ('4872', 'Abschr. aufgrund v. Verlustant. an Mitunt. §8 GewStG');
+INSERT INTO gifi (accno,description) VALUES ('4874', 'Abschr. a. Finanzanl. aufgrund steuerl. Sondervorschriften');
+INSERT INTO gifi (accno,description) VALUES ('4875', 'Abschreibungen auf Wertpapiere des Umlaufvermögens');
+INSERT INTO gifi (accno,description) VALUES ('4879', 'Vorwegn. künft. Wertschw. bei Wertpapieren des Umlaufv.');
+INSERT INTO gifi (accno,description) VALUES ('4880', 'Abschr. a. Umlaufv. ohne Wertpapiere (soweit unübl. Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('4882', 'Abschr. a. Umlaufv. steuerrechtl. bedingt (unübl. Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('4885', 'Vorwegn. künft. Wertschw. Uml.V. auß. Vorr./Wertp. d. Uml.V.');
+INSERT INTO gifi (accno,description) VALUES ('4886', 'Abschr. a. Uml.V. auß. Vorr./Wertp. d. Uml.V. (übl. Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('4887', 'Abschr. a. Umlaufv., steuerrechtlich bedingt (übl. Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('4890', 'Vorwegn. künftiger Wertschw. im Umlaufv. (unübl. Höhe)');
+INSERT INTO gifi (accno,description) VALUES ('4900', 'Sonstige betriebliche Aufwendungen');
+INSERT INTO gifi (accno,description) VALUES ('4905', 'Sonstige Aufwendungen betrieblich und regelmäßig');
+INSERT INTO gifi (accno,description) VALUES ('4910', 'Porto');
+INSERT INTO gifi (accno,description) VALUES ('4920', 'Telefon');
+INSERT INTO gifi (accno,description) VALUES ('4925', 'Telefax, Fernschreiber');
+INSERT INTO gifi (accno,description) VALUES ('4930', 'Bürobedarf');
+INSERT INTO gifi (accno,description) VALUES ('4940', 'Zeitschriften, Bücher');
+INSERT INTO gifi (accno,description) VALUES ('4945', 'Fortbildungskosten');
+INSERT INTO gifi (accno,description) VALUES ('4946', 'Freiwillige Sozialleistungen');
+INSERT INTO gifi (accno,description) VALUES ('4948', 'Vergütungen an freiberufliche Mitunternehmer §15 EStG');
+INSERT INTO gifi (accno,description) VALUES ('4950', 'Rechts- und Beratungskosten');
+INSERT INTO gifi (accno,description) VALUES ('4955', 'Buchführungskosten');
+INSERT INTO gifi (accno,description) VALUES ('4957', 'Abschluß- und Prüfungskosten');
+INSERT INTO gifi (accno,description) VALUES ('4960', 'Mieten für Einrichtungen');
+INSERT INTO gifi (accno,description) VALUES ('4968', 'Gewerbest. zu berücks. Miete f. Einrichtungen §8 GewStG');
+INSERT INTO gifi (accno,description) VALUES ('4969', 'Aufwendungen für Abraum- und Abfallbeseitigung');
+INSERT INTO gifi (accno,description) VALUES ('4970', 'Nebenkosten des Geldverkehrs');
+INSERT INTO gifi (accno,description) VALUES ('4980', 'Betriebsbedarf');
+INSERT INTO gifi (accno,description) VALUES ('4985', 'Werkzeuge und Kleingeräte');
+INSERT INTO gifi (accno,description) VALUES ('4990', 'Kalkulatorischer Unternehmerlohn');
+INSERT INTO gifi (accno,description) VALUES ('4991', 'Kalkulatorische Miete und Pacht');
+INSERT INTO gifi (accno,description) VALUES ('4992', 'Kalkulatorischer Zinsen');
+INSERT INTO gifi (accno,description) VALUES ('4993', 'Kalkulatorische Abschreibungen');
+INSERT INTO gifi (accno,description) VALUES ('4994', 'Kalkulatorische Wagnisse');
+INSERT INTO gifi (accno,description) VALUES ('4995', 'Kalkulatorischer Lohn für unentgeltliche Mitarbeiter');
+INSERT INTO gifi (accno,description) VALUES ('4996', 'Herstellungskosten');
+INSERT INTO gifi (accno,description) VALUES ('4997', 'Verwaltungskosten');
+INSERT INTO gifi (accno,description) VALUES ('4998', 'Vertriebskosten');
+INSERT INTO gifi (accno,description) VALUES ('4999', 'Gegenkonto 49960-49980');
+INSERT INTO gifi (accno,description) VALUES ('7000', 'Unfertige Erzeugnisse, unfertige Leistungen (Bestand)');
+INSERT INTO gifi (accno,description) VALUES ('7050', 'Unfertige Erzeugnisse (Bestand)');
+INSERT INTO gifi (accno,description) VALUES ('7080', 'Unfertige Leistungen (Bestand)');
+INSERT INTO gifi (accno,description) VALUES ('7090', 'In Ausführung befindliche Bauaufträge');
+INSERT INTO gifi (accno,description) VALUES ('7095', 'In Arbeit befindliche Bauaufträge');
+INSERT INTO gifi (accno,description) VALUES ('7100', 'Fertige Erzeugnisse und Waren (Bestand)');
+INSERT INTO gifi (accno,description) VALUES ('7110', 'Fertige Erzeugnisse (Bestand)');
+INSERT INTO gifi (accno,description) VALUES ('7140', 'Fertige Waren (Bestand)');
+INSERT INTO gifi (accno,description) VALUES ('8000', 'Erlöse (zur freien Verfügung)');
+INSERT INTO gifi (accno,description) VALUES ('8100', 'Steuerfreie Umsätze o. VSt-Abzug §4 Nr.8 ff. UStG');
+INSERT INTO gifi (accno,description) VALUES ('8110', 'Sonstige steuerfreie o. VSt-Abzug Umsätze Inland');
+INSERT INTO gifi (accno,description) VALUES ('8120', 'Steuerfreie Umsätze m. VSt-Abzug §4 Nr.1a, 1c, 2-7 UStG');
+INSERT INTO gifi (accno,description) VALUES ('8125', 'Steuerfreie innergem. Lief. §4 Nr.1b UStG');
+INSERT INTO gifi (accno,description) VALUES ('8130', 'Lieferung d. ersten Abnehmers bei innergem. Dreiecksgesch. §25 b Abs. 2 UStG');
+INSERT INTO gifi (accno,description) VALUES ('8135', 'Steuerfreie ig. Lief. v. Neufahrz. an Abn. ohne UST-ID');
+INSERT INTO gifi (accno,description) VALUES ('8140', 'Steuerfreie Umsätze Offshore usw.');
+INSERT INTO gifi (accno,description) VALUES ('8150', 'Sonstige steuerfreie Umsätze Ausland (§4,2-7)');
+INSERT INTO gifi (accno,description) VALUES ('8195', 'Erlöse aus Geldspielautomaten, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8196', 'Erlöse aus Geldspielautomaten, 15%/16% USt');
+INSERT INTO gifi (accno,description) VALUES ('8197', 'Erlöse aus Geldspielautomaten, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8200', 'Erlöse');
+INSERT INTO gifi (accno,description) VALUES ('8300', 'Erlöse, 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('8310', 'Erlöse a.i.Inland steuerpfl. EU-Lieferungen, 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('8315', 'Erlöse a.i.Inland steuerpfl. EU-Lieferungen, 15%/16% USt');
+INSERT INTO gifi (accno,description) VALUES ('8320', 'Erlöse a.i. anderen EU-Land steuerpfl. Lieferungen');
+INSERT INTO gifi (accno,description) VALUES ('8330', 'Erlöse a.i.Inland steuerpfl. EU-Lieferungen, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8335', 'Erlöse a.i.Inland steuerpfl. EU-Lieferungen, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8339', 'Erlöse a.i. and. EU-Land steuerpfl. sonst. Leist. (Nullreg.)');
+INSERT INTO gifi (accno,description) VALUES ('8340', 'Erlöse, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8400', 'Erlöse, 15%/16% USt');
+INSERT INTO gifi (accno,description) VALUES ('8410', 'Erlöse, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8500', 'Provisionserlöse');
+INSERT INTO gifi (accno,description) VALUES ('8504', 'Provisionserlöse steuerfrei (§4 Nr.8ff UStG)');
+INSERT INTO gifi (accno,description) VALUES ('8505', 'Provisionserlöse steuerfrei (§4 Nr.5 UStG)');
+INSERT INTO gifi (accno,description) VALUES ('8506', 'Provisionserlöse, 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('8507', 'Provisionserlöse, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8508', 'Provisionserlöse, 15%/16% USt');
+INSERT INTO gifi (accno,description) VALUES ('8509', 'Provisionserlöse, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8520', 'Erlöse Abfallverwertung');
+INSERT INTO gifi (accno,description) VALUES ('8540', 'Erlöse Leergut');
+INSERT INTO gifi (accno,description) VALUES ('8590', 'Verrechnete Sachbezüge (keine Waren)');
+INSERT INTO gifi (accno,description) VALUES ('8591', 'Sachbezüge, 7% USt (Waren)');
+INSERT INTO gifi (accno,description) VALUES ('8595', 'Sachbezüge, 15%/16% USt (Waren)');
+INSERT INTO gifi (accno,description) VALUES ('8596', 'Sachbezüge, 16% USt (Waren)');
+INSERT INTO gifi (accno,description) VALUES ('8597', 'Sachbezüge, 15% USt (Waren)');
+INSERT INTO gifi (accno,description) VALUES ('8600', 'Sonstige Erlöse betrieblich und regelmäßig');
+INSERT INTO gifi (accno,description) VALUES ('8610', 'Verrechnete sonstige Sachbezüge');
+INSERT INTO gifi (accno,description) VALUES ('8611', 'Verrechnete sonstige Sachbezüge 15%/16% USt (z.B. Kfz. Gestellung)');
+INSERT INTO gifi (accno,description) VALUES ('8612', 'Verrechnete sonstige Sachbezüge 16% USt (z.B. Kfz. Gestellung)');
+INSERT INTO gifi (accno,description) VALUES ('8613', 'Verrechnete sonstige Sachbezüge 15% USt (z.B. Kfz. Gestellung)');
+INSERT INTO gifi (accno,description) VALUES ('8614', 'Verrechnete sonstige Sachbezüge, ohne Umsatzsteuer');
+INSERT INTO gifi (accno,description) VALUES ('8625', 'Sonstige Erlöse betrieblich und regelmäßig, steuerfrei');
+INSERT INTO gifi (accno,description) VALUES ('8630', 'Sonstige Erlöse betrieblich und regelmäßig, 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('8640', 'Sonstige Erlöse betrieblich und regelmäßig, 15%/16% USt');
+INSERT INTO gifi (accno,description) VALUES ('8645', 'Sonstige Erlöse betrieblich und regelmäßig, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8647', 'Sonstige Erlöse betrieblich und regelmäßig, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8650', 'Erlöse Zinsen und Diskontspesen');
+INSERT INTO gifi (accno,description) VALUES ('8660', 'Erlöse Zinsen und Diskontspesen aus verbundenen Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('8700', 'Erlösschmälerungen');
+INSERT INTO gifi (accno,description) VALUES ('8705', 'Erlösschmälerungen aus steuerfreien Umsätzen §4 Nr. 1a UStG');
+INSERT INTO gifi (accno,description) VALUES ('8710', 'Erlösschmälerungen, 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('8720', 'Erlösschmälerungen, 15%/16% USt');
+INSERT INTO gifi (accno,description) VALUES ('8722', 'Erlösschmälerungen, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8723', 'Erlösschmälerungen, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8724', 'Erlösschmälerungen aus steuerfreien innergm. Lieferungen');
+INSERT INTO gifi (accno,description) VALUES ('8725', 'Erlösschmäl. a. im Inland steuerpfl. EU-Lieferungen, 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('8726', 'Erlösschmäl. a. im Inland steuerpfl. EU-Lieferungen, 15%/16% USt');
+INSERT INTO gifi (accno,description) VALUES ('8727', 'Erlösschmäl. a. im anderen EU-Land steuerpfl. Lief.');
+INSERT INTO gifi (accno,description) VALUES ('8728', 'Erlösschmäl. a. im Inland steuerpfl. EU-Lieferungen, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8729', 'Erlösschmäl. a. im Inland steuerpfl. EU-Lieferungen, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8730', 'Gewährte Skonti');
+INSERT INTO gifi (accno,description) VALUES ('8731', 'Gewährte Skonti, 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('8735', 'Gewährte Skonti, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8736', 'Gewährte Skonti, 15% USt');
+INSERT INTO gifi (accno,description) VALUES ('8740', 'Gewährte Boni');
+INSERT INTO gifi (accno,description) VALUES ('8750', 'Gewährte Boni, 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('8760', 'Gewährte Boni, 15%/16% USt');
+INSERT INTO gifi (accno,description) VALUES ('8762', 'Gewährte Boni, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8764', 'Gewährte Boni, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8770', 'Gewährte Rabatte');
+INSERT INTO gifi (accno,description) VALUES ('8780', 'Gewährte Rabatte, 7% USt');
+INSERT INTO gifi (accno,description) VALUES ('8790', 'Gewährte Rabatte, 15%/16% USt');
+INSERT INTO gifi (accno,description) VALUES ('8792', 'Gewährte Rabatte, 16% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8794', 'Gewährte Rabatte, 15% Ust');
+INSERT INTO gifi (accno,description) VALUES ('8800', 'Erlöse aus Anlagenverkäufen');
+INSERT INTO gifi (accno,description) VALUES ('8801', 'Erlöse aus Anlagenverkäufen 15%/16% USt (bei Buchverlust)');
+INSERT INTO gifi (accno,description) VALUES ('8810', 'Erlöse aus Anlagenverkäufen 16% USt (bei Buchverlust)');
+INSERT INTO gifi (accno,description) VALUES ('8815', 'Erlöse aus Anlagenverkäufen 15% USt (bei Buchverlust)');
+INSERT INTO gifi (accno,description) VALUES ('8820', 'Erlöse aus Anlagenverkäufen 15%/16% USt (bei Buchgewinn)');
+INSERT INTO gifi (accno,description) VALUES ('8829', 'Erlöse aus Anlagenverkäufen (bei Buchgewinn)');
+INSERT INTO gifi (accno,description) VALUES ('8830', 'Erlöse aus Anlagenverkäufen 16% USt (bei Buchgewinn)');
+INSERT INTO gifi (accno,description) VALUES ('8835', 'Erlöse aus Anlagenverkäufen 15% USt (bei Buchgewinn)');
+INSERT INTO gifi (accno,description) VALUES ('8840', 'Erträge aus Kursdifferenzen');
+INSERT INTO gifi (accno,description) VALUES ('8900', 'Eigenverbrauch');
+INSERT INTO gifi (accno,description) VALUES ('8905', 'Entnahme Gegenstände ohne USt');
+INSERT INTO gifi (accno,description) VALUES ('8908', 'Entnahme von Gegenstände, 16% USt §1 Abs.1 Nr.2a UStG');
+INSERT INTO gifi (accno,description) VALUES ('8909', 'Entnahme von Gegenstände, 15% USt §1 Abs.1 Nr.2a UStG');
+INSERT INTO gifi (accno,description) VALUES ('8910', 'Entnahme von Gegenstände, 15%/16% USt §1 Abs.1 Nr.2a UStG');
+INSERT INTO gifi (accno,description) VALUES ('8915', 'Entnahme von Gegenstände, 7% USt §1 Abs.1 Nr.2a UStG');
+INSERT INTO gifi (accno,description) VALUES ('8920', 'Entnahme v. sonst. Leist., 15%/16% USt §1 A.1 Nr.2b UStG');
+INSERT INTO gifi (accno,description) VALUES ('8930', 'Entnahme v. sonst. Leist., 7% USt §1 A.1 Nr.2b UStG');
+INSERT INTO gifi (accno,description) VALUES ('8937', 'Entnahme v. sonst. Leist., 16% USt §1 A.1 Nr.2b UStG');
+INSERT INTO gifi (accno,description) VALUES ('8938', 'Entnahme v. sonst. Leist., 15% USt §1 A.1 Nr.2b UStG');
+INSERT INTO gifi (accno,description) VALUES ('8939', 'Entnahme v. sonst. Leist., ohne USt §1 A.1 Nr.2b UStG');
+INSERT INTO gifi (accno,description) VALUES ('8940', 'Eigenverbr., 15%/16% Ust §4 A.1 Nr.5 1-7, A.7 EStG');
+INSERT INTO gifi (accno,description) VALUES ('8941', 'Eigenverbr., 7% Ust §4 A.1 Nr.5 1-7, A.7 EStG');
+INSERT INTO gifi (accno,description) VALUES ('8942', 'Eigenverbr., 16% Ust §4 A.1 Nr.5 1-7, A.7 EStG');
+INSERT INTO gifi (accno,description) VALUES ('8943', 'Eigenverbr., 15% Ust §4 A.1 Nr.5 1-7, A.7 EStG');
+INSERT INTO gifi (accno,description) VALUES ('8944', 'Eigenverbr., ohne Ust §4 A.1 Nr.5 1-7, A.7 EStG');
+INSERT INTO gifi (accno,description) VALUES ('8945', 'Unentgeltl. Leist. v. Ges. an Ges., 15%/16% USt §1A.1 Nr.3 UStG');
+INSERT INTO gifi (accno,description) VALUES ('8946', 'Unentgeltl. Leist. v. Ges. an Ges., 7% USt §1A.1 Nr.3 UStG');
+INSERT INTO gifi (accno,description) VALUES ('8947', 'Unentgeltl. Leist. v. Ges. an Ges., 16% USt §1A.1 Nr.3 UStG');
+INSERT INTO gifi (accno,description) VALUES ('8948', 'Unentgeltl. Leist. v. Ges. an Ges., 15% USt §1A.1 Nr.3 UStG');
+INSERT INTO gifi (accno,description) VALUES ('8949', 'Unentgeltl. Leist. v. Ges. an Ges., ohne USt §1A.1 Nr.3 UStG');
+INSERT INTO gifi (accno,description) VALUES ('8950', 'Nicht steuerbare Umsätze');
+INSERT INTO gifi (accno,description) VALUES ('8955', 'Umsatzsteuervergütungen');
+INSERT INTO gifi (accno,description) VALUES ('8960', 'Bestandsveränd. - unfertige Erzeugnisse');
+INSERT INTO gifi (accno,description) VALUES ('8970', 'Bestandsveränd. - unfertige Leistungen');
+INSERT INTO gifi (accno,description) VALUES ('8975', 'Bestandsveränd. - in Ausführung befindliche Bauaufträge');
+INSERT INTO gifi (accno,description) VALUES ('8977', 'Bestandsveränd. - in Arbeit befindliche Aufträge');
+INSERT INTO gifi (accno,description) VALUES ('8980', 'Bestandsveränd. - fertige Erzeugnisse');
+INSERT INTO gifi (accno,description) VALUES ('8990', 'Bestandsveränd. - andere aktivierte Eigenleistungen');
+INSERT INTO gifi (accno,description) VALUES ('9000', 'Saldenvorträge Sachkonten');
+INSERT INTO gifi (accno,description) VALUES ('9008', 'Saldenvorträge Debitoren');
+INSERT INTO gifi (accno,description) VALUES ('9009', 'Saldenvorträge Kreditoren');
+INSERT INTO gifi (accno,description) VALUES ('9060', 'Offene Posten aus 1990');
+INSERT INTO gifi (accno,description) VALUES ('9085', 'Offene Posten aus 1985');
+INSERT INTO gifi (accno,description) VALUES ('9086', 'Offene Posten aus 1986');
+INSERT INTO gifi (accno,description) VALUES ('9087', 'Offene Posten aus 1987');
+INSERT INTO gifi (accno,description) VALUES ('9088', 'Offene Posten aus 1988');
+INSERT INTO gifi (accno,description) VALUES ('9089', 'Offene Posten aus 1989');
+INSERT INTO gifi (accno,description) VALUES ('9090', 'Summenvortragskonto');
+INSERT INTO gifi (accno,description) VALUES ('9091', 'Offene Posten aus 1991');
+INSERT INTO gifi (accno,description) VALUES ('9092', 'Offene Posten aus 1992');
+INSERT INTO gifi (accno,description) VALUES ('9093', 'Offene Posten aus 1993');
+INSERT INTO gifi (accno,description) VALUES ('9094', 'Offene Posten aus 1994');
+INSERT INTO gifi (accno,description) VALUES ('9095', 'Offene Posten aus 1995');
+INSERT INTO gifi (accno,description) VALUES ('9096', 'Offene Posten aus 1996');
+INSERT INTO gifi (accno,description) VALUES ('9097', 'Offene Posten aus 1997');
+INSERT INTO gifi (accno,description) VALUES ('9098', 'Offene Posten aus 1998');
+INSERT INTO gifi (accno,description) VALUES ('9100', 'Saldovortragskonto der Statistikkonten');
+INSERT INTO gifi (accno,description) VALUES ('9101', 'Verkaufstage');
+INSERT INTO gifi (accno,description) VALUES ('9102', 'Anzahl der Barkunden');
+INSERT INTO gifi (accno,description) VALUES ('9103', 'Beschäftigte Personen');
+INSERT INTO gifi (accno,description) VALUES ('9104', 'Unbezahlte Personen');
+INSERT INTO gifi (accno,description) VALUES ('9105', 'Verkaufskräfte');
+INSERT INTO gifi (accno,description) VALUES ('9106', 'Geschäftsraum qm');
+INSERT INTO gifi (accno,description) VALUES ('9107', 'Verkaufsraum qm');
+INSERT INTO gifi (accno,description) VALUES ('9108', 'Veränderungsrate positiv');
+INSERT INTO gifi (accno,description) VALUES ('9109', 'Veränderungsrate negativ');
+INSERT INTO gifi (accno,description) VALUES ('9110', 'Plan-WE (in Prozent)');
+INSERT INTO gifi (accno,description) VALUES ('9120', 'Erweiterungsinvestitionen');
+INSERT INTO gifi (accno,description) VALUES ('9135', 'Auftragseingang im Geschäftsjahr');
+INSERT INTO gifi (accno,description) VALUES ('9140', 'Auftragsbestand');
+INSERT INTO gifi (accno,description) VALUES ('9190', 'Gegenkonto für statistische Mengeneinheiten Konten 91010-91190');
+INSERT INTO gifi (accno,description) VALUES ('9199', 'Gegenkonto zu 91200, 91350-91400');
+INSERT INTO gifi (accno,description) VALUES ('9200', 'Beschäftigte Personen');
+INSERT INTO gifi (accno,description) VALUES ('9209', 'Gegenkonto zu 92000');
+INSERT INTO gifi (accno,description) VALUES ('9210', 'Produktive Löhne');
+INSERT INTO gifi (accno,description) VALUES ('9219', 'Gegenkonto zu 92100');
+INSERT INTO gifi (accno,description) VALUES ('9230', 'Baukostenzuschüsse');
+INSERT INTO gifi (accno,description) VALUES ('9232', 'Investitionszulagen');
+INSERT INTO gifi (accno,description) VALUES ('9234', 'Investitionszuschüsse');
+INSERT INTO gifi (accno,description) VALUES ('9239', 'Gegenkonto zu 92300-92380');
+INSERT INTO gifi (accno,description) VALUES ('9240', 'Investitionsverbindlichkeiten bei den Leistungsverbindlichkeiten');
+INSERT INTO gifi (accno,description) VALUES ('9244', 'Gegenkonto zu 92400');
+INSERT INTO gifi (accno,description) VALUES ('9245', 'Forderungen aus Anlagenverkäufen bei den sonstigen Vermögensgegenst.');
+INSERT INTO gifi (accno,description) VALUES ('9249', 'Gegenkonto zu 92450');
+INSERT INTO gifi (accno,description) VALUES ('9250', 'Eigenkapitalersetzende Gesellschafterdarlehen');
+INSERT INTO gifi (accno,description) VALUES ('9255', 'Ungesicherte Gesellschafterdarlehen mit Restlaufzeit > 5 Jahre');
+INSERT INTO gifi (accno,description) VALUES ('9259', 'Gegenkonto zu 92500-92580');
+INSERT INTO gifi (accno,description) VALUES ('9260', 'Kurzfristige Rückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('9262', 'Mittelfristige Rückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('9264', 'Langfristige Rückstellungen');
+INSERT INTO gifi (accno,description) VALUES ('9269', 'Gegenkonto zu 92600-92680');
+INSERT INTO gifi (accno,description) VALUES ('9270', 'Gegenkonto zu 92710-92780');
+INSERT INTO gifi (accno,description) VALUES ('9271', 'Verb. a. d. Begebung u. Übertragung v. Wechseln');
+INSERT INTO gifi (accno,description) VALUES ('9272', 'Verb. a. d. Begebung u. Übertr. v. Wechseln gg. verb. U.');
+INSERT INTO gifi (accno,description) VALUES ('9273', 'Verb. a. Bürgsch., Wechsel- u. Scheckbürgsch.');
+INSERT INTO gifi (accno,description) VALUES ('9274', 'Verb. a. Bürgsch., Wechsel- u. Scheckbürgsch. gg. verb. U.');
+INSERT INTO gifi (accno,description) VALUES ('9275', 'Verb. aus Gewährleistungsverträgen');
+INSERT INTO gifi (accno,description) VALUES ('9276', 'Verb. aus Gewährleistungsverträgen gg. verbund. Untern.');
+INSERT INTO gifi (accno,description) VALUES ('9277', 'Haftung a. d. Best. von Sicherheiten für fremde Verbindl.');
+INSERT INTO gifi (accno,description) VALUES ('9278', 'Haftung a.d. Best. v. Sicherh. f. fr. Verbindl. gg. verb. U.');
+INSERT INTO gifi (accno,description) VALUES ('9280', 'Gegenkonto zu 92810-92840');
+INSERT INTO gifi (accno,description) VALUES ('9281', 'Verpflichtungen aus Miet- und Leasingverträgen');
+INSERT INTO gifi (accno,description) VALUES ('9282', 'Verpflichtungen aus Miet- und Leasingverträgen gg. verb. Unternehm.');
+INSERT INTO gifi (accno,description) VALUES ('9283', 'Andere Verpflichtungen gem. §285 Nr.3 HGB');
+INSERT INTO gifi (accno,description) VALUES ('9284', 'Andere Verpflichtungen gem. §285 Nr.3 HGB gg. verb. Unternehmen');
+INSERT INTO gifi (accno,description) VALUES ('9410', 'Aussteh. Einl. §26 A.3 DMBilG nicht eingef. (Aktivausw.)');
+INSERT INTO gifi (accno,description) VALUES ('9411', 'Aussteh. Einl. §26 A.3 DMBilG eingef. (Aktivausweis)');
+INSERT INTO gifi (accno,description) VALUES ('9413', 'Aufw. f. Ingangs. u. Erw. d. Gesch.Betr. §31A.1 Nr.2 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9415', 'Nichtentgeltl. erw. immat. Verm.Gegenst. §31A.1 Nr.1 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9416', 'Nutzungsrechte gem. § 9 Abs.3 Satz 2 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9420', 'Ford. gg. verb. Untern. a. Ausgleichsverb. gem. §25 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9421', 'Ford. gg. verb. U. a. Ausgl.Verb. §25 DMBilG Restl. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('9422', 'Ford. gg. verb. U. a. Ausgl.Verb. §25 DMBilG Restl. gr. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('9426', 'Eingeforderte Einlagen §26 Abs. 3 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9427', 'Ausgleichsforderungen §24 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9428', 'Ausgleichsford. §24 DMBilG - Restlaufz. bis 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('9429', 'Ausgleichsford. §24 DMBilG - Restlaufz. größer 1 Jahr');
+INSERT INTO gifi (accno,description) VALUES ('9430', 'Ford. nach dem VermG §7 Abs. 6 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9431', 'Ford. nach dem VermG §7 A.6 DMBilG - Restl. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('9432', 'Ford. nach dem VermG §7 A.6 DMBilG - Restl. gr. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('9433', 'Vermögensvorteile §31 Abs.1 Nr. 3 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9434', 'Kapitalentwertungskonto');
+INSERT INTO gifi (accno,description) VALUES ('9435', 'Kapitalentwertungskonto §28 Abs.1 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9436', 'Kapitalentwertungskonto §26 Abs.4 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9438', 'Sonderverlustkonto aus Rückstellungen §17 Abs.4 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9440', 'Beteiligunsentwertungskonto §24 Abs.5 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9445', 'Vorläufige Gewinnrücklage §31 Abs.1 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9446', 'Sonderrücklage §7 Abs.6 Satz 2 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9447', 'Sonderrücklage §17 Abs.4 Satz 3 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9448', 'Sonderrücklage §24 Abs. 5 Satz 3 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9449', 'Sonderrücklage §27 Abs. 2 Satz 3 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9450', 'Rückst. f. Umweltbeeinträchtigung §17 A.2a DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9451', 'Nachrangiges Kapital §16 Abs. 3 Satz 2 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9453', 'Berichtig. v. Wertans. §36 DMBilG - Erhöhung d. Aktiva');
+INSERT INTO gifi (accno,description) VALUES ('9454', 'Berichtig. v. Wertans. §36 DMBilG - Verm. d. Aktivp.');
+INSERT INTO gifi (accno,description) VALUES ('9455', 'Berichtig. v. Wertans. §36 DMBilG - Erhöhung d. Passiva');
+INSERT INTO gifi (accno,description) VALUES ('9456', 'Berichtig. v. Wertans. §36 DMBilG - Verm. d. Passivp.');
+INSERT INTO gifi (accno,description) VALUES ('9457', 'Verb. gg. verb. Untern. a. Ausgleichsford. gem. §24 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9458', 'Verb. gg. verb. U. a. Ausgl.Ford. §24 DMBilG Restl. b. 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('9459', 'Verb. gg. verb. U. a. Ausgl.Ford. §24 DMBilG Restl. 1 b. 5 J');
+INSERT INTO gifi (accno,description) VALUES ('9460', 'Verb. gg. verb. U. a. Ausgl.Ford. §24 DMBilG Restl. gr. 5 J');
+INSERT INTO gifi (accno,description) VALUES ('9462', 'Verb. gg. verb. Untern. §26 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9463', 'Verb. gg. verb. Untern. §26 DMBilG - Restl. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('9464', 'Verb. gg. verb. Untern. §26 DMBilG - Restl. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('9465', 'Verb. gg. verb. Untern. §26 DMBilG - Restl. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('9467', 'Ausgleichsverbindlichkeiten §25 Abs.1 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9468', 'Ausgleichsverb. §25 Abs.1 DMBilG - Restlaufz. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('9469', 'Ausgleichsverb. §25 A.1 DMBilG - Restlaufz. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('9470', 'Ausgleichsverb. §25 A.1 DMBilG - Restlaufz. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('9472', 'Verb. nach dem VermG §7 Abs.6 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9473', 'Verb. nach dem VermG §7 A.6 DMBilG - Restl. bis 1 J.');
+INSERT INTO gifi (accno,description) VALUES ('9474', 'Verb. nach dem VermG §7 A.6 DMBilG - Restl. 1 bis 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('9475', 'Verb. nach dem VermG §7 A.6 DMBilG - Restl. größer 5 J.');
+INSERT INTO gifi (accno,description) VALUES ('9476', 'Verb. aus Rückzahlungsverpfl. 17 Abs.4a DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9477', 'Verb. a. Rückzahlg.Verpfl. - Restl. b. 1 J. §17 A.4a DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9478', 'Verb. a. Rückzahlg.Verpfl. - Restl. 1 b. 5 J. §17A.4a DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9479', 'Verb. a. Rückzahlg.Verpfl. - Restl. gr. 5 J. §17 A.4a DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9480', 'Auflösung Kapitalentwertungskonto §28 A.2 Satz 4 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9481', 'Entnahmen a. vorläufigen Gewinnrücklagen §31 A.6 DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9482', 'Entnahmen a. Sonderrückl. zum Ausgleich von Verlusten');
+INSERT INTO gifi (accno,description) VALUES ('9486', 'Abschreibungen auf Ausgleichsforderungen DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9487', 'Erträge aus der Auflösung von Rückstellungen DMBilG');
+INSERT INTO gifi (accno,description) VALUES ('9500', 'Anteil für Konto 09000-09090');
+INSERT INTO gifi (accno,description) VALUES ('9510', 'Anteil für Konto 09100-09190');
+INSERT INTO gifi (accno,description) VALUES ('9520', 'Anteil für Konto 09200-09290');
+INSERT INTO gifi (accno,description) VALUES ('9530', 'Anteil für Konto 08300-08390');
+INSERT INTO gifi (accno,description) VALUES ('9540', 'Anteil für Konto 08100-08190');
+INSERT INTO gifi (accno,description) VALUES ('9570', 'Anteil für Konto 08700-08790');
+INSERT INTO gifi (accno,description) VALUES ('9580', 'Anteil für Konto 08800-08890');
+INSERT INTO gifi (accno,description) VALUES ('9590', 'Anteil für Konto 08900-08990');
+INSERT INTO gifi (accno,description) VALUES ('9600', 'Name des Gesellschafters (Vollhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9610', 'Tätigkeitsvergütung (Vollhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9620', 'Tantieme (Vollhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9630', 'Darlehensverzinsung (Vollhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9640', 'Gebrauchsüberlassung (Vollhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9650', 'Sonstige Vergütungen (Vollhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9690', 'Restanteil (Vollhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9700', 'Name des Gesellschafters (Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9710', 'Tätigkeitsvergütung (Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9720', 'Tantieme (Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9730', 'Darlehensverzinsung (Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9740', 'Gebrauchsüberlassung (Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9750', 'Sonstige Vergütungen (Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9790', 'Restanteil (Teilhafter)');
+INSERT INTO gifi (accno,description) VALUES ('9890', 'Statistisches Konto für passive Lohnveredelung');
+INSERT INTO gifi (accno,description) VALUES ('9899', 'Gegenkonto zu 9890');
diff --git a/sql-ledger/sql/Italy-chart.sql b/sql-ledger/sql/Italy-chart.sql
new file mode 100644
index 0000000..0af8e9f
--- /dev/null
+++ b/sql-ledger/sql/Italy-chart.sql
@@ -0,0 +1,179 @@
+--
+-- Chart of Accounts for Italy
+--
+-- From: Luca Venturini <luca@yepa.com>
+-- 9 Oct 2001
+--
+-- ('2001101'5 Conto ('6470005' diventa tassa (negativa)
+-- ('2001102'5 IVA su acquisti diventa Iva su acq. (20%)
+-- ('2001102'5 Introdotto un conto per ogni aliquota IVA
+-- ('2001102'7 Modificato numero di conto per la Ritenuta d'acconto
+-- ('2001103'1 Inseriti Fornitore-test e Consulente-test
+-- ('2001111'5 Invertito i ruoli di ('6470005' e ('6470010' (erano sbagliati)
+-- ('2001111'5 Eliminata l'applicabilita' della RA al cliente test
+-- ('2001112'0 Aggiunto IC_expense al conto ('7005005' (mancava un conto di default per i servizi)
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2010000','COSTI DI RICERCA, DI SVILUPPO E DI PUBBLICITA\'','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2010005','Spese di ricerca e di sviluppo','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2010010','Spese di pubblicita\'','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2015000','DIRITTI DI BREV. IND. E DIRITTI DI UTILIZZ DELLE OPERE DELL\'INGEGNO','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2015005','Brevetti','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2020005','Concessioni, licenze e diritti simili','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2025005','Avviamento','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2245000','TERRENI E FABBRICATI','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2245010','Fabbricati civili','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2250000','IMPIANTI E MACCHINARI','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2250005','Impianti generici','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2255000','ATTREZZATURE INDUSTRIALI E COMMERCIALI','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2255005','Attrezzature','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2255010','Mobili','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2255015','Macchine d\'ufficio','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2255025','Autovetture','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3005000','RIMANENZE MATERIE PRIME, SUSSIDIARIE E DI CONSUMO','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3005005','Rimanenze materie prime','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3020000','RIMANENZE PRODOTTI FINITI E MERCI','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3020005','Rimanenze prodotti finiti','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4001000','CREDITI VERSO CL. PER FATT. EM. ESIGIBILI ENTRO L\'ESER. SUCC.','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4001001','Crediti verso clienti per fatture emesse','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4064000','CREDITI VERSO ALTRI - CREDITI D\'IMPOSTA','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4064005','IRPEF acconto','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4064020','IRPEG acconto','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4064800','Credito verso erario per IVA','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4400000','DISPONIBILITA\' LIQUIDE','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4480105','Banca ...c/c','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4480400','Assegni','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4480500','Cassa e valori','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5005000','CAPITALE','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5005005','Capitale sociale','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5005010','Versamenti in conto capitale','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5020000','RISERVA LEGALE','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5020005','Riserva legale','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5080000','UTILI (PERDITE) PORTATI A NUOVO','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5080005','Utili esercizi precedenti','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5080010','Perdite esercizi precedenti','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5090000','UTILE (PERDITA) DELL\'ESERCIZIO','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5090005','Utile dell\'esercizio','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5090010','Perdita dell\'esercizio','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6200000','TRATTAMENTO DI FINE RAPPORTO DI LAVORO SUBORDINATO','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6220005','Trattamento di fine rapporto di lavoro subordinato','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6220010','Anticipazioni erogate su trattamento di fine rapporto di lavoro subordinato','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6435000','DEBITI VERSO BANCHE ESIGIBILI ENTRO ES. SUCC.','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6435005','Banca di ... c/c','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6436000','DEBITI VERSO BANCHE ESIGIBILI OLTRE ES. SUCC.','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6436005','Mutuo banca di ...','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6450000','DEBITI VERSO FORNITORI FATT. RICEVUTE ESIGIBILI ENTRO ES. SUCC.','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6450001','Debiti verso fornitori per fatture ricevute','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6470000','DEBITI TRIBUTARI','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6470005','IRPEF dipendenti','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6470010','IRPEF terzi','A','','L','AP_tax:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6470015','IVA da versare','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6470020','IVA in sospeso','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6470025','IRPEG sul reddito d\'esercizio','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6470030','ILOR sul reddito d\'esercizio','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6470050','Imposta patrimoniale','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6475000','DEBITI VERSO ISTITUTI PREV. ESIGIBILI ENTRO ES. SUCC.','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6475005','INPS','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6475010','INAIL','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6475020','Servizio sanitario nazionale (S.S.N.)','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6475025','ENASARCO','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480000','ALTRI DEBITI - IVA C/ERARIO','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480003','IVA su acquisti (4%)','A','','L','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480004','IVA su acquisti (10%)','A','','L','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480005','IVA su acquisti (20%)','A','','L','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480006','IVA a credito su acquisti U.E.','A','','L','AP_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480010','IVA su fatture emesse','A','','L','AR_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480011','IVA a debito su acquisti U.E.','A','','L','AR_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480015','IVA su corrispettivi','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480020','IVA versata','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480025','IVA acconto','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480030','IVA a credito','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480035','IVA ulteriore detrazione','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480040','Crediti d\'imposta diversi','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480045','IVA pro-rata indetraibile','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480050','IVA da contabilità separata','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6480055','IVA c/riepilogativo','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6600000','RATEI E RISCONTI PASSIVI','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6690005','Ratei passivi','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('6692005','Risconti passivi','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7005000','COSTI PER MATERIE PRIME, SUSSIDIARIE, DI CONSUMO E DI MERCI','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7005005','Materie prime','A','','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7005015','Merci destinate alla rivendita','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7005020','Materiali di consumo destinati alla produzione','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7005030','Materiali di pulizia','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7005035','Combustibile per riscaldamento','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7005040','Cancelleria','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7005045','Materiale pubblicitario','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7005050','Carburanti e lubrificanti','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025000','SPESE DI GESTIONE','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025005','Energia elettrica','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025015','Spese telefoniche','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025025','Spese pubblicità/propaganda','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025030','Spese di assicurazione','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025040','Pulizia locali','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025055','Viaggi e soggiorni amministratori','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025060','Spese di rappresentanza per servizi interamente detraibili','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025065','Altre spese di rappresentanza','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7025100','Altri servizi','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7028000','CARBURANTI E LUBRIFICANTI PER AUTOTRAZIONE','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7028005','Carburanti e lubrificanti autovetture','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7028010','Carburanti e lubrificanti autocarri etc.','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7030000','COMPENSI PROFESSIONALI','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7030005','Consulenza fiscale e tributaria','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7030015','Consulenza legale','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7030030','Compenso amministratori','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7035000','COSTI PER GODIMENTO BENI DI TERZI','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7035005','Fitti passivi','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7035050','Canoni di leasing','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7040000','COSTI PER IL PERSONALE','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7040005','Salari e stipendi','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7040010','Oneri sociali INPS','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7040015','Oneri sociali INAIL','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7040020','Oneri sociali C.E.','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7043000','AMMORTAMENTI E SVALUTAZIONI','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7043005','Ammortamenti immobilizzazioni immateriali','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7043100','Ammortamenti immobilizzazioni materiali','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7056000','ONERI DIVERSI DI GESTIONE','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7056010','Imposta di registro, bolli ,CC.GG., etc.','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7056015','Imposta camerale','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7056025','Tributi locali diversi','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7056040','Tassa possesso autoveicoli','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7260000','INTERESSI E ONERI FINANZIARI','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7260020','Interessi passivi bancari','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7260025','Interessi passivi mutui','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7875000','IMPOSTE SUL REDDITO DELL\'ESERCIZIO','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7875005','IRPEG corrente','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7875020','IRPEG differita','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8005000','RICAVI DELLE VENDITE','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8005005','Ricavi cessione beni','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8015000','RICAVI DELLE PRESTAZIONI','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8015005','Ricavi per prestazioni a terzi','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8015015','Noleggio impianti e macchinari','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8041000','INCREMENTI IMMOBILIZZAZIONI IMMATERIALI','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8041005','Brevetti','A','','I','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8041010','Spese di costituzione società','A','','I','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8041020','Spese pubblicità e propaganda','A','','I','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8045000','ALTRI RICAVI E PROVENTI','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8045001','Cessione di materie prime, sussidiarie e semilavorati','A','','I','AR_amount');
+--
+-- foreign exchange gain / loss
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9990000','Foreign Exchange Gain','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('9990010','Foreign Exchange Loss','A','','E','');
+--
+-- insert taxes
+--
+--Ritenuta d'acconto
+INSERT INTO tax (chart_id, rate) VALUES ((SELECT id FROM chart WHERE accno = '6470010'), -0.2);
+--IVA Acquisti 4%
+INSERT INTO tax (chart_id, rate) VALUES ((SELECT id FROM chart WHERE accno = '6480003'), 0.04);
+--IVA Acquisti 10%
+INSERT INTO tax (chart_id, rate) VALUES ((SELECT id FROM chart WHERE accno = '6480004'), 0.1);
+--IVA Acquisti 20%
+INSERT INTO tax (chart_id, rate) VALUES ((SELECT id FROM chart WHERE accno = '6480005'), 0.2);
+--IVA Fatture Emesse
+INSERT INTO tax (chart_id, rate) VALUES ((SELECT id FROM chart WHERE accno = '6480010'), 0.2);
+--IVA su corrispettivi
+INSERT INTO tax (chart_id, rate) VALUES ((SELECT id FROM chart WHERE accno = '6480015'), 0.2);
+--
+-- update defaults
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '3020005'), income_accno_id = (select id from chart where accno = '8005005'), expense_accno_id = (select id from chart where accno = '7005005'), fxgain_accno_id = (select id from chart where accno = '9990000'), fxloss_accno_id = (select id from chart where accno = '9990010'), invnumber = '20010000', sonumber = '1000', ponumber = '1000', curr = 'EUR', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Oracle-indices.sql b/sql-ledger/sql/Oracle-indices.sql
new file mode 100644
index 0000000..e55915b
--- /dev/null
+++ b/sql-ledger/sql/Oracle-indices.sql
@@ -0,0 +1,57 @@
+create index acc_trans_trans_id_key on acc_trans (trans_id);
+create index acc_trans_chart_id_key on acc_trans (chart_id);
+create index acc_trans_transdate_key on acc_trans (transdate);
+create index acc_trans_source_key on acc_trans (source);
+create index ap_id_key on ap (id);
+create index ap_transdate_key on ap (transdate);
+create index ap_invnumber_key on ap (invnumber);
+create index ap_ordnumber_key on ap (ordnumber);
+create index ap_vendor_id_key on ap (vendor_id);
+create index ap_employee_id_key on ap (employee_id);
+create index ar_id_key on ar (id);
+create index ar_transdate_key on ar (transdate);
+create index ar_invnumber_key on ar (invnumber);
+create index ar_ordnumber_key on ar (ordnumber);
+create index ar_customer_id_key on ar (customer_id);
+create index ar_employee_id_key on ar (employee_id);
+create index assembly_id_key on assembly (id);
+create index chart_id_key on chart (id);
+create unique index chart_accno_key on chart (accno);
+create index chart_category_key on chart (category);
+create index chart_link_key on chart (link);
+create index chart_gifi_accno_key on chart (gifi_accno);
+create index customer_id_key on customer (id);
+create index customer_customer_id_key on customertax (customer_id);
+create index customer_customernumber_key on customer (customernumber);
+create index customer_name_key on customer (name);
+create index customer_contact_key on customer (contact);
+create index employee_id_key on employee (id);
+create unique index employee_login_key on employee (login);
+create index employee_name_key on employee (name);
+create index exchangerate_ct_key on exchangerate (curr, transdate);
+create unique index gifi_accno_key on gifi (accno);
+create index gl_id_key on gl (id);
+create index gl_transdate_key on gl (transdate);
+create index gl_reference_key on gl (reference);
+create index gl_description_key on gl (description);
+create index gl_employee_id_key on gl (employee_id);
+create index invoice_id_key on invoice (id);
+create index invoice_trans_id_key on invoice (trans_id);
+create index makemodel_parts_id_key on makemodel (parts_id);
+create index oe_id_key on oe (id);
+create index oe_transdate_key on oe (transdate);
+create index oe_ordnumber_key on oe (ordnumber);
+create index oe_employee_id_key on oe (employee_id);
+create index orderitems_trans_id_key on orderitems (trans_id);
+create index parts_id_key on parts (id);
+create index parts_partnumber_key on parts (partnumber);
+create index parts_description_key on parts (description);
+create index partstax_parts_id_key on partstax (parts_id);
+create index vendor_id_key on vendor (id);
+create index vendor_name_key on vendor (name);
+create index vendor_vendornumber_key on vendor (vendornumber);
+create index vendor_contact_key on vendor (contact);
+create index vendortax_vendor_id_key on vendortax (vendor_id);
+create index shipto_trans_id_key on shipto (trans_id);
+create index project_id_key on project (id);
+create index partsgroup_id_key on partsgroup (id);
diff --git a/sql-ledger/sql/Oracle-tables.sql b/sql-ledger/sql/Oracle-tables.sql
new file mode 100644
index 0000000..d2bf7c7
--- /dev/null
+++ b/sql-ledger/sql/Oracle-tables.sql
@@ -0,0 +1,388 @@
+-- Oracle-tables.sql
+-- Paulo Rodrigues: added functions and triggers, Oct. 31, 2001
+--
+-- Modified for use with SL 2.0 and Oracle 9i2, Dec 13, 2002
+--
+ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD';
+--
+CREATE SEQUENCE id START WITH 10000 INCREMENT BY 1 MAXVALUE 2147483647 MINVALUE 1 CACHE 2;
+SELECT ID.NEXTVAL FROM DUAL;
+--
+CREATE TABLE makemodel (
+ parts_id INTEGER,
+ name VARCHAR2(100)
+);
+--
+CREATE TABLE gl (
+ id INTEGER,
+ reference VARCHAR2(50),
+ description VARCHAR2(100),
+ transdate DATE DEFAULT SYSDATE,
+ employee_id INTEGER,
+ notes VARCHAR2(4000)
+);
+--
+CREATE TABLE chart (
+ id INTEGER,
+ accno VARCHAR2(20) NOT NULL,
+ description VARCHAR2(100),
+ charttype CHAR(1) DEFAULT 'A',
+ category CHAR(1),
+ link VARCHAR2(100),
+ gifi_accno VARCHAR2(20)
+);
+--
+CREATE TABLE gifi (
+ accno VARCHAR2(20),
+ description VARCHAR2(100)
+);
+--
+CREATE TABLE defaults (
+ inventory_accno_id INTEGER,
+ income_accno_id INTEGER,
+ expense_accno_id INTEGER,
+ fxgain_accno_id INTEGER,
+ fxloss_accno_id INTEGER,
+ invnumber VARCHAR2(30),
+ sonumber VARCHAR2(30),
+ yearend VARCHAR2(5),
+ weightunit VARCHAR2(5),
+ businessnumber VARCHAR2(30),
+ version VARCHAR2(8),
+ curr VARCHAR2(500),
+ closedto DATE,
+ revtrans CHAR(1) DEFAULT '0',
+ ponumber VARCHAR2(30)
+);
+INSERT INTO defaults (version) VALUES ('2.0.8');
+--
+CREATE TABLE acc_trans (
+ trans_id INTEGER,
+ chart_id INTEGER,
+ amount FLOAT,
+ transdate DATE DEFAULT SYSDATE,
+ source VARCHAR2(20),
+ cleared CHAR(1) DEFAULT '0',
+ fx_transaction CHAR(1) DEFAULT '0',
+ project_id INTEGER
+);
+--
+CREATE TABLE invoice (
+ id INTEGER,
+ trans_id INTEGER,
+ parts_id INTEGER,
+ description VARCHAR2(4000),
+ qty FLOAT,
+ allocated FLOAT,
+ sellprice FLOAT,
+ fxsellprice FLOAT,
+ discount FLOAT,
+ assemblyitem CHAR(1) DEFAULT '0',
+ unit VARCHAR2(5),
+ project_id INTEGER,
+ deliverydate DATE
+);
+--
+CREATE TABLE vendor (
+ id INTEGER,
+ name VARCHAR2(35),
+ addr1 VARCHAR2(35),
+ addr2 VARCHAR2(35),
+ addr3 VARCHAR2(35),
+ addr4 VARCHAR2(35),
+ contact VARCHAR2(35),
+ phone VARCHAR2(20),
+ fax VARCHAR2(20),
+ email VARCHAR2(50),
+ notes VARCHAR2(4000),
+ terms INTEGER DEFAULT 0,
+ taxincluded CHAR(1),
+ vendornumber VARCHAR2(40),
+ cc VARCHAR2(50),
+ bcc VARCHAR2(50)
+);
+--
+CREATE TABLE customer (
+ id INTEGER,
+ name VARCHAR2(35),
+ addr1 VARCHAR2(35),
+ addr2 VARCHAR2(35),
+ addr3 VARCHAR2(35),
+ addr4 VARCHAR2(35),
+ contact VARCHAR2(35),
+ phone VARCHAR2(20),
+ fax VARCHAR2(20),
+ email VARCHAR2(50),
+ notes VARCHAR2(4000),
+ discount FLOAT,
+ taxincluded CHAR(1),
+ creditlimit FLOAT,
+ terms INTEGER DEFAULT 0,
+ customernumber VARCHAR2(40),
+ cc VARCHAR2(50),
+ bcc VARCHAR2(50)
+);
+--
+CREATE TABLE parts (
+ id INTEGER,
+ partnumber VARCHAR2(30),
+ description VARCHAR2(4000),
+ unit VARCHAR2(5),
+ listprice FLOAT,
+ sellprice FLOAT,
+ lastcost FLOAT,
+ priceupdate DATE DEFAULT SYSDATE,
+ weight FLOAT,
+ onhand FLOAT DEFAULT 0,
+ notes VARCHAR2(4000),
+ makemodel CHAR(1) DEFAULT '0',
+ assembly CHAR(1) DEFAULT '0',
+ alternate CHAR(1) DEFAULT '0',
+ rop FLOAT,
+ inventory_accno_id INTEGER,
+ income_accno_id INTEGER,
+ expense_accno_id INTEGER,
+ bin VARCHAR2(20),
+ obsolete CHAR(1) DEFAULT '0',
+ bom CHAR(1) DEFAULT '0',
+ image VARCHAR2(100),
+ drawing VARCHAR2(100),
+ microfiche VARCHAR2(100),
+ partsgroup_id INTEGER
+);
+--
+CREATE TABLE assembly (
+ id INTEGER,
+ parts_id INTEGER,
+ qty FLOAT,
+ bom CHAR(1)
+);
+--
+CREATE TABLE ar (
+ id INTEGER,
+ invnumber VARCHAR2(30),
+ transdate DATE DEFAULT SYSDATE,
+ customer_id INTEGER,
+ taxincluded CHAR(1),
+ amount FLOAT,
+ netamount FLOAT,
+ paid FLOAT,
+ datepaid DATE,
+ duedate DATE,
+ invoice CHAR(1) DEFAULT '0',
+ shippingpoint VARCHAR2(100),
+ terms INTEGER DEFAULT 0,
+ notes VARCHAR2(4000),
+ curr CHAR(3),
+ ordnumber VARCHAR2(30),
+ employee_id INTEGER
+);
+--
+CREATE TABLE ap (
+ id INTEGER,
+ invnumber VARCHAR2(30),
+ transdate DATE DEFAULT SYSDATE,
+ vendor_id INTEGER,
+ taxincluded CHAR(1) DEFAULT '0',
+ amount FLOAT,
+ netamount FLOAT,
+ paid FLOAT,
+ datepaid DATE,
+ duedate DATE,
+ invoice CHAR(1) DEFAULT '0',
+ ordnumber VARCHAR2(30),
+ curr CHAR(3),
+ notes VARCHAR2(4000),
+ employee_id INTEGER
+);
+--
+CREATE TABLE partstax (
+ parts_id INTEGER,
+ chart_id INTEGER
+);
+--
+CREATE TABLE tax (
+ chart_id INTEGER,
+ rate FLOAT,
+ taxnumber VARCHAR2(30)
+);
+--
+CREATE TABLE customertax (
+ customer_id INTEGER,
+ chart_id INTEGER
+);
+--
+CREATE TABLE vendortax (
+ vendor_id INTEGER,
+ chart_id INTEGER
+);
+--
+CREATE TABLE oe (
+ id INTEGER,
+ ordnumber VARCHAR2(30),
+ transdate DATE DEFAULT SYSDATE,
+ vendor_id INTEGER,
+ customer_id INTEGER,
+ amount FLOAT,
+ netamount FLOAT,
+ reqdate DATE,
+ taxincluded CHAR(1),
+ shippingpoint VARCHAR2(100),
+ notes VARCHAR2(4000),
+ curr CHAR(3),
+ employee_id INTEGER,
+ closed CHAR(1) DEFAULT '0'
+);
+--
+CREATE TABLE orderitems (
+ trans_id INTEGER,
+ parts_id INTEGER,
+ description VARCHAR2(4000),
+ qty FLOAT,
+ sellprice FLOAT,
+ discount FLOAT,
+ unit VARCHAR2(5),
+ project_id INTEGER,
+ reqdate DATE
+);
+--
+CREATE TABLE exchangerate (
+ curr CHAR(3),
+ transdate DATE,
+ buy FLOAT,
+ sell FLOAT
+);
+--
+CREATE TABLE employee (
+ id INTEGER,
+ login VARCHAR2(20),
+ name VARCHAR2(35),
+ addr1 VARCHAR2(35),
+ addr2 VARCHAR2(35),
+ addr3 VARCHAR2(35),
+ addr4 VARCHAR2(35),
+ workphone VARCHAR2(20),
+ homephone VARCHAR2(20),
+ startdate DATE DEFAULT SYSDATE,
+ enddate DATE,
+ notes VARCHAR2(4000)
+);
+--
+CREATE TABLE shipto (
+ trans_id INTEGER,
+ shiptoname VARCHAR2(35),
+ shiptoaddr1 VARCHAR2(35),
+ shiptoaddr2 VARCHAR2(35),
+ shiptoaddr3 VARCHAR2(35),
+ shiptoaddr4 VARCHAR2(35),
+ shiptocontact VARCHAR2(35),
+ shiptophone VARCHAR2(20),
+ shiptofax VARCHAR2(20),
+ shiptoemail VARCHAR2(50)
+);
+--
+CREATE TABLE project (
+ id INTEGER,
+ projectnumber VARCHAR2(50),
+ description VARCHAR2(4000)
+);
+--
+CREATE TABLE partsgroup (
+ id INTEGER,
+ partsgroup VARCHAR2(100)
+);
+--
+-- functions
+--
+CREATE OR REPLACE FUNCTION current_date RETURN date AS
+BEGIN
+ return(sysdate);--
+END;;
+--
+-- triggers
+--
+CREATE OR REPLACE TRIGGER glid BEFORE INSERT ON gl FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER chartid BEFORE INSERT ON chart FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER invoiceid BEFORE INSERT ON invoice FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER vendorid BEFORE INSERT ON vendor FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER customerid BEFORE INSERT ON customer FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER partsid BEFORE INSERT ON parts FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER arid BEFORE INSERT ON ar FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER apid BEFORE INSERT ON ap FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER oeid BEFORE INSERT ON oe FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER employeeid BEFORE INSERT ON employee FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER projectid BEFORE INSERT ON project FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE OR REPLACE TRIGGER partsgroupid BEFORE INSERT ON partsgroup FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+
diff --git a/sql-ledger/sql/Oracle-upgrade-1.8.0-1.8.4.sql b/sql-ledger/sql/Oracle-upgrade-1.8.0-1.8.4.sql
new file mode 100644
index 0000000..a3293a6
--- /dev/null
+++ b/sql-ledger/sql/Oracle-upgrade-1.8.0-1.8.4.sql
@@ -0,0 +1,28 @@
+--
+ALTER TABLE chart ADD gifi_accno VARCHAR2(20);
+--
+CREATE TABLE gifi (
+ accno VARCHAR2(20),
+ description VARCHAR2(100)
+);
+--
+CREATE UNIQUE INDEX chart_accno_key ON chart (accno);
+--
+CREATE TABLE mtemp (
+ parts_id INTEGER,
+ name VARCHAR2(100)
+);
+INSERT INTO mtemp SELECT parts_id, name FROM makemodel;
+DROP TABLE makemodel;
+ALTER TABLE mtemp RENAME TO makemodel;
+--
+ALTER TABLE defaults ADD closedto DATE;
+ALTER TABLE defaults ADD revtrans CHAR(1);
+--
+ALTER TABLE ap ADD notes VARCHAR2(4000);
+--
+ALTER TABLE customer ADD businessnumber VARCHAR2(40);
+ALTER TABLE vendor ADD businessnumber VARCHAR2(40);
+--
+UPDATE defaults SET version = '1.8.4', revtrans = '0';
+--
diff --git a/sql-ledger/sql/Oracle-upgrade-1.8.4-1.8.5.sql b/sql-ledger/sql/Oracle-upgrade-1.8.4-1.8.5.sql
new file mode 100644
index 0000000..d228b9e
--- /dev/null
+++ b/sql-ledger/sql/Oracle-upgrade-1.8.4-1.8.5.sql
@@ -0,0 +1,77 @@
+--
+ALTER TABLE customer ADD (customernumber VARCHAR2(40));
+UPDATE customer SET customernumber = businessnumber;
+ALTER TABLE customer DROP COLUMN businessnumber;
+CREATE INDEX customer_customernumber_key ON customer (customernumber);
+--
+ALTER TABLE vendor ADD (vendornumber VARCHAR2(40));
+UPDATE vendor SET vendornumber = businessnumber;
+ALTER TABLE vendor DROP COLUMN businessnumber;
+CREATE INDEX vendor_vendornumber_key ON vendor (vendornumber);
+--
+CREATE TABLE employee (
+ id INTEGER,
+ login VARCHAR2(20),
+ name VARCHAR2(35),
+ addr1 VARCHAR2(35),
+ addr2 VARCHAR2(35),
+ addr3 VARCHAR2(35),
+ addr4 VARCHAR2(35),
+ workphone VARCHAR2(20),
+ homephone VARCHAR2(20),
+ startdate DATE DEFAULT SYSDATE,
+ enddate DATE,
+ notes VARCHAR2(4000)
+);
+--
+CREATE OR REPLACE TRIGGER employeeid BEFORE INSERT ON employee FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+CREATE INDEX employee_id_key ON employee (id);
+CREATE UNIQUE INDEX employee_login_key ON employee (login);
+CREATE INDEX employee_name_key ON employee (name);
+--
+ALTER TABLE gl ADD (employee_id INTEGER);
+CREATE INDEX gl_employee_id_key ON gl (employee_id);
+ALTER TABLE ar ADD (employee_id INTEGER);
+CREATE INDEX ar_employee_id_key ON ar (employee_id);
+ALTER TABLE ap ADD (employee_id INTEGER);
+CREATE INDEX ap_employee_id_key ON ap (employee_id);
+ALTER TABLE oe ADD (employee_id INTEGER);
+CREATE INDEX oe_employee_id_key ON oe (employee_id);
+--
+ALTER TABLE invoice ADD (unit VARCHAR2(5));
+ALTER TABLE orderitems ADD (unit VARCHAR2(5));
+--
+UPDATE chart SET gifi_accno = '' WHERE gifi_accno = NULL;
+ALTER TABLE chart RENAME TO chartold;
+CREATE TABLE chart (
+ id INTEGER,
+ accno VARCHAR2(20) NOT NULL,
+ description VARCHAR2(100),
+ charttype CHAR(1) DEFAULT 'A',
+ category CHAR(1),
+ link VARCHAR2(100),
+ gifi_accno VARCHAR2(20)
+);
+INSERT INTO chart (id, accno, description, charttype, category, link, gifi_accno) SELECT id, accno, description, charttype, category, link, gifi_accno from chartold;
+DROP TABLE chartold;
+CREATE INDEX chart_id_key ON chart (id);
+CREATE UNIQUE INDEX chart_accno_key ON chart (accno);
+CREATE INDEX chart_category_key ON chart (category);
+CREATE INDEX chart_link_key ON chart (link);
+CREATE INDEX chart_gifi_accno_key ON chart (gifi_accno);
+--
+ALTER TABLE parts MODIFY inventory_accno_id;
+--
+ALTER TABLE defaults ADD (sonumber VARCHAR2(30));
+UPDATE defaults SET sonumber = ordnumber;
+ALTER TABLE defaults DROP COLUMN ordnumber;
+ALTER TABLE defaults ADD (ponumber VARCHAR2(30));
+--
+UPDATE defaults SET version = '1.8.5';
+--
diff --git a/sql-ledger/sql/Oracle-upgrade-1.8.5-2.0.0.sql b/sql-ledger/sql/Oracle-upgrade-1.8.5-2.0.0.sql
new file mode 100644
index 0000000..2d2231b
--- /dev/null
+++ b/sql-ledger/sql/Oracle-upgrade-1.8.5-2.0.0.sql
@@ -0,0 +1,100 @@
+--
+alter table customer add (cc VARCHAR2(50));
+alter table customer add (bcc VARCHAR2(50));
+--
+alter table vendor add (cc VARCHAR2(50));
+alter table vendor add (bcc VARCHAR2(50));
+--
+create table shipto (
+ trans_id integer,
+ shiptoname varchar2(35),
+ shiptoaddr1 varchar2(35),
+ shiptoaddr2 varchar2(35),
+ shiptoaddr3 varchar2(35),
+ shiptoaddr4 varchar2(35),
+ shiptocontact varchar2(35),
+ shiptophone varchar2(20),
+ shiptofax varchar2(20),
+ shiptoemail VARCHAR2(50)
+);
+--
+insert into shipto (trans_id, shiptoname, shiptoaddr1, shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact, shiptophone, shiptofax, shiptoemail) select id, shiptoname, shiptoaddr1, shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact, shiptophone, shiptofax, shiptoemail from customer where shiptoname != '' or shiptoname is not null;
+--
+insert into shipto (trans_id, shiptoname, shiptoaddr1, shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact, shiptophone, shiptofax, shiptoemail) select distinct on (a.id) a.id, c.shiptoname, c.shiptoaddr1, c.shiptoaddr2, c.shiptoaddr3, c.shiptoaddr4, c.shiptocontact, c.shiptophone, c.shiptofax, c.shiptoemail from customer c, ar a where a.customer_id = c.id;
+--
+insert into shipto (trans_id, shiptoname, shiptoaddr1, shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact, shiptophone, shiptofax, shiptoemail) select distinct on (o.id) o.id, c.shiptoname, c.shiptoaddr1, c.shiptoaddr2, c.shiptoaddr3, c.shiptoaddr4, c.shiptocontact, c.shiptophone, c.shiptofax, c.shiptoemail from customer c, oe o where o.customer_id = c.id;
+--
+create index shipto_trans_id_key on shipto (trans_id);
+--
+create table custome (
+ id integer,
+ name varchar2(35),
+ addr1 varchar2(35),
+ addr2 varchar2(35),
+ addr3 varchar2(35),
+ addr4 varchar2(35),
+ contact varchar2(35),
+ phone varchar2(20),
+ fax varchar2(20),
+ email VARCHAR2(50),
+ notes RCHAR2(4000),
+ discount float,
+ taxincluded char(1),
+ creditlimit float DEFAULT 0,
+ terms integer DEFAULT 0,
+ customernumber VARCHAR2(40),
+ cc VARCHAR2(50),
+ bcc VARCHAR2(50)
+);
+insert into custome (id, name, addr1, addr2, addr3, addr4, contact, phone, fax, email, notes, discount, taxincluded, creditlimit, terms, customernumber) select id, name, addr1, addr2, addr3, addr4, contact, phone, fax, email, notes, discount, taxincluded, creditlimit, terms, customernumber from customer;
+--
+drop table customer;
+alter table custome rename to customer;
+create index customer_id_key on customer (id);
+create index customer_name_key on customer (name);
+create index customer_contact_key on customer (contact);
+--
+alter table parts add (bom char(1) default '0');
+update parts set bom = '0';
+update parts set bom = '1' where assembly = '1';
+alter table parts add (image VARCHAR2(100));
+alter table parts add (drawing VARCHAR2(100));
+alter table parts add (microfiche VARCHAR2(100));
+--
+alter table gl add (notes VARCHAR2(4000));
+--
+alter table oe add (closed char(1) default '0');
+update oe set closed = '0';
+--
+create table project (
+ id integer,
+ projectnumber VARCHAR2(50),
+ description VARCHAR2(4000)
+);
+--
+create index project_id_key on project (id);
+--
+alter table acc_trans add (project_id integer);
+update acc_trans set cleared = '0' where cleared = '1';
+--
+alter table invoice add (project_id integer);
+alter table invoice add (deliverydate date);
+alter table orderitems add (project_id integer);
+alter table orderitems add (reqdate date);
+--
+CREATE OR REPLACE TRIGGER projectid BEFORE INSERT ON project FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+ FROM DUAL;--
+END;;
+--
+alter table gl add (reference VARCHAR2(50));
+update gl set reference = source;
+alter table gl drop column source;
+--
+create index gl_reference_key on gl (reference);
+create index acc_trans_source_key on acc_trans (source);
+--
+update defaults set version = '2.0.0';
+--
diff --git a/sql-ledger/sql/Oracle-upgrade-2.0.0-2.0.8.sql b/sql-ledger/sql/Oracle-upgrade-2.0.0-2.0.8.sql
new file mode 100644
index 0000000..eb65e9c
--- /dev/null
+++ b/sql-ledger/sql/Oracle-upgrade-2.0.0-2.0.8.sql
@@ -0,0 +1,19 @@
+--
+create table partsgroup (id integer, partsgroup varchar2(100));
+create index partsgroup_id_key on partsgroup (id);
+--
+alter table parts add (partsgroup_id integer);
+--
+alter table assembly add (bom char(1));
+update assembly set bom = '0' where assembly.id = parts.id and parts.bom = '0';
+update assembly set bom = '1' where assembly.id = parts.id and parts.bom = '1';
+--
+CREATE OR REPLACE TRIGGER partsgroupid BEFORE INSERT ON partsgroup FOR EACH ROW
+BEGIN
+ SELECT id.nextval
+ INTO :new.id
+FROM DUAL;--
+END;;
+--
+update defaults set version = '2.0.8';
+--
diff --git a/sql-ledger/sql/Pg-indices.sql b/sql-ledger/sql/Pg-indices.sql
new file mode 100644
index 0000000..27a9e43
--- /dev/null
+++ b/sql-ledger/sql/Pg-indices.sql
@@ -0,0 +1,57 @@
+create index acc_trans_trans_id_key on acc_trans (trans_id);
+create index acc_trans_chart_id_key on acc_trans (chart_id);
+create index acc_trans_transdate_key on acc_trans (transdate);
+create index acc_trans_source_key on acc_trans (lower(source));
+create index ap_id_key on ap (id);
+create index ap_transdate_key on ap (transdate);
+create index ap_invnumber_key on ap (lower(invnumber));
+create index ap_ordnumber_key on ap (lower(ordnumber));
+create index ap_vendor_id_key on ap (vendor_id);
+create index ap_employee_id_key on ap (employee_id);
+create index ar_id_key on ar (id);
+create index ar_transdate_key on ar (transdate);
+create index ar_invnumber_key on ar (lower(invnumber));
+create index ar_ordnumber_key on ar (lower(ordnumber));
+create index ar_customer_id_key on ar (customer_id);
+create index ar_employee_id_key on ar (employee_id);
+create index assembly_id_key on assembly (id);
+create index chart_id_key on chart (id);
+create unique index chart_accno_key on chart (accno);
+create index chart_category_key on chart (category);
+create index chart_link_key on chart (link);
+create index chart_gifi_accno_key on chart (gifi_accno);
+create index customer_id_key on customer (id);
+create index customer_customer_id_key on customertax (customer_id);
+create index customer_customernumber_key on customer (customernumber);
+create index customer_name_key on customer (name);
+create index customer_contact_key on customer (contact);
+create index employee_id_key on employee (id);
+create unique index employee_login_key on employee (login);
+create index employee_name_key on employee (name);
+create index exchangerate_ct_key on exchangerate (curr, transdate);
+create unique index gifi_accno_key on gifi (accno);
+create index gl_id_key on gl (id);
+create index gl_transdate_key on gl (transdate);
+create index gl_reference_key on gl (lower(reference));
+create index gl_description_key on gl (lower(description));
+create index gl_employee_id_key on gl (employee_id);
+create index invoice_id_key on invoice (id);
+create index invoice_trans_id_key on invoice (trans_id);
+create index makemodel_parts_id_key on makemodel (parts_id);
+create index oe_id_key on oe (id);
+create index oe_transdate_key on oe (transdate);
+create index oe_ordnumber_key on oe (lower(ordnumber));
+create index oe_employee_id_key on oe (employee_id);
+create index orderitems_trans_id_key on orderitems (trans_id);
+create index parts_id_key on parts (id);
+create index parts_partnumber_key on parts (lower(partnumber));
+create index parts_description_key on parts (lower(description));
+create index partstax_parts_id_key on partstax (parts_id);
+create index vendor_id_key on vendor (id);
+create index vendor_name_key on vendor (name);
+create index vendor_vendornumber_key on vendor (vendornumber);
+create index vendor_contact_key on vendor (contact);
+create index vendortax_vendor_id_key on vendortax (vendor_id);
+create index shipto_trans_id_key on shipto (trans_id);
+create index project_id_key on project (id);
+create index partsgroup_id_key on partsgroup (id);
diff --git a/sql-ledger/sql/Pg-tables.sql b/sql-ledger/sql/Pg-tables.sql
new file mode 100644
index 0000000..aed9787
--- /dev/null
+++ b/sql-ledger/sql/Pg-tables.sql
@@ -0,0 +1,289 @@
+CREATE SEQUENCE id
+ start 10000;
+--
+SELECT nextval ('id');
+--
+CREATE TABLE makemodel (
+ parts_id int,
+ name text
+);
+--
+CREATE TABLE gl (
+ id int DEFAULT nextval ( 'id' ),
+ reference text,
+ description text,
+ transdate date DEFAULT current_date,
+ employee_id int,
+ notes text
+);
+--
+CREATE TABLE chart (
+ id int DEFAULT nextval ( 'id' ),
+ accno text NOT NULL,
+ description text,
+ charttype char(1) DEFAULT 'A',
+ category char(1),
+ link text,
+ gifi_accno text
+);
+--
+CREATE TABLE gifi (
+ accno text,
+ description text
+);
+--
+CREATE TABLE defaults (
+ inventory_accno_id int,
+ income_accno_id int,
+ expense_accno_id int,
+ fxgain_accno_id int,
+ fxloss_accno_id int,
+ invnumber text,
+ sonumber text,
+ yearend varchar(5),
+ weightunit varchar(5),
+ businessnumber text,
+ version varchar(8),
+ curr text,
+ closedto date,
+ revtrans bool DEFAULT 'f',
+ ponumber text
+);
+INSERT INTO defaults (version) VALUES ('2.0.8');
+--
+CREATE TABLE acc_trans (
+ trans_id int,
+ chart_id int,
+ amount float,
+ transdate date DEFAULT current_date,
+ source text,
+ cleared bool DEFAULT 'f',
+ fx_transaction bool DEFAULT 'f',
+ project_id int
+);
+--
+CREATE TABLE invoice (
+ id int DEFAULT nextval ( 'id' ),
+ trans_id int,
+ parts_id int,
+ description text,
+ qty float4,
+ allocated float4,
+ sellprice float,
+ fxsellprice float,
+ discount float4,
+ assemblyitem bool DEFAULT 'f',
+ unit varchar(5),
+ project_id int,
+ deliverydate date
+);
+--
+CREATE TABLE vendor (
+ id int DEFAULT nextval ( 'id' ),
+ name varchar(35),
+ addr1 varchar(35),
+ addr2 varchar(35),
+ addr3 varchar(35),
+ addr4 varchar(35),
+ contact varchar(35),
+ phone varchar(20),
+ fax varchar(20),
+ email text,
+ notes text,
+ terms int2 DEFAULT 0,
+ taxincluded bool,
+ vendornumber text,
+ cc text,
+ bcc text
+);
+--
+CREATE TABLE customer (
+ id int DEFAULT nextval ( 'id' ),
+ name varchar(35),
+ addr1 varchar(35),
+ addr2 varchar(35),
+ addr3 varchar(35),
+ addr4 varchar(35),
+ contact varchar(35),
+ phone varchar(20),
+ fax varchar(20),
+ email text,
+ notes text,
+ discount float4,
+ taxincluded bool,
+ creditlimit float DEFAULT 0,
+ terms int2 DEFAULT 0,
+ customernumber text,
+ cc text,
+ bcc text
+);
+--
+CREATE TABLE parts (
+ id int DEFAULT nextval ( 'id' ),
+ partnumber text,
+ description text,
+ unit varchar(5),
+ listprice float,
+ sellprice float,
+ lastcost float,
+ priceupdate date DEFAULT current_date,
+ weight float4,
+ onhand float4 DEFAULT 0,
+ notes text,
+ makemodel bool DEFAULT 'f',
+ assembly bool DEFAULT 'f',
+ alternate bool DEFAULT 'f',
+ rop float4,
+ inventory_accno_id int,
+ income_accno_id int,
+ expense_accno_id int,
+ bin text,
+ obsolete bool DEFAULT 'f',
+ bom bool DEFAULT 'f',
+ image text,
+ drawing text,
+ microfiche text,
+ partsgroup_id int
+);
+--
+CREATE TABLE assembly (
+ id int,
+ parts_id int,
+ qty float,
+ bom bool
+);
+--
+CREATE TABLE ar (
+ id int DEFAULT nextval ( 'id' ),
+ invnumber text,
+ transdate date DEFAULT current_date,
+ customer_id int,
+ taxincluded bool,
+ amount float,
+ netamount float,
+ paid float,
+ datepaid date,
+ duedate date,
+ invoice bool DEFAULT 'f',
+ shippingpoint text,
+ terms int2 DEFAULT 0,
+ notes text,
+ curr char(3),
+ ordnumber text,
+ employee_id int
+);
+--
+CREATE TABLE ap (
+ id int DEFAULT nextval ( 'id' ),
+ invnumber text,
+ transdate date DEFAULT current_date,
+ vendor_id int,
+ taxincluded bool DEFAULT 'f',
+ amount float,
+ netamount float,
+ paid float,
+ datepaid date,
+ duedate date,
+ invoice bool DEFAULT 'f',
+ ordnumber text,
+ curr char(3),
+ notes text,
+ employee_id int
+);
+--
+CREATE TABLE partstax (
+ parts_id int,
+ chart_id int
+);
+--
+CREATE TABLE tax (
+ chart_id int,
+ rate float,
+ taxnumber text
+);
+--
+CREATE TABLE customertax (
+ customer_id int,
+ chart_id int
+);
+--
+CREATE TABLE vendortax (
+ vendor_id int,
+ chart_id int
+);
+--
+CREATE TABLE oe (
+ id int default nextval('id'),
+ ordnumber text,
+ transdate date default current_date,
+ vendor_id int,
+ customer_id int,
+ amount float8,
+ netamount float8,
+ reqdate date,
+ taxincluded bool,
+ shippingpoint text,
+ notes text,
+ curr char(3),
+ employee_id int,
+ closed bool default 'f'
+);
+--
+CREATE TABLE orderitems (
+ trans_id int,
+ parts_id int,
+ description text,
+ qty float4,
+ sellprice float8,
+ discount float4,
+ unit varchar(5),
+ project_id int,
+ reqdate date
+);
+--
+CREATE TABLE exchangerate (
+ curr char(3),
+ transdate date,
+ buy float8,
+ sell float8
+);
+--
+CREATE TABLE employee (
+ id int DEFAULT nextval ('id'),
+ login text,
+ name Varchar(35),
+ addr1 varchar(35),
+ addr2 varchar(35),
+ addr3 varchar(35),
+ addr4 varchar(35),
+ workphone varchar(20),
+ homephone varchar(20),
+ startdate date default current_date,
+ enddate date,
+ notes text
+);
+--
+create table shipto (
+ trans_id int,
+ shiptoname varchar(35),
+ shiptoaddr1 varchar(35),
+ shiptoaddr2 varchar(35),
+ shiptoaddr3 varchar(35),
+ shiptoaddr4 varchar(35),
+ shiptocontact varchar(35),
+ shiptophone varchar(20),
+ shiptofax varchar(20),
+ shiptoemail text
+);
+--
+create table project (
+ id int default nextval('id'),
+ projectnumber text,
+ description text
+);
+--
+create table partsgroup (
+ id int default nextval('id'),
+ partsgroup text
+);
+--
diff --git a/sql-ledger/sql/Pg-upgrade-1.2.6-1.2.7.sql b/sql-ledger/sql/Pg-upgrade-1.2.6-1.2.7.sql
new file mode 100644
index 0000000..159f31b
--- /dev/null
+++ b/sql-ledger/sql/Pg-upgrade-1.2.6-1.2.7.sql
@@ -0,0 +1,4 @@
+--
+-- add the field shiptoemail to the customer table
+--
+alter table customer add column shiptoemail text;
diff --git a/sql-ledger/sql/Pg-upgrade-1.2.7-1.4.0.sql b/sql-ledger/sql/Pg-upgrade-1.2.7-1.4.0.sql
new file mode 100644
index 0000000..04e1a79
--- /dev/null
+++ b/sql-ledger/sql/Pg-upgrade-1.2.7-1.4.0.sql
@@ -0,0 +1,173 @@
+--
+CREATE TABLE newap (
+ id int DEFAULT nextval ( 'id' ),
+ invnumber text,
+ transdate date DEFAULT current_date,
+ vendor int,
+ taxincluded bool DEFAULT FALSE,
+ amount float,
+ netamount float,
+ paid float,
+ datepaid date,
+ duedate date,
+ invoice bool DEFAULT FALSE,
+ ordnumber text
+);
+--
+INSERT INTO newap (id, invnumber, transdate, vendor, amount, netamount, paid,
+datepaid, duedate, invoice, ordnumber)
+SELECT id, invnumber, transdate, vendor, amount, netamount, paid,
+datepaid, duedate, invoice, ordnumber
+FROM ap;
+--
+DROP TABLE ap;
+ALTER TABLE newap RENAME TO ap;
+--
+CREATE TABLE newar (
+ id int DEFAULT nextval ( 'id' ),
+ invnumber text,
+ transdate date DEFAULT current_date,
+ customer int,
+ taxincluded bool DEFAULT FALSE,
+ amount float,
+ netamount float,
+ paid float,
+ datepaid date,
+ duedate date,
+ invoice bool DEFAULT FALSE,
+ shippingpoint text,
+ terms int2,
+ notes text
+);
+--
+INSERT INTO newar (id, invnumber, transdate, customer, amount, netamount, paid,
+datepaid, duedate, invoice, shippingpoint, terms, notes)
+SELECT id, invnumber, transdate, customer, amount, netamount, paid,
+datepaid, duedate, invoice, shippingpoint, terms, notes
+FROM ar;
+--
+DROP TABLE ar;
+ALTER TABLE newar RENAME TO ar;
+--
+CREATE TABLE newcustomer (
+ id int DEFAULT nextval ( 'id' ),
+ name varchar(35),
+ addr1 varchar(35),
+ addr2 varchar(35),
+ addr3 varchar(35),
+ contact varchar(35),
+ phone varchar(20),
+ fax varchar(20),
+ email text,
+ notes text,
+ ytd float,
+ discount float4,
+ taxincluded bool,
+ creditlimit float,
+ terms int2,
+ shiptoname varchar(35),
+ shiptoaddr1 varchar(35),
+ shiptoaddr2 varchar(35),
+ shiptoaddr3 varchar(35),
+ shiptocontact varchar(20),
+ shiptophone varchar(20),
+ shiptofax varchar(20),
+ shiptoemail text
+);
+INSERT INTO newcustomer (
+id, name, addr1, addr2, addr3, contact, phone, fax, email, notes, ytd,
+discount, creditlimit, terms, shiptoname, shiptoaddr1, shiptoaddr2,
+shiptoaddr3, shiptocontact, shiptophone, shiptofax, shiptoemail )
+SELECT id, name, addr1, addr2, addr3, contact, phone, fax, email, notes, ytd,
+discount, creditlimit, terms, shiptoname, shiptoaddr1, shiptoaddr2,
+shiptoaddr3, shiptocontact, shiptophone, shiptofax, shiptoemail
+FROM customer;
+--
+DROP TABLE customer;
+ALTER TABLE newcustomer RENAME TO customer;
+--
+CREATE TABLE customertax (
+ customer_id int,
+ chart_id int
+);
+--
+CREATE TABLE newdefaults (
+ inventory_accno int,
+ income_accno int,
+ expense_accno int,
+ invnumber text,
+ ponumber text,
+ yearend varchar(5),
+ nativecurr varchar(3),
+ weightunit varchar(5)
+);
+--
+INSERT INTO newdefaults (
+inventory_accno, income_accno, expense_accno, invnumber, ponumber)
+SELECT inventory_accno, income_accno, expense_accno, invnumber, ponumber
+FROM defaults;
+--
+DROP TABLE defaults;
+ALTER TABLE newdefaults RENAME TO defaults;
+UPDATE defaults SET yearend = '1/31', nativecurr = 'CAD', weightunit = 'kg';
+--
+CREATE TABLE partstax (
+ parts_id int,
+ chart_id int
+);
+--
+CREATE TABLE tax (
+ chart_id int,
+ rate float,
+ number text
+);
+--
+CREATE TABLE newvendor (
+ id int DEFAULT nextval ( 'id' ),
+ name varchar(35),
+ addr1 varchar(35),
+ addr2 varchar(35),
+ addr3 varchar(35),
+ contact varchar(35),
+ phone varchar(20),
+ fax varchar(20),
+ email text,
+ notes text,
+ ytd float,
+ discount float4,
+ taxincluded bool,
+ creditlimit float,
+ terms int2
+);
+--
+INSERT INTO newvendor (
+id, name, addr1, addr2, addr3, contact, phone, fax, email, notes, ytd )
+SELECT id, name, addr1, addr2, addr3, contact, phone, fax, email, notes, ytd
+FROM vendor;
+--
+DROP TABLE vendor;
+ALTER TABLE newvendor RENAME TO vendor;
+--
+CREATE TABLE vendortax (
+ vendor_id int,
+ chart_id int
+);
+--
+ALTER TABLE chart RENAME TO oldchart;
+--
+CREATE TABLE chart (
+ id int DEFAULT nextval( 'id' ),
+ accno int UNIQUE,
+ description text,
+ balance float,
+ type char(1),
+ gifi int,
+ category char(1),
+ link text
+);
+--
+INSERT INTO chart SELECT * FROM oldchart;
+--
+DROP TABLE oldchart;
+--
+
diff --git a/sql-ledger/sql/Pg-upgrade-1.4.0-1.6.0.sql b/sql-ledger/sql/Pg-upgrade-1.4.0-1.6.0.sql
new file mode 100644
index 0000000..e0a3892
--- /dev/null
+++ b/sql-ledger/sql/Pg-upgrade-1.4.0-1.6.0.sql
@@ -0,0 +1,126 @@
+alter table acc_trans rename column accno to chart_id;
+update acc_trans set chart_id =
+ (select id from chart where accno = acc_trans.chart_id);
+--
+alter table parts rename column inventory_accno to inventory_accno_id;
+alter table parts rename column income_accno to income_accno_id;
+alter table parts rename column expense_accno to expense_accno_id;
+alter table parts rename column number to partnumber;
+update parts set inventory_accno_id =
+ (select id from chart where chart.accno = parts.inventory_accno_id);
+update parts set income_accno_id =
+ (select id from chart where chart.accno = parts.income_accno_id);
+update parts set expense_accno_id =
+ (select id from chart where chart.accno = parts.expense_accno_id);
+--
+create table assembly (id int, parts_id int, qty float);
+--
+alter table defaults rename column inventory_accno to inventory_accno_id;
+alter table defaults rename column income_accno to income_accno_id;
+alter table defaults rename column expense_accno to expense_accno_id;
+alter table defaults add column businessnumber text;
+alter table defaults add column version varchar(8);
+update defaults set inventory_accno_id =
+ (select id from chart where chart.accno = defaults.inventory_accno_id);
+update defaults set income_accno_id =
+ (select id from chart where chart.accno = defaults.income_accno_id);
+update defaults set expense_accno_id =
+ (select id from chart where chart.accno = defaults.expense_accno_id);
+update defaults set version = '1.6.0';
+--
+alter table invoice rename column inventory_accno to inventory_accno_id;
+alter table invoice rename column income_accno to income_accno_id;
+alter table invoice rename column expense_accno to expense_accno_id;
+alter table invoice rename column number to partnumber;
+alter table invoice add column assemblyitem bool;
+update invoice set assemblyitem = 'f';
+update invoice set inventory_accno_id =
+ (select id from chart where invoice.inventory_accno_id = chart.accno);
+update invoice set income_accno_id =
+ (select id from chart where invoice.income_accno_id = chart.accno);
+update invoice set expense_accno_id =
+ (select id from chart where invoice.expense_accno_id = chart.accno);
+--
+alter table gl rename column comment to description;
+--
+create table newvendor (
+ id int default nextval ( 'id' ),
+ name varchar(35),
+ addr1 varchar(35),
+ addr2 varchar(35),
+ addr3 varchar(35),
+ addr4 varchar(35),
+ contact varchar(35),
+ phone varchar(20),
+ fax varchar(20),
+ email text,
+ notes text,
+ terms int2,
+ taxincluded bool
+);
+insert into newvendor (
+ id, name, addr1, addr2, addr3, contact, phone, fax, email, notes, terms,
+ taxincluded)
+ select
+ id, name, addr1, addr2, addr3, contact, phone, fax, email, notes, terms,
+ taxincluded from vendor;
+drop table vendor;
+alter table newvendor rename to vendor;
+--
+create table newcustomer (
+ id int default nextval ( 'id' ),
+ name varchar(35),
+ addr1 varchar(35),
+ addr2 varchar(35),
+ addr3 varchar(35),
+ addr4 varchar(35),
+ contact varchar(35),
+ phone varchar(20),
+ fax varchar(20),
+ email text,
+ notes text,
+ discount float4,
+ taxincluded bool,
+ creditlimit float,
+ terms int2,
+ shiptoname varchar(35),
+ shiptoaddr1 varchar(35),
+ shiptoaddr2 varchar(35),
+ shiptoaddr3 varchar(35),
+ shiptoaddr4 varchar(35),
+ shiptocontact varchar(20),
+ shiptophone varchar(20),
+ shiptofax varchar(20),
+ shiptoemail text
+);
+insert into newcustomer (
+ id, name, addr1, addr2, addr3, contact, phone, fax, email, notes, discount,
+ taxincluded, creditlimit, terms, shiptoname, shiptoaddr1, shiptoaddr2,
+ shiptoaddr3, shiptocontact, shiptophone, shiptofax, shiptoemail
+ )
+ select
+ id, name, addr1, addr2, addr3, contact, phone, fax, email, notes, discount,
+ taxincluded, creditlimit, terms, shiptoname, shiptoaddr1, shiptoaddr2,
+ shiptoaddr3, shiptocontact, shiptophone, shiptofax, shiptoemail
+ from customer;
+drop table customer;
+alter table newcustomer rename to customer;
+--
+drop index chart_accno_key;
+alter table chart rename to oldchart;
+create table chart (
+ id int default nextval('id'),
+ accno int unique,
+ description text,
+ charttype char(1),
+ gifi int,
+ category char(1),
+ link text
+);
+insert into chart (id, accno, description, charttype, gifi, category, link)
+ select id, accno, description, type, gifi, category, link from oldchart;
+drop table oldchart;
+--
+alter table tax rename column number to taxnumber;
+--
+-- apply
diff --git a/sql-ledger/sql/Pg-upgrade-1.6.0-1.8.0.sql b/sql-ledger/sql/Pg-upgrade-1.6.0-1.8.0.sql
new file mode 100644
index 0000000..4e98e1f
--- /dev/null
+++ b/sql-ledger/sql/Pg-upgrade-1.6.0-1.8.0.sql
@@ -0,0 +1,104 @@
+--
+create table def (
+ inventory_accno_id int,
+ income_accno_id int,
+ expense_accno_id int,
+ fxgain_accno_id int,
+ fxloss_accno_id int,
+ invnumber text,
+ ordnumber text,
+ yearend varchar(5),
+ weightunit varchar(5),
+ businessnumber text,
+ version varchar(8),
+ curr text
+);
+insert into def (inventory_accno_id, income_accno_id, expense_accno_id, invnumber, ordnumber, yearend, weightunit, businessnumber, version, curr) select inventory_accno_id, income_accno_id, expense_accno_id, invnumber, ponumber, yearend, weightunit, businessnumber, version, nativecurr from defaults;
+drop table defaults;
+alter table def rename to defaults;
+update defaults set version = '1.8.0';
+--
+-- create a default accno for exchange rate gain and loss
+--
+select accno into temp from chart where category = 'I' order by accno desc limit 1;
+update temp set accno = accno + 1;
+insert into chart (accno) select accno from temp;
+update chart set description = 'Foreign Exchange Gain', category = 'I', charttype = 'A' where accno = (select accno from temp);
+update defaults set fxgain_accno_id = (select id from chart where chart.accno = temp.accno);
+drop table temp;
+select accno into temp from chart where category = 'E' order by accno desc limit 1;
+update temp set accno = accno + 1;
+insert into chart (accno) select accno from temp;
+update chart set description = 'Foreign Exchange Loss', category = 'E', charttype = 'A' where accno = (select accno from temp);
+update defaults set fxloss_accno_id = (select id from chart where chart.accno = temp.accno);
+drop table temp;
+--
+alter table parts add column bin text;
+alter table parts alter column onhand set default 0;
+update parts set onhand = 0 where onhand = NULL;
+alter table parts add column obsolete bool;
+alter table parts alter column obsolete set default 'f';
+update parts set obsolete = 'f';
+--
+alter table ap rename column vendor to vendor_id;
+alter table ap add column curr char(3);
+--
+alter table ar rename column customer to customer_id;
+alter table ar add column curr char(3);
+alter table ar add column ordnumber text;
+--
+alter table acc_trans add column source text;
+alter table acc_trans add column cleared bool;
+alter table acc_trans alter column cleared set default 'f';
+alter table acc_trans add column fx_transaction bool;
+alter table acc_trans alter column fx_transaction set default 'f';
+update acc_trans set cleared = 'f', fx_transaction = 'f';
+--
+create table oe (
+ id int default nextval('id'),
+ ordnumber text,
+ transdate date default current_date,
+ vendor_id int,
+ customer_id int,
+ amount float8,
+ netamount float8,
+ reqdate date,
+ taxincluded bool,
+ shippingpoint text,
+ notes text,
+ curr char(3)
+);
+--
+create table orderitems (
+ trans_id int,
+ parts_id int,
+ description text,
+ qty float4,
+ sellprice float8,
+ discount float4
+);
+--
+alter table invoice rename to invoiceold;
+create table invoice (
+ id int default nextval('id'),
+ trans_id int,
+ parts_id int,
+ description text,
+ qty float4,
+ allocated float4,
+ sellprice float8,
+ fxsellprice float8,
+ discount float4,
+ assemblyitem bool default 'f'
+);
+insert into invoice (id, trans_id, parts_id, description, qty, allocated, sellprice, fxsellprice, discount, assemblyitem) select id, trans_id, parts_id, description, qty, allocated, sellprice, sellprice, discount, assemblyitem from invoiceold;
+update invoice set assemblyitem = 'f' where assemblyitem = NULL;
+drop table invoiceold;
+--
+create table exchangerate (
+ curr char(3),
+ transdate date,
+ buy float8,
+ sell float8
+);
+--
diff --git a/sql-ledger/sql/Pg-upgrade-1.8.0-1.8.4.sql b/sql-ledger/sql/Pg-upgrade-1.8.0-1.8.4.sql
new file mode 100644
index 0000000..57b24f1
--- /dev/null
+++ b/sql-ledger/sql/Pg-upgrade-1.8.0-1.8.4.sql
@@ -0,0 +1,21 @@
+--
+alter table chart add column gifi_accno text;
+--
+create table gifi (accno text, description text);
+create unique index gifi_accno_key on gifi (accno);
+--
+create table mtemp (parts_id int, name text);
+insert into mtemp select parts_id, name from makemodel;
+drop table makemodel;
+alter table mtemp rename to makemodel;
+--
+alter table defaults add column closedto date;
+alter table defaults add column revtrans bool;
+--
+alter table ap add column notes text;
+--
+alter table customer add column businessnumber text;
+alter table vendor add column businessnumber text;
+--
+update defaults set version = '1.8.4', revtrans = 'f';
+--
diff --git a/sql-ledger/sql/Pg-upgrade-1.8.4-1.8.5.sql b/sql-ledger/sql/Pg-upgrade-1.8.4-1.8.5.sql
new file mode 100644
index 0000000..807857a
--- /dev/null
+++ b/sql-ledger/sql/Pg-upgrade-1.8.4-1.8.5.sql
@@ -0,0 +1,63 @@
+--
+alter table customer rename column businessnumber to customernumber;
+create index customer_customernumber_key on customer (customernumber);
+alter table vendor rename column businessnumber to vendornumber;
+create index vendor_vendornumber_key on vendor (vendornumber);
+--
+CREATE TABLE employee (
+ id int DEFAULT nextval ('id'),
+ login text,
+ name varchar(35),
+ addr1 varchar(35),
+ addr2 varchar(35),
+ addr3 varchar(35),
+ addr4 varchar(35),
+ workphone varchar(20),
+ homephone varchar(20),
+ startdate date default current_date,
+ enddate date,
+ notes text
+);
+--
+create index employee_id_key on employee (id);
+create unique index employee_login_key on employee (login);
+create index employee_name_key on employee (name);
+--
+alter table gl add column employee_id int;
+create index gl_employee_id_key on gl (employee_id);
+alter table ar add column employee_id int;
+create index ar_employee_id_key on ar (employee_id);
+alter table ap add column employee_id int;
+create index ap_employee_id_key on ap (employee_id);
+alter table oe add column employee_id int;
+create index oe_employee_id_key on oe (employee_id);
+--
+alter table invoice add column unit varchar(5);
+alter table orderitems add column unit varchar(5);
+--
+update chart set gifi_accno = '' where gifi_accno = NULL;
+alter table chart rename to chartold;
+CREATE TABLE chart (
+ id int DEFAULT nextval ('id'),
+ accno text NOT NULL,
+ description text,
+ charttype char(1) DEFAULT 'A',
+ category char(1),
+ link text,
+ gifi_accno text
+);
+insert into chart (id, accno, description, charttype, category, link, gifi_accno) select id, accno, description, charttype, category, link, gifi_accno from chartold;
+drop table chartold;
+create index chart_id_key on chart (id);
+create unique index chart_accno_key on chart (accno);
+create index chart_category_key on chart (category);
+create index chart_link_key on chart (link);
+create index chart_gifi_accno_key on chart (gifi_accno);
+--
+alter table parts alter column inventory_accno_id drop default;
+--
+alter table defaults rename ordnumber to sonumber;
+alter table defaults add column ponumber text;
+--
+update defaults set version = '1.8.5', ponumber = sonumber;
+--
diff --git a/sql-ledger/sql/Pg-upgrade-1.8.5-2.0.0.sql b/sql-ledger/sql/Pg-upgrade-1.8.5-2.0.0.sql
new file mode 100644
index 0000000..ebc1d07
--- /dev/null
+++ b/sql-ledger/sql/Pg-upgrade-1.8.5-2.0.0.sql
@@ -0,0 +1,92 @@
+--
+alter table customer add column cc text;
+alter table customer add column bcc text;
+--
+alter table vendor add column cc text;
+alter table vendor add column bcc text;
+--
+create table shipto (
+ trans_id int,
+ shiptoname varchar(35),
+ shiptoaddr1 varchar(35),
+ shiptoaddr2 varchar(35),
+ shiptoaddr3 varchar(35),
+ shiptoaddr4 varchar(35),
+ shiptocontact varchar(35),
+ shiptophone varchar(20),
+ shiptofax varchar(20),
+ shiptoemail text
+);
+--
+insert into shipto (trans_id, shiptoname, shiptoaddr1, shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact, shiptophone, shiptofax, shiptoemail) select id, shiptoname, shiptoaddr1, shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact, shiptophone, shiptofax, shiptoemail from customer where shiptoname != '' or shiptoname is not null;
+--
+insert into shipto (trans_id, shiptoname, shiptoaddr1, shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact, shiptophone, shiptofax, shiptoemail) select distinct on (a.id) a.id, c.shiptoname, c.shiptoaddr1, c.shiptoaddr2, c.shiptoaddr3, c.shiptoaddr4, c.shiptocontact, c.shiptophone, c.shiptofax, c.shiptoemail from customer c, ar a where a.customer_id = c.id;
+--
+insert into shipto (trans_id, shiptoname, shiptoaddr1, shiptoaddr2, shiptoaddr3, shiptoaddr4, shiptocontact, shiptophone, shiptofax, shiptoemail) select distinct on (o.id) o.id, c.shiptoname, c.shiptoaddr1, c.shiptoaddr2, c.shiptoaddr3, c.shiptoaddr4, c.shiptocontact, c.shiptophone, c.shiptofax, c.shiptoemail from customer c, oe o where o.customer_id = c.id;
+--
+create index shipto_trans_id_key on shipto (trans_id);
+--
+create table custome (
+ id int default nextval('id'),
+ name varchar(35),
+ addr1 varchar(35),
+ addr2 varchar(35),
+ addr3 varchar(35),
+ addr4 varchar(35),
+ contact varchar(35),
+ phone varchar(20),
+ fax varchar(20),
+ email text,
+ notes text,
+ discount float4,
+ taxincluded bool,
+ creditlimit float DEFAULT 0,
+ terms int2 DEFAULT 0,
+ customernumber text,
+ cc text,
+ bcc text
+);
+insert into custome (id, name, addr1, addr2, addr3, addr4, contact, phone, fax, email, notes, discount, taxincluded, creditlimit, terms, customernumber) select id, name, addr1, addr2, addr3, addr4, contact, phone, fax, email, notes, discount, taxincluded, creditlimit, terms, customernumber from customer;
+--
+drop table customer;
+alter table custome rename to customer;
+create index customer_id_key on customer (id);
+create index customer_name_key on customer (name);
+create index customer_contact_key on customer (contact);
+--
+alter table parts add column bom boolean;
+alter table parts alter column bom set default 'f';
+update parts set bom = 'f';
+update parts set bom = 't' where assembly;
+alter table parts add column image text;
+alter table parts add column drawing text;
+alter table parts add column microfiche text;
+--
+alter table gl add column notes text;
+--
+alter table oe add column closed bool;
+alter table oe alter column closed set default 'f';
+update oe set closed = 'f';
+--
+create table project (
+ id int default nextval('id'),
+ projectnumber text,
+ description text
+);
+--
+create index project_id_key on project (id);
+--
+alter table acc_trans add column project_id int;
+update acc_trans set cleared = '0' where cleared = '1';
+--
+alter table invoice add column project_id int;
+alter table invoice add column deliverydate date;
+alter table orderitems add column project_id int;
+alter table orderitems add column reqdate date;
+--
+alter table gl rename source to reference;
+create index gl_reference_key on gl (reference);
+create index acc_trans_source_key on acc_trans (lower(source));
+--
+update defaults set version = '2.0.0';
+--
diff --git a/sql-ledger/sql/Pg-upgrade-2.0.0-2.0.8.sql b/sql-ledger/sql/Pg-upgrade-2.0.0-2.0.8.sql
new file mode 100644
index 0000000..ef73b1c
--- /dev/null
+++ b/sql-ledger/sql/Pg-upgrade-2.0.0-2.0.8.sql
@@ -0,0 +1,12 @@
+--
+create table partsgroup (id int default nextval('id'), partsgroup text);
+create index partsgroup_id_key on partsgroup (id);
+--
+alter table parts add partsgroup_id int;
+--
+alter table assembly add bom bool;
+update assembly set bom = '0' where assembly.id = parts.id and parts.bom = '0';
+update assembly set bom = '1' where assembly.id = parts.id and parts.bom = '1';
+--
+update defaults set version = '2.0.8';
+--
diff --git a/sql-ledger/sql/Poland-chart.sql b/sql-ledger/sql/Poland-chart.sql
new file mode 100644
index 0000000..64960ca
--- /dev/null
+++ b/sql-ledger/sql/Poland-chart.sql
@@ -0,0 +1,337 @@
+-- Chart of Account for Poland
+-- From: Peter Dabrowski <meritage@mail.com>
+-- Sun, 23 March 2003
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('000000000','Aktywa Trwa³e','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('001000000','¦rodki Trwa³e','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('001010000','Grunty w³asne i prawa wieczystego u¿ytkowania gruntów','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('001020000','Budynki, locale i obiekty in¿ynierii l±dowej i wodnej','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('001030000','Urz±dzenia techniczne i maszyny','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('001040000','¦rodki transportu','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('001050000','Inne ¶rodki trwa³e','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('002000000','Warto¶ci niematerialne i prawne','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('002010000','Koszty zakoñczonych prac rozwojowych','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('002020000','Nabyta warto¶æ firmy','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('002080000','Inne warto¶ci niematerialne i prawne','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('002090000','Zaliczki na warto¶ci niematerialne i prawne','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003000000','D³ugoterminowe aktywa finansowe','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003010000','W jednostkach powi±zanych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003010100','Udzia³y lub akcje','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003010200','Inne papiery warto¶ciowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003010300','Udzielone porzyczki','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003010400','Inne d³ugoterminowe aktywa finansowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003020000','W pozosta³ych jednostkach','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003020100','Udzia³y lub akcje','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003020200','Inne papiery warto¶ciowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003020300','Udzielone po¿yczki','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003020400','Inne d³ugoterminowe aktywa finansowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003090000','Inne investycje d³ugoterminowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('003090100','Inne rodzaje d³ugoterminowych aktywów finansowych','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('004000000','Investycje w nieruchomo¶ci i prawa','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('004010000','Nieruchomo¶ci','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('004020000','Warto¶ci niematerialne i prawne','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('005000000','D³ugoterminowe rozliczenia miêdzyokresowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('005010000','Aktywa z tytu³u odroczonego podatku dochodowego','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('005020000','Inne rozliczenia miêdzyokresowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('006000000','Nale¿no¶ci d³ugoterminowe','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('006010000','Od jednostek powi±zanych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('006020000','Od pozosta³ych jednostek','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('007000000','Odpisy umorzeniowe ¶rodków trwa³ych oraz warto¶ci niematerialnych i prawnych','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('007010000','Odpisy umorzeniowe warto¶ci gruntów i prawa wieczystego u¿ytkowania gruntów','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('007020000','Odpisy umorzeniowe budynków, lokali i obiektów in¿ynierii l±dowej i wodnej','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('007030000','Odpisy umorzeniowe urz±dzeñ technicznych i maszyn','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('007040000','Odpisy umorzeniowe ¶rodków transportu','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('007050000','Odpisy umorzeniowe ulepszeñ obcych ¶rodków trwa³ych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('007090000','Odpisy umorzeniowe innych ¶rodków trwa³ych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('008000000','¦rodki trwa³e w budowie','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('008010000','Inwestycje budowy ¶rodka trwa³ego','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('008020000','Ulepszenia ¶rodka trwa³ego','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('008030000','Nak³ady na budowê ¶rodka trwa³ego','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('008040000','Zaliczki na ¶rodki trwa³e w budowie','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('008050000','Ulepszenia obcych ¶rodków trwa³ych','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('009000000','Odpisy aktualizuj±ce d³ugoterminowe aktywa finansowe','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('009010000','Odpisy aktualizuj±ce udzia³y i akcje w obcych jednostkach','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('009020000','Odpisy aktualizuj±ce lokaty','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('009030000','Odpisy aktualizuj±ce udzielone porzyczki d³ugoterminowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('009090000','Odpisy aktualizuj±ce inne rodzaje d³ugoterminowych aktywów finansowych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('100000000','¦rodki pieniê¿ne, rachunki bankowe oraz inne krótkoterminowe aktywa finansowe','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('110000000','¦rodki pieniê¿ne w kasie','A','','A','AR:AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('110010000','Kasa krajowych ¶rodków pieniê¿nych','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('110020000','Kasa zagranicznych ¶rodków pieniê¿nych','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('113000000','Rachunki i kredyty bankowe','A','','A','AR:AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('113010000','Rachunek bie¿±cy','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('113020000','Rachunek ¶rodków wyodrêbnionych i zablokowanych','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('113030000','Rachunki kredytów bankowych','A','','A','AR_paid:AP_amount:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('113040000','Rachunek ¶rodków walutowych','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114000000','Krótkoterminowe aktywa finansowe','A','','A','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114010000','Krótkoterminowe aktywa finansowe w jednostkach powi±zanych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114010100','Udzia³y lub akcje','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114010200','Inne papiery warto¶ciowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114010300','Udzielone po¿yczki','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114010400','Inne krótkoterminowe aktywa finansowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114020000','Krótkoterminowe aktywa finansowe w pozosta³ych jednostkach','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114020100','Udzia³y lub akcje','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114020200','Inne papiery warto¶ciowe','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('114020400','Inne krótkoterminowe aktywa finansowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('115000000','Inne ¶rodki pieniê¿ne','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('116000000','Inne aktywa pieniê¿ne','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('117000000','Inne inwestycje krótkoterminowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('118000000','Krótkoterminowe rozliczenia miêdzyokresowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('200000000','Rozrachunki i roszczenia','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('220000000','Nale¿no¶ci krótkoterminowe','A','','L','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('220010000','Nale¿no¶ci od jednostek powi±zanych','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('220010100','Nale¿no¶ci z tytu³u dostaw i us³ug','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('220010110','Nale¿no¶ci z tytu³u dostaw i us³ug, o okresie sp³aty do 12 miesiêcy','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('220010120','Nale¿no¶ci z tytu³u dostaw i us³ug, o okresie sp³aty powy¿ej 12 miesiêcy','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('220010200','Inne nale¿no¶ci','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('220010210','Zobowi±zania z tytu³u pokrycia kosztów ogólnego zarz±du','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('220010220','Zobowi±zania z tytu³u rozliczeñ VAT','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('221010000','Nale¿no¶ci od pozosta³ych jednostek','A','','L','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('221020100','Nale¿no¶ci z tytu³u dostaw i us³ug','A','','L','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('221020110','Nale¿no¶ci z tytu³u dostaw i us³ug, o okresie sp³aty do 12 miesiêcy','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('221020120','Nale¿no¶ci z tytu³u dostaw i us³ug, o okresie sp³aty powy¿ej 12 miesiêcy','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('221020200','Nale¿no¶ci z tytu³u podatków, dotacji, ce³, ubezpieczeñ spo³ecznych i zdrowotnych oraz innych ¶wiadczeñ','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('221020300','Zaliczki przekazane dostawcom','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('221020400','Nale¿no¶ci dochodzone na drodze s±dowej','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('221020500','Inne nale¿no¶ci','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222000000','Zobowi±zania krótkoterminowe','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222010000','Zobowi±zania wobec jednostek powiazanych','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222010100','Zobowi±zania z tytu³u dostaw i us³ug','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222010200','Zobowi±zania o okresie wymagalno¶ci do 12 miesiêcy','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222010300','Zobowi±zania o okresie wymagalno¶ci powy¿ej 12 miesiêcy','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222010400','Inne zobowi±zania','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020000','Zobowi±zania wobec pozosta³ych jednostek','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020100','Kredyty i po¿yczki','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020200','Zobowi±zania z tytu³u emisji d³u¿nych papierów warto¶ciowych','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020300','Inne zobowi±zania finasowe','A','','L','AP_Amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020400','Zobowiazania z tytu³u dostaw i us³ug','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020500','Zobowi±zania o okresie wymagalno¶ci do 12 miesiêcy ','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020600','Zobowi±zania o okresie wymagalno¶ci powy¿ej 12 miesiêy','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020700','Zaliczki otrzmane na dostawy','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020800','Zobowi±zania wekslowe','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222020900','Zobowi±zania z tytu³u podatków, ce³, ubezpieczeñ i innych ¶wiadczeñ','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222021000','Zobowi±zania z tytu³u wynagrodzeñ','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('222021100','Inne zobowi±zania','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223000000','Rozrachunki publicznoprawne','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223010000','Rozrachunki z urzêdem skarbowym z tytu³u VAT','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223020000','Rozliczenie nale¿nego VAT','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223020100','Rozliczenie nale¿nego VAT-22%','A','','L','AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223020200','Rozliczenie nale¿nego VAT-7%','A','','L','AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223020300','Rozliczenie nale¿nego VAT-0%','A','','L','AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223030000','Rozliczenie naliczonego VAT','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223030100','Rozliczenie naliczonego VAT-22%','A','','L','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223030200','Rozliczenie naliczonego VAT-7%','A','','L','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223030300','Rozliczenie naliczonego VAT-0%','A','','L','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223040000','Korekty naliczonego VAT','A','','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223050000','Rozrachunki z Urzêdem Celnym','A','','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223060000','Rozrachunki z Urzêdem Skarbowym z tytu³u znaków akcyzy','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223070000','Rozrachunki z Urzêdem Skarbowym z tytu³u podatku akcyzowego','A','','L','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223080000','Rozliczenie znaków akcyzy','A','','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223090000','Rozrachunki z ZUS','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('223100000','Rozrachunki z Urzêdem Skarbowym z tytu³u podatku dochodowego od osób prawnych','A','','L','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('224000000','Rozrachunki z pracownikami','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('224010000','Rozrachunki z tytu³u wynagrodzeñ','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('224020000','Rozrachunki z tytu³u po¿yczek udzielonych pracownikom','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('224090000','Inne rozrachunki z pracownikami','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225000000','Zobowi±zania d³ugoterminowe','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225010000','Zobowi±zania wobec jednostek powi±zanych','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225010100','Zobowi±zania z tytu³u wyodrêbnienia sk³adników maj±tkowych','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225010200','Zobowi±zania z tytu³u podzia³u zysku','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225020000','Zobowi±zania wobec pozosta³ych jednostek','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225020100','Kredyty i po¿yczki otrzymane','A','','L','AR_amount:AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225020200','Kredyty i po¿yczki udzielone','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225020300','Zobowi±zania z tytu³u emisji d³u¿nych papierów warto¶ciowych','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225020400','Inne zobowi±zania kredytowe','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225020500','Inne zobowi±zania','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225030000','Rozrachunki z tytu³u wp³at na kapita³ zak³adowy','A','','L','AR_amount:APamount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225040000','Rozrachunki z tytu³u wk³adów niepieniê¿nych na kapita³ zak³adowy','A','','L','AR_amount:AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225050000','Rozrachunki z tytu³u podwy¿szenia kapita³u ze ¶rodków w³asnych spó³ki','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225060000','Rozrachunki z tytu³u umorzenia udzia³ów w³asnych','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225070000','Rozrachunki z tytu³u dywident','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225080000','Rozrachunki z tytu³u dop³at i zwrotu dop³at','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('225090000','Pozosta³e rozrachunki ze wspólnikami','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('229000000','Odpisy aktualizuj±ce rozrachunki','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('300000000','Materia³y i towary','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330000000','Rozliczenie zakupu','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330010000','Rozliczenie warto¶ci materia³ów i towarów w drodze','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330020000','Warto¶ci dostaw niefakturowanych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330030000','Przychody wszelkich dostaw i us³ug i ich rozliczanie','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330040000','Odhylenia cen ewidencyjnych od rzeczywistych cen nabycia lub zakupu','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330050000','Koszty zakupu zawarte w fakturach dostawców','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330060000','Op³aty manipulacyjne policzone przez Urz±d Celny','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330070000','Niedobory, szkody i nadwy¿ki w transporcie','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330080000','Znaki akcyzy wed³ug dokumentu SAD','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330090000','Reklamacje faktur dostawców','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('331000000','Materia³y','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('331010000','Materia³y w magazynach w³asnych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('331020000','Materia³y w magazynach obcych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('331030000','Materia³y w przerobie','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('333000000','Towary','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('333010000','Towary w magazynach w³asnych','A','','A','IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('333020000','Towary w magazynach obcych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('333030000','Towary w detalu','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('334000000','Odchylenia od cen ewidencyjnych materia³ów i towarów','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('334010000','Odpisy aktualizuj±ce warto¶æ materia³ów','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('334020000','Odpisy aktualizuj±ce warto¶æ towarów','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('400000000','Koszty wed³ug rodzajów i ich rozliczeñ','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440000000','Koszty wed³ug rodzajów','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440010000','Zu¿ycie materia³ów i energii','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440010100','Zu¿ycie materia³ów biurowych','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440020000','Us³ugi obce','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440020100','Us³ugi celne','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440020200','Us³ugi telekomunikacyjne','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440020300','Us³ugi pocztowe','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440020400','Us³ugi kurierskie i transportowe','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440020500','Analizy sanitarne','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440020600','Us³ugi graficzne i drukarskie','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440030000','Podatki i op³aty','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440030100','Op³aty i prowizje bankowe','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440030200','Op³aty s±dowe, prawnicze i notarialne','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440030300','Op³aty skarbowe','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440030400','Koncesje','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440040000','Wynagrodzenia za pracê','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('441000000','¦wiadczenia na rzecz pracowników','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('442000000','Amortyzacja','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('443000000','Pozosta³e','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('449000000','Rozliczenie kosztów','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('449010000','Nie podlegaj±ce rozliczeniu w czasie','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('449020000','Przypadaj±ce na przysz³e okresy','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('449030000','Koszty zgromadzone','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('449040000','Koszty nie wliczane do warto¶ci sprzeda¿y','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('500000000','Koszty wed³ug typów dzia³alno¶ci i ich rozliczenie','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('550000000','Koszty dzia³alno¶ci podstawowej-produkcyjnej','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('550010000','Rozliczone koszta dzia³alno¶ci','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('550020000','Koszty nie zakoñczonych d³ugotrwa³ych us³ug','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('550030000','Straty zwi±zane z wykonaniem d³ugotrwa³ych us³ug','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('552000000','Koszty dzia³alno¶ci podstawowej-handlowej','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('552010000','Koszty utrzymania punktów sprzeda¼y detalicznej','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('550200000','Koszty utrzymania hurtowni','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('552030000','Koszty sprzeda¿y wyrobów','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('552040000','Podatek akcyzowy','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('552050000','Op³aty celne','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('553000000','Koszty dzia³alno¶ci pomocniczej','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('553010000','¦wiadczenia us³ug transportowych','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('555000000','Koszty zarz±du','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('555010000','Koszty zarz±dzania jednostk±','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('555020000','¦wiadczenia us³ug na potrzeby reprezentacji i reklamy','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('558000000','Rozliczenie kosztów dzia³alno¶ci','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('600000000','Produkty i rozliczenia miêdzyokresowe','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('660000000','Pó³produkty i produkty w toku','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('661000000','Produkty gotowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('661010000','Wyroby gotowe','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('661020000','Wyroby poza jednostk±','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('662000000','Odchylenia od cen ewidencyjnych produktów','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('662010000','Odchylenia od cen evidencyjnych wyrobów gotowych','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('662020000','Odhylenia od cen evidencyjnych pó³fabrykatów','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('664000000','Rozliczenia miêdzyokresowe kosztów','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('664010000','Czynne rozliczenia miêdzyokresowe kosztów','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('664020000','Bierne rozliczenia miêdzyokresowe kosztów','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('665000000','Pozosta³e rozliczenia miêdzyokresowe','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('665010000','Czynne rozliczenia przysz³ych okresów','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('665020000','Bierne rozliczenia przysz³ych okresów','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('700000000','Przychody i koszty zwi±zane z ich osi±gniêciem','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770000000','Sprzeda¿ produktów','A','','I','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770010000','Sprzeda¿ produktów na kraj','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770020000','Sprzeda¿ produktów na eksport','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770030000','Sprzeda¿ us³ug na kraj','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770040000','Sprzeda¿ us³ug na eksport','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770100000','Koszty sprzedanych produktów','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770110000','Koszt w³asny sprzeda¿y produktów na kraj','A','','E','IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770120000','Koszt w³asny sprzeda¿y produktów na eksport','A','','E','IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770130000','Koszt w³asny sprzeda¿y us³ug na kraj','A','','E','IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770140000','Koszt w³asny sprzeda¿y us³ug na export','A','','E','IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773000000','Sprzeda¿ towarów','A','','I','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773010000','Sprzeda¿ hurtowa towarów','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773020000','Sprzeda¿ detaliczna towarów','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773030000','Sprzeda¿ wysy³kowa towarów','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773040000','Prowizja komisowa','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773100000','Warto¶æ sprzedanych towarów w cenach zakupu','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773110000','Warto¶æ sprzedanych towarów w sprzeda¿y hurtowej','A','','E','IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773120000','Warto¶æ sprzedanych towarów w sprzeda¿y detalicznej','A','','E','IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773130000','Warto¶æ sprzedanych towarów w sprzeda¿y wysy³kowej','A','','E','IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('773140000','Prowizja komisowa','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('774000000','Sprzeda¿ materia³ów','A','','I','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('774010000','Materia³y','A','','I','AP_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('774020000','Opakowania','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('774030000','Odpady','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('774100000','Warto¶æ sprzedanych materia³ów','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('774110000','Warto¶æ w cenach zakupu sprzedanych materia³ów','A','','E','IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('774120000','Warto¶æ w cenach zakupu sprzedanych opakowañ','A','','E','IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('774130000','Warto¶æ w cenach zakupu sprzedanych odpadów','A','','E','IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775000000','Przychody finansowe','A','','I','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775010000','Kwoty nale¿ne ze sprzeda¿y aktywów finansowych','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775020000','Kwoty nale¿ne z tytu³u dywident','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775030000','Otrzymane odsetki','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775040000','Przychody ze zbycia investycji','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775050000','Aktualizacja warto¶ci investycji-przychody','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775060000','Dodatnie ró¿nice kursu walut','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775070000','Pozosta³e przychody finansowe','A','','I','AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775100000','Koszty finansowe','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775110000','Warto¶æ sprzedanych investycji','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775120000','Odpisy z tytu³u utraty warto¶ci investycji-koszty','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775130000','Odsetki zap³acone','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775140000','Ujemne ró¿nice kursu walut','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('775190000','Pozosta³e koszty finansowe','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776000000','Pozosta³e przychody operacyjne','A','','I','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776010000','Przychody ze zbycia niefinansowych aktywów trwa³ych','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776020000','Otrzymane dotacje','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776030000','Przychody z us³ug socjalnych','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776040000','Przychody ze wzrostu warto¶ci niefinansowych aktywów trwa³ych','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776090000','Inne pozosta³e przychody operacyjne','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776100000','Pozosta³e koszty operacyjne','A','','E','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776110000','Warto¶æ sprzedanych niefinansowych aktywów trwa³ych','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776120000','Dotacje przekazane','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776130000','Odpisy z tytu³u utraty warto¶ci aktywów niefinansowych','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('776140000','Inne pozosta³e koszty operacyjne','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('777000000','Zyski nadzwyczajne','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('777100000','Straty nadzwyczajne','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779000000','Obroty wewnêtrzne','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779010000','Koszt wyrobów w³asnej produkcji wydanych do w³asnych sklepów','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779020000','¦wiadczenia na rzecz ¶rodków trwa³ych w budowie','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779040000','Koszt niedoborów produktów','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779050000','Koszt zaniechania okre¶lonego rodzaju dzia³alno¶ci','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779100000','Koszt obrotów wewnêtrznych','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779110000','Koszt wytworzenia wyrobów gotowych wydanych do w³asnych sklepów','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779120000','Koszt wytworzenia ¶wiadczeñ na rzecz ¶rodków trwa³ych w budowie','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779130000','Koszt wytworzenia zakoñczonych prac rozwojowych','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779140000','Koszt wytworzenia produktów uznanych za niedobory','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('779150000','Koszt zaniechania okre¶lonego rodzaju dzia³alno¶ci','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('800000000','Kapita³y w³asne i wynik finansowy','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('880000000','Kapita³ podstawowy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('880010000','Kapita³ zak³adowy','A','','Q','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('881000000','Fundusze wydzielone jednostkom zale¿nym','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('882000000','Nale¿ne wp³aty na kapita³ podstawowy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('883000000','Fundusze wydzielone jednostkom zale¿nym','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('884000000','Kapita³ zapasowy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('885000000','Kapita³ rezerwowy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('886000000','Kapita³ z aktualizacji wyceny','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('887000000','Rozliczenia wyniku finansowego','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('888000000','Rezerwy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('888010000','Rezerwa z tytu³u odroczonego podatku dochodowego','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('888020000','Rezerwa na ¶wiadczenia','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('888020100','Rezerwa d³ugoterminowa na ¶wiadczenia emerytalne i podobne','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('888020200','Rezerwa krótkoterminowa na ¶wiadczenia emerytalne i podobne','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('889090000','Pozosta³e rezerwy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('889090100','Pozosta³e rezerwy d³ugoterminowe','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('889090200','Pozosta³e rezerwy krótkoterminowe','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('890000000','Rozliczenia miêdzyokresowe','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('890010000','Ujemna warto¶æ firmy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('890020000','Inne rozliczenia miêdzyokresowe','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('890020100','Inne rozliczenia miêdzyokresowe d³ugoterminowe','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('890020200','Inne rozliczenia miêdzyokresowe krótkoterminowe','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('891000000','Fundusze specjalne','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('892000000','Wynik finansowy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('893000000','Odpisy z zysku netto w ci±gu roku obrotowego','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('893010000','Podatek dochodowy','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('893020000','Inne obowi±zkowe obci±¿enia wyniku finansowego','A','','Q','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '223020100'),0.22);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '223020200'),0.07);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '223020300'),0);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '223030100'),0.22);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '223030200'),0.07);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '223030300'),0);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '333000000'), income_accno_id = (select id from chart where accno = '773010000'), expense_accno_id = (select id from chart where accno = '773110000'), fxgain_accno_id = (select id from chart where accno = '775060000'), fxloss_accno_id = (select id from chart where accno = '775140000'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'PLN:USD:EUR', weightunit = 'kg';
+--
+
+
diff --git a/sql-ledger/sql/Simplified_Chinese_Default-chart.sql b/sql-ledger/sql/Simplified_Chinese_Default-chart.sql
new file mode 100644
index 0000000..680adb8
--- /dev/null
+++ b/sql-ledger/sql/Simplified_Chinese_Default-chart.sql
@@ -0,0 +1,78 @@
+-- Default chart of accounts -- sample only
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2190','Ó¦¸¶ËùµÃË°','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2600','³¤ÆÚ¸ºÕ®','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3300','¹É·Ý×ʱ¾','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3500','±£ÁôÓ¯âÅ','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4000','ÏúÊÛÓ¯âÅ','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4300','ÚÑѯӯâÅ','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4400','ÆäËüÓ¯âÅ','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5000','»õÏú³É±¾','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5400','н×ÊÖ§³ö','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5600','ÈÕ³£¼°¹ÜÀíÖ§³ö','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1205','´ôÕʱ¸µÖ','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1000','Á÷¶¯×ʲú','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800','×ʱ¾×ʲú','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1825','ÀۼƷÖÆÚ¸¶¿î - װ諼°É豸.','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1845','ÀۼƷÖÆÚ¸¶¿î - ÔËÊ乤¾ß','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000','Á÷¶¯¸ºÕ®','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2620','ÒøÐнè¿î','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3600','Á÷¶¯Ó¯âÅ','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2160','Ó¦¸¶¹«Ë¾Ë°','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3590','±£ÁôÓ¯âÅ - È¥Äê¶È','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3350','ÆÕͨ¹É·Ý','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1500','´æ»õ×ʲú','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5615','¹ã¸æÐÐÏú','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5790','¹¤¾ß','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5700','°ì¹«ÓÃÆ·','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5800','ȨÀû½ð','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5610','»á¼Æ·¨Îñ','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5685','±£ÏÕ','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5660','·ÖÆÚÖ§³ö','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5620','»µÕÊ','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5680','ËùµÃË°','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5690','ÀûÏ¢¼°ÒøÐÐÊÖÐø·Ñ','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5410','н×Ê','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5420','±£ÏÕÖ§³ö','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5430','ÍËÐݽðÖ§³ö','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5440','²¹³¥½ðÖ§³ö','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5470','Ô±¹¤¸£Àû','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4030','ÏúÊÛ / ÈíÌå','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4440','ÀûÏ¢','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5100','ÔË·Ñ','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5760','×â½ð','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1530','¿â´æ / ÈíÌå','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1540','¿â´æ / ¶þ¼¶Êг¡Áã¼þ','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4040','ÏúÊÛ / ¶þ¼¶Êг¡Áã¼þ','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5030','»õÏú³É±¾ / ÈíÌå','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5010','²É¹º','A','','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5040','»õÏú³É±¾ / ¶þ¼¶Êг¡Áã¼þ','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1065','ÁãÓýð','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1820','°ì¹«ÊÒװ諼°É豸','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5785','Â÷Ѽ°ÓéÀÖ','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2680','¹É¶«´û¿î','A','','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5795','×¢²á·Ñ','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5780','µçÐÅ·Ñ','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5781','Íø·Á¬Ïß·Ñ','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5765','άÐÞ¹ÜÀí·Ñ','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2311','µØ·½Ë°','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4430','ÔËÏú·Ñ','A','','I','IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1520','¿â´æ / Ó²Ìå','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5020','»õÏú³É±¾ / Ó²Ìå','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2100','Ó¦¸¶ÕÊ¿î','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1840','ÔËÊ乤¾ß','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4330','³ÌʽÉè¼Æ','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4020','ÏúÊÛ / Ó²Ìå','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4320','ÚÑѯ','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200','Ó¦ÊÕÕÊ¿î','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1061','֧Ʊ»§Í·','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2310','ÉÌÆ··þÎñË°','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+--
+-- exchange rate
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4450','Foreign Exchange Gain','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5810','Foreign Exchange Loss','A','','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2310'),0.07);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2311'),0.08);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '5010'), fxgain_accno_id = (select id from chart where accno = '4450'), fxloss_accno_id = (select id from chart where accno = '5810'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'CAD', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Spain-chart.sql b/sql-ledger/sql/Spain-chart.sql
new file mode 100644
index 0000000..8c304a8
--- /dev/null
+++ b/sql-ledger/sql/Spain-chart.sql
@@ -0,0 +1,132 @@
+-- Chart of Accounts for Spain (Cuadro del Plan de Contabilidad español)
+-- From: Federico Montesino Pouzols <fedemp@arrok.com>
+-- 23 Apr 2002
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('099999999','Grupo 1: financiación básica','H','','','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('100000000','Capital','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('110000000','Reservas','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('120000000','Resultados pendientes de aplicación','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('130000000','Ingresos a distribuir en varios ejercicios','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('140000000','Provisiones para riesgos y gastos','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('150000000','Empréstitos y otras emisiones análogas','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('160000000','Deudas a largo plazo con empresas del grupo y asociadas','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('170000000','Deudas a largo plazo por prestamos recibidos y otros conceptos','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('180000000','Fianzas y depósitos recibidos a largo plazo','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('190000000','Situaciones transitorias de financiación','A','','A','');
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('199999999','Grupo 2: inmovilizado','H','','','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('200000000','Gastos de establecimiento','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('210000000','Inmovilizaciones inmateriales','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('220000000','Inmovilizaciones materiales','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('230000000','Inmovilizaciones materiales en curso','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('240000000','Inversiones financieras en empresas del grupo y asociadas','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('250000000','Otras inversiones financieras permanentes','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('260000000','Fianzas y depósitos constituidos a largo plazo','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('270000000','Gastos a distribuir en varios ejercicios','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('280000000','Amortización acumulada del inmovilizado','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('290000000','Provisiones de inmovilizado','A','','A','');
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('299999999','Grupo 3: existencias','H','','','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('300000000','Comerciales','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('310000000','Materias primas','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('320000000','Otros aprovisionamientos','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('330000000','Productos en curso','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('340000000','Productos semiterminados','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('350000000','Productos terminados','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('360000000','Subproductos, residuos y materiales recuperados','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('390000000','Provisiones por depreciación de existencias','A','','A','');
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('399999999','Grupo 4: acreedores y deudores por operaciones de tráfico','H','','','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('400000000','Proveedores','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('410000000','Acreedores varios','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('430000000','Clientes','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('431000000','Clientes, efectos comerciales a cobrar','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('440000000','Deudores varios','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('460000000','Personal','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('470000000','Administraciones públicas','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('472000000','Hacienda Pública, IVA soportado','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('472000001','IVA soportado 4%','A','','P','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('472000002','IVA soportado 7%','A','','P','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('472000003','IVA soportado 16%','A','','P','AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('475100000','Hacienda Pública, acreedor por retenciones practicadas','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('473000000','Hacienda Pública, retenciones y pagos a cuenta','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('477000000','Hacienda Pública, IVA repercutido','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('477000001','IVA repercutido 4%','A','','P','AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('477000002','IVA repercutido 7%','A','','P','AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('477000003','IVA repercutido 16%','A','','P','AR_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('480000000','Ajustes por periodificación','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('490000000','Provisiones por operaciones de tráfico','A','','P','');
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('499999999','Grupo 5: cuentas financieras','H','','','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('500000000','Empréstitos y otras emisiones análogas a corto plazo','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('510000000','Deudas a corto plazo con empresas del grupo y asociadas','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('520000000','Deudas a corto plazo por préstamos recibidos y otros conceptos','A','','P','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('530000000','Inversiones financieras a corto plazo en empresas del grupo y asociadas','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('540000000','Otras inversiones financieras temporales','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('550000000','Otras cuentas no bancarias','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('560000000','Fianzas y depósitos recibidos y constituidos a corto plazo','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('569000000','Tesorería','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('570000000','Caja, euros','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('571000000','Caja, moneda extranjera','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('572000000','Bancos e instituciones de crédito, c/c. vista, euros','A','','A','AR_paid:AP_paid:AP_amount:AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('573000000','Bancos e instituciones de crédito, c/c. vista, moneda extranjera','A','','A','AR_paid:AP_paid:AP_amount:AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('574000000','Bancos e instituciones de crédito, cuentas de ahorro, euros','A','','A','AR_paid:AP_paid:AP_amount:AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('575000000','Bancos e instituciones de crédito, cuentas de ahorro, moneda extranjera','A','','A','AR_paid:AP_paid:AP_amount:AR_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('580000000','Ajustes por periodificación','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('590000000','Provisiones financieras','A','','P','');
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('599999999','Grupo 6: compras y gastos','H','','','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('600000000','Compras','A','','E','AP:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('608000000','Devoluciones de compras y operaciones similares','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('610000000','Variación de existencias','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('620000000','Servicios exteriores','A','','E','IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('630000000','Tributos','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('640000000','Gastos de personal','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('650000000','Otros gastos de gestión','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('660000000','Gastos financieros','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('665000000','Descuentos sobre ventas por pronto pago','A','','E','IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('668000000','Diferencias negativas de cambio','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('670000000','Pérdidas procedentes del inmovilizado y gastos excepcionales','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('680000000','Dotaciones para amortizaciones','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('690000000','Dotaciones a las provisiones','A','','E','');
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('699999999','Grupo 7: ventas e ingresos','H','','','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('700000000','Ventas de mercaderías, de producción propia, de servicios, etc.','A','','I','AR:IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('708000000','Devoluciones de ventas y operaciones similares','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('710000000','Variación de existencias','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('730000000','Trabajos realizados para la empresa','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('740000000','Subvenciones a la explotación','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('750000000','Otros ingresos de gestión','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('760000000','Ingresos financieros','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('765000000','Descuentos sobre compras por pronto pago','A','','I','IC_sale:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('768000000','Diferencias positivas de cambio','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('770000000','Beneficios procedentes de inmovilizados e ingresos excepcionales','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('790000000','Excesos y aplicaciones de provisiones','A','','I','');
+--
+-- Taxes in Spain
+--
+-- IVA: 4, 7 or 16%
+-- IVA soportado
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '472000000'), 0.0);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '472000001'), 0.04);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '472000002'), 0.07);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '472000003'), 0.16);
+-- Recargo equivalente: 0.5, 1 or 4%
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '472000004'), 0.005);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '472000005'), 0.01);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '472000006'), 0.04);
+--
+-- IVA repercutido
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '477000000'), 0.0);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '477000001'), 0.04);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '477000002'), 0.07);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '477000003'), 0.16);
+-- Recargo equivalente: 0.5, 1 or 4%
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '477000004'), 0.005);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '477000005'), 0.01);
+INSERT INTO "tax" ("chart_id", "rate") VALUES ((SELECT id FROM chart WHERE accno = '477000006'), 0.04);
+--
+-- update defaults
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '300000000'), income_accno_id = (select id from chart where accno = '700000000'), expense_accno_id = (select id from chart where accno = '600000000'), fxgain_accno_id = (select id from chart where accno = '768000000'), fxloss_accno_id = (select id from chart where accno = '668000000'), invnumber = 'F00000000', sonumber = '100000000', ponumber = '100000000', yearend = '31/12', curr = 'EUR', weightunit = 'Kg', businessnumber = '';
+--
diff --git a/sql-ledger/sql/Swiss-German-chart.sql b/sql-ledger/sql/Swiss-German-chart.sql
new file mode 100644
index 0000000..75959ef
--- /dev/null
+++ b/sql-ledger/sql/Swiss-German-chart.sql
@@ -0,0 +1,160 @@
+-- Swiss chart of accounts
+-- adapted to numeric representation of chart no.
+--
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('10000','AKTIVEN','H','1','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11000','UMLAUFSVERMÖGEN','H','10000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11100','Flüssige Mittel','H','11000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11102','Bank CS Kt. 177929-11','A','11100','A','AR_paid:AP_paid');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11110','Forderungen','H','11000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11120','Vorräte und angefangene Arbeiten','H','11000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11128','Angefangene Arbeiten','A','11120','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11130','Aktive Rechnungsabgrenzung','A','11000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('14000','ANLAGEVERMÖGEN','H','10000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('18000','AKTIVIERTER AUFWAND UND AKTIVE BERICHTIGUNGSPOSTEN','H','10000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('18182','Entwicklungsaufwand','A','18000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('20000','PASSIVEN','H','2','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21000','FREMDKAPITAL KURZFRISTIG','H','20000','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21200','Kurzfristige Verbindlichkeiten aus Lieferungen und Leistungen','H','21000','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21201','Lieferanten','A','21200','L','AP');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21202','Personalaufwand','A','21200','L','AP');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21203','Sozialversicherungen','A','21200','L','AP');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21205','Leasing','A','21200','L','AP');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21210','Kurzfristige Finanzverbindlichkeiten','H','21000','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21220','Andere kurzfristige Verbindlichkeiten','H','21000','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21222','MWST (3,6)','A','21220','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21229','Gewinnausschüttung','A','21220','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21230','Passive Rechnungsabgrenzung, kurzfristige Rückstellungen','H','21000','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21235','Rückstellungen','A','21230','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('24000','FREMDKAPITAL LANGFRISTIG','H','20000','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('24256','Gesellschafter','A','24000','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('28000','EIGENKAPITAL','H','20000','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('28280','Stammkapital','A','28000','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('28290','Reserven, Bilanzgewinn','H','28000','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('28291','Reserven','A','28290','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('28295','Gewinnvortrag','A','28290','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('28296','Jahresgewinn','A','28290','Q','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('30000','BETRIEBSERTRAG AUS LIEFERUNGEN UND LEISTUNGEN','H','30000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('31000','PRODUKTIONSERTRAG','H','30000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('31001','Computer','A','31000','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('31005','Übrige Produkte','A','31000','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('32000','HANDELSERTRAG','H','30000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('32001','Hardware','A','32000','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('32002','Software OSS','A','32000','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('32003','Software kommerz.','A','32000','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('32005','Übrige','A','32000','I','AR_amount:IC_sale');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('34000','DIENSTLEISTUNGSERTRAG','H','30000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('34001','Beratung','A','34000','I','AR_amount:IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('34002','Installation','A','34000','I','AR_amount:IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('36000','ÜBRIGER ERTRAG','H','30000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('37000','EIGENLEISTUNGEN UND EIGENVERBRAUCH','H','30000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('37001','Eigenleistungen','A','37000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('37002','Eigenverbrauch','A','37000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('38000','BESTANDESÄNDERUNGEN ANGEFANGENE UND FERTIGGESTELLTE ARBEITUNG AUS PRODUKTION UND DIENSTLEISTUNG','H','30000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('38001','Bestandesänderungen','A','38000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('39000','ERTRAGSMINDERUNGEN AUS PRODUKTIONS-, HANDELS- UND DIENSTLEISTUNGSERTRÄGEN','H','30000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('40000','AUFWAND FÜR MATERIAL, WAREN UND DIENSTLEISTUNGEN','H','40000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('41000','MATERIALAUFWAND','H','40000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('41001','Computer','A','41000','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('41005','Übrige Produkte','A','41000','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('42000','HANDELSWARENAUFWAND','H','40000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('42001','Hardware','A','42000','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('42002','Software OSS','A','32000','I','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('42003','Software kommerz.','A','42000','I','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('42005','Übrige','A','42000','E','AP_amount:IC_cogs');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('44000','AUFWAND FÜR DRITTLEISTUNGEN','H','40000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('46000','ÜBRIGER AUFWAND','H','40000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('47000','DIREKTE EINKAUFSSPESEN','H','40000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('47001','Einkaufsspesen','A','47000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('48000','BESTANDESVERÄNDERUNGEN, MATERIAL- UND WARENVERLUSTE','H','40000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('48001','Bestandesänderungen','A','48000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('49000','AUFWANDMINDERUNGEN','H','40000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('49005','Aufwandminderungen','A','49000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('50000','PERSONALAUFWAND','H','50000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('57000','SOZIALVERSICHERUNGSAUFWAND','H','50000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('58000','ÜBRIGER PERSONALAUFWAND','H','58000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('58005','Sonstiger Personalaufwand','A','58000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('59000','ARBEITSLEISTUNGEN DRITTER','H','50000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('60000','SONSTIGER BETRIEBSAUFWAND','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('61000','RAUMAUFWAND','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('61900','UNTERHALT, REPARATUREN, ERSATZ, LEASINGAUFWAND MOBILE SACHANLAGEN','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('61901','Unterhalt','A','61900','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('62000','FAHRZEUG- UND TRANSPORTAUFWAND','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('62002','Transportaufwand','A','62000','E','AP_amount');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('63000','SACHVERSICHERUNGEN, ABGABEN, GEBÜHREN, BEWILLIGUNGEN','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('65000','VERWALTUNGS- UND INFORMATIKAUFWAND','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('66000','WERBEAUFWAND','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('67000','ÜBRIGER BETRIEBSAUFWAND','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('67001','Übriger Betriebsaufwand','A','67000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('68000','FINANZERFOLG','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('68001','Finanzaufwand','A','68000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('68002','Bankspesen','A','68000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('68005','Finanzertrag','A','68000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('69000','ABSCHREIBUNGEN','H','60000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('69001','Abschreibungen','A','69000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('80000','AUSSERORDENTLICHER UND BETRIEBSFREMDER ERFOLG, STEUERN','H','80000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('80001','Ausserordentlicher Ertrag','A','80000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('80002','Ausserordentlicher Aufwand','A','80000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('89000','STEUERAUFWAND','H','80000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('89001','Steuern','A','80000','E','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('90000','ABSCHLUSS','H','90000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('91000','ERFOLGSRECHNUNG','H','91000','I','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('92000','BILANZ','H','92000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('93000','GEWINNVERWENDUNG','H','93000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('99000','SAMMEL- UND FEHLBUCHUNGEN','H','99000','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11121','Warenvorräte','A','11120','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('44001','Aufwand für Drittleistungen','A','44000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('63001','Betriebsversicherungen','A','63000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('57004','Unfallversicherung','A','57000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('57005','Krankentaggeldversicherung','A','57000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('57003','Berufliche Vorsorge','A','57000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('57002','FAK','A','57000','E','AP_amount:IC_income:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('65009','Übriger Verwaltungsaufwand','A','65000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('65003','Porti','A','65000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('65002','Telekomm','A','65000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('65001','Büromaterial','A','65000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('18181','Gründungsaufwand','A','18000','A','IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('50001','Löhne und Gehälter','A','50000','E','IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('50002','Erfolgsbeteiligungen','A','50000','E','IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21216','Gesellschafter','A','21210','L','AP');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('62001','Fahrzeugaufwand','A','62000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('58003','Spesen','A','58000','E','IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('65004','Fachliteratur','A','65000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('39001','Skonti','A','39000','I','IC_sale:IC_cogs:IC_income:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('39002','Rabatte, Preisnachlässe','A','39000','I','IC_sale:IC_cogs:IC_income:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('36005','Kursgewinn','A','39000','I','IC_sale:IC_cogs:IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('39006','Kursverlust','A','39000','E','IC_sale:IC_cogs:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('39005','Verluste aus Forderungen','A','39000','E','IC_sale:IC_cogs:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('14151','Mobiliar und Einrichtungen','A','14150','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('14152','Büromaschinen, EDV','A','14150','A','IC');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11119','Verrechnungssteuer','A','11110','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11118','MWST Vorsteuer auf Investitionen','A','11110','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('36004','Versand','A','36000','I','IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('36001','Reisezeit','A','36000','I','IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('36002','Reise (Fahrt)','A','36000','I','IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11117','MWST Vorsteuer auf Aufwand','A','11110','A','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21228','Geschuldete Steuern','A','21220','L','AP');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21223','MWST (7,6)','A','21220','L','AR_tax:AP_tax:IC_taxpart:IC_expense:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('57001','AHV, IV, EO, ALV','A','57000','E','AP_amount:IC_income:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21221','MWST (2,4)','A','21220','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21224','MWST (7.6) 1/2','A','21220','L','AR_tax:AP_tax:IC_taxpart:IC_expense:IC_taxservice:CT_tax');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('66001','Werbeaufwand','A','66000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21217','Privat','A','21210','L','AP');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11101','Kasse','A','11100','A','AR_paid:AP_paid');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('50005','Leistungen von Sozialversicherung','A','50000','E','AP_amount:IC_income:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('65005','Informatikaufwand','A','65000','E','AP_amount:IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('39004','Rundungsdifferenzen','A','39000','I','AR_paid:AP_paid');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('11111','Debitoren','A','11110','A','AR');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('61001','Miete','A','61000','E','IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('61002','Reinigung','A','61000','E','IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('61005','Übriger Raumaufwand','A','61000','E','IC_expense');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('36003','Essen','A','36000','I','IC_income');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('21231','Passive Rechnungsabgrenzung','A','21230','L','');
+INSERT INTO chart (accno,description,charttype,gifi_accno,category,link) VALUES ('67002','Produkteentwicklung','A','67000','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '21222'),0.036);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '21223'),0.076);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '21221'),0.024);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '21224'),0.076);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '11121'), income_accno_id = (select id from chart where accno = '34002'), expense_accno_id = (select id from chart where accno = '42005'), fxgain_accno_id = (select id from chart where accno = '36005'), fxloss_accno_id = (select id from chart where accno = '39006'), invnumber = '2002000', sonumber = '2002000', ponumber = '2002000', curr = 'EUR:USD', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/Swiss-German-gifi.sql b/sql-ledger/sql/Swiss-German-gifi.sql
new file mode 100644
index 0000000..ecd526d
--- /dev/null
+++ b/sql-ledger/sql/Swiss-German-gifi.sql
@@ -0,0 +1,55 @@
+--
+INSERT INTO gifi (accno,description) VALUES ('1','AKTIVEN');
+INSERT INTO gifi (accno,description) VALUES ('2','PASSIVEN');
+INSERT INTO gifi (accno,description) VALUES ('4','AUFWAND FÜR MATERIAL, WAREN UND DIENSTLEISTUNGEN');
+INSERT INTO gifi (accno,description) VALUES ('5','PERSONALAUFWAND');
+INSERT INTO gifi (accno,description) VALUES ('10000','ANLAGEVERMÖGEN');
+INSERT INTO gifi (accno,description) VALUES ('11000','Forderungen');
+INSERT INTO gifi (accno,description) VALUES ('11100','Bank');
+INSERT INTO gifi (accno,description) VALUES ('11110','MWST Vorsteuer auf Investitionen');
+INSERT INTO gifi (accno,description) VALUES ('11120','Angefangene Arbeiten');
+INSERT INTO gifi (accno,description) VALUES ('14150','Büromaschinen, EDV');
+INSERT INTO gifi (accno,description) VALUES ('18000','Gründungsaufwand');
+INSERT INTO gifi (accno,description) VALUES ('20000','FREMDKAPITAL LANGFRISTIG');
+INSERT INTO gifi (accno,description) VALUES ('21000','Kurzfristige Finanzverbindlichkeiten');
+INSERT INTO gifi (accno,description) VALUES ('21200','Sozialversicherungen');
+INSERT INTO gifi (accno,description) VALUES ('21210','Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('21220','MWST (3,6)');
+INSERT INTO gifi (accno,description) VALUES ('21230','Passive Rechnungsabgrenzung');
+INSERT INTO gifi (accno,description) VALUES ('24000','Gesellschafter');
+INSERT INTO gifi (accno,description) VALUES ('28000','Stammkapital');
+INSERT INTO gifi (accno,description) VALUES ('28290','Gewinnvortrag');
+INSERT INTO gifi (accno,description) VALUES ('30000','ÜBRIGER ERTRAG');
+INSERT INTO gifi (accno,description) VALUES ('31000','Computer');
+INSERT INTO gifi (accno,description) VALUES ('32000','Software kommerz.');
+INSERT INTO gifi (accno,description) VALUES ('34000','Beratung');
+INSERT INTO gifi (accno,description) VALUES ('36000','Essen');
+INSERT INTO gifi (accno,description) VALUES ('37000','Eigenleistungen');
+INSERT INTO gifi (accno,description) VALUES ('38000','Bestandesänderungen');
+INSERT INTO gifi (accno,description) VALUES ('39000','Rabatte, Preisnachlässe');
+INSERT INTO gifi (accno,description) VALUES ('40000','AUFWANDMINDERUNGEN');
+INSERT INTO gifi (accno,description) VALUES ('41000','Übrige Produkte');
+INSERT INTO gifi (accno,description) VALUES ('42000','Software kommerz.');
+INSERT INTO gifi (accno,description) VALUES ('44000','Aufwand für Drittleistungen');
+INSERT INTO gifi (accno,description) VALUES ('47000','Einkaufsspesen');
+INSERT INTO gifi (accno,description) VALUES ('48000','Bestandesänderungen');
+INSERT INTO gifi (accno,description) VALUES ('49000','Aufwandminderungen');
+INSERT INTO gifi (accno,description) VALUES ('50000','Löhne und Gehälter');
+INSERT INTO gifi (accno,description) VALUES ('57000','FAK');
+INSERT INTO gifi (accno,description) VALUES ('58000','Spesen');
+INSERT INTO gifi (accno,description) VALUES ('60000','VERWALTUNGS- UND INFORMATIKAUFWAND');
+INSERT INTO gifi (accno,description) VALUES ('61000','Reinigung');
+INSERT INTO gifi (accno,description) VALUES ('61900','Unterhalt');
+INSERT INTO gifi (accno,description) VALUES ('62000','Fahrzeugaufwand');
+INSERT INTO gifi (accno,description) VALUES ('63000','Betriebsversicherungen');
+INSERT INTO gifi (accno,description) VALUES ('65000','Übriger Verwaltungsaufwand');
+INSERT INTO gifi (accno,description) VALUES ('66000','Werbeaufwand');
+INSERT INTO gifi (accno,description) VALUES ('67000','Produkteentwicklung');
+INSERT INTO gifi (accno,description) VALUES ('68000','Finanzaufwand');
+INSERT INTO gifi (accno,description) VALUES ('69000','Abschreibungen');
+INSERT INTO gifi (accno,description) VALUES ('80000','AUSSERORDENTLICHER UND BETRIEBSFREMDER ERFOLG, STEUERN');
+INSERT INTO gifi (accno,description) VALUES ('90000','ABSCHLUSS');
+INSERT INTO gifi (accno,description) VALUES ('91000','ERFOLGSRECHNUNG');
+INSERT INTO gifi (accno,description) VALUES ('92000','BILANZ');
+INSERT INTO gifi (accno,description) VALUES ('93000','GEWINNVERWENDUNG');
+INSERT INTO gifi (accno,description) VALUES ('99000','SAMMEL- UND FEHLBUCHUNGEN');
diff --git a/sql-ledger/sql/Traditional_Chinese_Default-chart.sql b/sql-ledger/sql/Traditional_Chinese_Default-chart.sql
new file mode 100644
index 0000000..68ebeac
--- /dev/null
+++ b/sql-ledger/sql/Traditional_Chinese_Default-chart.sql
@@ -0,0 +1,78 @@
+-- Default chart of accounts -- sample only
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2190','À³¥I©Ò±oµ|','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2600','ªø´Á­t¶Å','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3300','ªÑ¥÷¸ê¥»','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3500','«O¯d¬Õ¾l','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4000','¾P°â¬Õ¾l','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4300','¿Ô¸ß¬Õ¾l','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4400','¨ä¥¦¬Õ¾l','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5000','³f¾P¦¨¥»','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5400','Á~¸ê¤ä¥X','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5600','¤é±`¤ÎºÞ²z¤ä¥X','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1205','§b±b³Æ©è','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1000','¬y°Ê¸ê²£','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800','¸ê¥»¸ê²£','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1825','²Ö­p¤À´Á¥I´Ú - ¸Ë¿X¤Î³]³Æ.','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1845','²Ö­p¤À´Á¥I´Ú - ¹B¿é¤u¨ã','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000','¬y°Ê­t¶Å','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2620','»È¦æ­É´Ú','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3600','¬y°Ê¬Õ¾l','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2160','À³¥I¤½¥qµ|','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3590','«O¯d¬Õ¾l - ¥h¦~«×','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3350','´¶³qªÑ¥÷','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1500','¦s³f¸ê²£','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5615','¼s§i¦æ¾P','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5790','¤u¨ã','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5700','¿ì¤½¥Î«~','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5800','Åv§Qª÷','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5610','·|­pªk°È','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5685','«OÀI','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5660','¤À´Á¤ä¥X','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5620','Ãa±b','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5680','©Ò±oµ|','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5690','§Q®§¤Î»È¦æ¤âÄò¶O','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5410','Á~¸ê','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5420','«OÀI¤ä¥X','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5430','°h¥ðª÷¤ä¥X','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5440','¸ÉÀvª÷¤ä¥X','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5470','­û¤uºÖ§Q','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4030','¾P°â / ³nÅé','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4440','§Q®§','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5100','¹B¶O','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5760','¯²ª÷','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1530','®w¦s / ³nÅé','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1540','®w¦s / ¤G¯Å¥«³õ¹s¥ó','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4040','¾P°â / ¤G¯Å¥«³õ¹s¥ó','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5030','³f¾P¦¨¥» / ³nÅé','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5010','±ÄÁÊ','A','','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5040','³f¾P¦¨¥» / ¤G¯Å¥«³õ¹s¥ó','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1065','¹s¥Îª÷','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1820','¿ì¤½«Ç¸Ë¿X¤Î³]³Æ','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5785','®È¶O¤Î®T¼Ö','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2680','ªÑªF¶U´Ú','A','','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5795','µù¥U¶O','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5780','¹q«H¶O','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5781','ºô¸ô³s½u¶O','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5765','ºû­×ºÞ²z¶O','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2311','¦a¤èµ|','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4430','¹B¾P¶O','A','','I','IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1520','®w¦s / µwÅé','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5020','³f¾P¦¨¥» / µwÅé','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2100','À³¥I±b´Ú','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1840','¹B¿é¤u¨ã','A','','A','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4330','µ{¦¡³]­p','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4020','¾P°â / µwÅé','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4320','¿Ô¸ß','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200','À³¦¬±b´Ú','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1061','¤ä²¼¤áÀY','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2310','°Ó«~ªA°Èµ|','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+--
+-- exchange rate
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4450','Foreign Exchange Gain','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5810','Foreign Exchange Loss','A','','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2310'),0.07);
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2311'),0.08);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '5010'), fxgain_accno_id = (select id from chart where accno = '4450'), fxloss_accno_id = (select id from chart where accno = '5810'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'USD', weightunit = 'kg';
+--
diff --git a/sql-ledger/sql/US_General-chart.sql b/sql-ledger/sql/US_General-chart.sql
new file mode 100644
index 0000000..4506a71
--- /dev/null
+++ b/sql-ledger/sql/US_General-chart.sql
@@ -0,0 +1,98 @@
+-- US_General COA
+-- modify as needed
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1000','CURRENT ASSETS','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1060','Checking Account','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1065','Petty Cash','A','','A','AR_paid:AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1200','Accounts Receivables','A','','A','AR');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1205','Allowance for doubtful accounts','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1500','INVENTORY ASSETS','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1520','Inventory / Hardware','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1530','Inventory / Software','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1540','Inventory / Aftermarket Parts','A','','A','IC');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1800','CAPITAL ASSETS','H','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1820','Office Furniture & Equipment','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1825','Accum. Amort. -Furn. & Equip.','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1840','Vehicle','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('1845','Accum. Amort. -Vehicle','A','','A','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2000','CURRENT LIABILITIES','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2100','Accounts Payable','A','','L','AP');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2600','LONG TERM LIABILITIES','H','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2620','Bank Loans','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2680','Loans from Shareholders','A','','L','AP_paid');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3300','SHARE CAPITAL','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3350','Common Shares','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3500','RETAINED EARNINGS','H','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3590','Retained Earnings - prior years','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('3600','Current Earnings','A','','Q','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4000','SALES REVENUE','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4020','Sales / Hardware','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4030','Sales / Software','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4040','Sales / Aftermarket Parts','A','','I','AR_amount:IC_sale');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4300','CONSULTING REVENUE','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4320','Consulting','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4330','Programming','A','','I','AR_amount:IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4400','OTHER REVENUE','H','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4430','Shipping & Handling','A','','I','IC_income');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4440','Interest','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('4450','Foreign Exchange Gain','A','','I','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5000','COST OF GOODS SOLD','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5010','Purchases','A','','E','AP_amount:IC_cogs:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5020','COGS / Hardware','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5030','COGS / Software','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5040','COGS / Aftermarket Parts','A','','E','AP_amount:IC_cogs');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5100','Freight','A','','E','AP_amount:IC_expense');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5400','PAYROLL EXPENSES','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5410','Wages & Salaries','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5600','GENERAL & ADMINISTRATIVE EXPENSES','H','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5610','Accounting & Legal','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5615','Advertising & Promotions','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5620','Bad Debts','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5660','Amortization Expense','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5685','Insurance','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5690','Interest & Bank Charges','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5700','Office Supplies','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5760','Rent','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5765','Repair & Maintenance','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5780','Telephone','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5785','Travel & Entertainment','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5790','Utilities','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5795','Registrations','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5800','Licenses','A','','E','AP_amount');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5810','Foreign Exchange Loss','A','','E','');
+--
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2110','Accrued Income Tax - Federal','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2120','Accrued Income Tax - State','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2130','Accrued Franchise Tax','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2140','Accrued Real & Personal Prop Tax','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2150','Sales Tax','A','','L','AR_tax:AP_tax:IC_taxpart:IC_taxservice:CT_tax');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2160','Accrued Use Tax Payable','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2210','Accrued Wages','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2220','Accrued Comp Time','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2230','Accrued Holiday Pay','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2240','Accrued Vacation Pay','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2310','Accr. Benefits - 401K','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2320','Accr. Benefits - Stock Purchase','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2330','Accr. Benefits - Med, Den','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2340','Accr. Benefits - Payroll Taxes','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2350','Accr. Benefits - Credit Union','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2360','Accr. Benefits - Savings Bond','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2370','Accr. Benefits - Garnish','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('2380','Accr. Benefits - Charity Cont.','A','','L','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5420','Wages - Overtime','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5430','Benefits - Comp Time','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5440','Benefits - Payroll Taxes','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5450','Benefits - Workers Comp','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5460','Benefits - Pension','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5470','Benefits - General Benefits','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5510','Inc Tax Exp - Federal','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5520','Inc Tax Exp - State','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5530','Taxes - Real Estate','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5540','Taxes - Personal Property','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5550','Taxes - Franchise','A','','E','');
+insert into chart (accno,description,charttype,gifi_accno,category,link) values ('5560','Taxes - Foreign Withholding','A','','E','');
+--
+insert into tax (chart_id,rate) values ((select id from chart where accno = '2150'),0.05);
+--
+update defaults set inventory_accno_id = (select id from chart where accno = '1520'), income_accno_id = (select id from chart where accno = '4020'), expense_accno_id = (select id from chart where accno = '5020'), fxgain_accno_id = (select id from chart where accno = '4450'), fxloss_accno_id = (select id from chart where accno = '5810'), invnumber = '1000', sonumber = '1000', ponumber = '1000', curr = 'USD:CAD:EUR', weightunit = 'lbs';
+--
diff --git a/sql-ledger/templates/Brazilian_Portuguese-balance_sheet.html b/sql-ledger/templates/Brazilian_Portuguese-balance_sheet.html
new file mode 100644
index 0000000..20c3c51
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-balance_sheet.html
@@ -0,0 +1,103 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+ <p>BALAN&Ccedil;O<br>
+ <%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>VALORES<br>
+ <hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td> </td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAL</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>BALAN&Ccedil;O<b>
+ <hr align=left width=250 size=5 noshade></b></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>S&Oacute;CIOS (%)<br>
+ <hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAIS</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
+
+
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-check.tex b/sql-ledger/templates/Brazilian_Portuguese-check.tex
new file mode 100644
index 0000000..ea62b00
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-check.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Número da Fatura} & \textbf{Data da Fatura}
+ & \textbf{Prazo} & \textbf{Aplicação} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-income_statement.html b/sql-ledger/templates/Brazilian_Portuguese-income_statement.html
new file mode 100644
index 0000000..3531122
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-income_statement.html
@@ -0,0 +1,77 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+ <p>DECLARA&Ccedil;&Atilde;O DE RENDIMENTOS<br>
+ <%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>RENDIMENTOS<br>
+ <hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4> </td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Total</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>DESPESAS<br>
+ <hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td> </td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Total</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>RENDIMENTOS / (PREJUIZO)</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-invoice.html b/sql-ledger/templates/Brazilian_Portuguese-invoice.html
new file mode 100644
index 0000000..2871238
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-invoice.html
@@ -0,0 +1,315 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4> Telefone:
+ <%tel%>
+ <br>
+ Fax:
+ <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>FATURA</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right> Data</th>
+ <td width=10>&nbsp;</td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Entrega</th>
+ <td width=10>&nbsp;</td><td><%duedate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>N&uacute;mero</th>
+ <td>&nbsp;</td><td><%invnumber%></td></tr>
+ </table></tr>
+
+<!--
+ <tr>
+ <th align=right>Clerk:</th><td>&nbsp;</td><td><%employee%></td>
+ </tr>
+-->
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </table></td>
+ </table>
+
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color="ffffff">Para:</font></th>
+ <th align=left><font color="ffffff">Transportar Para:</font></th>
+ </tr>
+
+<!--
+ other variables which can be use:
+ contact, shiptocontact, shiptophone, shiptofax
+-->
+
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>N&uacute;mero</font></th>
+ <th align=left><font color=ffffff>Descri&ccedil;&atilde;o</font></th>
+ <th><font color=ffffff>Quant.</font></th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Pre&ccedil;o</font></th>
+ <th><font color=ffffff>Disc.</font></th>
+ <th><font color="ffffff">Total</font></th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+<!--
+you can also use netprice instead of sellprice if you
+don't want to show the discount
+netprice = sellprice - discount
+-->
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%invtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th colspan=5 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right>
+ <%taxdescription%>
+ em
+ <%taxbase%>
+ @
+ <%taxrate%>
+ %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th colspan=5 align=right>Pago</th>
+ <td colspan=2 align=right>- <%paid%></td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td colspan=3>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Fatura para<b>
+ <%terms%>
+ </b> dias</td>
+ <th colspan=2 align=right>Pendente</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Obs.:</td>
+ <td><%notes%></td>
+<%end notes%>
+ <td align=right> Pre&ccedil;os em<b>
+ <%currency%>
+ </b> <br>
+ <%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<%if paid%>
+<tr>
+ <td colspan=7>
+ <table width=60%>
+ <tr>
+ <th align=left>Pagamentos</th>
+ </tr>
+ <tr>
+ <td colspan=4>
+ <hr noshade>
+ </td>
+ </tr>
+ <tr>
+ <th align=left>Data</th>
+ <th align=left>Conta</th>
+ <th align=left>Origem</th>
+ <th align=left>Total</th>
+ </tr>
+<%end paid%>
+
+<%foreach payment%>
+ <tr>
+ <td><%paymentdate%></td>
+ <td><%paymentaccount%></td>
+ <td><%paymentsource%></td>
+ <td><%payment%></td>
+ </tr>
+<%end payment%>
+
+<%if paid%>
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+<%end paid%>
+
+<tr>
+ <th colspan=7>
+ <br>
+ Obrigado por estarmos fazendo neg&oacute;cio! </th>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3> </font> </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+<%foreach tax%>
+ <tr>
+
+ <th colspan=7 align=left><font size=-2>
+ <%taxdescription%>
+ Registro
+ <%taxnumber%>
+ </font></th>
+ </tr>
+<%end tax%>
+
+<%if taxincluded%>
+ <tr>
+
+ <th colspan=7 align=left><font size="-2">Impostos Inclusos.</font></th>
+ </tr>
+<%end taxincluded%>
+
+<!-- business number
+ <tr>
+ <th colspan=7 align=left><font size=-2>Business Number: <%businessnumber%></font></th>
+ </tr>
+-->
+
+<!-- banking information
+ <tr>
+ <th colspan=7 align=left>Banking Information:
+ <br>Bank
+ <br>Transit No.
+ <br>Account No.
+ </td>
+ </tr>
+-->
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-invoice.tex b/sql-ledger/templates/Brazilian_Portuguese-invoice.tex
new file mode 100644
index 0000000..15c407b
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-invoice.tex
@@ -0,0 +1,223 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefone & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Disc} & \textbf{Amount} \\
+ & carried forward from page <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{0.5cm}
+
+\parbox[t]{1cm}{\hfill}
+ \parbox[t]{10.5cm}{
+ \textbf{To}
+ \vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{0.3cm}
+
+%<%if contact%>
+%Attn: <%contact%>
+%\vspace{0.3cm}
+%<%end contact%>
+\vspace{0.5cm}
+
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\parbox[t]{7.5cm}{
+\textbf{Ship To}
+\vspace{0.5cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{0.3cm}
+
+\vspace{0.3cm}
+
+<%if shiptocontact%>
+Attn: <%shiptocontact%>
+\vspace{0.3cm}
+<%end shiptocontact%>
+
+<%if shiptophone%>
+Tel: <%shiptophone%>
+<%end shiptophone%>
+
+<%if shiptofax%>
+Fax: <%shiptofax%>
+<%end shiptofax%>
+
+<%shiptoemail%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{F A T U R A}
+\hfill
+
+\vspace{1cm}
+
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Data} & <%invdate%> \\
+ \textbf{Número} & <%invnumber%> \\
+ \textbf{Pedido} & <%ordnumber%> \\
+ \textbf{Produto} & <%employee%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Número} & \textbf{Descrição} & \textbf{Quant.} &
+ \textbf{Unid.} & \textbf{Preço} & \textbf{Disc.} & \textbf{Total} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> em <%taxbase%> & <%tax%> \\
+<%end tax%>
+<%if paid%>
+ \textbf{Pago} & - <%paid%> \\
+<%end paid%>
+ \hline
+ \textbf{Pendente} & \textbf{<%total%>} \\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Preços em \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+
+<%if paid%>
+\begin{tabularx}{10cm}{@{}lXlr@{}}
+ \textbf{Pagamentos} & & & \\
+ \hline
+ \textbf{Data} & \textbf{Conta} & \textbf{Origem} & \textbf{Total} \\
+<%end paid%>
+<%foreach payment%>
+ <%paymentdate%> & <%paymentaccount%> & <%paymentsource%> & <%payment%> \\
+<%end payment%>
+<%if paid%>
+\end{tabularx}
+<%end paid%>
+
+\vspace{1cm}
+
+\centerline{\textbf{Obrigado por estarmos fazendo negócio!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
+
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-packing_list.html b/sql-ledger/templates/Brazilian_Portuguese-packing_list.html
new file mode 100644
index 0000000..4cdee74
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-packing_list.html
@@ -0,0 +1,143 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>LISTA DE PRODUTOS</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Data</th>
+ <td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>N&uacute;mero</th>
+ <td></td><td><%invnumber%></td></tr>
+ </table></tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+ </table></td>
+ </table>
+
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color="ffffff">Para:</font></th>
+ </tr>
+
+ <tr>
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+<%if shiptocontact%>
+ <p>Obs.:
+ <%shiptocontact%>
+ <%end shiptocontact%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>N&uacute;mero</font></th>
+ <th align=left><font color=ffffff>Descri&ccedil;&atilde;o</font></th>
+ <th><font color="ffffff">Quant.</font></th>
+ <th>&nbsp;</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Obs.:</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ <%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3> </font> </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+
+
+
+
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-packing_list.tex b/sql-ledger/templates/Brazilian_Portuguese-packing_list.tex
new file mode 100644
index 0000000..4810230
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-packing_list.tex
@@ -0,0 +1,116 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Bin} \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{3.5cm}
+
+\textbf{LISTA DE PRODUTOS} \parbox{0.3cm}{\hfill} \textbf{L I S T}
+
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Data} & <%invdate%> \\
+ \textbf{Número} & <%invnumber%> \\
+ \textbf{Cliente} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Número} & \textbf{Descrição} & \textbf{Quant.} &
+ \textbf{Unid.} & \textbf{Bin} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%bin%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{ }}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-purchase_order.html b/sql-ledger/templates/Brazilian_Portuguese-purchase_order.html
new file mode 100644
index 0000000..54b25f3
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-purchase_order.html
@@ -0,0 +1,187 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4> O R D E M &nbsp;&nbsp; D E &nbsp;&nbsp; C O M P R A</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Data</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Requerido por</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>N&uacutemero</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Para:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>N&uacutemero</th>
+ <th align=left><font color=ffffff>Descri&ccedil&atildeo</th>
+ <th><font color=ffffff>Quant.</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Pre&ccedilo (unit.)</th>
+ <th><font color=ffffff>Total</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=6><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=4 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=4 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=2>Faturado em <b><%terms%></b> dias</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%ordtotal%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Obs.:</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Todos os pre&ccedilos em <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-purchase_order.tex b/sql-ledger/templates/Brazilian_Portuguese-purchase_order.tex
new file mode 100644
index 0000000..61bb518
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-purchase_order.tex
@@ -0,0 +1,198 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefone & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+ & carried forward from <%lastpage%> & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{0.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+\textbf{To}
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{0.3cm}
+
+<%if contact%>
+Attn: <%contact%>
+\vspace{0.3cm}
+<%end contact%>
+
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\parbox[t]{7.5cm}{
+\textbf{Ship To}
+\vspace{0.3cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{0.3cm}
+
+<%if shiptocontact%>
+Attn: <%shiptocontact%>
+\vspace{0.3cm}
+<%end shiptocontact%>
+
+<%if shiptophone%>
+Tel: <%shiptophone%>
+<%end shiptophone%>
+
+<%if shiptofax%>
+Fax: <%shiptofax%>
+<%end shiptofax%>
+
+<%shiptoemail%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{ORDEM DE COMPRA} \parbox{0.3cm}{\hfill} \textbf{O R D E R}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Data} & <%orddate%> \\
+<%if reqdate%>
+ \textbf{Requerido por} & <%reqdate%> \\
+<%end reqdate%>
+ \textbf{Número} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Número} & \textbf{Descrição} & \textbf{Quant.} &
+ \textbf{Unid.} & \textbf{Preço} & \textbf{Total} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> em <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Preços em \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+%\footnotetext[1]{\tiny }
+
+\end{document}
+
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-receipt.tex b/sql-ledger/templates/Brazilian_Portuguese-receipt.tex
new file mode 100644
index 0000000..ea62b00
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-receipt.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Número da Fatura} & \textbf{Data da Fatura}
+ & \textbf{Prazo} & \textbf{Aplicação} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-sales_order.html b/sql-ledger/templates/Brazilian_Portuguese-sales_order.html
new file mode 100644
index 0000000..480dc63
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-sales_order.html
@@ -0,0 +1,221 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4> Telefone:
+ <%tel%>
+ <br>
+ Fax:
+ <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>ORDEM DE VENDA</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Data</th>
+ <td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Requerido por</th>
+ <td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>N&uacute;mero</th>
+ <td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </table></tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </table></td>
+ </table>
+
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color="ffffff">Para:</font></th>
+ <th align=left><font color="ffffff">Transportar para:</font></th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>N&uacute;mero</font></th>
+ <th align=left><font color=ffffff>Descri&ccedil;&atilde;o</font></th>
+ <th><font color=ffffff>Quant.</font></th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Pre&ccedil;o</font></th>
+ <th><font color=ffffff>Disc.</font></th>
+ <th><font color="ffffff">Total</font></th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%ordtotal%></td>
+<%end taxincluded%>
+
+<%if not taxincluded%>
+ <th colspan=5 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right>
+ <%taxdescription%>
+ em
+ <%taxbase%>
+ @
+ <%taxrate%>
+ %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=5><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Faturar para<b>
+ <%terms%>
+ </b> dias</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%ordtotal%></th>
+ </tr>
+<%if taxincluded%>
+ <tr>
+ <td colspan=3>Impostos inclusos do total</td>
+ </tr>
+<%end taxincluded%>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Obs.:</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right> Pre&ccedil;os em<b>
+ <%currency%>
+ </b><br>
+ <%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3> </font> </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+
+
+
+
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-sales_order.tex b/sql-ledger/templates/Brazilian_Portuguese-sales_order.tex
new file mode 100644
index 0000000..4267143
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-sales_order.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefone & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Disc} & \textbf{Amount} \\
+ & carried forward from <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{ORDEM DE VENDA} \parbox{0.3cm}{\hfill} \textbf{O R D E R}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Data} & <%orddate%> \\
+ \textbf{Número} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Número} & \textbf{Descrição} & \textbf{Quant.} &
+ \textbf{Unid.} & \textbf{Preço} & \textbf{Disc.} & \textbf{Total} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> em <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Preços em \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-statement.html b/sql-ledger/templates/Brazilian_Portuguese-statement.html
new file mode 100644
index 0000000..963f658
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-statement.html
@@ -0,0 +1,125 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th><img src=http://www.sql-ledger.org/images/sql-ledger.png border=0 width=64 height=58></th>
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3>
+ <h4>RELAT&Oacute;RIO</h4>
+ </th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tel: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>N&uacute;mero da Fatura</th>
+ <th width=15%>Data</th>
+ <th width=15%>Prazo</th>
+ <th width=10%>Atual</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></table></td>
+ <th align=right><%c30total%>
+ <th align=right><%c60total%>
+ <th align=right><%c90total%>
+ </tr>
+ </table>
+
+
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Total</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+
+ <td>Porfavor pagar com<b>
+ <%company%>
+ </b>. </td>
+ </tr>
+ <tr height=20></tr>
+
+
diff --git a/sql-ledger/templates/Brazilian_Portuguese-statement.tex b/sql-ledger/templates/Brazilian_Portuguese-statement.tex
new file mode 100644
index 0000000..fbc5b03
--- /dev/null
+++ b/sql-ledger/templates/Brazilian_Portuguese-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{RELATÓRIO} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Número da Fatura \#} & \textbf{Data} & \textbf{Prazo} &
+ \textbf{Atual} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Totais} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Favor pagar com <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Danish-balance_sheet.html b/sql-ledger/templates/Danish-balance_sheet.html
new file mode 100644
index 0000000..61929ed
--- /dev/null
+++ b/sql-ledger/templates/Danish-balance_sheet.html
@@ -0,0 +1,96 @@
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>STATUS
+<br><%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>AKTIVER<br><hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td> </td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>SAMLEDE AKTIVER</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>PASSIVER<b><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Samlet gæld</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>KAPITAL<br><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Samlet egenkapital</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>SAMLET GÆLD OG EGENKAPITAL</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
diff --git a/sql-ledger/templates/Danish-check.tex b/sql-ledger/templates/Danish-check.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Danish-check.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Danish-income_statement.html b/sql-ledger/templates/Danish-income_statement.html
new file mode 100644
index 0000000..c065297
--- /dev/null
+++ b/sql-ledger/templates/Danish-income_statement.html
@@ -0,0 +1,73 @@
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>DRIFTSREGNSKAB
+<br><%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>INDTÆGTER<br><hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4> </td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Samlede indtægter</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>UDGIFTER<br><hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td> </td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Samlede udgifter</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>RESULTAT</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
diff --git a/sql-ledger/templates/Danish-invoice.html b/sql-ledger/templates/Danish-invoice.html
new file mode 100644
index 0000000..d150a84
--- /dev/null
+++ b/sql-ledger/templates/Danish-invoice.html
@@ -0,0 +1,273 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tlf.: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>F A K T U R A</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Fakturadato</th><td width=10>&nbsp;</td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Betalingsdato</th><td width=10>&nbsp;</td><td><%duedate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Fakturanummer</th><td>&nbsp;</td><td><%invnumber%></td></tr>
+ </tr>
+
+<!--
+ <tr>
+ <th align=right>Ekspederet af:</th><td>&nbsp;</td><td><%username%></td>
+ </tr>
+-->
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Faktureringsadresse:</th>
+ <%if shiptoname%>
+ <th align=left><font color=ffffff>Leveringsadresse:</th>
+ <%end shiptoname%>
+ </tr>
+
+<!--
+ other variables which can be use:
+ contact, shiptocontact, shiptophone, shiptofax
+-->
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <%if shiptoname%>
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ <%end shiptoname%>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Varenummer</th>
+ <th align=left><font color=ffffff>Beskrivelse</th>
+ <th><font color=ffffff>Antal</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Pris</th>
+ <th><font color=ffffff>Rabat</th>
+ <th><font color=ffffff>Beløb</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+<!--
+you can also use netprice instead of sellprice if you
+don't want to show the discount
+netprice = sellprice - discount
+-->
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%invtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th colspan=5 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%> på <%taxbase%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th colspan=5 align=right>Allerede betalt</th>
+ <td colspan=2 align=right>- <%paid%></td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td colspan=3>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Betalingsfrist <b><%terms%></b> dage</td>
+ <th colspan=2 align=right>At betale</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Bemærkninger</td>
+ <td><%notes%></td>
+<%end notes%>
+ <td align=right>
+ Alle priser i <b><%currency%></b>.
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <th colspan=7>
+ <br>Tak for handelen!
+ </th>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Betalingsfrist <%terms%> dage fra fakturadato. Betaling herefter påregnes
+ 1.5% per påbegyndt måned startende <%duedate%> og indtil det fulde beløb
+ er betalt. Returnerede varer modregnes 10% i ekspeditionsgebyr.
+ Et returnummer skal tildeles af <%company%> før varer returneres.
+ Returvarer skal forsendes forudbetalt og forsvarligt forsikret.
+ <%company%> kan ikke drages til ansvar for skade under transport.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=7 align=left><font size=-2><%taxdescription%> noteret som <%taxnumber%></th>
+ </tr>
+<%end tax%>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan=7 align=left><font size=-2>Alle beløb er inklusive moms.</th>
+ </tr>
+<%end taxincluded%>
+
+<!-- business number
+ <tr>
+ <th colspan=7 align=left><font size=-2>CVR-nummer: <%businessnumber%></font></th>
+ </tr>
+-->
+
+<!-- banking information
+ <tr>
+ <th colspan=7 align=left>Bank-oplysninger:
+ <br>Bank
+ <br>Banknummer
+ <br>Kontonummer
+ </td>
+ </tr>
+-->
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Danish-invoice.tex b/sql-ledger/templates/Danish-invoice.tex
new file mode 100644
index 0000000..6c3fa8b
--- /dev/null
+++ b/sql-ledger/templates/Danish-invoice.tex
@@ -0,0 +1,152 @@
+\documentclass[a4paper,twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage[danish]{babel}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Tlf. & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Nummer} & \textbf{Beskrivelse} & \textbf{Antal} &
+ \textbf{Enhed} & \textbf{Pris} & \textbf{Rabat} & \textbf{Beløb} \\
+ & overført fra side <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{F A K T U R A}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Dato} & <%invdate%> \\
+ \textbf{Nummer} & <%invnumber%> \\
+ \textbf{Kunde} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Nummer} & \textbf{Beskrivelse} & \textbf{Antal} &
+ \textbf{Enhed} & \textbf{Pris} & \textbf{Rabat} & \textbf{Beløb} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> på <%taxbase%> & <%tax%> \\
+<%end tax%>
+<%if paid%>
+ \textbf{Betalt} & - <%paid%> \\
+<%end paid%>
+ \hline
+ \textbf{At betale} & \textbf{<%total%>} \\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Alle priser i \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Tak for handelen!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Betalingsfrist <%terms%> dage fra fakturadato. Betaling herefter påregnes
+1.5\% per påbegyndt måned startende <%duedate%> og indtil det fulde beløb
+er betalt. Returnerede varer modregnes 10\% i ekspeditionsgebyr.
+Et returnummer skal tildeles af <%company%> før varer returneres.
+Returvarer skal forsendes forudbetalt og forsvarligt forsikret.
+<%company%> kan ikke drages til ansvar for skade under transport.}
+
+\end{document}
diff --git a/sql-ledger/templates/Danish-packing_list.html b/sql-ledger/templates/Danish-packing_list.html
new file mode 100644
index 0000000..76e02b4
--- /dev/null
+++ b/sql-ledger/templates/Danish-packing_list.html
@@ -0,0 +1,145 @@
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>F Ø L G E S E D D E L</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Dato</th><td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Nummer</th><td></td><td><%invnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Leveringsadresse:</th>
+ </tr>
+
+ <tr>
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+<%if shiptocontact%>
+ <p>Att.: <%shiptocontact%>
+<%end shiptocontact%>
+
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Varenummer</th>
+ <th align=left><font color=ffffff>Beskrivelse</th>
+ <th><font color=ffffff>Antal</th>
+ <th>&nbsp;</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Bemærkninger</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ <%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Returnerede varer modregnes 10% i ekspeditionsgebyr.
+ Et returnummer skal tildeles af <%company%> før varer returneres.
+ Returvarer skal forsendes forudbetalt og forsvarligt forsikret.
+ <%company%> kan ikke drages til ansvar for skade under transport.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
diff --git a/sql-ledger/templates/Danish-packing_list.tex b/sql-ledger/templates/Danish-packing_list.tex
new file mode 100644
index 0000000..0d6bfc4
--- /dev/null
+++ b/sql-ledger/templates/Danish-packing_list.tex
@@ -0,0 +1,123 @@
+\documentclass[a4paper,twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage[danish]{babel}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Tlf. & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Nummer} & \textbf{Beskrivelse} & \textbf{Antal} &
+ \textbf{Enhed} & \textbf{Varelager} \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{3.5cm}
+
+\textbf{F Ø L G E S E D D E L}
+
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Dato} & <%invdate%> \\
+ \textbf{Nummer} & <%invnumber%> \\
+ \textbf{Kunde} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Nummer} & \textbf{Beskrivelse} & \textbf{Antal} &
+ \textbf{Enhed} & \textbf{Varelager} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%bin%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Tak for ordren!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Returnerede varer modregnes 10\% i ekspeditionsgebyr.
+Et returnummer skal tildeles af <%company%> før varer returneres.
+Returvarer skal forsendes forudbetalt og forsvarligt forsikret.
+<%company%> kan ikke drages til ansvar for skade under transport.}
+
+\end{document}
diff --git a/sql-ledger/templates/Danish-purchase_order.html b/sql-ledger/templates/Danish-purchase_order.html
new file mode 100644
index 0000000..f9f21cd
--- /dev/null
+++ b/sql-ledger/templates/Danish-purchase_order.html
@@ -0,0 +1,191 @@
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tlf.: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>I N D K Ø B S O R D R E</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Ordredato</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Ønsket leveringsdato</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Ordrenummer</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Til:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Varenummer</th>
+ <th align=left><font color=ffffff>Beskrivelse</th>
+ <th><font color=ffffff>Antal</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Pris</th>
+ <th><font color=ffffff>Beløb</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=6><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=4 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=4 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=2>Betalingsfrist <b><%terms%></b> dage</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Bemærkninger</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Alle priser i <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Betalingsfrist <%terms%> dage fra fakturadato. Betaling herefter påregnes
+ 1.5% per påbegyndt måned startende <%duedate%> og indtil det fulde beløb
+ er betalt. Returnerede varer modregnes 10% i ekspeditionsgebyr.
+ Et returnummer skal tildeles af <%company%> før varer returneres.
+ Returvarer skal forsendes forudbetalt og forsvarligt forsikret.
+ <%company%> kan ikke drages til ansvar for skade under transport.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
diff --git a/sql-ledger/templates/Danish-purchase_order.tex b/sql-ledger/templates/Danish-purchase_order.tex
new file mode 100644
index 0000000..bdd7416
--- /dev/null
+++ b/sql-ledger/templates/Danish-purchase_order.tex
@@ -0,0 +1,143 @@
+\documentclass[a4paper,twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage[danish]{babel}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Tlf. & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Nummer} & \textbf{Beskrivelse} & \textbf{Antal} &
+ \textbf{Enhed} & \textbf{Pris} & \textbf{Beløb} \\
+ & carried forward from <%lastpage%> & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{I N D K Ø B S O R D R E}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Dato} & <%orddate%> \\
+<%if reqdate%>
+ \textbf{Ønsket leveringsdato} & <%reqdate%> \\
+<%end reqdate%>
+ \textbf{Ordrenummer} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Varenummer} & \textbf{Beskrivelse} & \textbf{Antal} &
+ \textbf{Enhed} & \textbf{Pris} & \textbf{Beløb} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Alle priser i \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+%\footnotetext[1]{\tiny }
+
+\end{document}
diff --git a/sql-ledger/templates/Danish-receipt.tex b/sql-ledger/templates/Danish-receipt.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Danish-receipt.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Danish-sales_order.html b/sql-ledger/templates/Danish-sales_order.html
new file mode 100644
index 0000000..f256522
--- /dev/null
+++ b/sql-ledger/templates/Danish-sales_order.html
@@ -0,0 +1,210 @@
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tlf.: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>S A L G S O R D R E</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Ordredato</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Ønsket leveringsdato</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Ordrenummer</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Til:</th>
+ <th align=left><font color=ffffff>Leveringsadresse:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Varenummer</th>
+ <th align=left><font color=ffffff>Beskrivelse</th>
+ <th><font color=ffffff>Antal</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Pris</th>
+ <th><font color=ffffff>Rabat</th>
+ <th><font color=ffffff>Beløb</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%ordtotal%></td>
+<%end taxincluded%>
+
+<%if not taxincluded%>
+ <th colspan=5 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%> på <%taxbase%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=5><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Betalingsfrist netto <b><%terms%></b> dage</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%ordtotal%></th>
+ </tr>
+<%if taxincluded%>
+ <tr>
+ <td colspan=3>Total er inklusive moms</td>
+ </tr>
+<%end taxincluded%>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Bemærkninger</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Alle priser i <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Et gebyr for annullering af ordre på 10% vil blive tillagt alle specialtilbud
+ og produkter som er blevet tilpasset, forbedret eller opgraderet på kundens anmodning.<br>
+ Varer som ikke kan returneres er anført ovenfor.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
diff --git a/sql-ledger/templates/Danish-sales_order.tex b/sql-ledger/templates/Danish-sales_order.tex
new file mode 100644
index 0000000..d7307cd
--- /dev/null
+++ b/sql-ledger/templates/Danish-sales_order.tex
@@ -0,0 +1,144 @@
+\documentclass[a4paper,twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage[danish]{babel}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Tlf. & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Nummer} & \textbf{Beskrivelse} & \textbf{Antal} &
+ \textbf{Enhed} & \textbf{Pris} & \textbf{Rabat} & \textbf{Beløb} \\
+ & Overført fra side <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{S A L G S O R D R E}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Dato} & <%orddate%> \\
+ \textbf{Ordrenummer} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Varenummer} & \textbf{Beskrivelse} & \textbf{Antal} &
+ \textbf{Enhed} & \textbf{Pris} & \textbf{Rabat} & \textbf{Beløb} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> på <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Alle priser i \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Et gebyr for annullering af ordre på 10\% vil blive tillagt alle specialtilbud
+og produkter som er blevet tilpasset, forbedret eller opgraderet på kundens anmodning.
+Varer som ikke kan returneres er anført ovenfor.
+}
+
+\end{document}
diff --git a/sql-ledger/templates/Danish-statement.html b/sql-ledger/templates/Danish-statement.html
new file mode 100644
index 0000000..6fca322
--- /dev/null
+++ b/sql-ledger/templates/Danish-statement.html
@@ -0,0 +1,121 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th><img src=http://www.sql-ledger.org/images/sql-ledger.png border=0 width=64 height=58></th>
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3><h4>S T A T E M E N T</h4></th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tel: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>Invoice #</th>
+ <th width=15%>Date</th>
+ <th width=15%>Due</th>
+ <th width=10%>Current</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></td>
+ <th align=right><%c30total%></td>
+ <th align=right><%c60total%></td>
+ <th align=right><%c90total%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Total Outstanding</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>Please make check payable to <b><%company%></b>.
+ </td>
+ </tr>
+ <tr height=20></tr>
+</table>
+
diff --git a/sql-ledger/templates/Danish-statement.tex b/sql-ledger/templates/Danish-statement.tex
new file mode 100644
index 0000000..0b63f75
--- /dev/null
+++ b/sql-ledger/templates/Danish-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{S T A T E M E N T} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Total outstanding} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Please make check payable to <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Default-balance_sheet.html b/sql-ledger/templates/Default-balance_sheet.html
new file mode 100644
index 0000000..478caab
--- /dev/null
+++ b/sql-ledger/templates/Default-balance_sheet.html
@@ -0,0 +1,100 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>BALANCE SHEET
+<br><%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>ASSETS<br><hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td> </td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAL ASSETS</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>LIABILITIES<b><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total Liabilities</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>SHAREHOLDER'S EQUITY<br><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total Equity</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAL LIABILITIES & EQUITY</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
+
+
+
diff --git a/sql-ledger/templates/Default-check.tex b/sql-ledger/templates/Default-check.tex
new file mode 100644
index 0000000..a1ab201
--- /dev/null
+++ b/sql-ledger/templates/Default-check.tex
@@ -0,0 +1,77 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{1.8cm}
+
+<%notes%>
+
+\vspace{0.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
+
+
diff --git a/sql-ledger/templates/Default-income_statement.html b/sql-ledger/templates/Default-income_statement.html
new file mode 100644
index 0000000..e9d6a40
--- /dev/null
+++ b/sql-ledger/templates/Default-income_statement.html
@@ -0,0 +1,82 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>INCOME STATEMENT
+<br><%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>INCOME<br><hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4> </td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Total Income</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>EXPENSES<br><hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td> </td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Total Expenses</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>INCOME / (LOSS)</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
+
+
+
+
+
+
+
+
diff --git a/sql-ledger/templates/Default-invoice.html b/sql-ledger/templates/Default-invoice.html
new file mode 100644
index 0000000..0ba06cc
--- /dev/null
+++ b/sql-ledger/templates/Default-invoice.html
@@ -0,0 +1,309 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Telephone: <%tel%>
+ <br>Facsimile: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>I N V O I C E</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Invoice Date</th><td width=10>&nbsp;</td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Due Date</th><td width=10>&nbsp;</td><td><%duedate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td>&nbsp;</td><td><%invnumber%></td></tr>
+ </tr>
+
+<!--
+ <tr>
+ <th align=right>Clerk:</th><td>&nbsp;</td><td><%employee%></td>
+ </tr>
+-->
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>To:</th>
+ <th align=left><font color=ffffff>Ship To:</th>
+ </tr>
+
+<!--
+ other variables which can be use:
+ contact, shiptocontact, shiptophone, shiptofax
+-->
+
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Number</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qt'y</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Price</th>
+ <th><font color=ffffff>Disc</th>
+ <th><font color=ffffff>Amount</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+<!--
+you can also use netprice instead of sellprice if you
+don't want to show the discount
+netprice = sellprice - discount
+-->
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%invtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th colspan=5 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%> on <%taxbase%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th colspan=5 align=right>Paid</th>
+ <td colspan=2 align=right>- <%paid%></td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td colspan=3>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Terms Net <b><%terms%></b> days</td>
+ <th colspan=2 align=right>Outstanding</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Notes</td>
+ <td><%notes%></td>
+<%end notes%>
+ <td align=right>
+ All prices in <b><%currency%></b> Funds
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<%if paid%>
+<tr>
+ <td colspan=7>
+ <table width=60%>
+ <tr>
+ <th align=left>Payments</th>
+ </tr>
+ <tr>
+ <td colspan=4>
+ <hr noshade>
+ </td>
+ </tr>
+ <tr>
+ <th align=left>Date</th>
+ <th align=left>Account</th>
+ <th align=left>Source</th>
+ <th align=left>Amount</th>
+ </tr>
+<%end paid%>
+
+<%foreach payment%>
+ <tr>
+ <td><%paymentdate%></td>
+ <td><%paymentaccount%></td>
+ <td><%paymentsource%></td>
+ <td><%payment%></td>
+ </tr>
+<%end payment%>
+
+<%if paid%>
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+<%end paid%>
+
+<tr>
+ <th colspan=7>
+ <br>Thank you for your valued business!
+ </th>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Payment due NET <%terms%> Days from date of Invoice.
+ Interest on overdue amounts will acrue at the rate of 1.5% per month
+ from due date until paid in full. Items returned are subject to
+ a 10% restocking charge. A return authorization must be obtained
+ from <%company%> before goods are returned. Returns must be shipped
+ prepaid and properly insured. <%company%> will not be responsible
+ for damages during transit.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=7 align=left><font size=-2><%taxdescription%> Registration <%taxnumber%></th>
+ </tr>
+<%end tax%>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan=7 align=left><font size=-2>Taxes shown are included in price.</th>
+ </tr>
+<%end taxincluded%>
+
+<!-- business number
+ <tr>
+ <th colspan=7 align=left><font size=-2>Business Number: <%businessnumber%></font></th>
+ </tr>
+-->
+
+<!-- banking information
+ <tr>
+ <th colspan=7 align=left>Banking Information:
+ <br>Bank
+ <br>Transit No.
+ <br>Account No.
+ </td>
+ </tr>
+-->
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Default-invoice.tex b/sql-ledger/templates/Default-invoice.tex
new file mode 100644
index 0000000..58a340d
--- /dev/null
+++ b/sql-ledger/templates/Default-invoice.tex
@@ -0,0 +1,231 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Disc} & \textbf{Amount} \\
+ & carried forward from page <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{0.5cm}
+
+\parbox[t]{1cm}{\hfill}
+ \parbox[t]{10.5cm}{
+ \textbf{To}
+ \vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{0.3cm}
+
+%<%if contact%>
+%Attn: <%contact%>
+%\vspace{0.3cm}
+%<%end contact%>
+\vspace{0.5cm}
+
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\parbox[t]{7.5cm}{
+\textbf{Ship To}
+\vspace{0.5cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{0.3cm}
+
+\vspace{0.3cm}
+
+<%if shiptocontact%>
+Attn: <%shiptocontact%>
+\vspace{0.3cm}
+<%end shiptocontact%>
+
+<%if shiptophone%>
+Tel: <%shiptophone%>
+<%end shiptophone%>
+
+<%if shiptofax%>
+Fax: <%shiptofax%>
+<%end shiptofax%>
+
+<%shiptoemail%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{I N V O I C E}
+\hfill
+
+\vspace{1cm}
+
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%invdate%> \\
+ \textbf{Number} & <%invnumber%> \\
+ \textbf{Order} & <%ordnumber%> \\
+ \textbf{Clerk} & <%employee%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Disc} & \textbf{Amount} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%> \\
+<%end tax%>
+<%if paid%>
+ \textbf{Paid} & - <%paid%> \\
+<%end paid%>
+ \hline
+ \textbf{Balance Owing} & \textbf{<%total%>} \\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ All prices in \textbf{<%currency%>} funds.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+
+<%if paid%>
+\begin{tabularx}{10cm}{@{}lXlr@{}}
+ \textbf{Payments} & & & \\
+ \hline
+ \textbf{Date} & \textbf{Account} & \textbf{Source} & \textbf{Amount} \\
+<%end paid%>
+<%foreach payment%>
+ <%paymentdate%> & <%paymentaccount%> & <%paymentsource%> & <%payment%> \\
+<%end payment%>
+<%if paid%>
+\end{tabularx}
+<%end paid%>
+
+\vspace{1cm}
+
+\centerline{\textbf{Thank You for your valued business!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Payment due NET <%terms%> Days from date of Invoice. Interest on overdue
+amounts will acrue at the rate of 1.5\% per month starting <%duedate%>
+until paid in full. Items returned are subject to a 10\% restocking charge.
+A return authorization must be obtained from <%company%> before goods are
+returned. Returns must be shipped prepaid and properly insured.
+<%company%> will not be responsible for damages during transit.}
+
+\end{document}
+
+
+
diff --git a/sql-ledger/templates/Default-packing_list.html b/sql-ledger/templates/Default-packing_list.html
new file mode 100644
index 0000000..07ba8d6
--- /dev/null
+++ b/sql-ledger/templates/Default-packing_list.html
@@ -0,0 +1,148 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>P A C K I N G &nbsp;&nbsp; L I S T</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Date</th><td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td></td><td><%invnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Ship To:</th>
+ </tr>
+
+ <tr>
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+<%if shiptocontact%>
+ <p>Attn: <%shiptocontact%>
+<%end shiptocontact%>
+
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Number</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qt'y</th>
+ <th>&nbsp;</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Notes</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ <%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Items returned are subject to
+ a 10% restocking charge. A return authorization must be obtained
+ from <%company%> before goods are returned. Returns must be shipped
+ prepaid and properly insured. <%company%> will not be responsible
+ for damages during transit.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Default-packing_list.tex b/sql-ledger/templates/Default-packing_list.tex
new file mode 100644
index 0000000..fce1782
--- /dev/null
+++ b/sql-ledger/templates/Default-packing_list.tex
@@ -0,0 +1,122 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Bin} \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{3.5cm}
+
+\textbf{P A C K I N G} \parbox{0.3cm}{\hfill} \textbf{L I S T}
+
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%invdate%> \\
+ \textbf{Number} & <%invnumber%> \\
+ \textbf{Customer} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Bin} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%bin%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Thank You for your valued business!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Items returned are subject to a 10\% restocking charge.
+A return authorization must be obtained from <%company%> before goods are
+returned. Returns must be shipped prepaid and properly insured.
+<%company%> will not be responsible for damages during transit.}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Default-purchase_order.html b/sql-ledger/templates/Default-purchase_order.html
new file mode 100644
index 0000000..7df399e
--- /dev/null
+++ b/sql-ledger/templates/Default-purchase_order.html
@@ -0,0 +1,224 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Telephone: <%tel%>
+ <br>Facsimile: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>P U R C H A S E &nbsp;&nbsp; O R D E R</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Order Date</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Required by</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left width=50%><font color=ffffff>To:</th>
+ <th align=left width=50%><font color=ffffff>Ship To:</th>
+ </tr>
+
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+
+<br>
+<%if contact%>
+<br>Attn: <%contact%>
+<%end contact%>
+<%if vendorphone%>
+<br>Tel: <%vendorphone%>
+<%end vendorphone%>
+<%if vendorfax%>
+<br>Fax: <%vendorfax%>
+<%end vendorfax%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+
+<br>
+<%if shiptocontact%>
+<br>Attn: <%shiptocontact%>
+<%end shiptocontact%>
+<%if shiptophone%>
+<br>Tel: <%shiptophone%>
+<%end shiptophone%>
+<%if shiptofax%>
+<br>Fax: <%shiptofax%>
+<%end shiptofax%>
+
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Number</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qt'y</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Price</th>
+ <th><font color=ffffff>Amount</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=6><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=4 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=4 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=2>Terms Net <b><%terms%></b> days</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%ordtotal%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Notes</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ All prices in <b><%currency%></b> Funds
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Payment due NET <%terms%> Days from date of Invoice.
+ Interest on overdue amounts will acrue at the rate of 1.5% per month
+ from due date until paid in full. Items returned are subject to
+ a 10% restocking charge. A return authorization must be obtained
+ from <%company%> before goods are returned. Returns must be shipped
+ prepaid and properly insured. <%company%> will not be responsible
+ for damages during transit.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Default-purchase_order.tex b/sql-ledger/templates/Default-purchase_order.tex
new file mode 100644
index 0000000..4e1deb2
--- /dev/null
+++ b/sql-ledger/templates/Default-purchase_order.tex
@@ -0,0 +1,198 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+ & carried forward from <%lastpage%> & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{0.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+\textbf{To}
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{0.3cm}
+
+<%if contact%>
+Attn: <%contact%>
+\vspace{0.3cm}
+<%end contact%>
+
+<%if vendorphone%>
+Tel: <%vendorphone%>
+<%end vendorphone%>
+
+<%if vendorfax%>
+Fax: <%vendorfax%>
+<%end vendorfax%>
+
+<%email%>
+}
+\parbox[t]{7.5cm}{
+\textbf{Ship To}
+\vspace{0.3cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{0.3cm}
+
+<%if shiptocontact%>
+Attn: <%shiptocontact%>
+\vspace{0.3cm}
+<%end shiptocontact%>
+
+<%if shiptophone%>
+Tel: <%shiptophone%>
+<%end shiptophone%>
+
+<%if shiptofax%>
+Fax: <%shiptofax%>
+<%end shiptofax%>
+
+<%shiptoemail%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{P U R C H A S E} \parbox{0.3cm}{\hfill} \textbf{O R D E R}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%orddate%> \\
+<%if reqdate%>
+ \textbf{Required by} & <%reqdate%> \\
+<%end reqdate%>
+ \textbf{Number} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ All prices in \textbf{<%currency%>} funds.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+%\footnotetext[1]{\tiny }
+
+\end{document}
+
+
diff --git a/sql-ledger/templates/Default-receipt.tex b/sql-ledger/templates/Default-receipt.tex
new file mode 100644
index 0000000..24427b3
--- /dev/null
+++ b/sql-ledger/templates/Default-receipt.tex
@@ -0,0 +1,74 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{1.8cm}
+
+<%notes%>
+
+\vspace{0.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
diff --git a/sql-ledger/templates/Default-sales_order.html b/sql-ledger/templates/Default-sales_order.html
new file mode 100644
index 0000000..c09e13a
--- /dev/null
+++ b/sql-ledger/templates/Default-sales_order.html
@@ -0,0 +1,212 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Telephone: <%tel%>
+ <br>Facsimile: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>S A L E S &nbsp;&nbsp; O R D E R</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Order Date</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Required by</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>To:</th>
+ <th align=left><font color=ffffff>Ship To:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Number</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qt'y</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Price</th>
+ <th><font color=ffffff>Disc</th>
+ <th><font color=ffffff>Amount</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%ordtotal%></td>
+<%end taxincluded%>
+
+<%if not taxincluded%>
+ <th colspan=5 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%> on <%taxbase%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=5><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Terms Net <b><%terms%></b> days</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%ordtotal%></th>
+ </tr>
+<%if taxincluded%>
+ <tr>
+ <td colspan=3>Tax is included in Total</td>
+ </tr>
+<%end taxincluded%>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Notes</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ All prices in <b><%currency%></b> Funds
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ A 10% order cancellation fee will be applied for any special order
+ products or products that have been customized, enhanced or
+ upgraded at customers request.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Default-sales_order.tex b/sql-ledger/templates/Default-sales_order.tex
new file mode 100644
index 0000000..d5ac40c
--- /dev/null
+++ b/sql-ledger/templates/Default-sales_order.tex
@@ -0,0 +1,143 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Disc} & \textbf{Amount} \\
+ & carried forward from <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{S A L E S} \parbox{0.3cm}{\hfill} \textbf{O R D E R}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%orddate%> \\
+ \textbf{Number} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Disc} & \textbf{Amount} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ All prices in \textbf{<%currency%>} funds.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+A 10\% order cancellation fee will be applied for any special order products or
+products that have been customized, enhanced or upgraded at customers request.
+Items which are non-returnable are indicated above.
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Default-statement.html b/sql-ledger/templates/Default-statement.html
new file mode 100644
index 0000000..6fca322
--- /dev/null
+++ b/sql-ledger/templates/Default-statement.html
@@ -0,0 +1,121 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th><img src=http://www.sql-ledger.org/images/sql-ledger.png border=0 width=64 height=58></th>
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3><h4>S T A T E M E N T</h4></th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tel: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>Invoice #</th>
+ <th width=15%>Date</th>
+ <th width=15%>Due</th>
+ <th width=10%>Current</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></td>
+ <th align=right><%c30total%></td>
+ <th align=right><%c60total%></td>
+ <th align=right><%c90total%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Total Outstanding</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>Please make check payable to <b><%company%></b>.
+ </td>
+ </tr>
+ <tr height=20></tr>
+</table>
+
diff --git a/sql-ledger/templates/Default-statement.tex b/sql-ledger/templates/Default-statement.tex
new file mode 100644
index 0000000..0b63f75
--- /dev/null
+++ b/sql-ledger/templates/Default-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{S T A T E M E N T} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Total outstanding} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Please make check payable to <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Dutch-balance_sheet.html b/sql-ledger/templates/Dutch-balance_sheet.html
new file mode 100644
index 0000000..16ede70
--- /dev/null
+++ b/sql-ledger/templates/Dutch-balance_sheet.html
@@ -0,0 +1,104 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>BALANS
+<br><%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>ACTIVA<br><hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td> </td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>Totaal Activa</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>PASSIVA<b><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Totaal Passiva</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>ONVERDEELD RESULTAAT<br><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Totaal Opbrengst</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAAL PASSIVA & RESULTAAT</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
+
+
+
+
+
+
+
diff --git a/sql-ledger/templates/Dutch-check.tex b/sql-ledger/templates/Dutch-check.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Dutch-check.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Dutch-income_statement.html b/sql-ledger/templates/Dutch-income_statement.html
new file mode 100644
index 0000000..ce4fd24
--- /dev/null
+++ b/sql-ledger/templates/Dutch-income_statement.html
@@ -0,0 +1,83 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>INKOMSTEN OVERZICHT
+<br><%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>INKOMSTEN<br><hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4> </td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Totaal Inkomsten</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>ONKOSTEN<br><hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td> </td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Totaal Onkosten</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>WINST / (VERLIES)</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
+
+
+
+
+
+
+
+
+
diff --git a/sql-ledger/templates/Dutch-invoice.html b/sql-ledger/templates/Dutch-invoice.html
new file mode 100644
index 0000000..9dc656c
--- /dev/null
+++ b/sql-ledger/templates/Dutch-invoice.html
@@ -0,0 +1,239 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>F A C T U U R</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Factuurdatum</th><td width=10>&nbsp;</td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Vervaldatum</th><td width=10>&nbsp;</td><td><%duedate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Factuurnummer</th><td>&nbsp;</td><td><%invnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Factuuradres:</th>
+ <th align=left><font color=ffffff>Verzendadres:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>Regel</th> -->
+ <th align=left><font color=ffffff>Artikelnummer</th>
+ <th align=left><font color=ffffff>Omschrijving</th>
+ <th><font color=ffffff>Aantal</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Prijs</th>
+ <th><font color=ffffff>Korting</th>
+ <th><font color=ffffff>Totaal</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+<!--
+you can also use netprice instead of sellprice if you
+don't want to show the discount
+netprice = sellprice - discount
+-->
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=5 align=right>Subtotaal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right>BTW <%taxrate%>%</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th colspan=5 align=right>Betaald</th>
+ <td colspan=2 align=right>- <%paid%></td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td colspan=3>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Betalen binnen <b><%terms%></b> dagen</td>
+ <th colspan=2 align=right>Openstaand</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Opmerkingen</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Alle prijzen in <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <th colspan=7>
+ Gaarne u betaling overmaken op onderstaande giro- of bankrekening
+ <br>ten name van <%company%>
+ <br>onder vermelding van het factuurnummer.
+ </th>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Op al onze aanbiedingen/leveringen zijn, met uitsluiting van eventuele inkoop- of andere voorwaarden van de opdrachtgever,
+<br>de Algemene Voorwaarden van <%company%> van toepassing.
+<br>Deze Algemene Voorwaarden zijn gedeponeerd bij de Kamer van Koophandel te ........
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+ <tr>
+ <th colspan=7 align=left><font size=-2>BTW nummer:<%taxnumber%></th>
+ </tr>
+
+ <tr>
+ <th colspan=7 align=left><font size=-2>Kamer van Koophandel te ...... nummer:<%businessnumber%></th>
+ </tr>
+
+ <tr>
+ <th colspan=7 align=left><font size=-2>Girorekening:.........</th>
+ </tr>
+
+ <tr>
+ <th colspan=7 align=left><font size=-2>Bankrekening:..........</th>
+ </tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Dutch-invoice.tex b/sql-ledger/templates/Dutch-invoice.tex
new file mode 100644
index 0000000..c19d8e2
--- /dev/null
+++ b/sql-ledger/templates/Dutch-invoice.tex
@@ -0,0 +1,138 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Disc} & \textbf{Amount} \\
+ & carried forward from page <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{F A K T U U R}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Datum} & <%invdate%> \\
+ \textbf{Faktuurnummer} & <%invnumber%> \\
+ \textbf{Klantnummer} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Artikelnr} & \textbf{Omschrijving} & \textbf{Aantal} &
+ \textbf{Eenheid} & \textbf{Prijs} & \textbf{Korting} & \textbf{Bedrag} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotaal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Totaal} & \textbf{<%total%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Alle prijzen in \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Dank voor uw gewaardeerde klandizie!}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Dutch-packing_list.html b/sql-ledger/templates/Dutch-packing_list.html
new file mode 100644
index 0000000..aea6ba7
--- /dev/null
+++ b/sql-ledger/templates/Dutch-packing_list.html
@@ -0,0 +1,121 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>P A K B O N</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Factuurdatum</th><td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Factuurnummer</th><td></td><td><%invnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Verzendadres:</th>
+ </tr>
+
+ <tr>
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Artikelnummer</th>
+ <th align=left><font color=ffffff>Omschrijving</th>
+ <th><font color=ffffff>Aantal</th>
+ <th>&nbsp;</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Opmerkingen</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ <%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+
diff --git a/sql-ledger/templates/Dutch-packing_list.tex b/sql-ledger/templates/Dutch-packing_list.tex
new file mode 100644
index 0000000..84289bc
--- /dev/null
+++ b/sql-ledger/templates/Dutch-packing_list.tex
@@ -0,0 +1,114 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefoon & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Nummer} & \textbf{Omschrijving} & \textbf{Aantal} &
+ \textbf{Eenheid} & \textbf{Bin} \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{3.5cm}
+
+\textbf{P A K B O N} \parbox{0.3cm}{\hfill} \textbf{L I S T}
+
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Datum} & <%invdate%> \\
+ \textbf{Faktuurnummer} & <%invnumber%> \\
+ \textbf{Klantnummer} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Nummer} & \textbf{Omschrijving} & \textbf{Aantal} &
+ \textbf{Eenheid} & \textbf{Bin} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%bin%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Dank voor uw gewaardeerde klandizie!}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Dutch-purchase_order.html b/sql-ledger/templates/Dutch-purchase_order.html
new file mode 100644
index 0000000..0cb58d7
--- /dev/null
+++ b/sql-ledger/templates/Dutch-purchase_order.html
@@ -0,0 +1,186 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>I N K O O P&nbsp;&nbsp;B E S T E L L I N G</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Bestel Datum</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Lever datum</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Bestel nummer</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>To:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Nummer</th>
+ <th align=left><font color=ffffff>Omschrijving</th>
+ <th><font color=ffffff>Aantal</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Prijs</th>
+ <th><font color=ffffff>Bedrag</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=6><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=4 align=right>Subtotaal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=4 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=2>Betalings termijn <b><%terms%></b> dagen</td>
+ <th colspan=2 align=right>Totaal</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Notes</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Alle prijzen in <b><%currency%></b>'s
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>&nbsp;
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Dutch-purchase_order.tex b/sql-ledger/templates/Dutch-purchase_order.tex
new file mode 100644
index 0000000..c6c68d1
--- /dev/null
+++ b/sql-ledger/templates/Dutch-purchase_order.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefoon & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotaal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Bestel Nummer} & \textbf{Omschrijving} & \textbf{Aantal} &
+ \textbf{Eenheid} & \textbf{Prijs} & \textbf{Bedrag} \\
+ & carried forward from <%lastpage%> & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{I N K O O P B E S T E L L I N G} \parbox{0.3cm}{\hfill} \textbf{O R D E R}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Datum} & <%orddate%> \\
+<%if reqdate%>
+ \textbf{Gewenste Leverdatum} & <%reqdate%> \\
+<%end reqdate%>
+ \textbf{Bestel Nummer} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Nummer} & \textbf{Omschrijving} & \textbf{Aantal} &
+ \textbf{Eenheid} & \textbf{Prijs} & \textbf{Bedrag} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotaal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Alle prijzen in \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Dutch-receipt.tex b/sql-ledger/templates/Dutch-receipt.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Dutch-receipt.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Dutch-sales_order.html b/sql-ledger/templates/Dutch-sales_order.html
new file mode 100644
index 0000000..42b20a9
--- /dev/null
+++ b/sql-ledger/templates/Dutch-sales_order.html
@@ -0,0 +1,208 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>V E R K O O P&nbsp;&nbsp;B E S T E L L I N G</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Bestel Datum</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Gewenste Leverdatum</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Bestel Nummer</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Aan:</th>
+ <th align=left><font color=ffffff>Verzenden aan:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Nummer</th>
+ <th align=left><font color=ffffff>Omschrijving</th>
+ <th><font color=ffffff>Aantal</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Prijs</th>
+ <th><font color=ffffff>Korting</th>
+ <th><font color=ffffff>Bedrag</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Totaal</th>
+ <td colspan=2 align=right><%ordtotal%></td>
+<%end taxincluded%>
+
+<%if not taxincluded%>
+ <th colspan=5 align=right>Subtotaal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%> over <%taxbase%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=5><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Betalingstermijn <b><%terms%></b> dagen</td>
+ <th colspan=2 align=right>Totaal</th>
+ <th colspan=2 align=right><%ordtotal%></th>
+ </tr>
+<%if taxincluded%>
+ <tr>
+ <td colspan=3>Totaal bedrag is inclusief BTW.</td>
+ </tr>
+<%end taxincluded%>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Opmerkingen:</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Alle prijzen in <b><%currency%></b>'s
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>&nbsp;
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Dutch-sales_order.tex b/sql-ledger/templates/Dutch-sales_order.tex
new file mode 100644
index 0000000..79acb4d
--- /dev/null
+++ b/sql-ledger/templates/Dutch-sales_order.tex
@@ -0,0 +1,134 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefoon & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotaal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Nummer} & \textbf{Omschrijving} & \textbf{Aantal} &
+ \textbf{Eenheid} & \textbf{Prijs} & \textbf{Korting} & \textbf{Bedrag} \\
+ & Transport van <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{V E R K O O P} \parbox{0.3cm}{\hfill} \textbf{B E S T E L L I N G}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Datum} & <%orddate%> \\
+ \textbf{Bestel Nummer} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Nummer} & \textbf{Omschrijving} & \textbf{Aantal} &
+ \textbf{Eenheid} & \textbf{Prijs} & \textbf{Korting} & \textbf{Bedrag} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotaal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> over <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Totaal} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Alle prijzen in \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Dutch-statement.html b/sql-ledger/templates/Dutch-statement.html
new file mode 100644
index 0000000..599a2f5
--- /dev/null
+++ b/sql-ledger/templates/Dutch-statement.html
@@ -0,0 +1,121 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th><img src=http://www.sql-ledger.org/images/sql-ledger.png border=0 width=64 height=58></th>
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3><h4>O P E N S T A A N D E &nbsp;&nbsp;F A C T U R E N</h4></th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tel: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>Factuur #</th>
+ <th width=15%>Datum</th>
+ <th width=15%>Vervaldatum</th>
+ <th width=10%>Huidig</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></td>
+ <th align=right><%c30total%></td>
+ <th align=right><%c60total%></td>
+ <th align=right><%c90total%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Totaal Openstaand</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>Maak de betalingen over aan<b><%company%></b>.
+ </td>
+ </tr>
+ <tr height=20></tr>
+</table>
+
diff --git a/sql-ledger/templates/Dutch-statement.tex b/sql-ledger/templates/Dutch-statement.tex
new file mode 100644
index 0000000..470bb1b
--- /dev/null
+++ b/sql-ledger/templates/Dutch-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Factuur \#} & \textbf{Datum} & \textbf{Vervaldatum} &
+ \textbf{Huidig} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{O P E N S T A A N D E F A C T U R E N} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Factuur \#} & \textbf{Datum} & \textbf{Vervaldatum} &
+ \textbf{Huidig} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Totaal openstaand} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Maak U betalingen over aan <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Estonian-balance_sheet.html b/sql-ledger/templates/Estonian-balance_sheet.html
new file mode 100644
index 0000000..dcfa40b
--- /dev/null
+++ b/sql-ledger/templates/Estonian-balance_sheet.html
@@ -0,0 +1,103 @@
+<head>
+ <title>Bilanss</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>BILANSS
+<br><%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>AKTIVA<br><hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td> </td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>AKTIVA KOKKU</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>PASSIVA<b><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Passiva kokku</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>AKTSIAKAPITAL<br><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Aktsiakapital kokku</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>KOKKU PASSIVA JA AKTSIAKAPITAL</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
+
+
+
diff --git a/sql-ledger/templates/Estonian-check.tex b/sql-ledger/templates/Estonian-check.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Estonian-check.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Estonian-income_statement.html b/sql-ledger/templates/Estonian-income_statement.html
new file mode 100644
index 0000000..b0594ea
--- /dev/null
+++ b/sql-ledger/templates/Estonian-income_statement.html
@@ -0,0 +1,84 @@
+<head>
+ <title>Kasumiaruanne</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>KASUMIARUANNE
+<br><%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>TULUD<br><hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4> </td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Tulud kokku</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>KULUD<br><hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td> </td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Kulud kokku</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>KASUM / (KAHJUM)</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
+
+
+
+
+
+
+
diff --git a/sql-ledger/templates/Estonian-invoice.html b/sql-ledger/templates/Estonian-invoice.html
new file mode 100644
index 0000000..8660fb8
--- /dev/null
+++ b/sql-ledger/templates/Estonian-invoice.html
@@ -0,0 +1,215 @@
+<head>
+ <title>Arve</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>A R V E</h4>
+ </th>
+ </tr>
+
+ </table>
+
+<!-- other variables you can use include
+tel, fax, signature, username, businessnumber -->
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Kuupäev</th><td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Arve Nr.</th><td></td><td><%invnumber%></td></tr>
+ </tr>
+
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Arve aadress:</th>
+ <th align=left><font color=ffffff>Tarneaadress:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Kood</th>
+ <th align=left><font color=ffffff>Selgitus</th>
+ <th colspan=2><font color=ffffff>Kogus</th>
+ <th><font color=ffffff>Hind</th>
+ <th><font color=ffffff>Alh%</th>
+ <th><font color=ffffff>Kogus</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+<!--
+you can also use netprice instead of sellprice if you
+don't want to show the discount
+netprice = sellprice - discount
+-->
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=5 align=right>Summa</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th colspan=5 align=right>Makstud</th>
+ <td colspan=2 align=right>- <%paid%></td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td colspan=3> </td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Maksetingimus <b><%terms%></b> päeva</td>
+ <th colspan=2 align=right>Lõppsumma</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Märkused</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Kõik hinnad: <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td colspan=7 align=right>Summa sõnadega: <%sum_as_words_ee%> </td></tr>
+
+<tr><td> </td></tr>
+
+<tr>
+ <th colspan=7>
+ Palun märkige pangatsheki saajaks <%company%>
+ <br>Täname meeldiva koostöö eest!
+ </th>
+</tr>
+
+
+<tr><td> </td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Maksetähtaeg <%terms%> päeva alates arve kuupäevast.
+ Intress tasumata summadelt on 1.5% kuus kuni arve täeliku tasumiseni.
+ Tagastatud toodetele kehtib 10% tagastamistasu. Enne toodete tagastamist on vajalik
+<%company%> nõusolek. Tagastavad tooted peavad olema makstud ning kindlustatud,
+<%company%> ei vastuta transpordi käigus tekkinud kahjude eest.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+<%foreach tax%>
+<tr>
+ <th colspan=7 align=left><font size=-2><%taxdescription%> Registration <%taxnumber%></th>
+</tr>
+<%end tax%>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Estonian-invoice.tex b/sql-ledger/templates/Estonian-invoice.tex
new file mode 100644
index 0000000..bfa2f7a
--- /dev/null
+++ b/sql-ledger/templates/Estonian-invoice.tex
@@ -0,0 +1,147 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefon & <%tel%>\\
+ Faks & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Vahesumma} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Kood} & \textbf{Kirjeldus} & \textbf{Kogus} &
+ \textbf{Ühik} & \textbf{Hind} & \textbf{Alh} & \textbf{Kokku} \\
+ & edasi kantud lehelt <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{A R V E}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Kuupäev} & <%invdate%> \\
+ \textbf{Number} & <%invnumber%> \\
+ \textbf{Klient} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Kood} & \textbf{Kirjeldus} & \textbf{Kogus} &
+ \textbf{Ühik} & \textbf{Hind} & \textbf{Alh} & \textbf{Kokku} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Vahesumma} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Summa} & \textbf{<%total%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Kõik hinnad \textbf{<%currency%>} funds.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Täname meeldiva koostöö eest!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Maksetähtaeg <%terms%> päeva alates arve kuupäevast.
+ Intress tasumata summadelt on 1.5\% kuus kuni arve täeliku tasumiseni.
+ Tagastatud toodetele kehtib 10\% tagastamistasu. Enne toodete tagastamist on vajalik <%company%> nõusolek. Tagastavad tooted peavad olema makstud ning kindlustatud, <%company%> ei vastuta transpordi käigus tekkinud kahjude eest.}
+
+\end{document}
+
+
+
diff --git a/sql-ledger/templates/Estonian-packing_list.html b/sql-ledger/templates/Estonian-packing_list.html
new file mode 100644
index 0000000..0006307
--- /dev/null
+++ b/sql-ledger/templates/Estonian-packing_list.html
@@ -0,0 +1,147 @@
+<head>
+ <title>Saateleht</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>S A A T E L E H T</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Kuupäev</th><td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td></td><td><%invnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Tarneaadress:</th>
+ </tr>
+
+ <tr>
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Kood</th>
+ <th align=left><font color=ffffff>Selgitus</th>
+ <th><font color=ffffff>Kogus</th>
+ <th> </th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Märkused</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ <%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Tagastatud toodetele kehtib 10% tagastamistasu. Enne toodete tagastamist on vajalik
+<%company%> nõusolek. Tagastavad tooted peavad olema makstud ning kindlustatud,
+ <%company%> ei vastuta transpordi käigus tekkinud kahjude eest.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+
+
+
+
+
+
diff --git a/sql-ledger/templates/Estonian-packing_list.tex b/sql-ledger/templates/Estonian-packing_list.tex
new file mode 100644
index 0000000..06c763a
--- /dev/null
+++ b/sql-ledger/templates/Estonian-packing_list.tex
@@ -0,0 +1,119 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefon & <%tel%>\\
+ Faks & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Kood} & \textbf{Kirjeldus} & \textbf{Kogus} &
+ \textbf{Ühik} & \textbf{Bin} \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{3.5cm}
+
+\textbf{S A A T E L E H T} \parbox{0.3cm}{\hfill}
+
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%invdate%> \\
+ \textbf{Number} & <%invnumber%> \\
+ \textbf{Customer} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Kood} & \textbf{Selgitus} & \textbf{Kogus} &
+ \textbf{Ühik} & \textbf{Bin} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%bin%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Täname meeldiva koostöö eest!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+ Tagastatud toodetele kehtib 10\% tagastamistasu. Enne toodete tagastamist on vajalik <%company%> nõusolek. Tagastavad tooted peavad olema makstud ning kindlustatud, <%company%> ei vastuta transpordi käigus tekkinud kahjude eest.}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Estonian-purchase_order.html b/sql-ledger/templates/Estonian-purchase_order.html
new file mode 100644
index 0000000..7ee0073
--- /dev/null
+++ b/sql-ledger/templates/Estonian-purchase_order.html
@@ -0,0 +1,195 @@
+<head>
+ <title>Ostutellimus</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>O S T U T E L L I M U S</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Tellimuse Kpv</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Required by</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>To:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Number</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qt'y</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Price</th>
+ <th><font color=ffffff>Amount</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=6><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=4 align=right>Vahesumma</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=4 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=2>Maksetähtaeg <b><%terms%></b> tööpäeva</td>
+ <th colspan=2 align=right>Kokku</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Märkused</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Kõik hinnad: <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Maksetähtaeg <%terms%> päeva alates arve kuupäevast.
+ Intress tasumata summadelt on 1.5% kuus kuni arve täeliku tasumiseni.
+ Tagastatud toodetele kehtib 10% tagastamistasu. Enne toodete tagastamist on vajalik
+<%company%> nõusolek. Tagastavad tooted peavad olema makstud ning kindlustatud,
+<%company%> ei vastuta transpordi käigus tekkinud kahjude eest.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Estonian-purchase_order.tex b/sql-ledger/templates/Estonian-purchase_order.tex
new file mode 100644
index 0000000..ee1d778
--- /dev/null
+++ b/sql-ledger/templates/Estonian-purchase_order.tex
@@ -0,0 +1,143 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefon & <%tel%>\\
+ Faks & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Vahesumma} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Kood} & \textbf{Kirjeldus} & \textbf{Kogus} &
+ \textbf{Ühik} & \textbf{Hind} & \textbf{Kogus} \\
+ & üle kantud lehelt <%lastpage%> & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{O S T U T E L L I M U S} \parbox{0.3cm}{\hfill}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%orddate%> \\
+<%if reqdate%>
+ \textbf{Required by} & <%reqdate%> \\
+<%end reqdate%>
+ \textbf{Number} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Kood} & \textbf{Kirjeldus} & \textbf{Kogus} &
+ \textbf{Ühik} & \textbf{Hind} & \textbf{Kokku} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Vahesumma} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Summa} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Kõik hinnad \textbf{<%currency%>} funds.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+%\footnotetext[1]{\tiny }
+
+\end{document}
+
+
diff --git a/sql-ledger/templates/Estonian-receipt.tex b/sql-ledger/templates/Estonian-receipt.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Estonian-receipt.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Estonian-sales_order.html b/sql-ledger/templates/Estonian-sales_order.html
new file mode 100644
index 0000000..d608b73
--- /dev/null
+++ b/sql-ledger/templates/Estonian-sales_order.html
@@ -0,0 +1,214 @@
+<head>
+ <title>Müügitellimus</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>M Ü Ü G I T E L L I M U S</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Tellimuse kpv</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Tarnekuupäev</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Tellija aadress:</th>
+ <th align=left><font color=ffffff>Tarneaadress:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>Nr.</th> -->
+ <th align=left><font color=ffffff>Kood</th>
+ <th align=left><font color=ffffff>Selgitus</th>
+ <th><font color=ffffff>Kogus</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Hind</th>
+ <th><font color=ffffff>Allh%</th>
+ <th><font color=ffffff>Summa</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Kokku</th>
+ <td colspan=2 align=right><%ordtotal%></td>
+<%end taxincluded%>
+
+<%if not taxincluded%>
+ <th colspan=5 align=right>Vahesumma</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%> <%taxbase%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=5><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Maksetähtaeg <b><%terms%></b> päeva</td>
+ <th colspan=2 align=right>Kokku</th>
+ <th colspan=2 align=right><%ordtotal%></th>
+ </tr>
+<%if taxincluded%>
+ <tr>
+ <td colspan=3>Summa sisaldab käibemaksu</td>
+ </tr>
+<%end taxincluded%>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Märkused</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Kõik hinnad <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Eritellimusel tehtud toodetel ning toodetel mida on kliendi soovil
+ kohandatud või täiendatud on tellimuse katkestamise tasu 10% tellimuse hinnast.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Estonian-sales_order.tex b/sql-ledger/templates/Estonian-sales_order.tex
new file mode 100644
index 0000000..beb32c5
--- /dev/null
+++ b/sql-ledger/templates/Estonian-sales_order.tex
@@ -0,0 +1,141 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefon & <%tel%>\\
+ Faks & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Vahesumma} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Kood} & \textbf{Kirjeldus} & \textbf{Kogus} &
+ \textbf{Ühik} & \textbf{Hind} & \textbf{Kirjeldus} & \textbf{Kokku} \\
+ & carried forward from <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{M Ü Ü G I T E L L I M U S} \parbox{0.3cm}{\hfill}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Kuupäev} & <%orddate%> \\
+ \textbf{Number} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Kood} & \textbf{Kirjeldus} & \textbf{Kogus} &
+ \textbf{Ühik} & \textbf{Hind} & \textbf{Alh} & \textbf{Kokku} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Vahesumma} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Summa} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Kõik hinnad \textbf{<%currency%>} funds.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+ Tagastatud toodetele kehtib 10\% tagastamistasu. Enne toodete tagastamist on vajalik <%company%> nõusolek. Tagastavad tooted peavad olema makstud ning kindlustatud, <%company%> ei vastuta transpordi käigus tekkinud kahjude eest.}
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Estonian-statement.html b/sql-ledger/templates/Estonian-statement.html
new file mode 100644
index 0000000..6fca322
--- /dev/null
+++ b/sql-ledger/templates/Estonian-statement.html
@@ -0,0 +1,121 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th><img src=http://www.sql-ledger.org/images/sql-ledger.png border=0 width=64 height=58></th>
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3><h4>S T A T E M E N T</h4></th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tel: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>Invoice #</th>
+ <th width=15%>Date</th>
+ <th width=15%>Due</th>
+ <th width=10%>Current</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></td>
+ <th align=right><%c30total%></td>
+ <th align=right><%c60total%></td>
+ <th align=right><%c90total%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Total Outstanding</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>Please make check payable to <b><%company%></b>.
+ </td>
+ </tr>
+ <tr height=20></tr>
+</table>
+
diff --git a/sql-ledger/templates/Estonian-statement.tex b/sql-ledger/templates/Estonian-statement.tex
new file mode 100644
index 0000000..0b63f75
--- /dev/null
+++ b/sql-ledger/templates/Estonian-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{S T A T E M E N T} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Total outstanding} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Please make check payable to <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/French-balance_sheet.html b/sql-ledger/templates/French-balance_sheet.html
new file mode 100644
index 0000000..56748d6
--- /dev/null
+++ b/sql-ledger/templates/French-balance_sheet.html
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional">
+
+<html>
+
+<head>
+
+<title>Bilan</title>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-15">
+
+</head>
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>BILAN DE VÉRIFICATION
+<br><%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>ACTIF<br><hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td> </td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>Total Actif</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>PASSIF<b><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total Passif</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>BENEFICES NON DISTRIBUÉS<br><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total Capital</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAL PASSIF & CAPITAL</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/sql-ledger/templates/French-check.tex b/sql-ledger/templates/French-check.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/French-check.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/French-income_statement.html b/sql-ledger/templates/French-income_statement.html
new file mode 100644
index 0000000..e76df09
--- /dev/null
+++ b/sql-ledger/templates/French-income_statement.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional">
+
+<html>
+
+<head>
+
+<title>Compte de Résultat</title>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-15">
+
+</head>
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>Compte de Résultat
+<br><%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>RECETTES<br><hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4> </td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Total Recettes</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>DÉPENSES<br><hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td> </td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Total Dépenses</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>BENEFICES / PERTES (en <%currency%> )</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
+</body>
+</html>
diff --git a/sql-ledger/templates/French-invoice.html b/sql-ledger/templates/French-invoice.html
new file mode 100644
index 0000000..901a317
--- /dev/null
+++ b/sql-ledger/templates/French-invoice.html
@@ -0,0 +1,309 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional">
+
+<html>
+
+<head>
+
+<title>A2A <%invnumber%> <%name%></title>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-15">
+
+</head>
+
+<body bgcolor="ffffff">
+
+<table width="100%">
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width="100%">
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tél&nbsp;: <%tel%>
+ <br>Fax&nbsp;: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>F A C T U R E</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width="100%" cellspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Date de facture</th><td width=10>&nbsp;</td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Date d'échéance</th><td width=10>&nbsp;</td><td><%duedate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>N° de facture</th><td>&nbsp;</td><td><%invnumber%></td></tr>
+ </tr>
+
+<!--
+ <tr>
+ <th align=right>Correspondant</th><td>&amp;nbsp;</td><td><%employee%></td>
+ </tr>
+-->
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width="100%">
+ <tr bgcolor="000000">
+ <th align=left><font color=ffffff>Adresse de facturation</font></th>
+ <th align=left><font color=ffffff>Adresse d'envoi</font></th>
+ </tr>
+
+<!--
+ d'autres variables pouvant être utilisées ici :
+ contact, shiptocontact, shiptophone, shiptofax
+-->
+
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width="100%">
+ <tr bgcolor="000000">
+<!-- <th align=right><font color="ffffff">N°</font></th> -->
+ <th align=left><font color="ffffff">N°</font></th>
+ <th align=left><font color="ffffff">Description</font></th>
+ <th><font color="ffffff">Qté</font></th>
+ <th>&nbsp;</th>
+ <th><font color="ffffff">Prix</font></th>
+ <th><font color="ffffff">Remise</font></th>
+ <th><font color="ffffff">Montant</font></th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+veuillez adapter le colspan si vous comptez inclure ce poste.
+ceci permettra de décaler le poste sous-total vers la gauche.
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+<!--
+vous pouvez également utiliser netprice à la place de sellprice
+si vous ne voulez pas afficher la remise
+netprice = sellprice - discount
+-->
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%invtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th colspan=5 align=right>Sous-total</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%></th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th colspan=5 align=right>Déjà payé</th>
+ <td colspan=2 align=right>- <%paid%></td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td colspan=3>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>À régler dans <b><%terms%></b> jours au plus tard.</td>
+ <th colspan=2 align=right>Solde à régler</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>À noter&nbsp;:</td>
+ <td><%notes%></td>
+<%end notes%>
+ <td align=right>
+ Tous prix indiqués en <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<%if paid%>
+<tr>
+ <td colspan=7>
+ <table width="60%">
+ <tr>
+ <th align=left>Détail règlements</th>
+ </tr>
+ <tr>
+ <td colspan=4>
+ <hr noshade>
+ </td>
+ </tr>
+ <tr>
+ <th align=left>Date</th>
+ <th align=left>Compte</th>
+ <th align=left>Source</th>
+ <th align=left>Montant</th>
+ </tr>
+<%end paid%>
+
+<%foreach payment%>
+ <tr>
+ <td><%paymentdate%></td>
+ <td><%paymentaccount%></td>
+ <td><%paymentsource%></td>
+ <td><%payment%></td>
+ </tr>
+<%end payment%>
+
+<%if paid%>
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>&nbsp;</td>
+</tr>
+<%end paid%>
+
+<tr>
+ <th colspan=7>
+ <!-- <br>Merci beaucoup&amp;nbsp;! -->
+ </th>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width="100%">
+ <tr valign=top>
+ <td><font size=-3>
+ &nbsp;
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+<!-- <%foreach tax%>
+ <tr>
+ <th colspan=7 align=left><font size=-2><%taxdescription%> Numéro de TVA <%taxnumber%></font></th>
+ </tr>
+<%end tax%> -->
+
+<%if taxincluded%>
+ <tr>
+ <th colspan=7 align=left><font size=-2>Les taxes affichés sont inclus dans le prix.</font></th>
+ </tr>
+<%end taxincluded%>
+
+<!-- business number
+ <tr>
+ <th colspan=7 align=left><font size=-2>Régistre de Commerce&amp;nbsp;: <%businessnumber%></font></th>
+ </tr>
+-->
+
+<!-- information banquaire -->
+ <tr><td>
+ <h6><center>N° TVA&nbsp;: &nbsp;&nbsp;Banque&nbsp;: &nbsp;&nbsp;N° de compte&nbsp;: &nbsp;&nbsp;Code SWIFT&nbsp;: </center>
+ </h6>
+ </td>
+ </tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
diff --git a/sql-ledger/templates/French-invoice.tex b/sql-ledger/templates/French-invoice.tex
new file mode 100644
index 0000000..2896fc9
--- /dev/null
+++ b/sql-ledger/templates/French-invoice.tex
@@ -0,0 +1,151 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage[frenchb]{babel}
+\usepackage[latin1]{inputenc}
+\usepackage{tabularx}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Téléphone & <%tel%>\\
+ Télécopieur & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Sous-total} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Numéro} & \textbf{Description} & \textbf{Qté} &
+ \textbf{Unité} & \textbf{Prix} & \textbf{Remise} & \textbf{Montant} \\
+ & reporté de la page <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{F A C T U R E}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date de facturation} & <%invdate%> \\
+ \textbf{Numéro de facture} & <%invnumber%> \\
+ \textbf{Numéro de client} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Numéro} & \textbf{Description} & \textbf{Qté} &
+ \textbf{Unité} & \textbf{Prix} & \textbf{Remise} & \textbf{Montant} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Sous-total} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> de <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%total%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Tous les prix indiqués sont en \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Merci de faire affaire avec nous!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Le paiement doit être acquitté au plus tard <%terms%> jours à partir de
+la date de facturation. Des intérêts seront perçus à raison de 1.5\% par
+mois après <%duedate%> jusqu'à ce que le paiement soit complet. Les
+éléments retournés seront sujets à un supplément de remmagasinnage de
+10\%. Une autorisation de renvoi doit être obtenue au préalable auprès de
+<%company%>. Les frais de transports et d'assurance sur les éléments
+retournés devront être couvert par le client de façon appropriée.
+<%company%> ne peut être tenue responsable des dommages survenus pendant
+le transit.}
+
+\end{document}
diff --git a/sql-ledger/templates/French-packing_list.html b/sql-ledger/templates/French-packing_list.html
new file mode 100644
index 0000000..3fa2fec
--- /dev/null
+++ b/sql-ledger/templates/French-packing_list.html
@@ -0,0 +1,152 @@
+CTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional">
+
+<html>
+
+<head>
+
+<title>A2A <%invnumber%> <%name%></title>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-15">
+
+</head>
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>L I S T E&nbsp;&nbsp;D ' E N V O I</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Date de facture&nbsp;:</th><td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Numéro de facture&nbsp;:</th><td></td><td><%invnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Adresse d'envoi</th>
+ </tr>
+
+ <tr>
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>N°</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qté</th>
+ <th>&nbsp;</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=center><%qty%></td>
+ <td><%unit%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>À noter&nbsp;:</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right><b>EXPÉDIÉ PAR&nbsp;:
+ <%shippingpoint%></b>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3><!--
+ Conditions d'envoi :
+ Items returned are subject to
+ a 10% restocking charge. A return authorization must be obtained
+ from <%company%> before goods are returned. Returns must be shipped
+ prepaid and properly insured. <%company%> will not be responsible
+ for damages during transit. -->
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/sql-ledger/templates/French-packing_list.tex b/sql-ledger/templates/French-packing_list.tex
new file mode 100644
index 0000000..87113de
--- /dev/null
+++ b/sql-ledger/templates/French-packing_list.tex
@@ -0,0 +1,125 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage[frenchb]{babel}
+\usepackage[latin1]{inputenc}
+\usepackage{tabularx}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Téléphone & <%tel%>\\
+ Télécopieur & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Numéro} & \textbf{Description} & \textbf{Qté} &
+ \textbf{Unité} & \textbf{Bin} \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{3.5cm}
+
+\textbf{L I S T E} \parbox{0.3cm}{\hfill} \textbf{D E}
+\parbox{0.3cm}{\hfill} \textbf{P A Q U E T A G E}
+
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date de facture} & <%invdate%> \\
+ \textbf{Numéro de facture} & <%invnumber%> \\
+ \textbf{Numéro de client} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Numéro} & \textbf{Description} & \textbf{Qté} &
+ \textbf{Unité} & \textbf{Bin} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%bin%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Merci de faire affaire avec nous!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Les éléments retournés seront sujets à un supplément de remmagasinnage de
+10\%. Une autorisation de renvoi doit être obtenue au préalable auprès de
+<%company%>. Les frais de transports et d'assurance sur les éléments
+retournés devront être couvert par le client de façon appropriée.
+<%company%> ne peut être tenue responsable des dommages survenus pendant
+le transit.}
+
+\end{document}
diff --git a/sql-ledger/templates/French-purchase_order.html b/sql-ledger/templates/French-purchase_order.html
new file mode 100644
index 0000000..a5da0ad
--- /dev/null
+++ b/sql-ledger/templates/French-purchase_order.html
@@ -0,0 +1,207 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional">
+
+<html>
+
+<head>
+
+<title>Commande <%ordnumber%> <%name%></title>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-15">
+
+</head>
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tél&nbsp;: <%tel%>
+ <br>Fax&nbsp;: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>B O N&nbsp;&nbsp;D E&nbsp;&nbsp;C O M M A N D E</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% cellspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Date commande</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Requis pour</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>N° commande</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Commandé par</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>N°</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qté</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Prix</th>
+ <th><font color=ffffff>Montant</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+veuillez ajuster le colspan si vous voulez inclure ce poste pour décaler le sous-total vers la droite.
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=6><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=4 align=right>Sous-total</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=4 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=2>À régler dans <b><%terms%></b> jours au plus tard</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>À noter&nbsp;:</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ Tous prix indiqués en <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>
+<!--
+<font size=-3>
+ Payment due NET <%terms%> Days from date of Invoice.
+ Interest on overdue amounts will acrue at the rate of 1.5% per month
+ from due date until paid in full. Items returned are subject to
+ a 10% restocking charge. A return authorization must be obtained
+ from <%company%> before goods are returned. Returns must be shipped
+ prepaid and properly insured. <%company%> will not be responsible
+ for damages during transit.
+ </font>
+-->
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/French-purchase_order.tex b/sql-ledger/templates/French-purchase_order.tex
new file mode 100644
index 0000000..670d59c
--- /dev/null
+++ b/sql-ledger/templates/French-purchase_order.tex
@@ -0,0 +1,143 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage[frenchb]{babel}
+\usepackage[latin1]{inputenc}
+\usepackage{tabularx}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Téléphone & <%tel%>\\
+ Télécopieur & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Sous-total} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+ & reporté de la page <%lastpage%> & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{B O N} \parbox{0.3cm}{\hfill} \textbf{D E} \parbox{0.3cm}{\hfill}
+\textbf{C O M M A N D E}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date de la commande} & <%orddate%> \\
+<%if reqdate%>
+ \textbf{Livrable le} & <%reqdate%> \\
+<%end reqdate%>
+ \textbf{Numéro de commande} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Numéro} & \textbf{Description} & \textbf{Qté} &
+ \textbf{Unité} & \textbf{Prix} & \textbf{Montant} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Sous-total} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> de <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Tous les prix indiqués sont en \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+%\footnotetext[1]{\tiny }
+
+\end{document}
diff --git a/sql-ledger/templates/French-receipt.tex b/sql-ledger/templates/French-receipt.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/French-receipt.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/French-sales_order.html b/sql-ledger/templates/French-sales_order.html
new file mode 100644
index 0000000..492e75e
--- /dev/null
+++ b/sql-ledger/templates/French-sales_order.html
@@ -0,0 +1,229 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional">
+
+<html>
+
+<head>
+
+<title>Commande <%ordnumber%> <%name%></title>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-15">
+
+</head>
+
+<body bgcolor="ffffff">
+
+<table width="100%">
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width="100%">
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Tél&nbsp;: <%tel%>
+ <br>Fax&nbsp;: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>B O N&nbsp;&nbsp;&nbsp;D E&nbsp;&nbsp;&nbsp;C O M M A N D E</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% cellspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Date commande</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Requis pour</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>N° commande</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width="100%">
+ <tr bgcolor="000000">
+ <th align=left><font color="ffffff">Commandé par</th>
+ <th align=left><font color="ffffff">Adresse d'envoi</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width="100%">
+ <tr bgcolor="000000">
+<!-- <th align=right><font color="ffffff">N°</th> -->
+ <th align=left><font color="ffffff">N°</th>
+ <th align=left><font color="ffffff">Description</th>
+ <th><font color="ffffff">Qté</th>
+ <th>&nbsp;</th>
+ <th><font color="ffffff">Prix</th>
+ <th><font color="ffffff">Remise</th>
+ <th><font color="ffffff">Montant</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%ordtotal%></td>
+<%end taxincluded%>
+
+<%if not taxincluded%>
+ <th colspan=5 align=right>Sous-total</th>
+ <td colspan=2 align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%></th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=5><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>À régler dans <b><%terms%></b> jours au plus tard</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%ordtotal%></th>
+ </tr>
+<%if taxincluded%>
+ <tr>
+ <td colspan=3>Taxe comprise dans Total</td>
+ </tr>
+<%end taxincluded%>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>À noter&nbsp;:</td>
+ <td><%notes%></td>
+<%end notes%>
+ <td align=right>
+ Tous prix indiqués en <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width="100%">
+ <tr valign=top>
+ <td><font size=-3>
+<!--
+ A 10% order cancellation fee will be applied for any special order
+ products or products that have been customized, enhanced or
+ upgraded at customers request.
+-->
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=5>
+ <h6><center>N° TVA&nbsp;: &nbsp;&nbsp;Banque&nbsp;: &nbsp;&nbsp;N° de compte&nbsp;: &nbsp;&nbsp;Code SWIFT&nbsp;: </center>
+ </h6>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
diff --git a/sql-ledger/templates/French-sales_order.tex b/sql-ledger/templates/French-sales_order.tex
new file mode 100644
index 0000000..88e142f
--- /dev/null
+++ b/sql-ledger/templates/French-sales_order.tex
@@ -0,0 +1,144 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage[frenchb]{babel}
+\usepackage[latin1]{inputenc}
+\usepackage{tabularx}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Téléphone & <%tel%>\\
+ Télécopieur & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Sous-total} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Numéro} & \textbf{Description} & \textbf{Qté} &
+ \textbf{Unité} & \textbf{Prix} & \textbf{Remise} & \textbf{Montant} \\
+ & reporté de la page <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{C O M M A N D E} \parbox{0.3cm}{\hfill} \textbf{C L I E N T}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date de la commande} & <%orddate%> \\
+ \textbf{Numéro de commande} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Numéro} & \textbf{Description} & \textbf{Qté} &
+ \textbf{Unité} & \textbf{Prix} & \textbf{Remise} & \textbf{Montant} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Sous-total} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> de <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Tous les prix indiqués sont en \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Un supplément de 10% sera appliqué à toute commande spécifique et à tout
+produit adapté, amélioré ou mis-à-jour à la demande du client. Les
+éléments non-retournables sont indiqués ci-dessus.
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/French-statement.html b/sql-ledger/templates/French-statement.html
new file mode 100644
index 0000000..c2c9a5d
--- /dev/null
+++ b/sql-ledger/templates/French-statement.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional">
+
+<html>
+
+<head>
+
+<title>Extrait de compte pour <%name%></title>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-15">
+
+</head>
+
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th></th>
+ <td align=right>
+ <h4>
+ Tél&nbsp;: <%tel%>
+ <br>Fax&nbsp;: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3><h4>E X T R A I T&nbsp;&nbsp;D E&nbsp;&nbsp;C O M P T E</h4></th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tél&nbsp;: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax&nbsp;: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>Facture n°</th>
+ <th width=15%>Date</th>
+ <th width=15%>Echeance</th>
+ <th width=10%>Actuel</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></td>
+ <th align=right><%c30total%></td>
+ <th align=right><%c60total%></td>
+ <th align=right><%c90total%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Solde impayé</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>Tout paiement au nom de <b><%company%></b>
+ </td>
+ </tr>
+ <tr height=20></tr>
+</table>
+</body>
+</html>
diff --git a/sql-ledger/templates/French-statement.tex b/sql-ledger/templates/French-statement.tex
new file mode 100644
index 0000000..0b63f75
--- /dev/null
+++ b/sql-ledger/templates/French-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{S T A T E M E N T} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Total outstanding} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Please make check payable to <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/German-balance_sheet.html b/sql-ledger/templates/German-balance_sheet.html
new file mode 100644
index 0000000..f0d6f5e
--- /dev/null
+++ b/sql-ledger/templates/German-balance_sheet.html
@@ -0,0 +1,100 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>BILANZ
+<br><%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>AKTIVA<br><hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td> </td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAL</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>PASSIVA<b><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>TOTAL</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>EIGENTUM<br><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>TOTAL</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAL PASSIVA & EIGETNTUM</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
+
+
+
diff --git a/sql-ledger/templates/German-check.tex b/sql-ledger/templates/German-check.tex
new file mode 100644
index 0000000..d6256e7
--- /dev/null
+++ b/sql-ledger/templates/German-check.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Rechnung} & \textbf{Ausgestellt}
+ & \textbf{Fällig} & \textbf{Verrechnet} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/German-income_statement.html b/sql-ledger/templates/German-income_statement.html
new file mode 100644
index 0000000..aa3c22f
--- /dev/null
+++ b/sql-ledger/templates/German-income_statement.html
@@ -0,0 +1,78 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>GEWINN & VERLUST
+<br><%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>EINNAHMEN<br><hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4> </td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Totale Einnahmen</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>AUSGABEN<br><hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td> </td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Totale Ausgaben</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>GEWINN / (VERLUST)</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/German-invoice.html b/sql-ledger/templates/German-invoice.html
new file mode 100644
index 0000000..b2128c9
--- /dev/null
+++ b/sql-ledger/templates/German-invoice.html
@@ -0,0 +1,265 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Telefon <%tel%>
+ <br>Telefax <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>R E C H N U N G</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Ausgestellt am</th><td width=10>&nbsp;</td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Bezahlbar bis</th><td width=10>&nbsp;</td><td><%duedate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Nummer</th><td>&nbsp;</td><td><%invnumber%></td></tr>
+ </tr>
+
+<!--
+ <tr>
+ <th align=right>Clerk:</th><td>&nbsp;</td><td><%username%></td>
+ </tr>
+-->
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>An:</th>
+ <th align=left><font color=ffffff>Lieferaddresse:</th>
+ </tr>
+
+<!--
+ other variables which can be use:
+ contact, shiptocontact, shiptophone, shiptofax
+-->
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Nummer</th>
+ <th align=left><font color=ffffff>Beschreibung</th>
+ <th><font color=ffffff>Anz.</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Preis</th>
+ <th><font color=ffffff>Rab</th>
+ <th><font color=ffffff>Total</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+<!--
+you can also use netprice instead of sellprice if you
+don't want to show the discount
+netprice = sellprice - discount
+-->
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%invtotal%></td>
+ </tr>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <tr>
+ <th colspan=5 align=right>Zwischensumme</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+<%end taxincluded%>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%> auf <%taxbase%></th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th colspan=5 align=right>Bezahlt</th>
+ <td colspan=2 align=right>- <%paid%></td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td colspan=3>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Bezahlbar innerhalb von <b><%terms%></b> Tagen</td>
+<%if total%>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%total%></th>
+<%end total%>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Bemerkungen:</td>
+ <td><%notes%></td>
+<%end notes%>
+ <td align=right>
+ Alle Preise in <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Rechnung ist bezahlbar innerhalb von <%terms%> Tagen.
+ Nach dem <%duedate%> werden Zinsen zu einem
+ monatlichen Satz von 1.5% verrechnet.
+ Waren bleiben im Besitz von <%company%> bis die Rechnung voll bezahlt ist.
+ Rückgaben werden mit 10% Lagergebühren belastet. Beschädigte Waren
+ und Waren ohne eine Rückgabenummer werden nicht entgegengenommen.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=7 align=left><font size=-2><%taxdescription%> Registration <%taxnumber%></th>
+ </tr>
+<%end tax%>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan=7 align=left><font size=-2>Steuern sind im Preis inbegriffen.</th>
+ </tr>
+<%end taxincluded%>
+
+<!-- business number
+ <tr>
+ <th colspan=7 align=left><font size=-2>Business Number: <%businessnumber%></font></th>
+ </tr>
+-->
+
+ <tr>
+ <th colspan=7 align=left>
+ <hr>
+ <br>Bankverbindung
+ <br>Bank
+ <br>Bankleitzahl
+ <br>Konto No.
+ </td>
+ </tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/German-invoice.tex b/sql-ledger/templates/German-invoice.tex
new file mode 100644
index 0000000..0b38bb5
--- /dev/null
+++ b/sql-ledger/templates/German-invoice.tex
@@ -0,0 +1,155 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefon & <%tel%>\\
+ Telefax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Nummer} & \textbf{Artikel} & \textbf{Anz} &
+ \textbf{Einh} & \textbf{Preis} & \textbf{Rab} & \textbf{Total} \\
+ & Übertrag von Seite <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{R E C H N U N G}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Datum} & <%invdate%> \\
+ \textbf{Nummer} & <%invnumber%> \\
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Nummer} & \textbf{Artikel} & \textbf{Anz} &
+ \textbf{Einh} & \textbf{Preis} & \textbf{Rab} & \textbf{Total} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Zwischensumme} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> auf <%taxbase%> & <%tax%> \\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%invtotal%>} \\
+<%if paid%>
+ \textbf{Bezahlt} & <%paid%> \\
+<%end paid%>
+<%if total%>
+ \textbf{Bezahlbar} & \textbf{<%total%>} \\
+<%end total%>
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Alle Preise in \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+%\vfill
+%\centerline{\textbf{salute}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Rechnung ist bezahlbar innerhalb von <%terms%> Tagen.
+Nach dem <%duedate%> werden Zinsen zu einem
+monatlichen Satz von 1.5\% verrechnet.
+Waren bleiben im Besitz von <%company%> bis die Rechnung voll bezahlt ist.
+Rückgaben werden mit 10 Prozent Lagergebühren belastet. Beschädigte Waren
+und Waren ohne eine Rückgabenummer werden nicht entgegengenommen.
+}
+
+\end{document}
+
+
diff --git a/sql-ledger/templates/German-packing_list.html b/sql-ledger/templates/German-packing_list.html
new file mode 100644
index 0000000..09ef402
--- /dev/null
+++ b/sql-ledger/templates/German-packing_list.html
@@ -0,0 +1,146 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>V E R P P A C K U N G S L I S T E</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Datum</th><td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Nummer</th><td></td><td><%invnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Zustellung an:</th>
+ </tr>
+
+ <tr>
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+<%if shiptocontact%>
+ <p>An: <%shiptocontact%>
+<%end shiptocontact%>
+
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Nummer</th>
+ <th align=left><font color=ffffff>Artikel</th>
+ <th><font color=ffffff>Anz</th>
+ <th>&nbsp;</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Bemerkungen</td>
+ <td><%notes%></td>
+<%end notes%>
+ <td align=right>
+ <%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Beschädigte Waren und Waren ohne Rückgabenummer werden nicht
+ entgegengenommen. Lagerkosten werden mit 10% berrechnet.
+ Waren müssen ausreichended verpackt und versichert sein.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/German-packing_list.tex b/sql-ledger/templates/German-packing_list.tex
new file mode 100644
index 0000000..dbfc93b
--- /dev/null
+++ b/sql-ledger/templates/German-packing_list.tex
@@ -0,0 +1,118 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefon & <%tel%>\\
+ Telefax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Nummer} & \textbf{Artikel} & \textbf{Anz} &
+ \textbf{Einh} & \textbf{Steige} \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{3.5cm}
+
+\textbf{P A C K I N G} \parbox{0.3cm}{\hfill} \textbf{L I S T}
+
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Datum} & <%invdate%> \\
+ \textbf{Nummer} & <%invnumber%> \\
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rll@{}}
+ \textbf{Nummer} & \textbf{Artikel} & \textbf{Anz} &
+ \textbf{Einh} & \textbf{Steige} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%bin%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Beschädigte Waren und Waren ohne Rückgabenummer werden nicht
+entgegengenommen. Lagerkosten werden mit 10\% berrechnet.
+Waren müssen ausreichended verpackt und versichert sein.
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/German-purchase_order.html b/sql-ledger/templates/German-purchase_order.html
new file mode 100644
index 0000000..9771d02
--- /dev/null
+++ b/sql-ledger/templates/German-purchase_order.html
@@ -0,0 +1,188 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Telefon <%tel%>
+ <br>Telefax <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>B E S T E L L U N G</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Bestellungsdatum</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Lieferbar bis</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Bestellnummer</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>An:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Nummer</th>
+ <th align=left><font color=ffffff>Artikel</th>
+ <th><font color=ffffff>Anz</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Preis</th>
+ <th><font color=ffffff>Total</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=6><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=4 align=right>Zwischensumme</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=4 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=2>Netto <b><%terms%></b> Tage</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Bemerkungen</td>
+ <td><%notes%></td>
+<%end notes%>
+ <td align=right>
+ Alle Preise in <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ &nbsp;
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/German-purchase_order.tex b/sql-ledger/templates/German-purchase_order.tex
new file mode 100644
index 0000000..f56f1a3
--- /dev/null
+++ b/sql-ledger/templates/German-purchase_order.tex
@@ -0,0 +1,143 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefon & <%tel%>\\
+ Telefax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Zwischensumme} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Nummer} & \textbf{Artikel} & \textbf{Anz} &
+ \textbf{Einh} & \textbf{Preis} & \textbf{Total} \\
+ & Übertrag von <%lastpage%> & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{B E S T E L L U N G}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Datum} & <%orddate%> \\
+<%if reqdate%>
+ \textbf{Lieferung bis} & <%reqdate%> \\
+<%end reqdate%>
+ \textbf{Nummer} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Nummer} & \textbf{Artikel} & \textbf{Anz} &
+ \textbf{Einh} & \textbf{Preis} & \textbf{Total} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Zwischensumme} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Alle Preise in \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+%\footnotetext[1]{\tiny }
+
+\end{document}
+
+
diff --git a/sql-ledger/templates/German-receipt.tex b/sql-ledger/templates/German-receipt.tex
new file mode 100644
index 0000000..d6256e7
--- /dev/null
+++ b/sql-ledger/templates/German-receipt.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Rechnung} & \textbf{Ausgestellt}
+ & \textbf{Fällig} & \textbf{Verrechnet} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/German-sales_order.html b/sql-ledger/templates/German-sales_order.html
new file mode 100644
index 0000000..edb8b90
--- /dev/null
+++ b/sql-ledger/templates/German-sales_order.html
@@ -0,0 +1,213 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Telefon <%tel%>
+ <br>Telefax <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>B E S T E L L U N G</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Datum</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Lieferbar bei</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Bestellnummer</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Verrechnet An:</th>
+ <th align=left><font color=ffffff>Lieferaddresse:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Nummer</th>
+ <th align=left><font color=ffffff>Artikel</th>
+ <th><font color=ffffff>Anz</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Preis</th>
+ <th><font color=ffffff>Rab</th>
+ <th><font color=ffffff>Total</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%discount%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=7><hr noshade></td>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan=5 align=right>Total</th>
+ <td colspan=2 align=right><%ordtotal%></td>
+ </tr>
+<%end taxincluded%>
+
+<%if not taxincluded%>
+ <tr>
+ <th colspan=5 align=right>Zwischensumme</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+<%end taxincluded%>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=5 align=right><%taxdescription%> auf <%taxbase%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=5><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=3>Netto <b><%terms%></b> Tage</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%ordtotal%></th>
+ </tr>
+<%if taxincluded%>
+ <tr>
+ <td colspan=3>Steuern sind im Preis inbegriffen</td>
+ </tr>
+<%end taxincluded%>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Bemerkungen</td>
+ <td><%notes%></td>
+<%end notes%>
+ <td align=right>
+ Alle Preise in <b><%currency%></b>
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Spezialprodukte werden nicht zurückgenommen. Für alle anderen Waren
+ wird eine 10% Stornogebühr verrechnet.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/German-sales_order.tex b/sql-ledger/templates/German-sales_order.tex
new file mode 100644
index 0000000..21948c6
--- /dev/null
+++ b/sql-ledger/templates/German-sales_order.tex
@@ -0,0 +1,142 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telefon & <%tel%>\\
+ Telefax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Zwischensumme} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Nummer} & \textbf{Artikel} & \textbf{Anz} &
+ \textbf{Einh} & \textbf{Preis} & \textbf{Rab} & \textbf{Total} \\
+ & Übertrag von Seite <%lastpage%> & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{B E S T E L L U N G}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Datum} & <%orddate%> \\
+ \textbf{Nummer} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrrr@{}}
+ \textbf{Nummer} & \textbf{Artikel} & \textbf{Anz} &
+ \textbf{Einh} & \textbf{Preis} & \textbf{Rab} & \textbf{Total} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%discount%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Zwischensumme} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> auf <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ Alle Preise in \textbf{<%currency%>}.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Spezialprodukte werden nicht zurückgenommen. Für alle anderen Waren
+wird eine 10\% Stornogebühr verrechnet.
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/German-statement.html b/sql-ledger/templates/German-statement.html
new file mode 100644
index 0000000..6fca322
--- /dev/null
+++ b/sql-ledger/templates/German-statement.html
@@ -0,0 +1,121 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th><img src=http://www.sql-ledger.org/images/sql-ledger.png border=0 width=64 height=58></th>
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3><h4>S T A T E M E N T</h4></th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tel: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>Invoice #</th>
+ <th width=15%>Date</th>
+ <th width=15%>Due</th>
+ <th width=10%>Current</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></td>
+ <th align=right><%c30total%></td>
+ <th align=right><%c60total%></td>
+ <th align=right><%c90total%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Total Outstanding</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>Please make check payable to <b><%company%></b>.
+ </td>
+ </tr>
+ <tr height=20></tr>
+</table>
+
diff --git a/sql-ledger/templates/German-statement.tex b/sql-ledger/templates/German-statement.tex
new file mode 100644
index 0000000..0b63f75
--- /dev/null
+++ b/sql-ledger/templates/German-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{S T A T E M E N T} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Total outstanding} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Please make check payable to <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Service-balance_sheet.html b/sql-ledger/templates/Service-balance_sheet.html
new file mode 100644
index 0000000..478caab
--- /dev/null
+++ b/sql-ledger/templates/Service-balance_sheet.html
@@ -0,0 +1,100 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>BALANCE SHEET
+<br><%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>ASSETS<br><hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td> </td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAL ASSETS</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>LIABILITIES<b><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total Liabilities</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>SHAREHOLDER'S EQUITY<br><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total Equity</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>TOTAL LIABILITIES & EQUITY</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
+
+
+
diff --git a/sql-ledger/templates/Service-check.tex b/sql-ledger/templates/Service-check.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Service-check.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Service-income_statement.html b/sql-ledger/templates/Service-income_statement.html
new file mode 100644
index 0000000..e9d6a40
--- /dev/null
+++ b/sql-ledger/templates/Service-income_statement.html
@@ -0,0 +1,82 @@
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>INCOME STATEMENT
+<br><%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>INCOME<br><hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4> </td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Total Income</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>EXPENSES<br><hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td> </td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td> </td>
+ <th align=left>Total Expenses</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>INCOME / (LOSS)</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
+
+
+
+
+
+
+
+
diff --git a/sql-ledger/templates/Service-invoice.html b/sql-ledger/templates/Service-invoice.html
new file mode 100644
index 0000000..8ae6897
--- /dev/null
+++ b/sql-ledger/templates/Service-invoice.html
@@ -0,0 +1,226 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ <br>Tel/Fax <%tel%> / <%fax%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>I N V O I C E</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Date</th><td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td></td><td><%invnumber%></td></tr>
+ </tr>
+
+<!-- prepared by: <%username%>
+-->
+
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>To:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Description</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Amount</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%description%></td>
+ <td>&nbsp;</td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=3><hr noshade></td>
+ </tr>
+
+ <tr>
+<%if taxincluded%>
+ <td>&nbsp;</td>
+ <th align=right>Total</th>
+ <td align=right><%invtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <td>&nbsp;</td>
+ <th align=right>Subtotal</th>
+ <td align=right><%subtotal%></td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=2 align=right><%taxdescription%></th>
+ <td align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+<!--
+ <%taxbase%> = total netamount for each tax bracket
+ <%taxrate%> = taxrate in percent
+-->
+
+<%if paid%>
+ <tr>
+ <td>&nbsp;</td>
+ <th align=right>Paid</th>
+ <td align=right><%paid%></td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td colspan=2><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td>
+<%if terms%>
+Terms &nbsp;Net <b><%terms%></b> days
+<%end terms%>
+</td>
+ <th align=right>Total</th>
+ <th align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<%if notes%>
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td>Notes</td>
+ <td><pre><%notes%></pre></td>
+ <td align=right>
+ &nbsp;
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+<%end notes%>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <th colspan=3>
+ Please make check payable to <%company%>
+ <br>Thank you for your valued business!
+ </th>
+</tr>
+
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Payment due NET <%terms%> Days from date of Invoice.
+ Interest on overdue amounts will acrue at the rate of 1.5% per month
+ from due date until paid in full.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=3 align=left><font size=-2><%taxdescription%> Registration <%taxnumber%></th>
+ </tr>
+<%end tax%>
+
+<!--
+ %username% = user name
+ %businessnumber% = business number
+-->
+
+<!-- banking information
+ <tr>
+ <th colspan=3 align=left><font size=-2>Banking Information:
+ <br>Bank
+ <br>Transit No.
+ <br>Account No.
+ </th>
+ </tr>
+-->
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Service-invoice.tex b/sql-ledger/templates/Service-invoice.tex
new file mode 100644
index 0000000..810a50e
--- /dev/null
+++ b/sql-ledger/templates/Service-invoice.tex
@@ -0,0 +1,151 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}p{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+ & carried forward from <%lastpage%> & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{I N V O I C E}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%invdate%> \\
+ \textbf{Number} & <%invnumber%> \\
+ \textbf{Customer} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}p{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+<%foreach number%>
+ <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%> \\
+<%end tax%>
+<%if paid%>
+ \textbf{Paid} & - <%paid%> \\
+<%end paid%>
+ \hline
+ \textbf{Balance Owing} & \textbf{<%total%>} \\
+
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ All prices in \textbf{<%currency%>} funds.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+\vfill
+\centerline{\textbf{Thank You for your valued business!}}
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+Payment due NET <%terms%> Days from date of Invoice. Interest on overdue
+amounts will acrue at the rate of 1.5\% per month starting <%duedate%>
+until paid in full.
+}
+
+\end{document}
+
+
diff --git a/sql-ledger/templates/Service-packing_list.html b/sql-ledger/templates/Service-packing_list.html
new file mode 100644
index 0000000..07ba8d6
--- /dev/null
+++ b/sql-ledger/templates/Service-packing_list.html
@@ -0,0 +1,148 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr>
+ <td width=10>
+ </td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <th colspan=2>
+ <h4 align=center>P A C K I N G &nbsp;&nbsp; L I S T</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Date</th><td width=10> </td><td><%invdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td></td><td><%invnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Ship To:</th>
+ </tr>
+
+ <tr>
+ <td><%shiptoname%>
+ <br><%shiptoaddr1%>
+ <br><%shiptoaddr2%>
+ <br><%shiptoaddr3%>
+ <br><%shiptoaddr4%>
+<%if shiptocontact%>
+ <p>Attn: <%shiptocontact%>
+<%end shiptocontact%>
+
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>Number</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qt'y</th>
+ <th>&nbsp;</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Notes</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ <%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Items returned are subject to
+ a 10% restocking charge. A return authorization must be obtained
+ from <%company%> before goods are returned. Returns must be shipped
+ prepaid and properly insured. <%company%> will not be responsible
+ for damages during transit.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Service-packing_list.tex b/sql-ledger/templates/Service-packing_list.tex
new file mode 100644
index 0000000..b5a6a8a
--- /dev/null
+++ b/sql-ledger/templates/Service-packing_list.tex
@@ -0,0 +1,120 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%invnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+\newpage
+
+\markright{<%company%>\hfill <%invnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}p{\descrwidth}@{\extracolsep\fill}rl@{}}
+ \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+
+\vspace{3.5cm}
+
+\textbf{P A C K I N G} \parbox{0.3cm}{\hfill} \textbf{L I S T}
+
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%invdate%> \\
+ \textbf{Number} & <%invnumber%> \\
+ \textbf{Customer} & <%customer_id%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}p{\descrwidth}@{\extracolsep\fill}rl@{}}
+ \textbf{Description} & \textbf{Qt'y} & \textbf{Unit} \\
+<%foreach number%>
+ <%description%> & <%qty%> & <%unit%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+%\vfill
+%\centerline{\textbf{Thank You for your valued business!}}
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+%\footnotetext[1]{\tiny
+%Items returned are subject to a 10\% restocking charge.
+%A return authorization must be obtained from <%company%> before goods are
+%returned. Returns must be shipped prepaid and properly insured.
+%<%company%> will not be responsible for damages during transit.}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Service-purchase_order.html b/sql-ledger/templates/Service-purchase_order.html
new file mode 100644
index 0000000..f2e9f7e
--- /dev/null
+++ b/sql-ledger/templates/Service-purchase_order.html
@@ -0,0 +1,194 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Telephone: <%tel%>
+ <br>Facsimile: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>P U R C H A S E &nbsp;&nbsp; O R D E R</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Order Date</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Required by</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>To:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Number</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qt'y</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Price</th>
+ <th><font color=ffffff>Amount</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=6><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=4 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=4 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=2>Terms Net <b><%terms%></b> days</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Notes</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ All prices in <b><%currency%></b> Funds
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Payment due NET <%terms%> Days from date of Invoice.
+ Interest on overdue amounts will acrue at the rate of 1.5% per month
+ from due date until paid in full. Items returned are subject to
+ a 10% restocking charge. A return authorization must be obtained
+ from <%company%> before goods are returned. Returns must be shipped
+ prepaid and properly insured. <%company%> will not be responsible
+ for damages during transit.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Service-purchase_order.tex b/sql-ledger/templates/Service-purchase_order.tex
new file mode 100644
index 0000000..e6cc92c
--- /dev/null
+++ b/sql-ledger/templates/Service-purchase_order.tex
@@ -0,0 +1,143 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+ & carried forward from <%lastpage%> & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{P U R C H A S E} \parbox{0.3cm}{\hfill} \textbf{O R D E R}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%orddate%> \\
+<%if reqdate%>
+ \textbf{Required by} & <%reqdate%> \\
+<%end reqdate%>
+ \textbf{Number} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}lp{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Number} & \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+<%foreach number%>
+ <%number%> & <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ All prices in \textbf{<%currency%>} funds.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+%\footnotetext[1]{\tiny }
+
+\end{document}
+
+
diff --git a/sql-ledger/templates/Service-receipt.tex b/sql-ledger/templates/Service-receipt.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Service-receipt.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Service-sales_order.html b/sql-ledger/templates/Service-sales_order.html
new file mode 100644
index 0000000..319cc3b
--- /dev/null
+++ b/sql-ledger/templates/Service-sales_order.html
@@ -0,0 +1,198 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+<tr valign=bottom>
+ <td width=10>&nbsp;</td>
+ <td>
+
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+
+ <td align=right>
+ <h4>
+ Telelephone: <%tel%>
+ <br>Facsimile: <%fax%>
+ </h4>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan=3>
+ <h4>S A L E S &nbsp;&nbsp; O R D E R</h4>
+ </th>
+ </tr>
+
+ </table>
+
+
+ <table width=100% callspacing=0 cellpadding=0>
+
+ <tr>
+ <td align=right>
+ <table>
+ <tr>
+ <th align=right>Order Date</th><td width=10>&nbsp;</td><td><%orddate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Required by</th><td width=10>&nbsp;</td><td><%reqdate%></td>
+ </tr>
+
+ <tr>
+ <th align=right>Number</th><td>&nbsp;</td><td><%ordnumber%></td></tr>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+ </td>
+ </table>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <th align=left><font color=ffffff>To:</th>
+ </tr>
+
+ <tr>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+<%if contact%>
+ <p>Attn: <%contact%>
+%end contact%>
+
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+<!-- <th align=right><font color=ffffff>No.</th> -->
+ <th align=left><font color=ffffff>Number</th>
+ <th align=left><font color=ffffff>Description</th>
+ <th><font color=ffffff>Qt'y</th>
+ <th>&nbsp;</th>
+ <th><font color=ffffff>Price</th>
+ <th><font color=ffffff>Amount</th>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+<!-- <td align=right><%runningnumber%>.</td>
+adjust the colspan if you include this to shift subtotal one to the right
+-->
+ <td><%number%></td>
+ <td><%description%></td>
+ <td align=right><%qty%></td>
+ <td><%unit%></td>
+ <td align=right><%sellprice%></td>
+ <td align=right><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan=6><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th colspan=4 align=right>Subtotal</th>
+ <td colspan=2 align=right><%subtotal%></td>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th colspan=4 align=right><%taxdescription%> @ <%taxrate%> %</th>
+ <td colspan=2 align=right><%tax%></td>
+ </tr>
+<%end tax%>
+
+ <tr>
+ <td colspan=2>&nbsp;</td>
+ <td colspan=4><hr noshade></td>
+ </tr>
+
+ <tr>
+ <td colspan=2>Terms Net <b><%terms%></b> days</td>
+ <th colspan=2 align=right>Total</th>
+ <th colspan=2 align=right><%total%></th>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ </tr>
+
+ </table>
+ </td>
+ </tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+<%if notes%>
+ <td>Notes</td>
+ <td><pre><%notes%></pre></td>
+<%end notes%>
+ <td align=right>
+ All prices in <b><%currency%></b> Funds
+ <br><%shippingpoint%>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+</tr>
+
+<tr><td>&nbsp;</td></tr>
+
+<tr>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><font size=-3>
+ Payment due NET <%terms%> Days from date of Invoice.
+ Interest on overdue amounts will acrue at the rate of 1.5% per month
+ from due date until paid in full. Items returned are subject to
+ a 10% restocking charge. A return authorization must be obtained
+ from <%company%> before goods are returned. Returns must be shipped
+ prepaid and properly insured. <%company%> will not be responsible
+ for damages during transit.
+ </font>
+ </td>
+ <td width=150>
+ X <hr noshade>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+
+</table>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Service-sales_order.tex b/sql-ledger/templates/Service-sales_order.tex
new file mode 100644
index 0000000..c5664e0
--- /dev/null
+++ b/sql-ledger/templates/Service-sales_order.tex
@@ -0,0 +1,139 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rr@{}}
+ Telephone & <%tel%>\\
+ Facsimile & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%ordnumber%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%ordnumber%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}p{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+ & carried forward from <%lastpage%> & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{2cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{3.5cm}
+
+\textbf{S A L E S} \parbox{0.3cm}{\hfill} \textbf{O R D E R}
+\hfill
+\begin{tabular}[t]{l@{\hspace{0.3cm}}l}
+ \textbf{Date} & <%orddate%> \\
+ \textbf{Number} & <%ordnumber%>
+\end{tabular}
+
+\vspace{1cm}
+
+\begin{tabular*}{\textwidth}{@{}p{\descrwidth}@{\extracolsep\fill}rlrr@{}}
+ \textbf{Description} & \textbf{Qt'y} &
+ \textbf{Unit} & \textbf{Price} & \textbf{Amount} \\
+<%foreach number%>
+ <%description%> & <%qty%> &
+ <%unit%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+
+\parbox{\textwidth}{
+\rule{\textwidth}{2pt}
+
+\vspace{0.2cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ <%taxdescription%> on <%taxbase%> & <%tax%>\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>}\\
+\end{tabularx}
+
+\vspace{0.3cm}
+
+\hfill
+ All prices in \textbf{<%currency%>} funds.
+
+\vspace{12pt}
+
+<%if notes%>
+ <%notes%>
+<%end if%>
+
+}
+
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+%\footnotetext[1]{\tiny }
+
+\end{document}
+
diff --git a/sql-ledger/templates/Service-statement.html b/sql-ledger/templates/Service-statement.html
new file mode 100644
index 0000000..6fca322
--- /dev/null
+++ b/sql-ledger/templates/Service-statement.html
@@ -0,0 +1,121 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th><img src=http://www.sql-ledger.org/images/sql-ledger.png border=0 width=64 height=58></th>
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3><h4>S T A T E M E N T</h4></th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tel: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>Invoice #</th>
+ <th width=15%>Date</th>
+ <th width=15%>Due</th>
+ <th width=10%>Current</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></td>
+ <th align=right><%c30total%></td>
+ <th align=right><%c60total%></td>
+ <th align=right><%c90total%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Total Outstanding</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>Please make check payable to <b><%company%></b>.
+ </td>
+ </tr>
+ <tr height=20></tr>
+</table>
+
diff --git a/sql-ledger/templates/Service-statement.tex b/sql-ledger/templates/Service-statement.tex
new file mode 100644
index 0000000..0b63f75
--- /dev/null
+++ b/sql-ledger/templates/Service-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{S T A T E M E N T} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Total outstanding} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Please make check payable to <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_A4-balance_sheet.html b/sql-ledger/templates/Spanish_A4-balance_sheet.html
new file mode 100644
index 0000000..aef74d0
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-balance_sheet.html
@@ -0,0 +1,100 @@
+<head>
+ <title>Hoja de Balance</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>HOJA DE BALANCE
+<br><%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>ACTIVOS<br><hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td>&nbsp;</td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>Total de activos</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>PASIVOS<b><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total de pasivos</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>CAPITAL<br><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Capital total</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>Total de pasivos y capital</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
diff --git a/sql-ledger/templates/Spanish_A4-check.tex b/sql-ledger/templates/Spanish_A4-check.tex
new file mode 100644
index 0000000..a1ef969
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-check.tex
@@ -0,0 +1,71 @@
+\documentclass[a4paper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_A4-income_statement.html b/sql-ledger/templates/Spanish_A4-income_statement.html
new file mode 100644
index 0000000..fbb5653
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-income_statement.html
@@ -0,0 +1,77 @@
+<head>
+ <title>Balance de Situación</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>BALANCE DE SITUACIÓN
+<br><%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>INGRESOS<br><hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4>&nbsp;</td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2>&nbsp;</td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td>&nbsp;</td>
+ <th align=left>Total de ingresos</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>GASTOS<br><hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td>&nbsp;</td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2>&nbsp;</td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td>&nbsp;</td>
+ <th align=left>Total de gastos</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>GANANCIA/(PERDIDA)</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
diff --git a/sql-ledger/templates/Spanish_A4-invoice.html b/sql-ledger/templates/Spanish_A4-invoice.html
new file mode 100644
index 0000000..d274936
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-invoice.html
@@ -0,0 +1,153 @@
+<head>
+ <title>Factura de Instalaciones Industriales San José</title>
+</head>
+
+<body bgcolor="ffffff">
+ <!-- Cabecera -->
+ <table width="100%">
+ <tr valign=bottom>
+ <td width="10">&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th colspan="4"> </th>
+ <th align="left">
+ <h4>F A C T U R A</h4>
+ </th>
+ </tr>
+
+ <tr>
+ <td colspan="5"> </td>
+ </tr>
+
+ <tr>
+ <td colspan="4"> </td>
+ <td align="left"><%name%></td>
+ </tr>
+
+ <tr>
+ <td>Número</td>
+ <td>Fecha</td>
+ <td>Cód. Cliente</td>
+ <td width="10%"> </td>
+ <td><%addr1%></td>
+ </tr>
+ <tr>
+ <td><b><%invnumber%></b></td>
+ <td><b><%invdate%></b></td>
+ <td><b><%customer_id%></b></td>
+ <td> </td>
+ <td><%addr2%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr3%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr4%></td>
+ </tr>
+ </table>
+ </table>
+
+ <!-- Cuerpo -->
+ <table width=100% cellspacing=0 cellpadding=0>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <!-- <th align=left><font color=ffffff>Número</th> -->
+ <!-- <th><font color=ffffff>Cant.</th> -->
+ <th align="left"><font color="ffffff">Cant.</th>
+ <th align="left"><font color="ffffff">Descripción</th>
+ <th align="left"><font color="ffffff">Precio</th>
+ <!-- <th align="left"><font color="ffffff">Dto.</th> -->
+ <th align="left"><font color="ffffff">Importe</th>
+ </tr>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <!-- <td><%number%></td> -->
+ <!-- <td><%unit%></td> -->
+ <td align="right"><%qty%></td>
+ <td align="left"><%description%></td>
+ <td align="right"><%sellprice%></td>
+ <!-- <td align=right><%discount%></td> -->
+ <td align="right"><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+ </table>
+
+ <!-- Subtotales, impuestos y totales -->
+ <table width="100%">
+ <tr>
+<%if taxincluded%>
+ <th align=right>Total</th>
+ <td align=right><%invtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th align="right">Base imponible</th>
+ <td align="right"><%subtotal%> &euro;</td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th align="right">IVA (<%taxrate%>%) sobre <%taxbase%>:</th>
+ <td align="right"><%tax%> &euro;</td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th align="right">Pagado:</th>
+ <td align="right"><%paid%> &euro;</td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th align="right">Total:</th>
+ <th align="right"><%invtotal%> &euro;</th>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ </table>
+
+
+ <!-- Pie -->
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>Notas</td>
+ <td><%notes%></td>
+<%end notes%>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan="2" align="left"><font size=-2>Los precios incluyen impuestos.</th>
+ </tr>
+<%end taxincluded%>
+
+ </table>
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Spanish_A4-invoice.tex b/sql-ledger/templates/Spanish_A4-invoice.tex
new file mode 100644
index 0000000..1d0619e
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-invoice.tex
@@ -0,0 +1,108 @@
+\documentclass[a4paper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\usepackage{marvosym} % Euro \EUR
+\usepackage{fancyhdr}
+\setlength{\topmargin}{0cm}
+\setlength{\topskip}{0cm}
+\setlength{\headheight}{0cm}
+\setlength{\headsep}{0.5cm}
+\setlength{\textheight}{24.2cm}
+\setlength{\textwidth}{19cm}
+\setlength{\oddsidemargin}{-1.4cm}
+\setlength{\evensidemargin}{-1.4cm}
+\setlength{\footskip}{1cm}
+
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{13.0cm}
+
+\newsavebox{\hdr}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\sbox{\hdr}{
+
+\begin{minipage}[t]{0.6\linewidth}
+\vspace{2.2cm}
+
+\begin{tabular}[t]{p{1.7cm}p{2.4cm}p{1.7cm}}\\
+\centering{Número} & \centering{Fecha} & C. Cliente\\
+\centering{<%invnumber%>} & \centering{<%invdate%>} & \centering{<%customer_id%>}
+\end{tabular}
+\end{minipage}
+
+\begin{minipage}[t]{0.4\linewidth}
+\textbf{F A C T U R A}
+\vspace{1cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+\end{minipage}
+
+}
+
+\pagestyle{fancy}
+\renewcommand{\headrulewidth}{0cm}
+\renewcommand{\footrulewidth}{0cm}
+\cfoot{\thepage}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+%\thispagestyle{empty} %use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+\newpage
+\usebox{\hdr}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%end pagebreak%>
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\usebox{\hdr}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%foreach number%>
+ <%qty%> & <%description%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+\parbox{\textwidth}{
+\vspace{12pt}
+<%if notes%>
+ <%notes%>
+<%end if%>
+}
+
+\vfill
+
+\begin{flushright}
+\begin{tabularx}{10cm}{Xr@{}}
+ \textbf{Base imponible} & \textbf{<%subtotal%>} \EUR \\
+<%foreach tax%>
+ IVA (<%taxrate%>\%) sobre <%taxbase%> & <%tax%> \EUR\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%invtotal%>} \EUR\\
+\end{tabularx}
+\end{flushright}
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_A4-packing_list.html b/sql-ledger/templates/Spanish_A4-packing_list.html
new file mode 100644
index 0000000..c34d189
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-packing_list.html
@@ -0,0 +1,155 @@
+<head>
+ <title>Albarán de Instalaciones Industriales San José</title>
+</head>
+
+<body bgcolor="ffffff">
+ <!-- Cabecera -->
+ <table width="100%">
+ <tr valign=bottom>
+ <td width="10">&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th colspan="5"> </th>
+ <th align="left">
+ <h4>A L B A R Á N</h4>
+ </th>
+ </tr>
+
+ <tr>
+ <td colspan="6"> </td>
+ </tr>
+
+ <tr>
+ <td colspan="5"> </td>
+ <td align="left"><%name%></td>
+ </tr>
+
+ <tr>
+ <td>Número</td>
+ <td>Factura</td>
+ <td>Fecha</td>
+ <td>Cód. Cliente</td>
+ <td width="10%"> </td>
+ <td><%addr1%></td>
+ </tr>
+ <tr>
+ <td><b><%ordnumber%></b></td>
+ <td><b><%invnumber%></b></td>
+ <td><b><%invdate%></b></td>
+ <td><b><%customer_id%></b></td>
+ <td> </td>
+ <td><%addr2%></td>
+ </tr>
+ <tr>
+ <td colspan="5">
+ <td><%addr3%></td>
+ </tr>
+ <tr>
+ <td colspan="5">
+ <td><%addr4%></td>
+ </tr>
+ </table>
+ </table>
+
+ <!-- Cuerpo -->
+ <table width=100% cellspacing=0 cellpadding=0>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <!-- <th align=left><font color=ffffff>Número</th> -->
+ <!-- <th><font color=ffffff>Cant.</th> -->
+ <th align="left"><font color="ffffff">Cant.</th>
+ <th align="left"><font color="ffffff">Descripción</th>
+ <th align="left"><font color="ffffff">Precio</th>
+ <!-- <th align="left"><font color="ffffff">Dto.</th> -->
+ <th align="left"><font color="ffffff">Importe</th>
+ </tr>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <!-- <td><%number%></td> -->
+ <!-- <td><%unit%></td> -->
+ <td align="right"><%qty%></td>
+ <td align="left"><%description%></td>
+ <td align="right"><%sellprice%></td>
+ <!-- <td align=right><%discount%></td> -->
+ <td align="right"><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+ </table>
+
+ <!-- Subtotales, impuestos y totales -->
+ <table width="100%">
+ <tr>
+<%if taxincluded%>
+ <th align=right>Total</th>
+ <td align=right><%invtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th align="right">Base imponible</th>
+ <td align="right"><%subtotal%> &euro;</td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th align="right">IVA (<%taxrate%>%) sobre <%taxbase%>:</th>
+ <td align="right"><%tax%> &euro;</td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th align="right">Pagado:</th>
+ <td align="right"><%paid%> &euro;</td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th align="right">Total:</th>
+ <th align="right"><%invtotal%> &euro;</th>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ </table>
+
+
+ <!-- Pie -->
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>Notas</td>
+ <td><%notes%></td>
+<%end notes%>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan="2" align="left"><font size=-2>Los precios incluyen impuestos.</th>
+ </tr>
+<%end taxincluded%>
+
+ </table>
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Spanish_A4-packing_list.tex b/sql-ledger/templates/Spanish_A4-packing_list.tex
new file mode 100644
index 0000000..312c349
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-packing_list.tex
@@ -0,0 +1,108 @@
+\documentclass[a4paper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\usepackage{marvosym} % Euro \EUR
+\usepackage{fancyhdr}
+\setlength{\topmargin}{0cm}
+\setlength{\topskip}{0cm}
+\setlength{\headheight}{0cm}
+\setlength{\headsep}{0.5cm}
+\setlength{\textheight}{24.2cm}
+\setlength{\textwidth}{19cm}
+\setlength{\oddsidemargin}{-1.4cm}
+\setlength{\evensidemargin}{-1.4cm}
+\setlength{\footskip}{1cm}
+
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{13.0cm}
+
+\newsavebox{\hdr}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\sbox{\hdr}{
+
+\begin{minipage}[t]{0.6\linewidth}
+\vspace{2.2cm}
+
+\begin{tabular}[t]{p{1.7cm}p{1.7cm}p{2.4cm}p{1.7cm}}\\
+\centering{Número} & \centering{Número} & \centering{Fecha} & C. Cliente\\
+ \centering{<%ordnumber%>} & \centering{<%invnumber%>} & \centering{<%invdate%>} & \centering{<%customer_id%>}
+\end{tabular}
+\end{minipage}
+
+\begin{minipage}[t]{0.4\linewidth}
+\textbf{A L B A R Á N}
+\vspace{1cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+\end{minipage}
+
+}
+
+\pagestyle{fancy}
+\renewcommand{\headrulewidth}{0cm}
+\renewcommand{\footrulewidth}{0cm}
+\cfoot{\thepage}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+%\thispagestyle{empty} %use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+\newpage
+\usebox{\hdr}
+\vspace{0.5cm}
+
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%end pagebreak%>
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\usebox{\hdr}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%foreach number%>
+ <%qty%> & <%description%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+\parbox{\textwidth}{
+\vspace{12pt}
+<%if notes%>
+ <%notes%>
+<%end if%>
+}
+
+\vfill
+
+\begin{flushright}
+\begin{tabularx}{10cm}{Xr@{}}
+ \textbf{Base imponible} & \textbf{<%subtotal%>} \EUR \\
+<%foreach tax%>
+ IVA (<%taxrate%>\%) sobre <%taxbase%> & <%tax%> \EUR\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%invtotal%>} \EUR\\
+\end{tabularx}
+\end{flushright}
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_A4-purchase_order.html b/sql-ledger/templates/Spanish_A4-purchase_order.html
new file mode 100644
index 0000000..693fe65
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-purchase_order.html
@@ -0,0 +1,153 @@
+<head>
+ <title>Pedido de Instalaciones Industriales San José</title>
+</head>
+
+<body bgcolor="ffffff">
+ <!-- Cabecera -->
+ <table width="100%">
+ <tr valign=bottom>
+ <td width="10">&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th colspan="4"> </th>
+ <th align="left">
+ <h4>P E D I D O</h4>
+ </th>
+ </tr>
+
+ <tr>
+ <td colspan="5"> </td>
+ </tr>
+
+ <tr>
+ <td colspan="4"> </td>
+ <td align="left"><%name%></td>
+ </tr>
+
+ <tr>
+ <td>Número</td>
+ <td>Fecha</td>
+ <td>Cód. Proveedor</td>
+ <td width="10%"> </td>
+ <td><%addr1%></td>
+ </tr>
+ <tr>
+ <td><b><%ordnumber%></b></td>
+ <td><b><%orddate%></b></td>
+ <td><b><%vendor_id%></b></td>
+ <td> </td>
+ <td><%addr2%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr3%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr4%></td>
+ </tr>
+ </table>
+ </table>
+
+ <!-- Cuerpo -->
+ <table width=100% cellspacing=0 cellpadding=0>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <!-- <th align=left><font color=ffffff>Número</th> -->
+ <!-- <th><font color=ffffff>Cant.</th> -->
+ <th align="left"><font color="ffffff">Cant.</th>
+ <th align="left"><font color="ffffff">Descripción</th>
+ <th align="left"><font color="ffffff">Precio</th>
+ <!-- <th align="left"><font color="ffffff">Dto.</th> -->
+ <th align="left"><font color="ffffff">Importe</th>
+ </tr>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <!-- <td><%number%></td> -->
+ <!-- <td><%unit%></td> -->
+ <td align="right"><%qty%></td>
+ <td align="left"><%description%></td>
+ <td align="right"><%sellprice%></td>
+ <!-- <td align=right><%discount%></td> -->
+ <td align="right"><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+ </table>
+
+ <!-- Subtotales, impuestos y totales -->
+ <table width="100%">
+ <tr>
+<%if taxincluded%>
+ <th align="right">Total</th>
+ <td align="right"><%ordtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th align="right">Base imponible</th>
+ <td align="right"><%subtotal%> &euro;</td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th align="right">IVA (<%taxrate%>%) sobre <%taxbase%>:</th>
+ <td align="right"><%tax%> &euro;</td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th align="right">Pagado:</th>
+ <td align="right"><%paid%> &euro;</td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th align="right">Total:</th>
+ <th align="right"><%ordtotal%> &euro;</th>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ </table>
+
+
+ <!-- Pie -->
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>Notas</td>
+ <td><%notes%></td>
+<%end notes%>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan="2" align="left"><font size=-2>Los precios incluyen impuestos.</th>
+ </tr>
+<%end taxincluded%>
+
+ </table>
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Spanish_A4-purchase_order.tex b/sql-ledger/templates/Spanish_A4-purchase_order.tex
new file mode 100644
index 0000000..f8300ae
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-purchase_order.tex
@@ -0,0 +1,107 @@
+\documentclass[a4paper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\usepackage{marvosym} % Euro \EUR
+\usepackage{fancyhdr}
+\setlength{\topmargin}{0cm}
+\setlength{\topskip}{0cm}
+\setlength{\headheight}{0cm}
+\setlength{\headsep}{0.5cm}
+\setlength{\textheight}{24.2cm}
+\setlength{\textwidth}{19cm}
+\setlength{\oddsidemargin}{-1.4cm}
+\setlength{\evensidemargin}{-1.4cm}
+\setlength{\footskip}{1cm}
+
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{13.0cm}
+
+\newsavebox{\hdr}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\sbox{\hdr}{
+\begin{minipage}[t]{0.6\linewidth}
+\vspace{2.2cm}
+
+\begin{tabular}[t]{p{1.7cm}p{2.4cm}p{1.7cm}}\\
+\centering{Número} & \centering{Fecha} & C. Cliente\\
+\centering{<%ordnumber%>} & \centering{<%orddate%>} & \centering{<%vendor_id%>}
+\end{tabular}
+\end{minipage}
+
+\begin{minipage}[t]{0.4\linewidth}
+\textbf{P E D I D O}
+\vspace{1cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+\end{minipage}
+
+}
+
+\pagestyle{fancy}
+\renewcommand{\headrulewidth}{0cm}
+\renewcommand{\footrulewidth}{0cm}
+\cfoot{\thepage}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+%\thispagestyle{empty} %use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+\newpage
+\usebox{\hdr}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%end pagebreak%>
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\usebox{\hdr}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%foreach number%>
+ <%qty%> & <%description%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+\parbox{\textwidth}{
+\vspace{12pt}
+<%if notes%>
+ <%notes%>
+<%end if%>
+}
+
+\vfill
+
+\begin{flushright}
+\begin{tabularx}{10cm}{Xr@{}}
+ \textbf{Base imponible} & \textbf{<%subtotal%>} \EUR \\
+<%foreach tax%>
+ IVA (<%taxrate%>\%) sobre <%taxbase%> & <%tax%> \EUR\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>} \EUR\\
+\end{tabularx}
+\end{flushright}
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_A4-receipt.tex b/sql-ledger/templates/Spanish_A4-receipt.tex
new file mode 100644
index 0000000..a1ef969
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-receipt.tex
@@ -0,0 +1,71 @@
+\documentclass[a4paper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_A4-sales_order.html b/sql-ledger/templates/Spanish_A4-sales_order.html
new file mode 100644
index 0000000..d54f375
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-sales_order.html
@@ -0,0 +1,153 @@
+<head>
+ <title>Presupuesto de Instalaciones Industriales San José</title>
+</head>
+
+<body bgcolor="ffffff">
+ <!-- Cabecera -->
+ <table width="100%">
+ <tr valign=bottom>
+ <td width="10">&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th colspan="4"> </th>
+ <th align="left">
+ <h4>P R E S U P U E S T O</h4>
+ </th>
+ </tr>
+
+ <tr>
+ <td colspan="5"> </td>
+ </tr>
+
+ <tr>
+ <td colspan="4"> </td>
+ <td align="left"><%name%></td>
+ </tr>
+
+ <tr>
+ <td>Número</td>
+ <td>Fecha</td>
+ <td>Cód. Cliente</td>
+ <td width="10%"> </td>
+ <td><%addr1%></td>
+ </tr>
+ <tr>
+ <td><b><%ordnumber%></b></td>
+ <td><b><%orddate%></b></td>
+ <td><b><%customer_id%></b></td>
+ <td> </td>
+ <td><%addr2%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr3%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr4%></td>
+ </tr>
+ </table>
+ </table>
+
+ <!-- Cuerpo -->
+ <table width=100% cellspacing=0 cellpadding=0>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <!-- <th align=left><font color=ffffff>Número</th> -->
+ <!-- <th><font color=ffffff>Cant.</th> -->
+ <th align="left"><font color="ffffff">Cant.</th>
+ <th align="left"><font color="ffffff">Descripción</th>
+ <th align="left"><font color="ffffff">Precio</th>
+ <!-- <th align="left"><font color="ffffff">Dto.</th> -->
+ <th align="left"><font color="ffffff">Importe</th>
+ </tr>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <!-- <td><%number%></td> -->
+ <!-- <td><%unit%></td> -->
+ <td align="right"><%qty%></td>
+ <td align="left"><%description%></td>
+ <td align="right"><%sellprice%></td>
+ <!-- <td align=right><%discount%></td> -->
+ <td align="right"><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+ </table>
+
+ <!-- Subtotales, impuestos y totales -->
+ <table width="100%">
+ <tr>
+<%if taxincluded%>
+ <th align=right>Total</th>
+ <td align=right><%ordtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th align="right">Base imponible</th>
+ <td align="right"><%subtotal%> &euro;</td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th align="right">IVA (<%taxrate%>%) sobre <%taxbase%>:</th>
+ <td align="right"><%tax%> &euro;</td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th align="right">Pagado:</th>
+ <td align="right"><%paid%> &euro;</td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th align="right">Total:</th>
+ <th align="right"><%ordtotal%> &euro;</th>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ </table>
+
+
+ <!-- Pie -->
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>Notas</td>
+ <td><%notes%></td>
+<%end notes%>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan="2" align="left"><font size=-2>Los precios incluyen impuestos.</th>
+ </tr>
+<%end taxincluded%>
+
+ </table>
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Spanish_A4-sales_order.tex b/sql-ledger/templates/Spanish_A4-sales_order.tex
new file mode 100644
index 0000000..f8300ae
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-sales_order.tex
@@ -0,0 +1,107 @@
+\documentclass[a4paper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\usepackage{marvosym} % Euro \EUR
+\usepackage{fancyhdr}
+\setlength{\topmargin}{0cm}
+\setlength{\topskip}{0cm}
+\setlength{\headheight}{0cm}
+\setlength{\headsep}{0.5cm}
+\setlength{\textheight}{24.2cm}
+\setlength{\textwidth}{19cm}
+\setlength{\oddsidemargin}{-1.4cm}
+\setlength{\evensidemargin}{-1.4cm}
+\setlength{\footskip}{1cm}
+
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{13.0cm}
+
+\newsavebox{\hdr}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\sbox{\hdr}{
+\begin{minipage}[t]{0.6\linewidth}
+\vspace{2.2cm}
+
+\begin{tabular}[t]{p{1.7cm}p{2.4cm}p{1.7cm}}\\
+\centering{Número} & \centering{Fecha} & C. Cliente\\
+\centering{<%ordnumber%>} & \centering{<%orddate%>} & \centering{<%vendor_id%>}
+\end{tabular}
+\end{minipage}
+
+\begin{minipage}[t]{0.4\linewidth}
+\textbf{P E D I D O}
+\vspace{1cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+\end{minipage}
+
+}
+
+\pagestyle{fancy}
+\renewcommand{\headrulewidth}{0cm}
+\renewcommand{\footrulewidth}{0cm}
+\cfoot{\thepage}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+%\thispagestyle{empty} %use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+\newpage
+\usebox{\hdr}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%end pagebreak%>
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\usebox{\hdr}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%foreach number%>
+ <%qty%> & <%description%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+\parbox{\textwidth}{
+\vspace{12pt}
+<%if notes%>
+ <%notes%>
+<%end if%>
+}
+
+\vfill
+
+\begin{flushright}
+\begin{tabularx}{10cm}{Xr@{}}
+ \textbf{Base imponible} & \textbf{<%subtotal%>} \EUR \\
+<%foreach tax%>
+ IVA (<%taxrate%>\%) sobre <%taxbase%> & <%tax%> \EUR\\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>} \EUR\\
+\end{tabularx}
+\end{flushright}
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_A4-statement.html b/sql-ledger/templates/Spanish_A4-statement.html
new file mode 100644
index 0000000..6fca322
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-statement.html
@@ -0,0 +1,121 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th><img src=http://www.sql-ledger.org/images/sql-ledger.png border=0 width=64 height=58></th>
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3><h4>S T A T E M E N T</h4></th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tel: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>Invoice #</th>
+ <th width=15%>Date</th>
+ <th width=15%>Due</th>
+ <th width=10%>Current</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></td>
+ <th align=right><%c30total%></td>
+ <th align=right><%c60total%></td>
+ <th align=right><%c90total%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Total Outstanding</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>Please make check payable to <b><%company%></b>.
+ </td>
+ </tr>
+ <tr height=20></tr>
+</table>
+
diff --git a/sql-ledger/templates/Spanish_A4-statement.tex b/sql-ledger/templates/Spanish_A4-statement.tex
new file mode 100644
index 0000000..268bb1a
--- /dev/null
+++ b/sql-ledger/templates/Spanish_A4-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[a4paper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{S T A T E M E N T} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Total outstanding} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Please make check payable to <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_Letter-balance_sheet.html b/sql-ledger/templates/Spanish_Letter-balance_sheet.html
new file mode 100644
index 0000000..aef74d0
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-balance_sheet.html
@@ -0,0 +1,100 @@
+<head>
+ <title>Hoja de Balance</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>HOJA DE BALANCE
+<br><%period%>
+</h2>
+
+<table border=0>
+<tr>
+ <th align=left width=400 colspan=2>ACTIVOS<br><hr align=left width=250 size=5 noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach asset_account%>
+<tr>
+ <td>&nbsp;</td>
+ <td><%asset_account%></td>
+ <td align=right><%asset_this_period%></td>
+ <td align=right><%asset_last_period%></td>
+</tr>
+<%end asset_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>Total de activos</th>
+ <td align=right><%total_assets_this_period%><hr noshade size=2></td>
+ <td align=right><%total_assets_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>PASIVOS<b><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach liability_account%>
+<tr>
+ <td></td>
+ <td><%liability_account%></td>
+ <td align=right><%liability_this_period%></td>
+ <td align=right><%liability_last_period%></td>
+</tr>
+<%end liability_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Total de pasivos</th>
+ <td align=right><%total_liabilities_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_liabilities_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr>
+ <th align=left colspan=4>CAPITAL<br><hr align=left width=250 size=5 noshade></th>
+</tr>
+
+<%foreach equity_account%>
+<tr>
+ <td></td>
+ <td><%equity_account%></td>
+ <td align=right><%equity_this_period%></td>
+ <td align=right><%equity_last_period%></td>
+</tr>
+<%end equity_account%>
+
+<tr>
+ <td colspan=2> </td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td></td>
+ <th align=left>Capital total</th>
+ <td align=right><%total_equity_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_equity_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>Total de pasivos y capital</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+</table>
diff --git a/sql-ledger/templates/Spanish_Letter-check.tex b/sql-ledger/templates/Spanish_Letter-check.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-check.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_Letter-income_statement.html b/sql-ledger/templates/Spanish_Letter-income_statement.html
new file mode 100644
index 0000000..fbb5653
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-income_statement.html
@@ -0,0 +1,77 @@
+<head>
+ <title>Balance de Situación</title>
+</head>
+
+<body bgcolor=ffffff>
+
+<h2 align=center>
+<%company%>
+<br><%address%>
+
+<p>BALANCE DE SITUACIÓN
+<br><%period%>
+</h2>
+
+
+<table width=100% border=0>
+<tr>
+ <th width=400 align=left colspan=2>INGRESOS<br><hr width=300 size=5 align=left noshade></th>
+ <th><%this_period%></th>
+ <th><%last_period%></th>
+</tr>
+
+<%foreach income_account%>
+<tr>
+ <td width=4>&nbsp;</td>
+ <td><%income_account%></td>
+ <td align=right><%income_this_period%></td>
+ <td align=right><%income_last_period%></td>
+</tr>
+<%end income_account%>
+
+<tr>
+ <td colspan=2>&nbsp;</td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td>&nbsp;</td>
+ <th align=left>Total de ingresos</th>
+ <td align=right><%total_income_this_period%><hr noshade size=2></td>
+ <td align=right><%total_income_last_period%><hr noshade size=2></td>
+</tr>
+
+<tr>
+ <th align=left colspan=2>GASTOS<br><hr width=300 size=5 align=left noshade></th>
+</tr>
+
+<%foreach expense_account%>
+<tr>
+ <td>&nbsp;</td>
+ <td><%expense_account%></td>
+ <td align=right><%expenses_this_period%></td>
+ <td align=right><%expenses_last_period%></td>
+</tr>
+<%end expense_account%>
+
+<tr>
+ <td colspan=2>&nbsp;</td>
+ <td><hr noshade size=1></td>
+ <td><hr noshade size=1></td>
+</tr>
+
+<tr valign=top>
+ <td>&nbsp;</td>
+ <th align=left>Total de gastos</th>
+ <td align=right><%total_expenses_this_period%><br><hr noshade size=2</td>
+ <td align=right><%total_expenses_last_period%><br><hr noshade size=2</td>
+</tr>
+
+<tr valign=top>
+ <th align=left colspan=2>GANANCIA/(PERDIDA)</th>
+ <td align=right><%total_this_period%><br><hr noshade size=2></td>
+ <td align=right><%total_last_period%><br><hr noshade size=2></td>
+</tr>
+
+</table>
diff --git a/sql-ledger/templates/Spanish_Letter-invoice.html b/sql-ledger/templates/Spanish_Letter-invoice.html
new file mode 100644
index 0000000..d274936
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-invoice.html
@@ -0,0 +1,153 @@
+<head>
+ <title>Factura de Instalaciones Industriales San José</title>
+</head>
+
+<body bgcolor="ffffff">
+ <!-- Cabecera -->
+ <table width="100%">
+ <tr valign=bottom>
+ <td width="10">&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th colspan="4"> </th>
+ <th align="left">
+ <h4>F A C T U R A</h4>
+ </th>
+ </tr>
+
+ <tr>
+ <td colspan="5"> </td>
+ </tr>
+
+ <tr>
+ <td colspan="4"> </td>
+ <td align="left"><%name%></td>
+ </tr>
+
+ <tr>
+ <td>Número</td>
+ <td>Fecha</td>
+ <td>Cód. Cliente</td>
+ <td width="10%"> </td>
+ <td><%addr1%></td>
+ </tr>
+ <tr>
+ <td><b><%invnumber%></b></td>
+ <td><b><%invdate%></b></td>
+ <td><b><%customer_id%></b></td>
+ <td> </td>
+ <td><%addr2%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr3%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr4%></td>
+ </tr>
+ </table>
+ </table>
+
+ <!-- Cuerpo -->
+ <table width=100% cellspacing=0 cellpadding=0>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <!-- <th align=left><font color=ffffff>Número</th> -->
+ <!-- <th><font color=ffffff>Cant.</th> -->
+ <th align="left"><font color="ffffff">Cant.</th>
+ <th align="left"><font color="ffffff">Descripción</th>
+ <th align="left"><font color="ffffff">Precio</th>
+ <!-- <th align="left"><font color="ffffff">Dto.</th> -->
+ <th align="left"><font color="ffffff">Importe</th>
+ </tr>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <!-- <td><%number%></td> -->
+ <!-- <td><%unit%></td> -->
+ <td align="right"><%qty%></td>
+ <td align="left"><%description%></td>
+ <td align="right"><%sellprice%></td>
+ <!-- <td align=right><%discount%></td> -->
+ <td align="right"><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+ </table>
+
+ <!-- Subtotales, impuestos y totales -->
+ <table width="100%">
+ <tr>
+<%if taxincluded%>
+ <th align=right>Total</th>
+ <td align=right><%invtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th align="right">Base imponible</th>
+ <td align="right"><%subtotal%> &euro;</td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th align="right">IVA (<%taxrate%>%) sobre <%taxbase%>:</th>
+ <td align="right"><%tax%> &euro;</td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th align="right">Pagado:</th>
+ <td align="right"><%paid%> &euro;</td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th align="right">Total:</th>
+ <th align="right"><%invtotal%> &euro;</th>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ </table>
+
+
+ <!-- Pie -->
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>Notas</td>
+ <td><%notes%></td>
+<%end notes%>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan="2" align="left"><font size=-2>Los precios incluyen impuestos.</th>
+ </tr>
+<%end taxincluded%>
+
+ </table>
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Spanish_Letter-invoice.tex b/sql-ledger/templates/Spanish_Letter-invoice.tex
new file mode 100644
index 0000000..8fdd38a
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-invoice.tex
@@ -0,0 +1,110 @@
+% ve-invoice.tex
+\documentclass[letterpaper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+%\usepackage{marvosym} % Euro \EUR
+\usepackage{fancyhdr}
+\setlength{\topmargin}{0cm}
+\setlength{\topskip}{0cm}
+\setlength{\headheight}{0cm}
+\setlength{\headsep}{0.5cm}
+\setlength{\textheight}{24.2cm}
+\setlength{\textwidth}{19cm}
+\setlength{\oddsidemargin}{-1.4cm}
+\setlength{\evensidemargin}{-1.4cm}
+\setlength{\footskip}{1cm}
+
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{13.0cm}
+
+\newsavebox{\hdr}
+
+%Or whatever font you want!
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\sbox{\hdr}{
+
+\begin{minipage}[t]{0.6\linewidth}
+\vspace{2.2cm}
+
+\begin{tabular}[t]{p{1.7cm}p{2.4cm}p{1.7cm}}\\
+\centering{Número} & \centering{Fecha} & C. Cliente\\
+\centering{<%invnumber%>} & \centering{<%invdate%>} & \centering{<%customer_id%>}
+\end{tabular}
+\end{minipage}
+
+\begin{minipage}[t]{0.4\linewidth}
+\textbf{F A C T U R A}
+\vspace{1cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+\end{minipage}
+
+}
+
+\pagestyle{fancy}
+\renewcommand{\headrulewidth}{0cm}
+\renewcommand{\footrulewidth}{0cm}
+\cfoot{\thepage}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+%\thispagestyle{empty} %use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+\newpage
+\usebox{\hdr}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%end pagebreak%>
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\usebox{\hdr}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%foreach number%>
+ <%qty%> & <%description%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+\parbox{\textwidth}{
+\vspace{12pt}
+<%if notes%>
+ <%notes%>
+<%end if%>
+}
+
+\vfill
+
+\begin{flushright}
+\begin{tabularx}{10cm}{Xr@{}}
+ \textbf{Base imponible} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ IVA (<%taxrate%>\%) sobre <%taxbase%> & <%tax%> \\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%invtotal%>} \\
+\end{tabularx}
+\end{flushright}
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_Letter-packing_list.html b/sql-ledger/templates/Spanish_Letter-packing_list.html
new file mode 100644
index 0000000..c34d189
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-packing_list.html
@@ -0,0 +1,155 @@
+<head>
+ <title>Albarán de Instalaciones Industriales San José</title>
+</head>
+
+<body bgcolor="ffffff">
+ <!-- Cabecera -->
+ <table width="100%">
+ <tr valign=bottom>
+ <td width="10">&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th colspan="5"> </th>
+ <th align="left">
+ <h4>A L B A R Á N</h4>
+ </th>
+ </tr>
+
+ <tr>
+ <td colspan="6"> </td>
+ </tr>
+
+ <tr>
+ <td colspan="5"> </td>
+ <td align="left"><%name%></td>
+ </tr>
+
+ <tr>
+ <td>Número</td>
+ <td>Factura</td>
+ <td>Fecha</td>
+ <td>Cód. Cliente</td>
+ <td width="10%"> </td>
+ <td><%addr1%></td>
+ </tr>
+ <tr>
+ <td><b><%ordnumber%></b></td>
+ <td><b><%invnumber%></b></td>
+ <td><b><%invdate%></b></td>
+ <td><b><%customer_id%></b></td>
+ <td> </td>
+ <td><%addr2%></td>
+ </tr>
+ <tr>
+ <td colspan="5">
+ <td><%addr3%></td>
+ </tr>
+ <tr>
+ <td colspan="5">
+ <td><%addr4%></td>
+ </tr>
+ </table>
+ </table>
+
+ <!-- Cuerpo -->
+ <table width=100% cellspacing=0 cellpadding=0>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <!-- <th align=left><font color=ffffff>Número</th> -->
+ <!-- <th><font color=ffffff>Cant.</th> -->
+ <th align="left"><font color="ffffff">Cant.</th>
+ <th align="left"><font color="ffffff">Descripción</th>
+ <th align="left"><font color="ffffff">Precio</th>
+ <!-- <th align="left"><font color="ffffff">Dto.</th> -->
+ <th align="left"><font color="ffffff">Importe</th>
+ </tr>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <!-- <td><%number%></td> -->
+ <!-- <td><%unit%></td> -->
+ <td align="right"><%qty%></td>
+ <td align="left"><%description%></td>
+ <td align="right"><%sellprice%></td>
+ <!-- <td align=right><%discount%></td> -->
+ <td align="right"><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+ </table>
+
+ <!-- Subtotales, impuestos y totales -->
+ <table width="100%">
+ <tr>
+<%if taxincluded%>
+ <th align=right>Total</th>
+ <td align=right><%invtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th align="right">Base imponible</th>
+ <td align="right"><%subtotal%> &euro;</td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th align="right">IVA (<%taxrate%>%) sobre <%taxbase%>:</th>
+ <td align="right"><%tax%> &euro;</td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th align="right">Pagado:</th>
+ <td align="right"><%paid%> &euro;</td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th align="right">Total:</th>
+ <th align="right"><%invtotal%> &euro;</th>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ </table>
+
+
+ <!-- Pie -->
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>Notas</td>
+ <td><%notes%></td>
+<%end notes%>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan="2" align="left"><font size=-2>Los precios incluyen impuestos.</th>
+ </tr>
+<%end taxincluded%>
+
+ </table>
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Spanish_Letter-packing_list.tex b/sql-ledger/templates/Spanish_Letter-packing_list.tex
new file mode 100644
index 0000000..bf146ca
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-packing_list.tex
@@ -0,0 +1,108 @@
+\documentclass[letterpaper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+%\usepackage{marvosym} % Euro \EUR
+\usepackage{fancyhdr}
+\setlength{\topmargin}{0cm}
+\setlength{\topskip}{0cm}
+\setlength{\headheight}{0cm}
+\setlength{\headsep}{0.5cm}
+\setlength{\textheight}{24.2cm}
+\setlength{\textwidth}{19cm}
+\setlength{\oddsidemargin}{-1.4cm}
+\setlength{\evensidemargin}{-1.4cm}
+\setlength{\footskip}{1cm}
+
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{13.0cm}
+
+\newsavebox{\hdr}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\sbox{\hdr}{
+
+\begin{minipage}[t]{0.6\linewidth}
+\vspace{2.2cm}
+
+\begin{tabular}[t]{p{1.7cm}p{1.7cm}p{2.4cm}p{1.7cm}}\\
+\centering{Número} & \centering{Número} & \centering{Fecha} & C. Cliente\\
+ \centering{<%ordnumber%>} & \centering{<%invnumber%>} & \centering{<%invdate%>} & \centering{<%customer_id%>}
+\end{tabular}
+\end{minipage}
+
+\begin{minipage}[t]{0.4\linewidth}
+\textbf{A L B A R Á N}
+\vspace{1cm}
+
+<%shiptoname%>
+
+<%shiptoaddr1%>
+
+<%shiptoaddr2%>
+
+<%shiptoaddr3%>
+
+<%shiptoaddr4%>
+\end{minipage}
+
+}
+
+\pagestyle{fancy}
+\renewcommand{\headrulewidth}{0cm}
+\renewcommand{\footrulewidth}{0cm}
+\cfoot{\thepage}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+%\thispagestyle{empty} %use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+\newpage
+\usebox{\hdr}
+\vspace{0.5cm}
+
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%end pagebreak%>
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\usebox{\hdr}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%foreach number%>
+ <%qty%> & <%description%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+\parbox{\textwidth}{
+\vspace{12pt}
+<%if notes%>
+ <%notes%>
+<%end if%>
+}
+
+\vfill
+
+\begin{flushright}
+\begin{tabularx}{10cm}{Xr@{}}
+ \textbf{Base imponible} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ IVA (<%taxrate%>\%) sobre <%taxbase%> & <%tax%> \\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%invtotal%>} \\
+\end{tabularx}
+\end{flushright}
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_Letter-purchase_order.html b/sql-ledger/templates/Spanish_Letter-purchase_order.html
new file mode 100644
index 0000000..693fe65
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-purchase_order.html
@@ -0,0 +1,153 @@
+<head>
+ <title>Pedido de Instalaciones Industriales San José</title>
+</head>
+
+<body bgcolor="ffffff">
+ <!-- Cabecera -->
+ <table width="100%">
+ <tr valign=bottom>
+ <td width="10">&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th colspan="4"> </th>
+ <th align="left">
+ <h4>P E D I D O</h4>
+ </th>
+ </tr>
+
+ <tr>
+ <td colspan="5"> </td>
+ </tr>
+
+ <tr>
+ <td colspan="4"> </td>
+ <td align="left"><%name%></td>
+ </tr>
+
+ <tr>
+ <td>Número</td>
+ <td>Fecha</td>
+ <td>Cód. Proveedor</td>
+ <td width="10%"> </td>
+ <td><%addr1%></td>
+ </tr>
+ <tr>
+ <td><b><%ordnumber%></b></td>
+ <td><b><%orddate%></b></td>
+ <td><b><%vendor_id%></b></td>
+ <td> </td>
+ <td><%addr2%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr3%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr4%></td>
+ </tr>
+ </table>
+ </table>
+
+ <!-- Cuerpo -->
+ <table width=100% cellspacing=0 cellpadding=0>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <!-- <th align=left><font color=ffffff>Número</th> -->
+ <!-- <th><font color=ffffff>Cant.</th> -->
+ <th align="left"><font color="ffffff">Cant.</th>
+ <th align="left"><font color="ffffff">Descripción</th>
+ <th align="left"><font color="ffffff">Precio</th>
+ <!-- <th align="left"><font color="ffffff">Dto.</th> -->
+ <th align="left"><font color="ffffff">Importe</th>
+ </tr>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <!-- <td><%number%></td> -->
+ <!-- <td><%unit%></td> -->
+ <td align="right"><%qty%></td>
+ <td align="left"><%description%></td>
+ <td align="right"><%sellprice%></td>
+ <!-- <td align=right><%discount%></td> -->
+ <td align="right"><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+ </table>
+
+ <!-- Subtotales, impuestos y totales -->
+ <table width="100%">
+ <tr>
+<%if taxincluded%>
+ <th align="right">Total</th>
+ <td align="right"><%ordtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th align="right">Base imponible</th>
+ <td align="right"><%subtotal%> &euro;</td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th align="right">IVA (<%taxrate%>%) sobre <%taxbase%>:</th>
+ <td align="right"><%tax%> &euro;</td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th align="right">Pagado:</th>
+ <td align="right"><%paid%> &euro;</td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th align="right">Total:</th>
+ <th align="right"><%ordtotal%> &euro;</th>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ </table>
+
+
+ <!-- Pie -->
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>Notas</td>
+ <td><%notes%></td>
+<%end notes%>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan="2" align="left"><font size=-2>Los precios incluyen impuestos.</th>
+ </tr>
+<%end taxincluded%>
+
+ </table>
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Spanish_Letter-purchase_order.tex b/sql-ledger/templates/Spanish_Letter-purchase_order.tex
new file mode 100644
index 0000000..177f4b8
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-purchase_order.tex
@@ -0,0 +1,107 @@
+\documentclass[letterpaper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+%\usepackage{marvosym} % Euro \EUR
+\usepackage{fancyhdr}
+\setlength{\topmargin}{0cm}
+\setlength{\topskip}{0cm}
+\setlength{\headheight}{0cm}
+\setlength{\headsep}{0.5cm}
+\setlength{\textheight}{24.2cm}
+\setlength{\textwidth}{19cm}
+\setlength{\oddsidemargin}{-1.4cm}
+\setlength{\evensidemargin}{-1.4cm}
+\setlength{\footskip}{1cm}
+
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{13.0cm}
+
+\newsavebox{\hdr}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\sbox{\hdr}{
+\begin{minipage}[t]{0.6\linewidth}
+\vspace{2.2cm}
+
+\begin{tabular}[t]{p{1.7cm}p{2.4cm}p{1.7cm}}\\
+\centering{Número} & \centering{Fecha} & C. Cliente\\
+\centering{<%ordnumber%>} & \centering{<%orddate%>} & \centering{<%vendor_id%>}
+\end{tabular}
+\end{minipage}
+
+\begin{minipage}[t]{0.4\linewidth}
+\textbf{O R D E N \quad D E \quad C O M P R A}
+\vspace{1cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+\end{minipage}
+
+}
+
+\pagestyle{fancy}
+\renewcommand{\headrulewidth}{0cm}
+\renewcommand{\footrulewidth}{0cm}
+\cfoot{\thepage}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+%\thispagestyle{empty} %use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+\newpage
+\usebox{\hdr}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%end pagebreak%>
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\usebox{\hdr}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%foreach number%>
+ <%qty%> & <%description%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+\parbox{\textwidth}{
+\vspace{12pt}
+<%if notes%>
+ <%notes%>
+<%end if%>
+}
+
+\vfill
+
+\begin{flushright}
+\begin{tabularx}{10cm}{Xr@{}}
+ \textbf{Base imponible} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ IVA (<%taxrate%>\%) sobre <%taxbase%> & <%tax%> \\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>} \\
+\end{tabularx}
+\end{flushright}
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_Letter-receipt.tex b/sql-ledger/templates/Spanish_Letter-receipt.tex
new file mode 100644
index 0000000..5b64e81
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-receipt.tex
@@ -0,0 +1,71 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.4cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.0cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+
+\fontfamily{cmss}\fontsize{9pt}{9pt}\selectfont
+
+\parbox[t]{12cm}{
+ <%company%>
+
+ <%address%>}
+\hfill
+\parbox[t]{6cm}{\hfill <%source%>}
+
+\vspace*{0.6cm}
+
+<%text_amount%> \dotfill <%decimal%>/100 \makebox[0.5cm]{\hfill}
+
+\vspace{0.5cm}
+
+\hfill <%datepaid%> \makebox[2cm]{\hfill} <%amount%>
+
+\vspace{0.5cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+\vspace{2.8cm}
+
+<%company%>
+
+\vspace{0.5cm}
+
+<%name%> \hfill <%datepaid%> \hfill <%source%>
+
+\vspace{0.5cm}
+\begin{tabularx}{\textwidth}{lXrr@{}}
+\textbf{Invoice No.} & \textbf{Invoice Date}
+ & \textbf{Due} & \textbf{Applied} \\
+<%foreach invnumber%>
+<%invnumber%> & <%invdate%> \dotfill
+ & <%due%> & <%paid%> \\
+<%end invnumber%>
+\end{tabularx}
+
+\vfill
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_Letter-sales_order.html b/sql-ledger/templates/Spanish_Letter-sales_order.html
new file mode 100644
index 0000000..d54f375
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-sales_order.html
@@ -0,0 +1,153 @@
+<head>
+ <title>Presupuesto de Instalaciones Industriales San José</title>
+</head>
+
+<body bgcolor="ffffff">
+ <!-- Cabecera -->
+ <table width="100%">
+ <tr valign=bottom>
+ <td width="10">&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th colspan="4"> </th>
+ <th align="left">
+ <h4>P R E S U P U E S T O</h4>
+ </th>
+ </tr>
+
+ <tr>
+ <td colspan="5"> </td>
+ </tr>
+
+ <tr>
+ <td colspan="4"> </td>
+ <td align="left"><%name%></td>
+ </tr>
+
+ <tr>
+ <td>Número</td>
+ <td>Fecha</td>
+ <td>Cód. Cliente</td>
+ <td width="10%"> </td>
+ <td><%addr1%></td>
+ </tr>
+ <tr>
+ <td><b><%ordnumber%></b></td>
+ <td><b><%orddate%></b></td>
+ <td><b><%customer_id%></b></td>
+ <td> </td>
+ <td><%addr2%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr3%></td>
+ </tr>
+ <tr>
+ <td colspan="4">
+ <td><%addr4%></td>
+ </tr>
+ </table>
+ </table>
+
+ <!-- Cuerpo -->
+ <table width=100% cellspacing=0 cellpadding=0>
+ <tr>
+ <td>
+ <table width=100%>
+ <tr bgcolor=000000>
+ <!-- <th align=left><font color=ffffff>Número</th> -->
+ <!-- <th><font color=ffffff>Cant.</th> -->
+ <th align="left"><font color="ffffff">Cant.</th>
+ <th align="left"><font color="ffffff">Descripción</th>
+ <th align="left"><font color="ffffff">Precio</th>
+ <!-- <th align="left"><font color="ffffff">Dto.</th> -->
+ <th align="left"><font color="ffffff">Importe</th>
+ </tr>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+
+<%foreach number%>
+ <tr valign=top>
+ <!-- <td><%number%></td> -->
+ <!-- <td><%unit%></td> -->
+ <td align="right"><%qty%></td>
+ <td align="left"><%description%></td>
+ <td align="right"><%sellprice%></td>
+ <!-- <td align=right><%discount%></td> -->
+ <td align="right"><%linetotal%></td>
+ </tr>
+<%end number%>
+
+ <tr>
+ <td colspan="4"><hr noshade></td>
+ </tr>
+ </table>
+
+ <!-- Subtotales, impuestos y totales -->
+ <table width="100%">
+ <tr>
+<%if taxincluded%>
+ <th align=right>Total</th>
+ <td align=right><%ordtotal%></td>
+<%end taxincluded%>
+<%if not taxincluded%>
+ <th align="right">Base imponible</th>
+ <td align="right"><%subtotal%> &euro;</td>
+<%end taxincluded%>
+ </tr>
+
+<%foreach tax%>
+ <tr>
+ <th align="right">IVA (<%taxrate%>%) sobre <%taxbase%>:</th>
+ <td align="right"><%tax%> &euro;</td>
+ </tr>
+<%end tax%>
+
+<%if paid%>
+ <tr>
+ <th align="right">Pagado:</th>
+ <td align="right"><%paid%> &euro;</td>
+ </tr>
+<%end paid%>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+
+ <tr>
+ <th align="right">Total:</th>
+ <th align="right"><%ordtotal%> &euro;</th>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ </table>
+
+
+ <!-- Pie -->
+ <table width="100%">
+ <tr valign=top>
+<%if notes%>
+ <td>Notas</td>
+ <td><%notes%></td>
+<%end notes%>
+ </tr>
+
+<%if taxincluded%>
+ <tr>
+ <th colspan="2" align="left"><font size=-2>Los precios incluyen impuestos.</th>
+ </tr>
+<%end taxincluded%>
+
+ </table>
+
+
+</body>
+</html>
+
diff --git a/sql-ledger/templates/Spanish_Letter-sales_order.tex b/sql-ledger/templates/Spanish_Letter-sales_order.tex
new file mode 100644
index 0000000..fd51cb6
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-sales_order.tex
@@ -0,0 +1,107 @@
+\documentclass[letterpaper,oneside]{article}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+%\usepackage{marvosym} % Euro \EUR
+\usepackage{fancyhdr}
+\setlength{\topmargin}{0cm}
+\setlength{\topskip}{0cm}
+\setlength{\headheight}{0cm}
+\setlength{\headsep}{0.5cm}
+\setlength{\textheight}{24.2cm}
+\setlength{\textwidth}{19cm}
+\setlength{\oddsidemargin}{-1.4cm}
+\setlength{\evensidemargin}{-1.4cm}
+\setlength{\footskip}{1cm}
+
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{13.0cm}
+
+\newsavebox{\hdr}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\sbox{\hdr}{
+\begin{minipage}[t]{0.6\linewidth}
+\vspace{2.2cm}
+
+\begin{tabular}[t]{p{1.7cm}p{2.4cm}p{1.7cm}}\\
+\centering{Número} & \centering{Fecha} & C. Cliente\\
+\centering{<%ordnumber%>} & \centering{<%orddate%>} & \centering{<%vendor_id%>}
+\end{tabular}
+\end{minipage}
+
+\begin{minipage}[t]{0.4\linewidth}
+\textbf{P E D I D O}
+\vspace{1cm}
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+\end{minipage}
+
+}
+
+\pagestyle{fancy}
+\renewcommand{\headrulewidth}{0cm}
+\renewcommand{\footrulewidth}{0cm}
+\cfoot{\thepage}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+%\thispagestyle{empty} %use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+\newpage
+\usebox{\hdr}
+%\markboth{\usebox{\hdr}}{\usebox{\hdr}}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%end pagebreak%>
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\usebox{\hdr}
+\vspace{0.5cm}
+
+\begin{tabular*}{\textwidth}{rp{\descrwidth}rr}
+ \textbf{Cant.} & \textbf{Descripción} & \textbf{Precio} & \textbf{Importe} \\ \hline
+<%foreach number%>
+ <%qty%> & <%description%> & <%sellprice%> & <%linetotal%> \\
+<%end number%>
+\end{tabular*}
+
+\parbox{\textwidth}{
+\vspace{12pt}
+<%if notes%>
+ <%notes%>
+<%end if%>
+}
+
+\vfill
+
+\begin{flushright}
+\begin{tabularx}{10cm}{Xr@{}}
+ \textbf{Base imponible} & \textbf{<%subtotal%>} \\
+<%foreach tax%>
+ IVA (<%taxrate%>\%) sobre <%taxbase%> & <%tax%> \\
+<%end tax%>
+ \hline
+ \textbf{Total} & \textbf{<%ordtotal%>} \\
+\end{tabularx}
+\end{flushright}
+
+%\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\end{document}
+
diff --git a/sql-ledger/templates/Spanish_Letter-statement.html b/sql-ledger/templates/Spanish_Letter-statement.html
new file mode 100644
index 0000000..6fca322
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-statement.html
@@ -0,0 +1,121 @@
+
+<body bgcolor=ffffff>
+
+<table width=100%>
+ <tr>
+ <td width=10>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <td>
+ <h4>
+ <%company%>
+ <br><%address%>
+ </h4>
+ </td>
+ <th><img src=http://www.sql-ledger.org/images/sql-ledger.png border=0 width=64 height=58></th>
+ <td align=right>
+ <h4>
+ Tel: <%tel%>
+ <br>Fax: <%fax%>
+ </h4>
+ </td>
+ </tr>
+ <tr>
+ <th colspan=3><h4>S T A T E M E N T</h4></th>
+ </tr>
+ <tr>
+ <td colspan=3 align=right><%statementdate%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr valign=top>
+ <td><%name%>
+ <br><%addr1%>
+ <br><%addr2%>
+ <br><%addr3%>
+ <br><%addr4%>
+ <br>
+<%if customerphone%>
+ <br>Tel: <%customerphone%>
+<%end customerphone%>
+<%if customerfax%>
+ <br>Fax: <%customerfax%>
+<%end customerfax%>
+<%if email%>
+ <br><%email%>
+<%end email%>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>
+ <table width=100%>
+ <tr>
+ <th align=left>Invoice #</th>
+ <th width=15%>Date</th>
+ <th width=15%>Due</th>
+ <th width=10%>Current</th>
+ <th width=10%>30</th>
+ <th width=10%>60</th>
+ <th width=10%>90+</th>
+ </tr>
+<%foreach invnumber%>
+ <tr>
+ <td><%invnumber%></td>
+ <td><%invdate%></td>
+ <td><%duedate%></td>
+ <td align=right><%c0%></td>
+ <td align=right><%c30%></td>
+ <td align=right><%c60%></td>
+ <td align=right><%c90%></td>
+ </tr>
+<%end invnumber%>
+ <tr>
+ <td colspan=7><hr size=1></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <th align=right><%c0total%></td>
+ <th align=right><%c30total%></td>
+ <th align=right><%c60total%></td>
+ <th align=right><%c90total%></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height=10></tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td align=right>
+ <table width=50%>
+ <tr>
+ <th>Total Outstanding</th>
+ <th align=right><%total%></th>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><hr noshade></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>Please make check payable to <b><%company%></b>.
+ </td>
+ </tr>
+ <tr height=20></tr>
+</table>
+
diff --git a/sql-ledger/templates/Spanish_Letter-statement.tex b/sql-ledger/templates/Spanish_Letter-statement.tex
new file mode 100644
index 0000000..0b63f75
--- /dev/null
+++ b/sql-ledger/templates/Spanish_Letter-statement.tex
@@ -0,0 +1,137 @@
+\documentclass[twoside]{scrartcl}
+\usepackage[frame]{xy}
+\usepackage{tabularx}
+\usepackage[latin1]{inputenc}
+\setlength{\voffset}{0.5cm}
+\setlength{\hoffset}{-2.0cm}
+\setlength{\topmargin}{0cm}
+\setlength{\headheight}{0.5cm}
+\setlength{\headsep}{1cm}
+\setlength{\topskip}{0pt}
+\setlength{\oddsidemargin}{1.0cm}
+\setlength{\evensidemargin}{1.0cm}
+\setlength{\textwidth}{19.2cm}
+\setlength{\textheight}{24.5cm}
+\setlength{\footskip}{1cm}
+\setlength{\parindent}{0pt}
+\renewcommand{\baselinestretch}{1}
+\begin{document}
+
+\newlength{\descrwidth}\setlength{\descrwidth}{10cm}
+
+\newsavebox{\hdr}
+\sbox{\hdr}{
+ \fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+ \parbox{\textwidth}{
+ \parbox[b]{12cm}{
+ <%company%>
+
+ <%address%>}\hfill
+ \begin{tabular}[b]{rrr@{}}
+ Tel & <%tel%>\\
+ Fax & <%fax%>
+ \end{tabular}
+
+ \rule[1.5ex]{\textwidth}{0.5pt}
+ }
+}
+
+\fontfamily{cmss}\fontshape{n}\selectfont
+
+\markboth{<%company%>\hfill <%statementdate%>}{\usebox{\hdr}}
+
+\pagestyle{myheadings}
+%\thispagestyle{empty} use this with letterhead paper
+
+<%pagebreak 90 27 48%>
+\end{tabular*}
+
+ \rule{\textwidth}{2pt}
+
+ \hfill
+ \begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Subtotal} & \textbf{<%sumcarriedforward%>} \\
+ \end{tabularx}
+
+\newpage
+
+\markright{<%company%>\hfill <%statementdate%>}
+
+\vspace*{-12pt}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+ carried forward from <%lastpage%> & & & & & & <%sumcarriedforward%> \\
+<%end pagebreak%>
+
+
+\fontfamily{cmss}\fontsize{10pt}{12pt}\selectfont
+
+\vspace*{1.5cm}
+
+\parbox[t]{1cm}{\hfill}
+\parbox[t]{10.5cm}{
+
+<%name%>
+
+<%addr1%>
+
+<%addr2%>
+
+<%addr3%>
+
+<%addr4%>
+
+}
+\parbox[t]{7.5cm}{
+<%if customerphone%>
+Tel: <%customerphone%>
+<%end customerphone%>
+
+<%if customerfax%>
+Fax: <%customerfax%>
+<%end customerfax%>
+
+<%email%>
+}
+\hfill
+
+\vspace{1cm}
+
+\textbf{S T A T E M E N T} \hfill
+
+\hfill <%statementdate%>
+
+\vspace{2cm}
+
+\begin{tabular*}{\textwidth}{@{}l@{\extracolsep\fill}ccrrrr@{}}
+ \textbf{Invoice \#} & \textbf{Date} & \textbf{Due} &
+ \textbf{Current} & \textbf{30} & \textbf{60} & \textbf{90+} \\
+<%foreach invnumber%>
+ <%invnumber%> & <%invdate%> & <%duedate%> &
+ <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+<%end invnumber%>
+\textbf{Subtotal} & & & <%c0total%> & <%c30total%> & <%c60total%> & <%c90total%>
+\end{tabular*}
+\rule{\textwidth}{1pt}
+
+\vspace{1cm}
+
+\hfill
+\begin{tabularx}{7cm}{Xr@{}}
+ \textbf{Total outstanding} & <%total%>
+\end{tabularx}
+
+\vfill
+
+Please make check payable to <%company%>
+
+\renewcommand{\thefootnote}{\fnsymbol{footnote}}
+
+\footnotetext[1]{\tiny
+}
+
+\end{document}
+
diff --git a/sql-ledger/users/members.default b/sql-ledger/users/members.default
new file mode 100644
index 0000000..5f7830d
--- /dev/null
+++ b/sql-ledger/users/members.default
@@ -0,0 +1,5 @@
+# SQL-Ledger Accounting members
+
+[root login]
+password=
+
diff --git a/test/cgi-test b/test/cgi-test
new file mode 100755
index 0000000..2dda484
--- /dev/null
+++ b/test/cgi-test
@@ -0,0 +1,560 @@
+#!/usr/bin/perl -Tw
+#
+# $Id: cgi-test,v 1.3 2001-08-21 02:32:54 ivan Exp $
+#
+# This is the beginning of a test suite for the web interface.
+# It's also excellent for populating your database with some meaningful test
+# data. (a derivative is used by the web demo)
+# It only works on an empty database (probably need empty counters too, and
+# no arbirary RADIUS attributes).
+# Usage: cgi-test http://base.freeside.url/with/path/ username password
+# (Yes, if you were properly paranoid and are using SSL, you'll need to get
+# libwww-perl working with SSL to use this.)
+
+use strict;
+#use diagnostics;
+use subs qw( big_ugly_data_structure );
+use CGI;
+use LWP::UserAgent;
+
+my ( $base_url, $username, $password ) = ( shift, shift, shift );
+#trust 'em
+$base_url =~ /^(.*)$/; $base_url = $1;
+$username =~ /^(.*)$/; $username = $1;
+$password =~ /^(.*)$/; $password = $1;
+
+my @data = &big_ugly_data_structure;
+
+my $ua = new LWP::UserAgent;
+{
+ local $^W = 0;
+ eval '
+ sub LWP::UserAgent::get_basic_credentials {
+ #my $self = shift;
+ ( $username, $password );
+ }
+ ';
+}
+
+my $data;
+while ( $data = shift @data ) {
+ my $cgi = new CGI ( $data->{'params'} );
+ my $full_url = $base_url. $data->{'url'}. '?'. $cgi->query_string;
+ #my $request = new HTTP::Request( 'POST', $full_url );
+ my $request = new HTTP::Request( 'GET', $full_url );
+ my $response = $ua->request( $request );
+ if ( $response->is_redirect ) {
+ die "Unexpected redirect!\n".
+ "URL: $full_url\n".
+ "To: ". $response->base. "\n"
+ ;
+ } elsif ( $response->is_success ) {
+ my $location = $response->base;
+ my $expected_location = $data->{'location'};
+ #if ( $location =~ /^$base_url$expected_location$/ ) {
+ if ( $location eq $base_url. $expected_location ) {
+ #warn "cool, got expected response $location from $full_url\n";
+ } else {
+ die "Strange, regular response, but unexpected base!\n".
+ "URL: $full_url\n".
+ "Base : ". $response->base. "\n".
+ "Expected: $base_url$expected_location\n".
+ "Output: ". $response->content. "\n"
+ ;
+ }
+ } elsif ( $response->is_error ) {
+ die "Strange, I got an error\n".
+ "URL: $full_url\n".
+ "Error: ". $response->error_as_HTML. "\n".
+ "Output: ". $response->content. "\n"
+ ;
+ } elsif ( $response->is_info ) {
+ die "Strange, I got an info reponse\n".
+ "URL: $full_url\n".
+ "Output: ". $response->content. "\n"
+ ;
+ } else {
+ die "Really strange, got an unrecognized response from LWP::UserAgent!\n";
+ }
+}
+
+#---
+
+sub big_ugly_data_structure {
+
+ (
+ { 'url' => 'edit/process/part_svc.cgi',
+ 'params' => {
+ 'svcpart' => '',
+ 'svc' => 'Shell',
+ 'svcdb' => 'svc_acct',
+ 'svc_acct__popnum_flag' => '',
+ 'svc_acct__popnum' => '',
+ 'svc_acct__dir_flag' => '',
+ 'svc_acct__dir' => '',
+ 'svc_acct__username_flag' => '',
+ 'svc_acct__username' => '',
+ 'svc_acct__uid_flag' => '',
+ 'svc_acct__uid' => '',
+ 'svc_acct__quota_flag' => 'F',
+ 'svc_acct__quota' => '10',
+ 'svc_acct__slipip_flag' => 'F',
+ 'svc_acct__slipip' => '',
+ 'svc_acct___password_flag' => '',
+ 'svc_acct___password' => '',
+ 'svc_acct__gid_flag' => '',
+ 'svc_acct__gid' => '',
+ 'svc_acct__shell_flag' => 'D',
+ 'svc_acct__shell' => '/bin/sh',
+ 'svc_acct__finger_flag' => '',
+ 'svc_acct__finger' => '',
+ 'svc_domain__domain_flag' => '',
+ 'svc_domain__domain' => '',
+ 'svc_acct_sm__domuser_flag' => '',
+ 'svc_acct_sm__domuser' => '',
+ 'svc_acct_sm__domuid_flag' => '',
+ 'svc_acct_sm__domuid' => '',
+ 'svc_acct_sm__domsvc_flag' => '',
+ 'svc_acct_sm__domsvc' => '',
+ },
+ 'location' => 'browse/part_svc.cgi',
+ },
+ { 'url' => 'edit/process/part_svc.cgi',
+ 'params' => {
+ 'svcpart' => '',
+ 'svc' => 'SLIP/PPP',
+ 'svcdb' => 'svc_acct',
+ 'svc_acct__popnum_flag' => '',
+ 'svc_acct__popnum' => '',
+ 'svc_acct__dir_flag' => '',
+ 'svc_acct__dir' => '',
+ 'svc_acct__username_flag' => '',
+ 'svc_acct__username' => '',
+ 'svc_acct__uid_flag' => '',
+ 'svc_acct__uid' => '',
+ 'svc_acct__quota_flag' => 'F',
+ 'svc_acct__quota' => '10',
+ 'svc_acct__slipip_flag' => 'D',
+ 'svc_acct__slipip' => '0.0.0.0',
+ 'svc_acct___password_flag' => '',
+ 'svc_acct___password' => '',
+ 'svc_acct__gid_flag' => '',
+ 'svc_acct__gid' => '',
+ 'svc_acct__shell_flag' => 'D',
+ 'svc_acct__shell' => '/bin/sh',
+ 'svc_acct__finger_flag' => '',
+ 'svc_acct__finger' => '',
+ 'svc_domain__domain_flag' => '',
+ 'svc_domain__domain' => '',
+ 'svc_acct_sm__domuser_flag' => '',
+ 'svc_acct_sm__domuser' => '',
+ 'svc_acct_sm__domuid_flag' => '',
+ 'svc_acct_sm__domuid' => '',
+ 'svc_acct_sm__domsvc_flag' => '',
+ 'svc_acct_sm__domsvc' => '',
+ },
+ 'location' => 'browse/part_svc.cgi',
+ },
+ { 'url' => 'edit/process/part_svc.cgi',
+ 'params' => {
+ 'svcpart' => '',
+ 'svc' => 'POP Mailbox',
+ 'svcdb' => 'svc_acct',,
+ 'svc_acct__popnum_flag' => 'F',
+ 'svc_acct__popnum' => '',
+ 'svc_acct__dir_flag' => '',
+ 'svc_acct__dir' => '',
+ 'svc_acct__username_flag' => '',
+ 'svc_acct__username' => '',
+ 'svc_acct__uid_flag' => '',
+ 'svc_acct__uid' => '',
+ 'svc_acct__quota_flag' => 'F',
+ 'svc_acct__quota' => '10',
+ 'svc_acct__slipip_flag' => 'F',
+ 'svc_acct__slipip' => '',
+ 'svc_acct___password_flag' => '',
+ 'svc_acct___password' => '',
+ 'svc_acct__gid_flag' => '',
+ 'svc_acct__gid' => '',
+ 'svc_acct__shell_flag' => 'F',
+ 'svc_acct__shell' => '/bin/passwd',
+ 'svc_acct__finger_flag' => '',
+ 'svc_acct__finger' => '',
+ 'svc_domain__domain_flag' => '',
+ 'svc_domain__domain' => '',
+ 'svc_acct_sm__domuser_flag' => '',
+ 'svc_acct_sm__domuser' => '',
+ 'svc_acct_sm__domuid_flag' => '',
+ 'svc_acct_sm__domuid' => '',
+ 'svc_acct_sm__domsvc_flag' => '',
+ 'svc_acct_sm__domsvc' => '',
+ },
+ 'location' => 'browse/part_svc.cgi',
+ },
+ { 'url' => 'edit/process/part_svc.cgi',
+ 'params' => {
+ 'svcpart' => '',
+ 'svc' => 'Domain',
+ 'svcdb' => 'svc_domain',,
+ 'svc_acct__popnum_flag' => '',
+ 'svc_acct__popnum' => '',
+ 'svc_acct__dir_flag' => '',
+ 'svc_acct__dir' => '',
+ 'svc_acct__username_flag' => '',
+ 'svc_acct__username' => '',
+ 'svc_acct__uid_flag' => '',
+ 'svc_acct__uid' => '',
+ 'svc_acct__quota_flag' => '',
+ 'svc_acct__quota' => '',
+ 'svc_acct__slipip_flag' => '',
+ 'svc_acct__slipip' => '',
+ 'svc_acct___password_flag' => '',
+ 'svc_acct___password' => '',
+ 'svc_acct__gid_flag' => '',
+ 'svc_acct__gid' => '',
+ 'svc_acct__shell_flag' => '',
+ 'svc_acct__shell' => '',
+ 'svc_acct__finger_flag' => '',
+ 'svc_acct__finger' => '',
+ 'svc_domain__domain_flag' => '',
+ 'svc_domain__domain' => '',
+ 'svc_acct_sm__domuser_flag' => '',
+ 'svc_acct_sm__domuser' => '',
+ 'svc_acct_sm__domuid_flag' => '',
+ 'svc_acct_sm__domuid' => '',
+ 'svc_acct_sm__domsvc_flag' => '',
+ 'svc_acct_sm__domsvc' => '',
+ },
+ 'location' => 'browse/part_svc.cgi',
+ },
+ { 'url' => 'edit/process/part_svc.cgi',
+ 'params' => {
+ 'svcpart' => '',
+ 'svc' => 'Domain email alias',
+ 'svcdb' => 'svc_acct_sm',,
+ 'svc_acct__popnum_flag' => '',
+ 'svc_acct__popnum' => '',
+ 'svc_acct__dir_flag' => '',
+ 'svc_acct__dir' => '',
+ 'svc_acct__username_flag' => '',
+ 'svc_acct__username' => '',
+ 'svc_acct__uid_flag' => '',
+ 'svc_acct__uid' => '',
+ 'svc_acct__quota_flag' => '',
+ 'svc_acct__quota' => '',
+ 'svc_acct__slipip_flag' => '',
+ 'svc_acct__slipip' => '',
+ 'svc_acct___password_flag' => '',
+ 'svc_acct___password' => '',
+ 'svc_acct__gid_flag' => '',
+ 'svc_acct__gid' => '',
+ 'svc_acct__shell_flag' => '',
+ 'svc_acct__shell' => '',
+ 'svc_acct__finger_flag' => '',
+ 'svc_acct__finger' => '',
+ 'svc_domain__domain_flag' => '',
+ 'svc_domain__domain' => '',
+ 'svc_acct_sm__domuser_flag' => '',
+ 'svc_acct_sm__domuser' => '',
+ 'svc_acct_sm__domuid_flag' => '',
+ 'svc_acct_sm__domuid' => '',
+ 'svc_acct_sm__domsvc_flag' => '',
+ 'svc_acct_sm__domsvc' => '',
+ },
+ 'location' => 'browse/part_svc.cgi',
+ },
+
+ { 'url' => 'edit/process/part_pkg.cgi',
+ 'params' => {
+ 'pkgpart' => '',
+ 'pkg' => 'Personal SLIP/PPP',
+ 'comment' => '$30/setup, $19.99/month',
+ 'setup' => '30',
+ 'recur' => '19.99',
+ 'freq' => '1',
+ 'pkg_svc1' => '0',
+ 'pkg_svc2' => '1',
+ 'pkg_svc3' => '0',
+ 'pkg_svc4' => '0',
+ 'pkg_svc5' => '0',
+ },
+ 'location' => 'browse/part_pkg.cgi',
+ },
+ { 'url' => 'edit/process/part_pkg.cgi',
+ 'params' => {
+ 'pkgpart' => '',
+ 'pkg' => 'Personal SLIP/PPP',
+ 'comment' => '$0/setup, $179.88/year',
+ 'setup' => '0',
+ 'recur' => '179.88',
+ 'freq' => '12',
+ 'pkg_svc1' => '0',
+ 'pkg_svc2' => '1',
+ 'pkg_svc3' => '0',
+ 'pkg_svc4' => '0',
+ 'pkg_svc5' => '0',
+ },
+ 'location' => 'browse/part_pkg.cgi',
+ },
+ { 'url' => 'edit/process/part_pkg.cgi',
+ 'params' => {
+ 'pkgpart' => '',
+ 'pkg' => 'Personal POP mailbox',
+ 'comment' => '$10/setup, $5/month',
+ 'setup' => '10',
+ 'recur' => '5',
+ 'freq' => '1',
+ 'pkg_svc1' => '0',
+ 'pkg_svc2' => '0',
+ 'pkg_svc3' => '1',
+ 'pkg_svc4' => '0',
+ 'pkg_svc5' => '0',
+ },
+ 'location' => 'browse/part_pkg.cgi',
+ },
+ { 'url' => 'edit/process/part_pkg.cgi',
+ 'params' => {
+ 'pkgpart' => '',
+ 'pkg' => 'Business SLIP/PPP',
+ 'comment' => '$30/setup, $29.99/month',
+ 'setup' => '30',
+ 'recur' => '29.99',
+ 'freq' => '1',
+ 'pkg_svc1' => '0',
+ 'pkg_svc2' => '1',
+ 'pkg_svc3' => '0',
+ 'pkg_svc4' => '1',
+ 'pkg_svc5' => '1',
+ },
+ 'location' => 'browse/part_pkg.cgi',
+ },
+ { 'url' => 'edit/process/part_pkg.cgi',
+ 'params' => {
+ 'pkgpart' => '',
+ 'pkg' => 'Business SLIP/PPP',
+ 'comment' => '$0/setup, $299.88/year',
+ 'setup' => '0',
+ 'recur' => '299.88',
+ 'freq' => '12',
+ 'pkg_svc1' => '0',
+ 'pkg_svc2' => '1',
+ 'pkg_svc3' => '0',
+ 'pkg_svc4' => '1',
+ 'pkg_svc5' => '1',
+ },
+ 'location' => 'browse/part_pkg.cgi',
+ },
+ { 'url' => 'edit/process/part_pkg.cgi',
+ 'params' => {
+ 'pkgpart' => '',
+ 'pkg' => 'Business POP mailbox',
+ 'comment' => '$10/setup, $5/month',
+ 'setup' => '10',
+ 'recur' => '5',
+ 'freq' => '1',
+ 'pkg_svc1' => '0',
+ 'pkg_svc2' => '0',
+ 'pkg_svc3' => '1',
+ 'pkg_svc4' => '0',
+ 'pkg_svc5' => '1',
+ },
+ 'location' => 'browse/part_pkg.cgi',
+ },
+ { 'url' => 'edit/process/part_pkg.cgi',
+ 'params' => {
+ 'pkgpart' => '',
+ 'pkg' => 'UNIX shell',
+ 'comment' => '$20/setup, $9.99/month',
+ 'setup' => '20',
+ 'recur' => '9.99',
+ 'freq' => '1',
+ 'pkg_svc1' => '1',
+ 'pkg_svc2' => '0',
+ 'pkg_svc3' => '0',
+ 'pkg_svc4' => '0',
+ 'pkg_svc5' => '0',
+ },
+ 'location' => 'browse/part_pkg.cgi',
+ },
+ { 'url' => 'edit/process/part_pkg.cgi',
+ 'params' => {
+ 'pkgpart' => '',
+ 'pkg' => 'Point-to-point T1',
+ 'comment' => '$1000/setup, $1000/month',
+ 'setup' => '1000',
+ 'recur' => '1000',
+ 'freq' => '1',
+ 'pkg_svc1' => '0',
+ 'pkg_svc2' => '0',
+ 'pkg_svc3' => '5',
+ 'pkg_svc4' => '1',
+ 'pkg_svc5' => '5',
+ },
+ 'location' => 'browse/part_pkg.cgi',
+ },
+ { 'url' => 'edit/process/part_pkg.cgi',
+ 'params' => {
+ 'pkgpart' => '',
+ 'pkg' => 'Cisco 2501 Router',
+ 'comment' => '$2500',
+ 'setup' => '2500',
+ 'recur' => '0',
+ 'freq' => '0',
+ 'pkg_svc1' => '0',
+ 'pkg_svc2' => '0',
+ 'pkg_svc3' => '0',
+ 'pkg_svc4' => '0',
+ 'pkg_svc5' => '0',
+ },
+ 'location' => 'browse/part_pkg.cgi',
+ },
+
+ { 'url' => 'edit/process/agent_type.cgi',
+ 'params' => {
+ 'typenum' => '',
+ 'atype' => 'Internal Sales',
+ 'pkgpart1' => 'ON',
+ 'pkgpart2' => 'ON',
+ 'pkgpart3' => 'ON',
+ 'pkgpart4' => 'ON',
+ 'pkgpart5' => 'ON',
+ 'pkgpart6' => 'ON',
+ 'pkgpart7' => 'ON',
+ 'pkgpart8' => 'ON',
+ 'pkgpart9' => 'ON',
+ },
+ 'location' => 'browse/agent_type.cgi',
+ },
+
+ { 'url' => 'edit/process/agent.cgi',
+ 'params' => {
+ 'agentnum' => '',
+ 'agent' => 'Internal Sales',
+ 'typenum' => '1',
+ 'freq' => '',
+ 'prog' => '',
+ },
+ 'location' => 'browse/agent.cgi',
+ },
+
+ { 'url' => 'edit/process/part_referral.cgi',
+ 'params' => {
+ 'refnum' => '',
+ 'referral' => 'Another customer',
+ },
+ 'location' => 'browse/part_referral.cgi',
+ },
+ { 'url' => 'edit/process/part_referral.cgi',
+ 'params' => {
+ 'refnum' => '',
+ 'referral' => 'Newspaper ad',
+ },
+ 'location' => 'browse/part_referral.cgi',
+ },
+
+ { 'url' => 'edit/process/svc_acct_pop.cgi',
+ 'params' => {
+ 'popnum' => '',
+ 'city' => 'Line Lexington',
+ 'state' => 'PA',
+ 'ac' => '215',
+ 'exch' => '996',
+ },
+ 'location' => 'browse/svc_acct_pop.cgi',
+ },
+ { 'url' => 'edit/process/svc_acct_pop.cgi',
+ 'params' => {
+ 'popnum' => '',
+ 'city' => 'Oakland',
+ 'state' => 'CA',
+ 'ac' => '510',
+ 'exch' => '208',
+ },
+ 'location' => 'browse/svc_acct_pop.cgi',
+ },
+
+ { 'url' => 'edit/process/cust_main.cgi',
+ 'params' => {
+ 'custnum' => '',
+ 'agentnum' => '1',
+ 'refnum' => '1',
+ 'last' => 'Hogan',
+ 'first' => 'Shawn D.',
+ 'ss' => '',
+ 'company' => 'Digital Point Solutions',
+ 'address1' => '3570 Tony Drive',
+ 'address2' => '',
+ 'city' => 'San Diego',
+ 'state' => 'CA / US',
+ 'zip' => '92122-2307',
+ 'daytime' => '',
+ 'night' => '',
+ 'fax' => '',
+ 'tax' => '',
+ 'invoicing_list_POST' => '',
+ 'invoicing_list' => '',
+ 'payby' => 'BILL',
+ 'CARD_payinfo' => '',
+ 'CARD_month' => '1',
+ 'CARD_year' => '1999',
+ 'CARD_payname' => '',
+ 'BILL_payinfo' => '',
+ 'BILL_month' => '12',
+ 'BILL_year' => '2037',
+ 'BILL_payname' => 'Accounts Payable',
+ 'COMP_payinfo' => '',
+ 'COMP_month' => '1',
+ 'COMP_year' => '1999',
+ 'pkgpart_svcpart' => '1_2',
+ 'username' => 'cyborg',
+ '_password' => '',
+ 'popnum' => '1',
+ 'otaker' => 'example',
+ },
+ 'location' => 'view/cust_main.cgi?1',
+ },
+ { 'url' => 'edit/process/cust_main.cgi',
+ 'params' => {
+ 'custnum' => '',
+ 'agentnum' => '1',
+ 'refnum' => '2',
+ 'last' => 'Ford',
+ 'first' => 'Bill',
+ 'ss' => '',
+ 'company' => 'Boardtown Corporation',
+ 'address1' => '116 East Main Street',
+ 'address2' => '',
+ 'city' => 'Starkville',
+ 'state' => 'MS / US',
+ 'zip' => '39759',
+ 'daytime' => '',
+ 'night' => '',
+ 'fax' => '',
+ 'tax' => '',
+ 'invoicing_list_POST' => '',
+ 'invoicing_list' => '',
+ 'payby' => 'BILL',
+ 'CARD_payinfo' => '',
+ 'CARD_month' => '1',
+ 'CARD_year' => '1999',
+ 'CARD_payname' => '',
+ 'BILL_payinfo' => '',
+ 'BILL_month' => '12',
+ 'BILL_year' => '2037',
+ 'BILL_payname' => 'Accounts Payable',
+ 'COMP_payinfo' => '',
+ 'COMP_month' => '1',
+ 'COMP_year' => '1999',
+ 'pkgpart_svcpart' => '3_3',
+ 'username' => 'billf',
+ '_password' => '',
+ 'popnum' => '',
+ 'otaker' => 'example',
+ },
+ 'location' => 'view/cust_main.cgi?2',
+ },
+
+
+ );
+}
+